Ø•”~ TIN-1_22.BCKlŽÐ TIN-1_22.BCKHBACKUP/LOG [SRC.TIN-1_22...]*.*; $1$DUA4:[ANONYMOUS.TIN]TIN-1_22.BCK/SAV MCQUILLIN /€@[Ï]“—V5.5 _HOBBES::  _$1$DUA4: V5.5-2 ~ yð*[SRC.TIN-1_22]$M$AKEFILE.;1+,e.-//€ 4-- -d0@î123KÿPWO.56`D.t…—7ÐU^1—89€]V‚—G/€HªJÿZ# Makefile for tin - for tin compiler flag options read INSTALL and README. # # Options that may need changing. For advanced options read the INSTALL file. # CC = cc COPTS = -c -O #CC = gcc #COPTS = -c -g # LD has to be changed to ln for AmigaDOS LD = $(CC) YACC = yacc #YACC = bison -y #DEBUG = DEBUG = -g -DDEBUG # Where are your news libdir & spooldir? LIBDIR = /usr/lib/news SPOOLDIR= /usr/spool/news NOVROOTDIR= $(SPOOLDIR) # Where do you want the binary & manual page installed? INS_BINARY_DIR = /usr/local/bin INS_DAEMON_DIR = $(LIBDIR) INS_MANUAL_DIR = /usr/local/man/man INS_MANUAL_EXT = 1 # From: address in posted articles (don't use both - read the INSTALL file) NNTP_INEWS_GATEWAY= NNTP_INEWS_DOMAIN= #.erlm.siemens.de # Default nntp server (can be overridden by NNTPSERVER environment variable) NNTP_DEFAULT_SERVER=# news.erlm.siemens.de # Use INN clientlibs config functions (add -DUSE_INN_NNTPLIB to COPTS line) INN_NNTPLIB= AMIGA_COPTS=-so -wc -m0s -DM_AMIGA -DSYSV -DSLOW_SCREEN_UPDATE \ -DNO_PIPING -DNO_SHELL_ESCAPE -DAMIGA_BBS -DLIBDIR=""uulib:"" \ -DSPOOLDIR=""uunews:"" PROJECT = tin EXE = tin EXED = tind MAKE = make SHELL = /bin/sh STRIP = strip STRIP2 = mcs -d #ROFF = nroff -man ROFF = groff -Tascii -man #BASE_VER= 1.21/tin-1.21 BASE_VER= 170993 VER = 1.22 MAIL_ADDR = "iain.lea@erlm.siemens.de" HFILES = config.h tin.h extern.h nntplib.h proto.h stpwatch.h amiga.h os_2.h \ win32.h CFILES = active.c amiga.c art.c curses.c debug.c envarg.c feed.c getline.c \ group.c hashstr.c help.c inews.c init.c kill.c lang.c mail.c \ main.c memory.c misc.c newsrc.c nntplib.c open.c os_2.c page.c \ parsdate.y post.c prompt.c rcfile.c save.c screen.c search.c \ select.c sigfile.c signal.c spooldir.c strftime.c thread.c \ wildmat.c win32.c xref.c OFILES = active.o amiga.o art.o curses.o debug.o envarg.o feed.o getline.o \ group.o hashstr.o help.o inews.o init.o kill.o lang.o mail.o \ main.o memory.o misc.o newsrc.o nntplib.o open.o os_2.o page.o \ parsdate.o post.o prompt.o rcfile.o save.o screen.o search.o \ select.o sigfile.o signal.o spooldir.o strftime.o thread.o \ wildmat.o win32.o xref.o SUPPORT = Makefile Makefile.ami Makefile.bcc Makefile.icc MANIFEST README \ README.AMI README.OS2 CHANGES INSTALL HACKERS TODO FTP \ *.[13] $(EXE).nrf $(EXE).lsm actived.c NNTP_PATCH = README.NNTP INSTALL.NNTP common.patch server.patch xindex.c \ xmotd.c xoverview.c xuser.c ALL_FILES = $(SUPPORT) $(NNTP_PATCH) $(HFILES) patchlev.h $(CFILES) LINTFLAGS=-a -c -h -n -x all: @echo "Makefile for the TIN v$(VER) Usenet newsreader. Configuration:" @echo " " @echo " Compiler=[$(CC)] Copts=[$(COPTS)] INN Lib=[$(INN_NNTPLIB)]" @echo " Install Bindir=[$(INS_BINARY_DIR)] Mandir=[$(INS_MANUAL_DIR)$(INS_MANUAL_EXT)] Manext=[$(INS_MANUAL_EXT)]" @echo " News Lib=[$(LIBDIR)] Spool=[$(SPOOLDIR)] Nov=[$(NOVROOTDIR)]" @echo " News Gateway=[$(NNTP_INEWS_GATEWAY)] Domain=[$(NNTP_INEWS_DOMAIN)] Server=[$(NNTP_DEFAULT_SERVER)]" @echo " " @echo "If the above options are OK make one of the following targets:" @echo " " @echo " make bsd [ BSD[I] / DGUX / NeXT / OSF1 / Pyramid / SunOS / Ultrix (nntp)]" @echo " make sysv [ SysV / HPUX 7&8 ] make sysvr4 [ SysVR4 / HPUX 9 ]" @echo " make aix [ IBM AIX (nntp) ] make amiga [ AmigaDOS ]" @echo " make apollo [ Apollo DomainOS ] make coherent [ Coherent 4.0 ]" @echo " make dynix [ Sequent DYNIX (nntp) ] make irix [ SGI Irix ]" @echo " make linux [ Linux (nntp) ] make minix [ Minix 386 ]" @echo " make mips [ Mips / CDC EPIX ] make ptx [ Sequent PTX ]" @echo " make qnx [ QNX 4.1 ] make sco [ SCO Unix ]" @echo " make sinix [ SNI Sinix ] make tower [ NCR Tower]" @echo " make xenix [ SCO Xenix 386 ]" @echo " " @echo "Note that targets marked with '(nntp)' have -DNNTP_ABLE defined automatically." @echo " " .c.o: $(CC) $(CFLAGS) $*.c # Uncomment for COHERENT os #.c.y: # $(YACC) $*.y # For IBM AIX aix: @echo "Compiling $(EXE) v$(VER) for IBM AIX..." @$(MAKE) CC=$(CC) CFLAGS='$(COPTS) -DSYSV -DRS6000 \ -DNNTP_INEWS_GATEWAY=\"$(NNTP_INEWS_GATEWAY)\" \ -DNNTP_INEWS_DOMAIN=\"$(NNTP_INEWS_DOMAIN)\" \ -DNNTP_DEFAULT_SERVER=\"$(NNTP_DEFAULT_SERVER)\" \ -DLIBDIR=\"$(LIBDIR)\" \ -DSPOOLDIR=\"$(SPOOLDIR)\" \ -DNOVROOTDIR=\"$(NOVROOTDIR)\"' \ LIBS="-lcurses -ltermcap $(INN_NNTPLIB)" \ EXE=tin linkit # For Commodore AmigaOS amiga: @echo "Compiling $(EXE) v$(VER) for AmigaDOS (Manx-C 5.2)..." $(MAKE) CC=$(CC) "CFLAGS=$(AMIGA_COPTS)" LIBS=-lc EXE=tin linkit # For Apollo apollo: @echo "Compiling $(EXE) v$(VER) for Apollo..." @$(MAKE) CC=$(CC) CFLAGS='$(COPTS) \ -DNNTP_INEWS_GATEWAY=\"$(NNTP_INEWS_GATEWAY)\" \ -DNNTP_INEWS_DOMAIN=\"$(NNTP_INEWS_DOMAIN)\" \ -DNNTP_DEFAULT_SERVER=\"$(NNTP_DEFAULT_SERVER)\" \ -DLIBDIR=\"$(LIBDIR)\" \ -DSPOOLDIR=\"$(SPOOLDIR)\" \ -DNOVROOTDIR=\"$(NOVROOTDIR)\"' \ LIBS="-lcurses -ltermcap $(INN_NNTPLIB)" \ EXE=tin linkit # For BSD-derived systems bsd: @echo "Compiling $(EXE) v$(VER) for BSD/BSDI/DGUX/NeXT/OSF1/Pyramid/SunOS/Ultrix..." @$(MAKE) CC=$(CC) CFLAGS='$(COPTS) -DBSD \ -DNNTP_INEWS_GATEWAY=\"$(NNTP_INEWS_GATEWAY)\" \ -DNNTP_INEWS_DOMAIN=\"$(NNTP_INEWS_DOMAIN)\" \ -DNNTP_DEFAULT_SERVER=\"$(NNTP_DEFAULT_SERVER)\" \ -DLIBDIR=\"$(LIBDIR)\" \ -DSPOOLDIR=\"$(SPOOLDIR)\" \ -DNOVROOTDIR=\"$(NOVROOTDIR)\"' \ LIBS="-lcurses -ltermcap $(INN_NNTPLIB)" \ EXE=tin linkit # For Coherent 4.0 # NETLIBS="-lsocket" \ # coherent: @echo "Compiling $(EXE) v$(VER) for Coherent 4.0..." @$(MAKE) CC=$(CC) CFLAGS='-c -DSYSV \ -DNNTP_INEWS_GATEWAY=\"$(NNTP_INEWS_GATEWAY)\" \ -DNNTP_INEWS_DOMAIN=\"$(NNTP_INEWS_DOMAIN)\" \ -DNNTP_DEFAULT_SERVER=\"$(NNTP_DEFAULT_SERVER)\" \ -DLIBDIR=\"$(LIBDIR)\" \ -DSPOOLDIR=\"$(SPOOLDIR)\" \ -DNOVROOTDIR=\"$(NOVROOTDIR)\"' \ LIBS="-lterm $(INN_NNTPLIB)" \ LFLAGS= EXE=tin linkit # For Sequent DYNIX dynix: @echo "Compiling $(EXE) v$(VER) for Sequent DYNIX..." @$(MAKE) CC=$(CC) CFLAGS='$(COPTS) -DBSD \ -DNNTP_INEWS_GATEWAY=\"$(NNTP_INEWS_GATEWAY)\" \ -DNNTP_INEWS_DOMAIN=\"$(NNTP_INEWS_DOMAIN)\" \ -DNNTP_DEFAULT_SERVER=\"$(NNTP_DEFAULT_SERVER)\" \ -DLIBDIR=\"$(LIBDIR)\" \ -DSPOOLDIR=\"$(SPOOLDIR)\" \ -DNOVROOTDIR=\"$(NOVROOTDIR)\"' \ LIBS="-lcurses -ltermcap -lseq $(INN_NNTPLIB)" \ EXE=tin linkit # For SGI Irix irix: @echo "Compiling $(EXE) v$(VER) for SGI Irix..." @$(MAKE) CC=$(CC) CFLAGS='$(COPTS) -cckr -DSYSV \ -DNNTP_INEWS_GATEWAY=\"$(NNTP_INEWS_GATEWAY)\" \ -DNNTP_INEWS_DOMAIN=\"$(NNTP_INEWS_DOMAIN)\" \ -DNNTP_DEFAULT_SERVER=\"$(NNTP_DEFAULT_SERVER)\" \ -DLIBDIR=\"$(LIBDIR)\" \ -DSPOOLDIR=\"$(SPOOLDIR)\" \ -DNOVROOTDIR=\"$(NOVROOTDIR)\"' \ LIBS="-lsun -lcurses -ltermcap $(INN_NNTPLIB)" \ EXE=tin linkit # For Linux linux: @echo "Compiling $(EXE) v$(VER) for Linux (NNTP Ready)..." @$(MAKE) CC=$(CC) CFLAGS='$(COPTS) -static -DSYSV \ -DNNTP_INEWS_GATEWAY=\"$(NNTP_INEWS_GATEWAY)\" \ -DNNTP_INEWS_DOMAIN=\"$(NNTP_INEWS_DOMAIN)\" \ -DNNTP_DEFAULT_SERVER=\"$(NNTP_DEFAULT_SERVER)\" \ -DLIBDIR=\"$(LIBDIR)\" \ -DSPOOLDIR=\"$(SPOOLDIR)\" \ -DNOVROOTDIR=\"$(NOVROOTDIR)\"' \ LIBS="-lcurses -ltermcap $(INN_NNTPLIB)" \ EXE=tin linkit # For Minix 386 minix: @echo "Compiling $(EXE) v$(VER) for Minix 386..." @$(MAKE) CC=$(CC) CFLAGS='$(COPTS) -DMINIX -D_POSIX_SOURCE \ -DNNTP_INEWS_GATEWAY=\"$(NNTP_INEWS_GATEWAY)\" \ -DNNTP_INEWS_DOMAIN=\"$(NNTP_INEWS_DOMAIN)\" \ -DNNTP_DEFAULT_SERVER=\"$(NNTP_DEFAULT_SERVER)\" \ -DLIBDIR=\"$(LIBDIR)\" \ -DSPOOLDIR=\"$(SPOOLDIR)\" \ -DNOVROOTDIR=\"$(NOVROOTDIR)\"' \ LIBS="-lcurses $(INN_NNTPLIB)" \ EXE=tin linkit chmem +131072 $(EXE) # For Mips/CDC EPIX mips: @echo "Compiling $(EXE) v$(VER) for Mips/CDC EPIX..." @$(MAKE) CC=$(CC) CFLAGS='$(COPTS) -DBSD -DEPIX -systype bsd43 \ -DNNTP_INEWS_GATEWAY=\"$(NNTP_INEWS_GATEWAY)\" \ -DNNTP_INEWS_DOMAIN=\"$(NNTP_INEWS_DOMAIN)\" \ -DNNTP_DEFAULT_SERVER=\"$(NNTP_DEFAULT_SERVER)\" \ -DLIBDIR=\"$(LIBDIR)\" \ -DSPOOLDIR=\"$(SPOOLDIR)\" \ -DNOVROOTDIR=\"$(NOVROOTDIR)\"' \ LIBS="-L/bsd43/usr/lib -lcurses -ltermcap -lc $(INN_NNTPLIB)" \ EXE=tin linkit # For Sequent PTX ptx: @echo "Compiling $(EXE) v$(VER) for Sequent PTX..." @$(MAKE) CC=$(CC) CFLAGS='$(COPTS) -DPTX \ -DNNTP_INEWS_GATEWAY=\"$(NNTP_INEWS_GATEWAY)\" \ -DNNTP_INEWS_DOMAIN=\"$(NNTP_INEWS_DOMAIN)\" \ -DNNTP_DEFAULT_SERVER=\"$(NNTP_DEFAULT_SERVER)\" \ -DLIBDIR=\"$(LIBDIR)\" \ -DSPOOLDIR=\"$(SPOOLDIR)\" \ -DNOVROOTDIR=\"$(NOVROOTDIR)\"' \ LIBS="-lcurses -ltermcap" \ NETLIBS="-lsocket -linet -lnsl_s $(INN_NNTPLIB)" \ EXE=tin linkit # For QNX qnx: @echo "Compiling $(EXE) v$(VER) for QNX 4.1 (Watcom C 8.5E)..." @$(MAKE) CC=$(CC) CFLAGS='$(COPTS) -2 -ml -M -fi=unix.h -Wc,-zt200 -D_POSIX_SOURCE_ -DQNX4 \ -DNNTP_INEWS_GATEWAY=\"$(NNTP_INEWS_GATEWAY)\" \ -DNNTP_INEWS_DOMAIN=\"$(NNTP_INEWS_DOMAIN)\" \ -DNNTP_DEFAULT_SERVER=\"$(NNTP_DEFAULT_SERVER)\" \ -DLIBDIR=\"$(LIBDIR)\" \ -DSPOOLDIR=\"$(SPOOLDIR)\" \ -DNOVROOTDIR=\"$(NOVROOTDIR)\"' \ LIBS="-lcurses $(INN_NNTPLIB)" \ LFLAGS="-Wc,-zt200 -2 -ml -M -N24K '-Wl,op H=1k'" \ EXE=tin linkit # For SCO Unix # NETLIBS="-lnsl_s -lsocket" \ # sco: @echo "Compiling $(EXE) v$(VER) for SCO Unix..." @$(MAKE) CC=$(CC) CFLAGS='$(COPTS) -DSYSV -DSCO_UNIX -UM_XENIX \ -DNNTP_INEWS_GATEWAY=\"$(NNTP_INEWS_GATEWAY)\" \ -DNNTP_INEWS_DOMAIN=\"$(NNTP_INEWS_DOMAIN)\" \ -DNNTP_DEFAULT_SERVER=\"$(NNTP_DEFAULT_SERVER)\" \ -DLIBDIR=\"$(LIBDIR)\" \ -DSPOOLDIR=\"$(SPOOLDIR)\" \ -DNOVROOTDIR=\"$(NOVROOTDIR)\"' \ LIBS="-lcurses -lgen -lc_s $(INN_NNTPLIB)" \ EXE=tin linkit # For SNI Sinix sinix: @echo "Compiling $(EXE) v$(VER) for SNI Sinix..." @$(MAKE) CC=$(CC) CFLAGS='$(COPTS) \ -DNNTP_INEWS_GATEWAY="\\"$(NNTP_INEWS_GATEWAY)\\" \ -DNNTP_INEWS_DOMAIN="\\"$(NNTP_INEWS_DOMAIN)\\" \ -DNNTP_DEFAULT_SERVER=\"$(NNTP_DEFAULT_SERVER)\" \ -DLIBDIR=\\"$(LIBDIR)\\" \ -DSPOOLDIR=\\"$(SPOOLDIR)\\" \ -DNOVROOTDIR=\\"$(NOVROOTDIR)\\"' \ LIBS="-lcurses $(INN_NNTPLIB)" \ EXE=tin linkit # For System V # NETLIBS="-lnet -lnsl_s" \ # sysv: @echo "Compiling $(EXE) v$(VER) for System V..." @$(MAKE) CC=$(CC) CFLAGS='$(COPTS) -DSYSV \ -DNNTP_INEWS_GATEWAY=\"$(NNTP_INEWS_GATEWAY)\" \ -DNNTP_INEWS_DOMAIN=\"$(NNTP_INEWS_DOMAIN)\" \ -DNNTP_DEFAULT_SERVER=\"$(NNTP_DEFAULT_SERVER)\" \ -DLIBDIR=\"$(LIBDIR)\" \ -DSPOOLDIR=\"$(SPOOLDIR)\" \ -DNOVROOTDIR=\"$(NOVROOTDIR)\"' \ LIBS="-lcurses -ltermcap $(INN_NNTPLIB)" \ EXE=tin linkit # For System V Release 4 # NETLIBS="-lnsl -lsocket" \ # sysvr4: @echo "Compiling $(EXE) v$(VER) for System V Release 4..." @$(MAKE) CC=$(CC) CFLAGS='$(COPTS) -DSVR4 \ -DNNTP_INEWS_GATEWAY=\"$(NNTP_INEWS_GATEWAY)\" \ -DNNTP_INEWS_DOMAIN=\"$(NNTP_INEWS_DOMAIN)\" \ -DNNTP_DEFAULT_SERVER=\"$(NNTP_DEFAULT_SERVER)\" \ -DLIBDIR=\"$(LIBDIR)\" \ -DSPOOLDIR=\"$(SPOOLDIR)\" \ -DNOVROOTDIR=\"$(NOVROOTDIR)\"' \ LIBS="-lcurses -ltermcap $(INN_NNTPLIB)" \ EXE=tin linkit # For NCR Tower # NETLIBS="-lnet -lnsl_s" \ # tower: @echo "Compiling $(EXE) v$(VER) for NCR Tower..." @$(MAKE) CC=$(CC) CFLAGS='$(COPTS) -DSYSV -DNCR -DISTRING \ -DNNTP_INEWS_GATEWAY=\"$(NNTP_INEWS_GATEWAY)\" \ -DNNTP_INEWS_DOMAIN=\"$(NNTP_INEWS_DOMAIN)\" \ -DNNTP_DEFAULT_SERVER=\"$(NNTP_DEFAULT_SERVER)\" \ -DLIBDIR=\"$(LIBDIR)\" \ -DSPOOLDIR=\"$(SPOOLDIR)\" \ -DNOVROOTDIR=\"$(NOVROOTDIR)\"' \ LIBS="-lcurses -ltermcap $(INN_NNTPLIB)" \ EXE=tin linkit # For Xenix 386 # NETLIBS="-lsocket" \ # xenix: @echo "Compiling $(EXE) v$(VER) for Xenix 386..." @$(MAKE) CC=$(CC) CFLAGS='-c -Zi -DSYSV \ -DNNTP_INEWS_GATEWAY="\\"$(NNTP_INEWS_GATEWAY)\\" \ -DNNTP_INEWS_DOMAIN="\\"$(NNTP_INEWS_DOMAIN)\\" \ -DNNTP_DEFAULT_SERVER="\\"$(NNTP_DEFAULT_SERVER)\\" \ -DLIBDIR=\\"$(LIBDIR)\\" \ -DSPOOLDIR=\\"$(SPOOLDIR)\\" \ -DNOVROOTDIR=\\"$(NOVROOTDIR)\\"' \ LIBS="-lcurses -ltinfo -lx $(INN_NNTPLIB)" \ LFLAGS=-Zi EXE=tin linkit # !!! THE FOLLOWING ARE SITE SPECIFIC - IGNORE !!! ccenter_obj: @echo "Compiling a CL target for SUN01 with NNTP ONLY..." #setopt program_name $(EXE) #setopt sys_load_flags -Dsun -Dsparc -I/usr/include -I. -L/usr/lib -lcurses -ltermcap #load -c -g -DBSD -DNNTP_ABLE -DNNTP_ONLY -lcurses -ltermcap $(CFILES) #link # @$(MAKE) CC=gcc CFLAGS='-c -O2 -Wall -DSYSV -DHAVE_ISPELL -DNNTP_ABLE -DDONT_HAVE_NNTP_EXTS -DNNTP_INEWS_GATEWAY=\"$(NNTP_INEWS_GATEWAY)\" -DNNTP_INEWS_DOMAIN=\"$(NNTP_INEWS_DOMAIN)\" -DDEBUG' \ # anl433: @echo "Compiling $(EXE) v$(VER) for ANL433 with NNTP..." @$(MAKE) CC=gcc CFLAGS='-c -O -Wall -DSYSV -DHAVE_MAIL_HANDLING -DHAVE_ISPELL -DNNTP_ABLE -DDEBUG \ -DDONT_HAVE_NNTP_EXTS \ -DNNTP_INEWS_GATEWAY=\"$(NNTP_INEWS_GATEWAY)\" \ -DNNTP_INEWS_DOMAIN=\"$(NNTP_INEWS_DOMAIN)\" \ -DNNTP_DEFAULT_SERVER=\"$(NNTP_DEFAULT_SERVER)\" \ -DLIBDIR=\"$(LIBDIR)\" \ -DSPOOLDIR=\"$(SPOOLDIR)\" \ -DNOVROOTDIR=\"$(NOVROOTDIR)\"' \ LIBS="-lcurses -ltermcap $(INN_NNTPLIB)" \ NETLIBS="-linet -lnsl_s" \ EXE=tin linkit daemon: @echo "Compiling $(EXE) v$(VER) for ANL433 with INDEX DAEMON..." @$(MAKE) CC=gcc CFLAGS='-c -O2 -DSYSV -DINDEX_DAEMON -DDEBUG' \ EXE=$(EXED) linkit dg01: @echo "Compiling $(EXE) v$(VER) for DG01 with NNTP ONLY..." @$(MAKE) CC=$(CC) CFLAGS='$(COPTS) -DBSD -DNNTP_ONLY -DDEBUG \ -DNNTP_INEWS_GATEWAY=\"$(NNTP_INEWS_GATEWAY)\" \ -DNNTP_INEWS_DOMAIN=\"$(NNTP_INEWS_DOMAIN)\" \ -DNNTP_DEFAULT_SERVER=\"$(NNTP_DEFAULT_SERVER)\" \ -DLIBDIR=\"$(LIBDIR)\" \ -DSPOOLDIR=\"$(SPOOLDIR)\" \ -DNOVROOTDIR=\"$(NOVROOTDIR)\"' \ LIBS="-lcurses -ltermcap $(INN_NNTPLIB)" \ EXE=tin linkit idefix: @echo "Compiling $(EXE) v$(VER) for IDEFIX with NNTP ONLY..." @$(MAKE) CC=$(CC) CFLAGS='$(COPTS) -DSYSV -DSCO_UNIX -UM_XENIX -DNNTP_ONLY \ -DNNTP_INEWS_GATEWAY=\"$(NNTP_INEWS_GATEWAY)\" \ -DNNTP_INEWS_DOMAIN=\"$(NNTP_INEWS_DOMAIN)\" \ -DNNTP_DEFAULT_SERVER=\"$(NNTP_DEFAULT_SERVER)\" \ -DLIBDIR=\"$(LIBDIR)\" \ -DSPOOLDIR=\"$(SPOOLDIR)\" \ -DNOVROOTDIR=\"$(NOVROOTDIR)\"' \ NETLIBS="-lnsl_s -lsocket" \ LIBS="-lcurses -lgen -lc_s $(INN_NNTPLIB)" \ EXE=tin linkit os2unix: @echo "Compiling $(EXE) v$(VER) for OS2UNIX with NNTP ONLY..." @$(MAKE) CC=$(CC) CFLAGS='$(COPTS) -DSYSV -DNNTP_ONLY -DDEBUG \ -DNNTP_INEWS_GATEWAY=\"$(NNTP_INEWS_GATEWAY)\" \ -DNNTP_INEWS_DOMAIN=\"$(NNTP_INEWS_DOMAIN)\" \ -DNNTP_DEFAULT_SERVER=\"$(NNTP_DEFAULT_SERVER)\" \ -DLIBDIR=\"$(LIBDIR)\" \ -DSPOOLDIR=\"$(SPOOLDIR)\" \ -DNOVROOTDIR=\"$(NOVROOTDIR)\"' \ LIBS="-lcurses -ltermcap -lx $(INN_NNTPLIB)" \ NETLIBS="-linet -lnsl_s" \ EXE=tin linkit mx331: @echo "Compiling $(EXE) v$(VER) for MX331 with NNTP ONLY..." @$(MAKE) CC=$(CC) CFLAGS='$(COPTS) -DSYSV -DNNTP_ONLY \ -DNNTP_INEWS_GATEWAY=\"$(NNTP_INEWS_GATEWAY)\" \ -DNNTP_INEWS_DOMAIN=\"$(NNTP_INEWS_DOMAIN)\" \ -DNNTP_DEFAULT_SERVER=\"$(NNTP_DEFAULT_SERVER)\" \ -DLIBDIR=\"$(LIBDIR)\" \ -DSPOOLDIR=\"$(SPOOLDIR)\" \ -DNOVROOTDIR=\"$(NOVROOTDIR)\"' \ LIBS="-lcurses $(INN_NNTPLIB)" \ EXE=tin linkit mx351: @echo "Compiling $(EXE) v$(VER) for MX351 with NNTP ONLY..." @$(MAKE) CC=$(CC) CFLAGS='$(COPTS) -DSVR4 -DNNTP_ONLY \ -DNNTP_INEWS_GATEWAY=\"$(NNTP_INEWS_GATEWAY)\" \ -DNNTP_INEWS_DOMAIN=\"$(NNTP_INEWS_DOMAIN)\" \ -DNNTP_DEFAULT_SERVER=\"$(NNTP_DEFAULT_SERVER)\" \ -DLIBDIR=\"$(LIBDIR)\" \ -DSPOOLDIR=\"$(SPOOLDIR)\" \ -DNOVROOTDIR=\"$(NOVROOTDIR)\"' \ NETLIBS="-lnsl -lsocket" \ LIBS="-lcurses -ltermlib $(INN_NNTPLIB)" \ EXE=tin linkit sparc10_1: @echo "Compiling $(EXE) v$(VER) for SPARC10 with NNTP ONLY..." @$(MAKE) CC=$(CC) CFLAGS='$(COPTS) -DBSD -DNNTP_ONLY \ -DNNTP_INEWS_GATEWAY=\"$(NNTP_INEWS_GATEWAY)\" \ -DNNTP_INEWS_DOMAIN=\"$(NNTP_INEWS_DOMAIN)\" \ -DNNTP_DEFAULT_SERVER=\"$(NNTP_DEFAULT_SERVER)\" \ -DLIBDIR=\"$(LIBDIR)\" \ -DSPOOLDIR=\"$(SPOOLDIR)\" \ -DNOVROOTDIR=\"$(NOVROOTDIR)\"' \ LIBS="-lcurses -ltermcap $(INN_NNTPLIB)" \ EXE=tin linkit sparc10cd: @echo "Compiling $(EXE) v$(VER) for SPARC10 with CDROM ABLE..." @$(MAKE) CC=$(CC) CFLAGS='$(COPTS) -DBSD -DCDROM_ABLE -DDEBUG' \ NNTPLIB="$(CDLIB)" \ LIBS="-lcurses -ltermcap $(INN_NNTPLIB)" \ EXE=cdtin linkit linkit: $(OFILES) @echo "Linking $(EXE) v$(VER)..." $(LD) $(LFLAGS) -o $(EXE) $(OFILES) $(NNTPLIB) $(NETLIBS) $(LIBS) @ls -l $(EXE) install: @echo "Installing $(EXE) v$(VER)..." @$(STRIP) $(EXE) @-$(STRIP2) $(EXE) @-mv $(EXE) $(INS_BINARY_DIR) @-rm $(INS_BINARY_DIR)/r$(EXE) @ln $(INS_BINARY_DIR)/$(EXE) $(INS_BINARY_DIR)/r$(EXE) @chmod 755 $(INS_BINARY_DIR)/$(EXE) @ls -l $(INS_BINARY_DIR)/$(EXE) $(INS_BINARY_DIR)/r$(EXE) @cp $(EXE).1 $(INS_MANUAL_DIR)$(INS_MANUAL_EXT)/$(EXE).$(INS_MANUAL_EXT) @chmod 644 $(INS_MANUAL_DIR)$(INS_MANUAL_EXT)/$(EXE).$(INS_MANUAL_EXT) install_setuid: @echo "Installing SETUID $(EXE) v$(VER)..." @$(STRIP) $(EXE) @-$(STRIP2) $(EXE) @-mv $(EXE) $(INS_BINARY_DIR) @chown news $(INS_BINARY_DIR)/$(EXE) @chgrp news $(INS_BINARY_DIR)/$(EXE) @-rm $(INS_BINARY_DIR)/r$(EXE) @ln $(INS_BINARY_DIR)/$(EXE) $(INS_BINARY_DIR)/r$(EXE) @su news -c "chmod 6755 $(INS_BINARY_DIR)/$(EXE)" @ls -l $(INS_BINARY_DIR)/$(EXE) $(INS_BINARY_DIR)/r$(EXE) @cp $(EXE).1 $(INS_MANUAL_DIR)$(INS_MANUAL_EXT)/$(EXE).$(INS_MANUAL_EXT) @chmod 644 $(INS_MANUAL_DIR)$(INS_MANUAL_EXT)/$(EXE).$(INS_MANUAL_EXT) install_daemon: @echo "Installing index daemon $(EXED) v$(VER)..." @$(STRIP) $(EXED) @-$(STRIP2) $(EXED) @-mv $(EXED) $(INS_DAEMON_DIR) @chown news $(INS_DAEMON_DIR)/$(EXED) @chmod 0755 $(INS_DAEMON_DIR)/$(EXED) @ls -l $(INS_DAEMON_DIR)/$(EXED) proto: @echo "Generating function prototypes for proto.h..." @echo "#if __STDC__" > PROTO.H @echo " " >> PROTO.H @cproto -e $(CFILES) >> PROTO.H @echo " " >> PROTO.H @echo "#else" >> PROTO.H @echo " " >> PROTO.H @cproto -e -f1 $(CFILES) >> PROTO.H @echo " " >> PROTO.H @echo "#endif" >> PROTO.H @-mv PROTO.H proto.h nroff: @echo "Creating nroff man page..." @-$(ROFF) $(EXE).1 > $(EXE).nrf manifest: @echo "Creating MANIFEST..." @echo "MANIFEST for $(PROJECT)-$(VER) (`date`)" > MANIFEST @echo "----------------------------------------------------" >> MANIFEST @wc -c $(ALL_FILES) >> MANIFEST shar: @echo "Generating shell archive..." @$(MAKE) nroff @$(MAKE) manifest @$(MAKE) chmod @shar -a -F -L75 -n $(PROJECT)-$(VER) -s $(MAIL_ADDR) \ -o ../$(PROJECT)-$(VER) $(ALL_FILES) uuencode: @$(MAKE) tar @echo "Uuencoding $(PROJECT).tar.Z..." @uuencode $(PROJECT).tar.Z $(PROJECT).tar.Z > $(PROJECT).tar.Z.uue @ls -l $(PROJECT).tar.Z.uue diff: @echo "Generating diffs against $(PROJECT)-$(BASE_VER)..." @$(MAKE) nroff @$(MAKE) manifest @$(MAKE) chmod @-mv -f $(PROJECT)-$(VER).diff $(PROJECT)-$(VER).diff- @-diff -rus ../$(BASE_VER) . > $(PROJECT)-$(VER).diff # @-diff -rcs ../$(BASE_VER) . > $(PROJECT)-$(VER).diff @ls -l $(PROJECT)-$(VER).diff patch: @$(MAKE) diff @echo "Generating patch against $(PROJECT)-$(BASE_VER)..." @-mv $(PROJECT)-$(VER).diff $(PROJECT)-$(VER).patch @shar -a -n $(PROJECT)-$(VER) -s $(MAIL_ADDR) -L75 \ -o ../patch-$(VER) $(PROJECT)-$(VER).patch @ls -l ../patch-$(VER).* tar: @echo "Generating compressed tar file..." @-rm $(PROJECT).tar $(PROJECT).tar.Z > /dev/null 2>&1 $(MAKE) chmod @tar cvf $(PROJECT).tar $(ALL_FILES) @echo "Compressing $(PROJECT).tar..." @compress $(PROJECT).tar @ls -l $(PROJECT).tar.Z gtar: @echo "Generating gzipped tar file..." @-rm $(PROJECT).t $(PROJECT).t.[gz] > /dev/null 2>&1 $(MAKE) chmod @tar cvf $(PROJECT).t $(ALL_FILES) @echo "Gzipping $(PROJECT).t..." @gzip $(PROJECT).t @ls -l $(PROJECT).t.[gz] ftptar: @echo "Creating FTP tar file with a directory of $(PROJECT)-$(VER)..." @-mkdir $(PROJECT)-$(VER) @chmod 755 $(PROJECT)-$(VER) @$(MAKE) chmod @cp $(ALL_FILES) $(PROJECT)-$(VER) @tar cvf $(PROJECT)-$(VER).tar $(PROJECT)-$(VER) @echo "Compressing $(PROJECT)-$(VER).tar..." @compress $(PROJECT)-$(VER).tar @ls -l $(PROJECT)-$(VER).tar.Z chmod: @chmod 644 $(ALL_FILES) zip: @echo "Generating zip archive file..." @-rm $(PROJECT).zip > /dev/null 2>&1 @zip $(PROJECT).zip $(ALL_FILES) @ls -l $(PROJECT).zip zoo: @echo "Generating zoo archive file..." @-rm $(PROJECT).zoo > /dev/null 2>&1 @zoo ah $(PROJECT).zoo $(ALL_FILES) @ls -l $(PROJECT).zoo tags: @echo "Generating tags (results in ./tags)..." @-rm tags @ctags $(HFILES) patchlev.h $(CFILES) lint: @echo "Linting source (results in ./LINT)..." @lint $(LINTFLAGS) -DNNTP_ABLE $(CFILES) > LINT clean: @echo "Cleaning..." -/bin/rm -f $(OFILES) clobber: @echo "Clobbering..." /bin/rm -f $(OFILES) $(EXE) tags cflow: @echo "Creating cflow for $(PROJECT)..." @cflow $(CFILES) > cflow.$(PROJECT) & cscope: @echo "Creating cscope database $(PROJECT)..." @cscope $(ALL_FILES) man: @echo "Printing $(EXE) manual..." @$(ROFF) $(EXE).1 | lpr print: for FILE in $(HFILES) patchlev.h $(CFILES) $(SUPPORT); do \ echo "Printing $$FILE..."; \ a2ps $$FILE | lpr; \ done actived: @echo "Compiling actived for AmigaDOS (Manx-C 5.2)..." $(CC) CFLAGS=$(AMIGA_COPTS) actived $(LD) actived -lc active.o: active.c $(HFILES) amiga.o: amiga.c $(HFILES) art.o: art.c $(HFILES) curses.o: curses.c $(HFILES) debug.o: debug.c $(HFILES) envarg.o: envarg.c $(HFILES) feed.o: feed.c $(HFILES) getline.o: getline.c $(HFILES) group.o: group.c $(HFILES) hashstr.o: hashstr.c $(HFILES) help.o: help.c $(HFILES) inews.o: inews.c $(HFILES) init.o: init.c $(HFILES) kill.o: kill.c $(HFILES) lang.o: lang.c $(HFILES) mail.o: mail.c $(HFILES) patchlev.h main.o: main.c $(HFILES) patchlev.h memory.o: memory.c $(HFILES) misc.o: misc.c $(HFILES) newsrc.o: newsrc.c $(HFILES) nntplib.o: nntplib.c $(HFILES) open.o: open.c $(HFILES) patchlev.h os_2.o: os_2.c $(HFILES) page.o: page.c $(HFILES) parsdate.o: parsdate.y $(HFILES) post.o: post.c $(HFILES) patchlev.h prompt.o: prompt.c $(HFILES) rcfile.o: rcfile.c $(HFILES) save.o: save.c $(HFILES) screen.o: screen.c $(HFILES) search.o: search.c $(HFILES) select.o: select.c $(HFILES) sigfile.o: sigfile.c $(HFILES) signal.o: signal.c $(HFILES) spooldir.o: spooldir.c $(HFILES) strftime.o: strftime.c $(HFILES) thread.o: thread.c $(HFILES) wildmat.o: wildmat.c win32.o: win32.c win32.h xref.o: xref.c $(HFILES) ð*[SRC.TIN-1_22]$M$AKEFILE.AMI;1+,f.//€ 4o-d0@î123KÿPWO56 yt…—7ÐU^1—89€]V‚—G/€HªJÿ CC = sc LD = $(CC) LFLAGS = link startup=cres EXE = tin MAKE = smake VER = 1.21 LIBS = CFLAGS = optimize stringmerge nostkchk parm=register optinlocal gst=tin.gst \ DEFINE M_AMIGA DEFINE SYSV DEFINE NO_SHELL_ESCAPE DEFINE NO_PIPING \ DEFINE SLOW_SCREEN_UPDATE DEFINE AMIGA_BBS DEFINE LIBDIR="uulib:" \ DEFINE DONT_LOG_USER DEFINE SPOOLDIR="uunews:" HFILES1 = config.h tin.h extern.h nntplib.h proto.h amiga.h os_2.h win32.h HFILES = tin.gst $(HFILES1) CFILES = active.c amiga.c art.c curses.c debug.c envarg.c feed.c getline.c \ group.c hashstr.c help.c inews.c init.c kill.c lang.c mail.c \ main.c memory.c misc.c newsrc.c nntplib.c open.c os_2.c page.c \ parsdate.y post.c prompt.c rcfile.c save.c screen.c search.c \ select.c sigfile.c signal.c spooldir.c strftime.c thread.c \ wildmat.c win32.c xref.c OFILES = active.o amiga.o art.o curses.o debug.o envarg.o feed.o getline.o \ group.o hashstr.o help.o inews.o init.o kill.o lang.o mail.o \ main.o memory.o misc.o newsrc.o nntplib.o open.o os_2.o page.o \ parsdate.o post.o prompt.o rcfile.o save.o screen.o search.o \ select.o sigfile.o signal.o spooldir.o strftime.o thread.o \ wildmat.o win32.o xref.o .c.o: $(CC) $(CFLAGS) $*.c tin: $(OFILES) @echo "Linking $(EXE) v$(VER)..." $(LD) $(LFLAGS) pname=$(EXE) $(OFILES) $(LIBS) @ls -l $(EXE) actived: @echo "Compiling actived for AmigaDOS ..." $(CC) CFLAGS=$(AMIGA_COPTS) actived $(LD) actived $(LIBS) tin.gst: $(HFILES1) $(CC) $(CFLAGS) makegst=tin.gst gst.h active.o: active.c $(HFILES) amiga.o: amiga.c $(HFILES) art.o: art.c $(HFILES) curses.o: curses.c $(HFILES) debug.o: debug.c $(HFILES) envarg.o: envarg.c $(HFILES) feed.o: feed.c $(HFILES) getline.o: getline.c $(HFILES) group.o: group.c $(HFILES) hashstr.o: hashstr.c $(HFILES) help.o: help.c $(HFILES) inews.o: inews.c $(HFILES) init.o: init.c $(HFILES) kill.o: kill.c $(HFILES) lang.o: lang.c $(HFILES) mail.o: mail.c $(HFILES) patchlev.h main.o: main.c $(HFILES) patchlev.h memory.o: memory.c $(HFILES) misc.o: misc.c $(HFILES) newsrc.o: newsrc.c $(HFILES) nntplib.o: nntplib.c $(HFILES) open.o: open.c $(HFILES) patchlev.h os_2.o: os_2.c $(HFILES) page.o: page.c $(HFILES) parsdate.o: parsdate.y $(HFILES) post.o: post.c $(HFILES) patchlev.h prompt.o: prompt.c $(HFILES) rcfile.o: rcfile.c $(HFILES) save.o: save.c $(HFILES) screen.o: screen.c $(HFILES) search.o: search.c $(HFILES) select.o: select.c $(HFILES) sigfile.o: sigfile.c $(HFILES) signal.o: signal.c $(HFILES) spooldir.o: spooldir.c $(HFILES) strftime.o: strftime.c $(HFILES) thread.o: thread.c $(HFILES) wildmat.o: wildmat.c win32.o: win32.c win32.h xref.o: xref.c $(HFILES) ð*[SRC.TIN-1_22]$M$AKEFILE.BCC;1+,g. //€ 4 -d0@î123KÿPWO 56`V¨t…—7ÐU^1—89€]V‚—G/€HªJÿ#============================================================= # # TIN.MAK - Makefile for project C:\tin\tin.prj # Created on 05/30/93 at 20:25 # #============================================================= .AUTODEPEND #============================================================= # Translator Definitions #============================================================= CC = bcc +TIN.CFG TASM = tasm.exe TLIB = tlib.exe TLINK = tlink LINK = link386 RC = brcc.exe RB = rc.exe LIBPATH = C:\BCOS2\LIB INCLUDEPATH = C:\BCOS2\INCLUDE;c:\curses;c:\tcpip\include;c:\tin #============================================================= # Implicit Rules #============================================================= .c.obj: $(CC) -c {$< } .cpp.obj: $(CC) -c {$< } .asm.obj: $(TASM) -Mx $*.asm,$*.obj .rc.res: $(RC) -r $*.rc #============================================================= # List Macros #============================================================= EXE_DEPENDENCIES = \ \curses\curseso.lib \ parsdate.obj \ curses.obj \ xref.obj \ win32.obj \ wildmat.obj \ thread.obj \ strftime.obj \ spooldir.obj \ signal.obj \ sigfile.obj \ select.obj \ search.obj \ screen.obj \ save.obj \ rcfile.obj \ prompt.obj \ post.obj \ page.obj \ os_2.obj \ open.obj \ nntplib.obj \ newsrc.obj \ misc.obj \ memory.obj \ main.obj \ mail.obj \ lang.obj \ kill.obj \ init.obj \ inews.obj \ help.obj \ hashstr.obj \ group.obj \ getline.obj \ feed.obj \ envarg.obj \ debug.obj \ art.obj \ active.obj #============================================================= # Explicit Rules #============================================================= tin.exe: tin.cfg $(EXE_DEPENDENCIES) $(TLINK) /s /c /Toe /ap /L$(LIBPATH) @&&| C:\BCOS2\LIB\C02.OBJ+ parsdate.obj+ curses.obj+ xref.obj+ win32.obj+ wildmat.obj+ thread.obj+ strftime.obj+ spooldir.obj+ signal.obj+ sigfile.obj+ select.obj+ search.obj+ screen.obj+ save.obj+ rcfile.obj+ prompt.obj+ post.obj+ page.obj+ os_2.obj+ open.obj+ nntplib.obj+ newsrc.obj+ misc.obj+ memory.obj+ main.obj+ mail.obj+ lang.obj+ kill.obj+ init.obj+ inews.obj+ help.obj+ hashstr.obj+ group.obj+ getline.obj+ feed.obj+ envarg.obj+ debug.obj+ art.obj+ active.obj tin,tin C:\BCOS2\LIB\C2.LIB+ C:\BCOS2\LIB\OS2.LIB+ c:\curses\curseso.lib+ C:\TCPIP\LIB\TCPIPDLL.LIB | #============================================================= # Individual File Dependencies #============================================================= parsdate.obj: tin.cfg parsdate.c curses.obj: tin.cfg curses.c xref.obj: tin.cfg xref.c win32.obj: tin.cfg win32.c wildmat.obj: tin.cfg wildmat.c thread.obj: tin.cfg thread.c strftime.obj: tin.cfg strftime.c spooldir.obj: tin.cfg spooldir.c signal.obj: tin.cfg signal.c sigfile.obj: tin.cfg sigfile.c select.obj: tin.cfg select.c search.obj: tin.cfg search.c screen.obj: tin.cfg screen.c save.obj: tin.cfg save.c rcfile.obj: tin.cfg rcfile.c prompt.obj: tin.cfg prompt.c post.obj: tin.cfg post.c page.obj: tin.cfg page.c os_2.obj: tin.cfg os_2.c open.obj: tin.cfg open.c nntplib.obj: tin.cfg nntplib.c newsrc.obj: tin.cfg newsrc.c misc.obj: tin.cfg misc.c memory.obj: tin.cfg memory.c main.obj: tin.cfg main.c mail.obj: tin.cfg mail.c lang.obj: tin.cfg lang.c kill.obj: tin.cfg kill.c init.obj: tin.cfg init.c inews.obj: tin.cfg inews.c help.obj: tin.cfg help.c hashstr.obj: tin.cfg hashstr.c group.obj: tin.cfg group.c getline.obj: tin.cfg getline.c feed.obj: tin.cfg feed.c envarg.obj: tin.cfg envarg.c debug.obj: tin.cfg debug.c art.obj: tin.cfg art.c active.obj: tin.cfg active.c pwd.obj: tin.cfg pwd.c #============================================================= # Compiler Configuration File #============================================================= tin.cfg: copy &&| -L$(LIBPATH) -I$(INCLUDEPATH) -vi- -DM_OS2 -DNNTP_ABLE -DDONT_REREAD_ACTIVE_FILE -DDEBUG -w-par -w-pro -w-pia -w-aus -w-rvl -w-rch | tin.cfg à,'5±~ TIN-1_22.BCKhd[SRC.TIN-1_22]$M$AKEFILE.ICC;1 øð*[SRC.TIN-1_22]$M$AKEFILE.ICC;1+,h.//€ 4ÿ-d0@î123KÿPWO56€Ëàt…—7€fî^1—89€]V‚—G/€HªJÿ*# IBM Developer's Workframe/2 Make File Creation run at 22:01:04 on 06/04/93 # Make File Creation run in directory: # C:\TIN; .SUFFIXES: .SUFFIXES: .c tin.exe: \ active.OBJ \ art.OBJ \ curses.OBJ \ debug.OBJ \ envarg.OBJ \ feed.OBJ \ getline.OBJ \ group.OBJ \ hashstr.OBJ \ help.OBJ \ inews.OBJ \ init.OBJ \ kill.OBJ \ lang.OBJ \ mail.OBJ \ main.OBJ \ memory.OBJ \ misc.OBJ \ newsrc.OBJ \ nntplib.OBJ \ open.OBJ \ os_2.OBJ \ page.OBJ \ parsdate.OBJ \ post.OBJ \ prompt.OBJ \ rcfile.OBJ \ save.OBJ \ screen.OBJ \ search.OBJ \ select.OBJ \ sigfile.OBJ \ signal.OBJ \ spooldir.OBJ \ strftime.OBJ \ thread.OBJ \ wildmat.OBJ \ win32.OBJ \ xref.OBJ \ MAKEFILE @REM @< active[] */ int reread_active_file = FALSE; int active_index = -1; /* * Compare two pointers to "group_t" structures - used in qsort. */ int cmp_group_p (group1, group2) group_p *group1; group_p *group2; { return (strcmp ((*group1)->name, (*group2)->name)); } /* * Compare two pointers to "notify_t" structures - used in qsort. */ int cmp_notify_p (notify1, notify2) notify_p *notify1; notify_p *notify2; { return (strcmp ((*notify1)->name, (*notify2)->name)); } /* * Get default array size for active[] from environment (AmigaDOS) * or just return the standard default. */ int get_active_num () { #ifdef ENV_VAR_GROUPS char *ptr; int num; ptr = getenv (ENV_VAR_GROUPS); if (ptr != (char *) 0) { num = atoi (ptr); return (num ? num : DEFAULT_ACTIVE_NUM); } #endif return DEFAULT_ACTIVE_NUM; } /* * Resync active file when SIGALRM signal received that * is triggered by alarm (reread_active_file_secs) call. */ void resync_active_file () { char old_group[PATH_LEN]; if (reread_active_file) { if (cur_groupnum >= 0 && group_top) { strcpy (old_group, active[my_group[cur_groupnum]].name); } else { old_group[0] = '\0'; } free_active_arrays (); max_active = get_active_num (); expand_active (); read_mail_active_file (); read_news_active_file (); read_attributes_file (); read_mailgroups_file (); read_newsgroups_file (); if (! read_cmd_line_groups ()) { read_newsrc (TRUE); toggle_my_groups (show_only_unread_groups, old_group); } set_groupname_len (FALSE); set_alarm_signal (); mail_setup (); group_selection_page (); } } /* * Find group name in active[] array and return index otherwise -1 */ int find_group_index (group) char *group; { int i = -1; long h; h = hash_groupname (group); i = group_hash[h]; /* * hash linked list chaining */ while (i >= 0) { if (strncmp (group, active[i].name, strlen (active[i].name)) == 0) { return (i); } i = active[i].next; } return (-1); } /* * parse line from news or mail active files */ int parse_active_line (line, max, min, moderated) char *line; long *max; long *min; char *moderated; { char *p, *q, *r; if (line[0] == '#' || line[0] == '\n') { return FALSE; } for (p = line; *p && *p != ' ' && *p != '\n'; p++) { continue; } if (*p != ' ') { error_message (txt_bad_active_file, line); return FALSE; } *p++ = '\0'; for (q = p; *q && *q != ' '; q++) { continue; } if (*q != ' ') { error_message (txt_bad_active_file, line); return FALSE;; } *q++ = '\0'; for (r = q; *r && *r != ' '; r++) { continue; } if (*r != ' ') { error_message (txt_bad_active_file, line); return FALSE; } *r++ = '\0'; if (*r) { strcpy (moderated, r); r = (char *) strchr (moderated, '\n'); if (*r) { *r = '\0'; } } *max = (long) atol (p); *min = (long) atol (q); return TRUE; } int parse_newsrc_active_line (fp, max, min, moderated, group) FILE *fp; long *max; long *min; char *moderated; char *group; { char *ptr, *s; char line[NNTP_STRLEN]; char buf[LEN]; while (fgets (buf, sizeof (buf), fp) != (char *) 0) { ptr = my_strpbrk (buf, ":!"); if (! ptr || *ptr != ':') { continue; } *ptr = '\0'; sprintf (line, "group %s", buf); put_server (line); debug_nntp ("parse_newsrc_active_line", buf); get_server (line, sizeof (line)); debug_nntp ("parse_newsrc_active_line", line); ptr = strchr (line, ' '); if (! ptr) { continue; } *ptr++ = '\0'; if (atoi (line) != OK_GROUP) { continue; } ptr = strchr (s=ptr, ' '); if (! ptr) { continue; } *ptr++ = '\0'; /* s now points to num of articles */ ptr = strchr (s=ptr, ' '); if (! ptr) { continue; } *ptr++ = '\0'; /* s now points to minimum article */ *min = atol (s); ptr = strchr (s=ptr, ' '); if (! ptr) { continue; } *ptr++ = '\0'; /* s now points to maximum article */ *max = atol (s); strcpy (group, ptr); strcpy (moderated, "n"); return TRUE; } return FALSE; } /* * Load the news active file into active[] and create copy * of active ~/.tin/active */ void read_news_active_file () { FILE *fp; char buf[LEN]; char moderated[PATH_LEN]; int i; long h, min, max; if ((update && update_fork) || ! update) { wait_message (txt_reading_news_active_file); } if (newsrc_active) { if ((fp = fopen (newsrc, "r")) == NULL) { if (cmd_line) { fputc ('\n', stderr); } error_message (txt_cannot_open, news_active_file); tin_done(1); } } else { if ((fp = open_news_active_fp ()) == NULL) { if (compiled_with_nntp) { sprintf (msg, txt_cannot_open_active_file, news_active_file, progname); error_message (msg, ""); } else { if (cmd_line) { fputc ('\n', stderr); } error_message (txt_cannot_open, news_active_file); } tin_done (1); } } if (num_active == -1) { num_active = 0; for (i = 0; i < TABLE_SIZE; i++) { group_hash[i] = -1; } } strcpy (moderated, "y"); while (1) { if (newsrc_active) { if (! parse_newsrc_active_line (fp, &max, &min, moderated, buf)) { break; } } else { if (fgets (buf, sizeof (buf), fp) == NULL) { break; } if (! parse_active_line (buf, &max, &min, moderated)) { continue; } } /* * Don't load group into active[] from active file if * 'x' junked group * '=' aliased group */ if (moderated[0] != 'x' && moderated[0] != '=') { /* * Load group into group hash table */ if (num_active >= max_active) { expand_active (); } h = hash_groupname (buf); if (group_hash[h] == -1) { group_hash[h] = num_active; } else { /* hash linked list chaining */ for (i=group_hash[h]; active[i].next >= 0; i=active[i].next) { if (strcmp(active[i].name, buf) == 0) { goto read_news_active_continue; /* kill dups */ } } if (strcmp(active[i].name, buf) == 0) goto read_news_active_continue; active[i].next = num_active; } /* * Load group info. */ active[num_active].type = GROUP_TYPE_NEWS; active[num_active].name = str_dup (buf); active[num_active].spooldir = spooldir; active[num_active].description = (char *) 0; active[num_active].max = max; active[num_active].min = min; active[num_active].moderated = moderated[0]; active[num_active].next = -1; /* hash chaining */ active[num_active].my_group = UNSUBSCRIBED; /* not in my_group[] yet */ active[num_active].unread = 0; active[num_active].newsrcmax = max; active[num_active].newsrcmin = min; active[num_active].newsrcsize = 0; active[num_active].newsrcupdate = FALSE; active[num_active].newsrc = NULL; #ifdef INDEX_DAEMON active[num_active].last_updated_time = 0L; #endif num_active++; } read_news_active_continue:; } fclose (fp); /* * exit if active file is empty */ if (! num_active) { error_message (txt_active_file_is_empty, news_active_file); tin_done (1); } if ((cmd_line && ! update && ! verbose) || (update && update_fork)) { wait_message ("\n"); } check_for_any_new_groups (); } /* * create ~/.tin/active if it does not exist (local news only) */ void backup_active (create) int create; { char buf[PATH_LEN]; FILE *fp; register int i; struct stat sb; joinpath (buf, rcdir, "active"); if (create) { if (stat (buf, &sb) != -1) { return; } } #ifdef VMS if ((fp = fopen (buf, "w", "fop=cif")) != (FILE *) 0) { #else if ((fp = fopen (buf, "w")) != (FILE *) 0) { #endif for (i = 0; i < num_active ; i++) { /* for each group */ fprintf (fp, "%s\n", active[i].name); } fclose (fp); chmod (buf, 0644); } } /* * Check for any newly created newsgroups. * * If reading news locally stat() the active file to get its * size otherwise do a LIST NEWGROUPS to the NNTP server */ void check_for_any_new_groups () { char old_active_file_server[LEN]; char old_active_file_attribute[LEN]; char buf[LEN], *ptr; FILE *fp = (FILE *) 0; group_p *sorted_active = (group_p *) 0; int group_not_found; int ch, num = 0; /* num == num_old_active groups */ int ch_default = 'n'; int update_old_active = FALSE; int max_old_active; int new_active_size; int old_active_size; long epoch; int compared; notify_p old_active = (notify_p) 0; notify_p *sorted_old_active = (notify_p *) 0; char *autosubscribe, *autounsubscribe; register int i, j; struct stat sb; struct tm *tm; if ((! check_for_new_newsgroups || (update && ! update_fork))) { return; } /* * reading news locally (local) or via NNTP (server name) */ if (read_news_via_nntp) { time (&epoch); tm = localtime (&epoch); sprintf (new_active_file_attribute, "%02d%02d%02d %02d%02d%02d", tm->tm_year, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); strcpy (new_active_file_server, nntp_server); max_old_active = 16; } else { backup_active (TRUE); strcpy (new_active_file_server, "local"); max_old_active = num_active; if (stat (news_active_file, &sb) >= 0) { sprintf (new_active_file_attribute, "%ld", sb.st_size); } } /* * find out if we have read news from here before otherwise -1 */ active_index = find_active_size_index (new_active_file_server); if (debug == 2) { if (active_index >= 0) { strcpy (old_active_file_server, active_size[active_index].server); strcpy (old_active_file_attribute, active_size[active_index].attribute); } else { strcpy (old_active_file_server, "UNKNOWN"); strcpy (old_active_file_attribute, "UNKNOWN"); } sprintf (msg, "Active size index=[%d] old=[%s %s] new=[%s %s]", active_index, old_active_file_server, old_active_file_attribute, new_active_file_server, new_active_file_attribute); error_message (msg, ""); sleep (2); } if (! read_news_via_nntp && active_index >= 0) { new_active_size = atoi (new_active_file_attribute); old_active_size = atoi (active_size[active_index].attribute); if (new_active_size <= old_active_size) { goto notify_groups_done; } } /* * Only check if spooldir is active news feed */ if (strcmp (spooldir_alias, "news") != 0) { goto notify_groups_done; } if ((fp = open_newgroups_fp (active_index)) == (FILE *) 0) { goto notify_groups_done; } Raw (TRUE); old_active = (notify_p) my_malloc ((unsigned) sizeof (struct t_notify) * max_old_active); if (old_active == (notify_p) 0) { error_message (txt_out_of_memory, progname); goto notify_groups_done; } while (fgets (buf, sizeof (buf), fp) != NULL) { if (buf[0] == '.') { break; } strncpy (old_active[num].name, buf, sizeof (old_active[num].name)); ptr = old_active[num].name; while (*ptr && *ptr != ' ' && *ptr != '\n') { ptr++; } *ptr = '\0'; old_active[num].visited = FALSE; num++; if (num >= max_old_active) { max_old_active= max_old_active + (max_old_active / 2); old_active= (notify_p) my_realloc( (char *) old_active, (unsigned) sizeof(struct t_notify) * max_old_active); if (old_active == (notify_p) 0) { error_message (txt_out_of_memory, progname); goto notify_groups_done; } } } /* * Check if there are user-set groups to be * automatically subscribed or unsubscribed. */ autosubscribe = getenv ("AUTOSUBSCRIBE"); autounsubscribe = getenv ("AUTOUNSUBSCRIBE"); if (read_news_via_nntp) { for (i = 0 ; i < num ; i++) { if (find_group_index (old_active[i].name) == -1) { continue; } if (! prompt_subscribe_group (old_active[i].name, autosubscribe, autounsubscribe)) { if (cmd_line) { printf ("\r\n"); fflush (stdout); } goto notify_groups_done; } } } else { wait_message (txt_checking_active_file); /* * The following code replaces the original check for new newsgroups, * a source of much aggravation. * * The original algorithm compared each group name in active to (on * average) 1/2 the groups in old_active, for ~N*N/2 string compares. * This works out to ~~ 8,000,000 comparisons for 4000 newsgroups. * * The new algorithm allocates an array of pointers to the active * and old_active array elements, sorts each pointer array with * quicksort, then scans through the two arrays in 1 pass; this takes * 2*N*Log2(N) string compares for the sorts, N for the final pass. * This should work out to ~~ 100,000 comparisons for the same 4000 * newsgroups, a BIG, BIG win. */ /* * Allocate arrays to be sorted */ sorted_active = (group_p *) my_malloc ( (unsigned) sizeof (group_p) * num_active); if (sorted_active == (group_p *) 0) { error_message (txt_out_of_memory, progname); goto notify_groups_done; } sorted_old_active = (notify_p *) my_malloc ( (unsigned) sizeof (notify_p) * num); if (sorted_old_active == (notify_p *) 0) { error_message (txt_out_of_memory, progname); goto notify_groups_done; } /* * Fill arrays to be sorted */ for (i = 0 ; i < num_active ; i++) { sorted_active[i] = &active[i]; } for (j = 0 ; j < num ; j++) { sorted_old_active[j] = &old_active[j]; } /* * Sort the arrays */ qsort (sorted_active, num_active, sizeof (group_p), cmp_group_p); qsort (sorted_old_active, num, sizeof (notify_p), cmp_notify_p); /* * Now do the pass through both arrays at once */ for (i = 0, j = 0 ; i < num_active ; i++) { group_not_found = TRUE; compared = 1; while ((j < num) && (0 > (compared = strcmp ( sorted_old_active[j]->name, sorted_active[i]->name)))) { j++; } if (compared == 0) { /* * found it so read in next group */ group_not_found = FALSE; sorted_old_active[j]->visited = TRUE; j++; } if (group_not_found == FALSE) { continue; } update_old_active = TRUE; /* * auto-subscribe/unsubscribe logic */ if (! prompt_subscribe_group (sorted_active[i]->name, autosubscribe, autounsubscribe)) { if (cmd_line) { printf ("\r\n"); fflush (stdout); } goto notify_groups_done; } } } if (cmd_line) { fputc ('\r', stdout); fflush (stdout); } CleartoEOLN(); if (! read_news_via_nntp) { /* * Look for bogus groups */ ch_default = 'y'; for (j = 0 ; j < num ; j++) { if (old_active[j].visited) { continue; } do { update_old_active= 1; fputc ('\r', stdout); CleartoEOLN (); printf (txt_delete_bogus_group, old_active[j].name, ch_default); fflush (stdout); ch = ReadCh (); if (ch == CR) { ch = ch_default; } } while (! strchr ("nqy\033", ch)); switch (ch) { case 'y': delete_group (old_active[j].name); break; case 'q': case ESC: goto notify_groups_done; case 'n': default: break; } printf ("\r\n"); fflush (stdout); } } /* * write active[] to ~/.tin/active (local spooldir) */ if (! read_news_via_nntp && update_old_active) { backup_active (FALSE); } notify_groups_done: if (fp != (FILE *) 0) { fclose (fp); } /* * update attribute field/create new entry with new size/date */ if (active_index >= 0) { if (active_size[active_index].attribute != (char *) 0) { free (active_size[active_index].attribute); active_size[active_index].attribute = (char *) 0; } active_size[active_index].attribute = str_dup (new_active_file_attribute); } else { sprintf (buf, "%s[%s]", new_active_file_server, new_active_file_attribute); load_active_size_info (buf); } /* * Free malloc'd arrays */ if (old_active != (notify_p) 0) { free ((char *) old_active); old_active = (notify_p) 0; } if (sorted_old_active != (notify_p *) 0) { free ((char *) sorted_old_active); sorted_old_active = (notify_p *) 0; } if (sorted_active != (group_p *) 0) { free ((char *) sorted_active); sorted_active = (group_p *) 0; } if (cmd_line) { Raw (FALSE); } } /* * prompt user if new group should be subscribed to */ int prompt_subscribe_group (group, autosubscribe, autounsubscribe) char *group; char *autosubscribe; char *autounsubscribe; { int ch, ch_default = 'n'; int idx; if ((autosubscribe != (char *) 0) && match_group_list (group, autosubscribe)) { idx = add_group (group, TRUE); subscribe (active[my_group[idx]].name, ':', my_group[idx], FALSE); return TRUE; } else if ((autounsubscribe != (char *) 0) && match_group_list (group, autounsubscribe)) { /* ignore this group */ return TRUE; } do { if (cmd_line) { fputc ('\r', stdout); CleartoEOLN (); } else { clear_message (); } printf (txt_subscribe_to_new_group, group, ch_default); fflush (stdout); ch = ReadCh (); if (ch == CR) { ch = ch_default; } } while (! strchr ("nqy\033", ch)); fputc (ch, stdout); fflush (stdout); switch (ch) { case 'y': idx = add_group (group, TRUE); subscribe (active[my_group[idx]].name, ':', my_group[idx], FALSE); break; case 'q': case ESC: return FALSE; case 'n': default: break; } if (cmd_line) { printf ("\r\n%s", txt_checking); fflush (stdout); } else { wait_message (txt_checking); } return TRUE; } int match_group_list (group, group_list) char *group; char *group_list; { char *separator; char pattern[LEN]; int accept, negate, list_len, group_len; accept = FALSE; list_len = strlen (group_list); /* * walk through comma-separated entries in list */ while (list_len > 0) { /* * find end/length of this entry */ separator = strchr (group_list, ','); if (separator != (char *) 0) { group_len = separator-group_list; } else { group_len = list_len; } if ((negate = ('!' == *group_list))) { /* * a '!' before the pattern inverts sense of match */ group_list++; group_len--; list_len--; } /* * copy out the entry and terminate it properly */ strncpy (pattern, group_list, group_len); pattern[group_len] = (char) 0; /* * do a regexp match using routines used in kill.c */ if (STR_MATCH(group, pattern)) { accept = ! negate; /* matched! */ } /* * now examine next entry if any */ if ((char) 0 != group_list[group_len]) { group_len++; /* skip the separator */ } group_list += group_len; list_len -= group_len; } return (accept); } /* * Per group attributes */ void set_default_attributes () { #ifndef INDEX_DAEMON register int i; for (i = 0; i < num_active ; i++) { active[i].attribute.maildir = default_maildir; active[i].attribute.savedir = default_savedir; active[i].attribute.sigfile = default_sigfile; active[i].attribute.organization = (default_organization[0] ? default_organization : (char *) 0); active[i].attribute.followup_to = (char *) 0; active[i].attribute.printer = default_printer; active[i].attribute.read_during_session = FALSE; active[i].attribute.show_only_unread = default_show_only_unread; active[i].attribute.thread_arts = default_thread_arts; active[i].attribute.sort_art_type = default_sort_art_type; active[i].attribute.show_author = default_show_author; active[i].attribute.auto_save= default_auto_save; active[i].attribute.batch_save = default_batch_save; active[i].attribute.delete_tmp_files = FALSE; active[i].attribute.post_proc_type = default_post_proc_type; } #endif /* INDEX_DAEMON */ } /* * Load the group attributes into active[].attribute from ~/.tin/attributes * * attribute.maildir = STRING * attribute.savedir = STRING * attribute.organization = STRING * attribute.sigfile = STRING * attribute.followup_to = STRING * attribute.printer = STRING * attribute.auto_save = ON/OFF * attribute.batch_save = ON/OFF * attribute.delete_tmp_files = ON/OFFЃ^vu~ TIN-1_22.BCK$d[SRC.TIN-1_22]ACTIVE.C;2Bx|0) * attribute.show_only_unread = ON/OFF * attribute.thread_arts = ON/OFF * attribute.show_author = NUM * 0=none, 1=name, 2=addr, 3=both * attribute.sort_art_type = NUM * 0=none, 1=subj descend, 2=subj ascend * 3=from descend, 4=from ascend * 5=date descend, 6=date ascend * attribute.post_proc_type = NUM * 0=none, 1=unshar, 2=uudecode * 3=uudecode & list zoo (unix) / lha (AmigaDOS) archive * 4=uudecode & extract zoo (unix) / lha (AmigaDOS) archive * 5=uudecode & list zip archive * 6=uudecode & extract zip archive */ void read_attributes_file () { #ifndef INDEX_DAEMON char buf[PATH_LEN]; char line[PATH_LEN]; FILE *fp; int num; int index = -1; set_default_attributes (); if ((fp = fopen (attributes_file, "r")) == (FILE *) 0) { return; } if ((update && update_fork) || ! update) { wait_message (txt_reading_attributes_file); } while (fgets (line, sizeof (line), fp) != NULL) { if (line[0] == '#' || line[0] == '\n') { continue; } if (match_string (line, "newsgroup=", buf, sizeof (buf))) { if (debug == 2) { error_message("group=[%s]",buf); } index = find_group_index (buf); continue; } if (match_string (line, "maildir=", buf, sizeof (buf))) { if (index >= 0) { active[index].attribute.maildir = str_dup (buf); if (debug == 2) { sprintf (msg, "maildir=[%s]", active[index].attribute.maildir); error_message (msg, ""); } } continue; } if (match_string (line, "savedir=", buf, sizeof (buf))) { if (index >= 0) { active[index].attribute.savedir = str_dup (buf); if (debug == 2) { sprintf (msg, "savedir=[%s]", active[index].attribute.savedir); error_message (msg, ""); } } continue; } if (match_string (line, "sigfile=", buf, sizeof (buf))) { if (index >= 0) { active[index].attribute.sigfile = str_dup (buf); if (debug == 2) { sprintf (msg, "sigfile=[%s]", active[index].attribute.sigfile); error_message (msg, ""); } } continue; } if (match_string (line, "organization=", buf, sizeof (buf))) { if (index >= 0) { active[index].attribute.organization = str_dup (buf); if (debug == 2) { error_message("organization=[%s]",active[index].attribute.organization); } } continue; } if (match_string (line, "followup_to=", buf, sizeof (buf))) { if (index >= 0) { active[index].attribute.followup_to = str_dup (buf); if (debug == 2) { error_message("followup_to=[%s]",active[index].attribute.followup_to); } } continue; } if (match_string (line, "printer=", buf, sizeof (buf))) { if (index >= 0) { active[index].attribute.printer = str_dup (buf); if (debug == 2) { error_message("printer=[%s]",active[index].attribute.printer); } } continue; } if (match_boolean (line, "show_only_unread=", &num)) { if (index >= 0) { active[index].attribute.show_only_unread = num; } continue; } if (match_boolean (line, "thread_arts=", &num)) { if (index >= 0) { active[index].attribute.thread_arts = num; } continue; } if (match_boolean (line, "auto_save=", &num)) { if (index >= 0) { active[index].attribute.auto_save = num; } continue; } if (match_boolean (line, "batch_save=", &num)) { if (index >= 0) { active[index].attribute.batch_save = num; } continue; } if (match_boolean (line, "delete_tmp_files=", &num)) { if (index >= 0) { active[index].attribute.delete_tmp_files = num; } continue; } if (match_number (line, "sort_art_type=", &num)) { if (index >= 0) { active[index].attribute.sort_art_type = num; } continue; } if (match_number (line, "show_author=", &num)) { if (index >= 0) { active[index].attribute.show_author = num; } continue; } if (match_number (line, "post_proc_type=", &num)) { if (index >= 0) { active[index].attribute.post_proc_type = num; } continue; } } fclose (fp); if ((cmd_line && ! update && ! verbose) || (update && update_fork)) { wait_message ("\n"); } #endif /* INDEX_DAEMON */ } /* * Save the group attributes from active[].attribute to ~/.tin/attributes */ void write_attributes_file () { #ifndef INDEX_DAEMON FILE *fp; register int i; #ifdef VMS if ((fp = fopen (attributes_file, "w", "fop=cif")) == (FILE *) 0) { #else if ((fp = fopen (attributes_file, "w")) == (FILE *) 0) { #endif return; } if (! cmd_line) { if ((update && update_fork) || ! update) { wait_message (txt_writing_attributes_file); } } fprintf (fp, "# Group attributes file\n#\n"); fprintf (fp, "# newsgroup=STRING (ie. alt.sources) [mandatory]\n#\n"); fprintf (fp, "# maildir=STRING (ie. ~/Mail)\n"); fprintf (fp, "# savedir=STRING (ie. ~user/News)\n"); fprintf (fp, "# organization=STRING\n"); fprintf (fp, "# sigfile=STRING (ie. $var/sig)\n"); fprintf (fp, "# followup_to=STRING\n"); fprintf (fp, "# printer=STRING\n"); fprintf (fp, "# auto_save=ON/OFF\n"); fprintf (fp, "# batch_save=ON/OFF\n"); fprintf (fp, "# delete_tmp_files=ON/OFF\n"); fprintf (fp, "# show_only_unread=ON/OFF\n"); fprintf (fp, "# thread_arts=ON/OFF\n#\n"); fprintf (fp, "# show_author=NUM\n"); fprintf (fp, "# 0=none, 1=name, 2=addr, 3=both\n#\n"); fprintf (fp, "# sort_art_type=NUM\n"); fprintf (fp, "# 0=none, 1=subj descend, 2=subj ascend,\n"); fprintf (fp, "# 3=from descend, 4=from ascend,\n"); fprintf (fp, "# 5=date descend, 6=date ascend\n#\n"); fprintf (fp, "# post_proc_type=NUM\n"); fprintf (fp, "# 0=none, 1=unshar, 2=uudecode,\n"); #ifdef M_AMIGA fprintf (fp, "# 3=uudecode & list lha archive,\n"); fprintf (fp, "# 4=uudecode & extract lha archive\n"); #else fprintf (fp, "# 3=uudecode & list zoo archive,\n"); fprintf (fp, "# 4=uudecode & extract zoo archive\n"); #endif fprintf (fp, "# 5=uudecode & list zip archive,\n"); fprintf (fp, "# 6=uudecode & extract zip archive\n\n"); for (i = 0 ; i < num_active ; i++) { fprintf (fp, "newsgroup=%s\n", active[i].name); fprintf (fp, "maildir=%s\n", active[i].attribute.maildir); fprintf (fp, "savedir=%s\n", active[i].attribute.savedir); fprintf (fp, "organization=%s\n", active[i].attribute.organization); fprintf (fp, "sigfile=%s\n", active[i].attribute.sigfile); fprintf (fp, "followup_to=%s\n", active[i].attribute.followup_to); fprintf (fp, "printer=%s\n", active[i].attribute.printer); fprintf (fp, "show_only_unread=%s\n", (active[i].attribute.show_only_unread ? "ON" : "OFF")); fprintf (fp, "thread_arts=%s\n", (active[i].attribute.thread_arts ? "ON" : "OFF")); fprintf (fp, "auto_save=%s\n", (active[i].attribute.auto_save ? "ON" : "OFF")); fprintf (fp, "batch_save=%s\n", (active[i].attribute.batch_save ? "ON" : "OFF")); fprintf (fp, "delete_tmp_files=%s\n", (active[i].attribute.delete_tmp_files ? "ON" : "OFF")); fprintf (fp, "sort_art_type=%d\n", active[i].attribute.sort_art_type); fprintf (fp, "show_author=%d\n", active[i].attribute.show_author); fprintf (fp, "post_proc_type=%d\n", active[i].attribute.post_proc_type); } fclose (fp); #endif /* INDEX_DAEMON */ } /* * Load the last updated time for each group in the active file so that * tind is more efficient and only has to stat the group dir and compare * the last changed time with the time read from the ~/.tin/active.times * file to determine if the group needs updating. * * alt.sources 71234589 * comp.archives 71234890 */ void read_active_times_file () { #ifdef INDEX_DAEMON char *p, *q; char buf[LEN]; char group[PATH_LEN]; FILE *fp; int i; long updated_time; if ((fp = fopen (active_times_file, "r")) == (FILE *) 0) { return; } while (fgets (buf, sizeof (buf), fp) != NULL) { /* * read the group name */ for (p = buf, q = group ; *p && *p != ' ' && *p != '\t' ; p++, q++) { *q = *p; } *q = '\0'; /* * read the last updated time */ updated_time = atol (p); /* * find the group in active[] and set updated time */ i = find_group_index (group); if (i >= 0) { active[i].last_updated_time = updated_time; } if (debug == 2) { printf ("group=[%-40.40s] [%ld]\n", active[i].name, active[i].last_updated_time); } } fclose (fp); #endif /* INDEX_DAEMON */ } /* * Save the last updated time for each group to ~/.tin/active.times */ void write_active_times_file () { #ifdef INDEX_DAEMON char buf[LEN]; char group[PATH_LEN]; FILE *fp; register int i; #ifdef VMS if ((fp = fopen (active_times_file, "w", "fop=cif")) == (FILE *) 0) { #else if ((fp = fopen (active_times_file, "w")) == (FILE *) 0) { #endif return; } for (i = 0 ; i < num_active ; i++) { fprintf (fp, "%s %ld\n", active[i].name, active[i].last_updated_time); } fclose (fp); #endif /* INDEX_DAEMON */ } void load_active_size_info (info) char *info; { char *ptr_name; char *ptr_size; char buf[PATH_LEN]; int i; /* * initialize active_size[] if no entries */ if (! num_active_size) { for (i = 0 ; i < max_active_size ; i++) { active_size[i].server = (char *) 0; active_size[i].attribute = (char *) 0; } } my_strncpy (buf, info, sizeof (buf)); ptr_name = buf; ptr_name = (char *) strchr (buf, ']'); if (ptr_name != (char *) 0) { *ptr_name = '\0'; } ptr_name = buf; ptr_name = (char *) strchr (buf, '['); if (ptr_name != (char *) 0) { ptr_size = ptr_name; *ptr_name = '\0'; if (num_active_size > max_active_size) { expand_active_size (); } active_size[num_active_size].server = str_dup (buf); active_size[num_active_size].attribute = str_dup (++ptr_size); if (debug == 2) { sprintf (buf, "ACTIVE server=[%s] attribute=[%s]", active_size[num_active_size].server, active_size[num_active_size].attribute); error_message ("%s", buf); } num_active_size++; } } int find_active_size_index (cur_active_server) char *cur_active_server; { int i, found = FALSE; for (i = 0 ; i < num_active_size ; i++) { if (strcmp (cur_active_server, active_size[i].server) == 0) { found = TRUE; break; } } return (found ? i : -1); } /* * check for message of the day (motd) file * * If reading news locally stat() the active file to get its * mtime otherwise do a XMOTD command to the NNTP server */ void read_motd_file () { #ifndef INDEX_DAEMON char buf[LEN]; char motd_file_date[32]; FILE *fp = (FILE *) 0; int lineno = 0; long new_motd_date = 0L; long old_motd_date = 0L; struct stat sb; struct tm *tm; if (update && ! update_fork) { return; } old_motd_date = atol (motd_file_info); /* * reading news locally (local) or via NNTP (server name) */ if (read_news_via_nntp) { if (! old_motd_date) { strcpy (motd_file_date, "920101 000000"); } else { tm = localtime (&old_motd_date); sprintf (motd_file_date, "%02d%02d%02d %02d%02d%02d", tm->tm_year, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); } time (&new_motd_date); } else { if (stat (motd_file, &sb) >=0) { new_motd_date = sb.st_mtime; } } if (old_motd_date && new_motd_date <= old_motd_date) { goto read_motd_done; } /* * Only check if spooldir is active news feed */ if (strcmp (spooldir_alias, "news") != 0) { goto read_motd_done; } if ((fp = open_motd_fp (motd_file_date)) != (FILE *) 0) { while (fgets (buf, sizeof (buf), fp) != NULL) { if (buf[0] == '.') { break; } printf ("%s", buf); lineno++; } fclose (fp); if (lineno) { wait_message (txt_cmdline_hit_any_key); Raw (TRUE); ReadCh (); Raw (FALSE); wait_message ("\n"); } } read_motd_done: /* * update motd tinrc entry with new date */ sprintf (motd_file_info, "%ld", new_motd_date); #endif /* INDEX_DAEMON */ } /* * find first occurrence of any char from str2 in str1 */ char * my_strpbrk (str1, str2) char *str1; char *str2; { register char *ptr1; register char *ptr2; for (ptr1 = str1; *ptr1 != '\0'; ptr1++) { for (ptr2 = str2; *ptr2 != '\0';) { if (*ptr1 == *ptr2++) { return (ptr1); } } } return (char *) 0; } ð*[SRC.TIN-1_22]ACTIVED.C;1+,w.//€ 4-d0@î123KÿPWO56 Ð8t…—7„c1—89€]V‚—G/€HªJÿ/* * Project : tin - a Usenet reader * Module : actived.c * Author : M.Tomlinson & I.Lea * Created : 23-08-92 * Updated : 02-08-93 * Notes : Creates an active file by looking through all the * .next files in the news directories, and writing * this to UULIB:newactive. The UULIB:newsgroups file * must exist. * Copyright : (c) Copyright 1991-93 by Mark Tomlinson & Iain Lea * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include #define NEWSGROUPS_FILE "UULIB:newsgroups" #define NEWSACTIVE_FILE "UULIB:newsactive" main () { char buf[20]; char groupname[81]; char next_path[90]; char *p, last[21]; FILE *fp, *ng, *active; long numgroups = 0, x; if ((ng = fopen (NEWSGROUPS_FILE, "r")) == (FILE *) 0) { perror (NEWSGROUPS_FILE); exit (1); } if ((active = fopen (NEWSACTIVE_FILE, "w")) == (FILE *) 0) { perror (NEWSACTIVE_FILE); exit (1); } while (fgets (groupname, 80, ng)) { for (p = groupname; *p && *p != ' ' && *p != '\t' && *p != '\n'; p++) { ; } *p = 0; sprintf (next_path,"UUNEWS:%s",groupname); for (p = &next_path[7]; *p ; p++) { if (*p == '.') { *p = '/'; /* convert to tree structure */ } } strcat (next_path,"/.next"); if (fp = fopen (next_path,"r")) { fgets (last,20,fp); x = atol (last) - 1; fclose (fp); } else { x = 0; } fprintf (active, "%s %05ld 00001 y\n", groupname, x); numgroups++; } fclose (ng); sprintf (buf, "%d", numgroups+1); setenv (ENV_VAR_GROUPS, buf); } ð*[SRC.TIN-1_22]AMIGA.C;1+,‹. //€ 4 -d0@î123KÿPWO 56€2t…—78ßg1—89€]V‚—G/€HªJÿ/* * Project : tin - a Usenet reader * Module : amiga.c * Author : M.Tomlinson & I.Lea * Created : 01-04-91 * Updated : 02-08-93 * Notes : Extra functions for Amiga port * Copyright : (c) Copyright 1991-93 by Mark Tomlinson & Iain Lea * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" #if defined(M_AMIGA) #include #include #ifdef __SASC # include # include #else # include # include # include # include #endif #include #include extern struct DosLibrary *DOSBase; int optind = 1; char *optarg; /* * dummy */ int chmod (file, mode) const char *file; int mode; { return 0; } /* * use the task addres for pid which is unique. */ int getpid (void) { return ((long) FindTask(0L) >> 2); } /* * stub for tputs */ #ifndef INDEX_DAEMON int tputs (str, count, func) char *str; int count; int (*func)(int); { if (! str) { return 0; } while (*str) { if (*str == '\n') func('\r'); func(*str++); } return 0; } #endif /* * stub for tzset */ void tzset (void) { #ifdef __SASC __daylight = 0; __timezone = 0; __tzname[0] = __tzname[1] = "GMT"; #endif } /* * joinpath tacks a file (or sub dir) on to the end of a directory name. * Not just as simple as putting a '/' between the two, as the directory * name may be an assign! */ void joinpath (str, dir, file) char *str; char *dir; char *file; { char c; if (strlen (dir) == 0) { strcpy (str, file); return; } c = dir[strlen(dir)-1]; if (c=='/' || c==':') { sprintf (str, "%s%s", dir, file); } else { sprintf (str, "%s/%s", dir, file); } } void sleep (seconds) int seconds; { Delay (50*seconds); } /* * I'm not really sure how well popen and pclose work, but they seem OK */ FILE * popen (command, mode) char *command; char *mode; { char cmd[256]; if (mode[0] == 'w') { sprintf (cmd, "run >NIL: %s", command); Execute (cmd, 0L, 0L); return fopen ("PIPE:", mode); } else { FILE *rp; rp = fopen ("PIPE:", mode); sprintf (cmd,"run %s >PIPE:",command); Execute (cmd, 0L, 0L); return rp; } } void pclose (pipe) FILE *pipe; { fclose (pipe); } /* * Directory stuff */ DIR * opendir (name) char *name; { DIR *di; di = calloc (1, sizeof (DIR)); di->Lock = Lock (name,ACCESS_READ); if (di->Lock == 0) { free (di); return 0; } if (Examine(di->Lock,&di->fib)==0) { UnLock(di->Lock); free (di); return 0; } return di; } struct dirent * readdir (di) DIR *di; { static struct dirent de; if (ExNext (di->Lock, &di->fib) == 0) { return 0; } de.d_name = di->fib.fib_FileName; de.d_reclen = strlen (de.d_name); return &de; } void closedir (di) DIR *di; { UnLock (di->Lock); free (di); } char getopt (argc, argv, options) int argc; char *argv[]; char *options; { char c,*z; static int subind = 0; for (;optind < argc ; optind++) { if (subind == 0) { c = argv[optind][0]; if (c != '-') { return EOF; } subind = 1; } c = argv[optind][subind]; if (c != 0) { break; } } if (optind == argc) { return EOF; } /* get rid of funnies */ if (c == ':' || c == '?') { return '?'; } if ((z = strchr (options,c)) == 0) { return '?'; } if (z[1] == ':') { if (argv[optind][subind+1]) { optarg = &argv[optind][subind+1]; } else { optarg = argv[++optind]; } optind++; subind = 0; return c; } subind++; return c; } int system (str) const char *str; { if (DOSBase->dl_lib.lib_Version >= 36) { return (System ((char *)str, 0L)); } else { return (!Execute((char *)str, 0L, 0L)); } } /* * The stat call in Aztec C doesn't tell us if the entry is a directory * or not. This one does. You will have to change to define * ST_DIRECT though */ int stat (name, buf) char *name; struct stat *buf; { BPTR dirlock; register struct FileInfoBlock *inf; if (! (dirlock = Lock (name, ACCESS_READ))) { return -1; } if (! (inf = malloc(sizeof(*inf)))) { UnLock (dirlock); return -1; } Examine (dirlock,inf); UnLock (dirlock); buf->st_attr = ((inf->fib_EntryType>0) ? ST_DIRECT : 0) | (inf->fib_Protection & 0xf); buf->st_size = inf->fib_Size; buf->st_mtime = ((inf->fib_Date.ds_Days + 2922) * (24 * 60) + inf->fib_Date.ds_Minute) * 60 + inf->fib_Date.ds_Tick / TICKS_PER_SECOND; free (inf); return 0; } /* * This getenv and setenv will use the WB2.0 calls if you have the new * rom. If not, it resorts to looking in the ENV: directory. */ char * getenv (name) register const char *name; { register FILE *fp; register char *ptr; static char buf[256]; static char value[256]; /* 2.0 style? */ if (DOSBase->dl_lib.lib_Version >= 36) { if (GetVar ((char *)name,value,256,0L) == -1) { return 0; } } else { if (strlen (name) > 252) { return 0; } strcpy (buf,"ENV:"); strcpy (&buf[4],name); if (! (fp = fopen(buf,"r"))) { return 0; } for (ptr = value; (*ptr=getc(fp))!=EOF && ++ptr < &value[256];); fclose(fp); *ptr = 0; } return value; } int setenv (name, value) char *name; char *value; { if (DOSBase->dl_lib.lib_Version >= 36) { SetVar ((char *)name,(char *)value,strlen(value)+1,GVF_LOCAL_ONLY); } return 0; } void make_post_cmd (cmd, name) char *cmd; char *name; { char *p; if ((p = getenv (ENV_VAR_POSTER)) != (char *) 0) { sprintf (cmd, p, name); } else { sprintf (cmd, DEFAULT_POSTER, name); } } #else /* * The ';' is to satisfy a really picky Ansi compiler */ ; #endif /* M_AMIGA */ ð*[SRC.TIN-1_22]AMIGA.H;1+,†.//€ 4I-d0@î123KÿPWO56`™Ût…—7€¡Fg1—89€]V‚—G/€HªJÿ/* * Project : tin - a Usenet reader * Module : amiga.h * Author : M.Tomlinson & I.Lea * Created : 17-09-92 * Updated : 20-06-93 * Notes : Directory support for AmigaDOS * Copyright : (c) Copyright 1991-93 by Mark Tomlinson & Iain Lea * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #if defined(M_AMIGA) #ifndef AMIGA_H #define AMIGA_H #include /* SAS-C and Aztec don't take the mode for mkdir() */ extern int mkdir(char *path); #define mkdir(p,m) mkdir(p) /* Replace Aztec's stat function with one that gives ST_DIRECT info */ struct stat { char st_attr; long st_mtime; long st_size; }; #define ST_DELETE 0x01 #define ST_EXECUTE 0x02 #define ST_WRITE 0x04 #define ST_READ 0x08 #define ST_DIRECT 0x10 /* Aztec's stat() doesn't give this information */ /* For opendir(), and readdir() */ struct dirent { char *d_name; long d_reclen; }; typedef struct { BPTR Lock; struct FileInfoBlock fib; int first; } DIR; extern DIR *opendir (char *name); extern struct dirent *readdir (DIR *di); extern void closedir (DIR *di); extern int stat(char *name, struct stat *buf); extern FILE *popen (char *command, char *mode); extern void pclose (FILE *pipe); extern void sleep(int secs); extern int tputs (char *cp, int count, int (*outc)(int)); extern int getpid(void); extern int setenv(char *, char *); extern int optind; extern char *optarg; extern char getopt (int argc, char *argv[], char *options); extern void make_post_cmd (char *cmd, char *name); extern void make_post_process_cmd(char *cmd, char *dir, char *file); #endif /* AMIGA_H */ #endif /* M_AMIGA */ ð*[SRC.TIN-1_22]ART.C;5+,ã.H//€ 4HF…-d0@î123KÿPWOI56à+™±Æ‹—7 ‰³Æ‹—89€]V‚—G/€HªJÿ /* * Project : tin - a Usenet reader * Module : art.c * Author : I.Lea & R.Skrenta * Created : 01-04-91 * Updated : 22-09-93 * Notes : * Copyright : (c) Copyright 1991-93 by Iain Lea & Rich Skrenta * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" #include "stpwatch.h" char index_file[PATH_LEN]; char *glob_art_group; static long last_read_article; /* * Construct the pointers to the basenotes of each thread * arts[] contains every article in the group. inthread is * set on each article that is after the first article in the * thread. Articles which have been expired have their thread * set to -2 (ART_EXPIRED). */ void find_base (index) int index; /* active[index] */ { register int i; register int j; top_base = 0; debug_print_arts (); if (active[index].attribute.show_only_unread) { for (i = 0; i < top; i++) { if (IGNORE_ART(i) || arts[i].inthread != FALSE) { continue; } if (top_base >= max_art) { expand_art (); } if (arts[i].unread == ART_UNREAD) { base[top_base++] = i; } else { for (j = i ; j >= 0 ; j = arts[j].thread) { if (arts[j].unread) { base[top_base++] = i; break; } } } } } else { for (i = 0; i < top; i++) { if (IGNORE_ART(i) || arts[i].inthread != FALSE) { continue; } if (top_base >= max_art) { expand_art (); } base[top_base++] = i; } } } /* * Count the number of non-expired articles in arts[] */ int num_of_arts () { int sum = 0; register int i; for (i = 0; i < top; i++) { if (arts[i].thread != ART_EXPIRED) { sum++; } } return sum; } /* * Return TRUE if arts[] contains any expired articles * (articles we have an entry for which don't have a * corresponding article file in the spool directory) */ int purge_needed (group_path) char *group_path; { register int i; for (i = 0; i < top; i++) { if (arts[i].thread == ART_EXPIRED) { return TRUE; } } return FALSE; } /* * Main group indexing routine. Group should be the name of the * newsgroup, i.e. "comp.unix.amiga". group_path should be the * same but with the .'s turned into /'s: "comp/unix/amiga" * * Will read any existing index, create or incrementally update * the index by looking at the articles in the spool directory, * and attempt to write a new index if necessary. */ int index_group (group, group_path) char *group; char *group_path; { int index; int killed = FALSE; int expired = FALSE; int modified = FALSE; long min; long max; register int i; glob_art_group = group; if (! update) { sprintf (msg, txt_group, group); wait_message (msg); } BegStopWatch("index_group"); index = find_group_index (group); if (index != -1) { set_alarm_clock_off (); set_signals_art (); hash_reclaim (); free_art_array (); /* * load article numbers into base[] */ setup_base (group, group_path); /* * load articles from xover/xindex file if it exists */ min = base[0]; max = (top_base ? base[top_base-1] : base[0]); if (! read_xover_file (group, min, max)) { read_xindex_file (group); } /* * add any articles to arts[] that are new or were killed */ modified = read_group (group, group_path); /* * check that user did not abort indexing */ if (modified == -1) { set_alarm_clock_on (); return FALSE; } /* * Stat all articles to see if any have expired */ if (purge_index_files) { if (! cmd_line) { sprintf (msg, txt_purge, group); wait_message (msg); } for (i = 0 ; i < top ; i++) { if (! stat_article (arts[i].artnum, group_path)) { expired = TRUE; if (cmd_line && verbose) { fputc ('P', stdout); fflush (stdout); } } } if (expired && cmd_line && verbose) { fputc ('\n', stdout); fflush (stdout); } } /* * If reading index file via XINDEX this is useless */ if (expired || modified || purge_needed (group_path)) { if (! cmd_line && index_file[0]) { wait_message (txt_writing_index_file); } write_xindex_file (group); } read_newsrc_line (group); killed = kill_any_articles (index); make_threads (FALSE); find_base (index); if ((modified || killed) && ! update) { clear_message (); } set_alarm_clock_on (); } EndStopWatch(); PrintStopWatch(); return TRUE; } /* * Index a group. Assumes any existing index has already been * loaded. Return values are: * TRUE loaded index and modified it * FALSE loaded index but not modified * -1 user aborted indexing operation */ int read_group (group, group_path) char *group; char *group_path; { char *ptr, buf[PATH_LEN]; char progress[PATH_LEN]; extern long head_next; int count = 0; int modified = FALSE; int respnum, total = 0; long art; register int i; static char dir[PATH_LEN] = ""; /* * change to groups spooldir to optimize fopen()'s on local articles */ #ifdef INDEX_DAEMON if (dir[0] == 0) #endif get_cwd (dir); joinpath (buf, active[my_group[cur_groupnum]].spooldir, group_path); my_chdir (buf); buf[0] = '\0'; sprintf (progress, txt_group, active[my_group[cur_groupnum]].name); /* * Count num of arts to index so the user has an idea of index time */ BegStopWatch("valid_artnum1"); for (i = 0; i < top_base; i++) { if (base[i] <= last_read_article || valid_artnum (base[i]) >= 0) { continue; } total++; } EndStopWatch(); PrintStopWatch(); /* * Reset the next article number index (for when HEAD fails) */ head_next = -1; for (i = 0; i < top_base; i++) { /* for each article # */ art = base[i]; /* * Do we already have this article in our index? Change * thread from (ART_EXPIRED) to (ART_NORMAL) if so and * skip the header eating. */ BegStopWatch("valid_artnum2"); if ((respnum = valid_artnum (art)) >= 0 || art <= last_read_article) { if (respnum >= 0) { arts[respnum].thread = ART_NORMAL; arts[respnum].unread = ART_UNREAD; } continue; } EndStopWatch(); PrintStopWatch(); /* * we've modified the index so it will need to be re-written */ if (! modified) { modified = TRUE; } if ((ptr = open_art_header (art)) == (char *) 0) { continue; } /* * Add article to arts[] */ if (top >= max_art) { expand_art(); } arts[top].artnum = art; arts[top].thread = ART_NORMAL; set_article (&arts[top]); if (! parse_headers (ptr, &arts[top])) { sprintf (buf, "FAILED parse_header(%ld)", art); debug_nntp ("read_group", buf); continue; } last_read_article = arts[top].artnum; /* used if arts are killed */ top++; if (++count % MODULO_COUNT_NUM == 0 && ! update) { if (input_pending ()) { if (read (STDIN_FILENO, buf, sizeof (buf)-1)) { if (buf[0] == ESC || buf[0] == 'q' || buf[0] == 'Q') { if (prompt_yn (cLINES, txt_abort_indexing, 'y')) { chdir (dir); return -1; } else { printf (progress); } } } } if (count == 0) { printf (progress); } else { printf ("\b\b\b\b\b\b\b\b\b%4d/%-4d", count, total); } fflush (stdout); } if (update && verbose) { fputc ('.', stdout); fflush (stdout); } } if (count && update && verbose) { fputc ('\n', stdout); fflush (stdout); } /* * change to previous dir before indexing started */ my_chdir (dir); return modified; } /* * Go through the articles in arts[] and use .thread to snake threads * through them. Use the subject line to construct threads. The * first article in a thread should have .inthread set to FALSE, the * rest TRUE. Only do unexprired articles we haven't visited yet * (arts[].thread == -1 ART_NORMAL). */ void make_threads (rethread) int rethread; { register int i; register int j; if (! cmd_line) { if (active[my_group[cur_groupnum]].attribute.thread_arts) { wait_message (tx ñ±Þa~ TIN-1_22.BCKãd[SRC.TIN-1_22]ART.C;5H‹Ólt_threading_arts); } else { wait_message (txt_unthreading_arts); } } /* if (debug == 2) { sprintf (msg, "rethread=[%d] thread_arts=[%d] attr_thread_arts=[%d]", rethread, default_thread_arts, active[my_group[cur_groupnum]].attribute.thread_arts); error_message (msg, ""); } */ /* * arts[].thread & arts[].inthread need to be reset if re-threading */ if (rethread || active[my_group[cur_groupnum]].attribute.thread_arts) { /* if (debug == 2) { error_message("Resetting .thread & .inthread", ""); } */ for (i=0 ; i < top ; i++) { arts[i].thread = ART_NORMAL; arts[i].inthread = FALSE; } } switch (active[my_group[cur_groupnum]].attribute.sort_art_type) { case SORT_BY_NOTHING: /* don't sort at all */ qsort ((char *) arts, top, sizeof (struct t_article), artnum_comp); break; case SORT_BY_SUBJ_DESCEND: case SORT_BY_SUBJ_ASCEND: qsort ((char *) arts, top, sizeof (struct t_article), subj_comp); break; case SORT_BY_FROM_DESCEND: case SORT_BY_FROM_ASCEND: qsort ((char *) arts, top, sizeof (struct t_article), from_comp); break; case SORT_BY_DATE_DESCEND: case SORT_BY_DATE_ASCEND: qsort ((char *) arts, top, sizeof (struct t_article), date_comp); break; default: break; } /* * FIXME - Once full group attributes are implemented what should the case be here? */ if (active[my_group[cur_groupnum]].attribute.thread_arts == 0 || default_thread_arts == 0) { /* if (debug == 2) { error_message("Returning before threading", ""); } */ return; } /* if (debug == 2) { error_message("Threading", ""); } */ for (i = 0; i < top; i++) { if (arts[i].thread != ART_NORMAL || IGNORE_ART(i)) { continue; } for (j = i+1; j < top; j++) { if (! IGNORE_ART(j) && arts[j].inthread == FALSE && ((arts[i].subject == arts[j].subject) || ((arts[i].part || arts[i].patch) && arts[i].archive == arts[j].archive))) { arts[i].thread = j; arts[j].inthread = TRUE; break; } } } } int parse_headers (buf, h) char *buf; struct t_article *h; { char buf2[HEADER_LEN]; char art_from_addr[LEN]; char art_full_name[LEN]; char *ptr, *ptrline, *s; int flag, n = 0, len = 0; int lineno = 0; int max_lineno = 25; int got_archive = FALSE; int got_date = FALSE; int got_from = FALSE; int got_lines = FALSE; int got_received = FALSE; int got_subject = FALSE; int got_xref = FALSE; n = strlen (buf); if (n == 0) { return FALSE; } buf[n-1] = '\0'; ptr = buf; while (1) { for (ptrline = ptr; *ptr && *ptr != '\n'; ptr++) { if (((*ptr) & 0xFF) < ' ') { *ptr = ' '; } } flag = *ptr; *ptr++ = '\0'; lineno++; switch (*ptrline) { case 'F': /* From: mandatory */ case 'T': /* To: mandatory (mailbox) */ if (! got_from) { if (match_header (ptrline, "From", buf2, HEADER_LEN) || match_header (ptrline, "To", buf2, HEADER_LEN)) { parse_from (buf2, art_from_addr, art_full_name); h->from = hash_str (art_from_addr); if (art_full_name[0]) { h->name = hash_str (art_full_name); } got_from = TRUE; } } break; case 'R': /* Received: If found its probably a mail article */ if (! got_received) { if (match_header (ptrline, "Received", buf2, HEADER_LEN)) { max_lineno = 50; got_received = TRUE; } } break; case 'S': /* Subject: mandatory */ if (! got_subject) { if (match_header (ptrline, "Subject", buf2, HEADER_LEN)) { s = eat_re (buf2); h->subject = hash_str (eat_re (s)); got_subject = TRUE; } } break; case 'D': /* Date: mandatory */ if (! got_date) { if (match_header (ptrline, "Date", buf2, HEADER_LEN)) { h->date = parsedate (buf2, (struct _TIMEINFO *) 0); got_date = TRUE; } } break; case 'X': /* Xref: optional */ if (! got_xref) { if (match_header (ptrline, "Xref", buf2, HEADER_LEN) || match_header (ptrline, "xref", buf2, HEADER_LEN)) { s = buf2; while (*s && *s == ' ') { s++; } h->xref = str_dup (s); got_xref = TRUE; } } break; case 'L': /* Lines: optional */ if (! got_lines) { if (match_header (ptrline, "Lines", buf2, HEADER_LEN)) { h->lines = atoi (buf2); got_lines = TRUE; } } break; case 'A': /* Archive-name: optional */ if (match_header (ptrline, "Archive-name", buf2, HEADER_LEN) || match_header (ptrline, "Archive-Name", buf2, HEADER_LEN)) { if ((s = (char *) strchr (buf2, '/')) != (char *) 0) { if (strncmp (s+1, "part", 4) == 0 || strncmp (s+1, "Part", 4) == 0) { h->part = str_dup (s+5); len = (int) strlen (h->part); if (h->part[len-1] == '\n') { h->part[len-1] = '\0'; } } else if (strncmp (s+1,"patch",5) == 0 || strncmp (s+1,"Patch",5) == 0) { h->patch = str_dup (s+6); len = (int) strlen (h->patch); if (h->patch[len-1] == '\n') { h->patch[len-1] = '\0'; } } if (h->part || h->patch) { s = buf2; while (*s && *s != '/') s++; *s = '\0'; s = buf2; h->archive = hash_str (s); got_archive = TRUE; } } } break; } if (! flag || lineno > max_lineno || got_archive) { if (got_from && got_date) { if (! got_subject) { h->subject = hash_str (""); } debug_print_header (h); return TRUE; } else { return FALSE; } } } /* NOTREACHED */ } /* * Write out an index file. Write the group name first so if * local indexing is done so we can disambiguate between group * name hash collisions by looking at the index file. */ void write_xindex_file (group) char *group; { char nam[LEN]; FILE *fp; int *iptr; int index; int realnum; long min_artnum = 0L; long max_artnum = 0L; register int i; if (! index_file[0]) { if (debug) { error_message (txt_no_index_file, ""); } return; } set_tin_uid_gid(); sprintf (nam, "%s.%d", index_file, process_id); #ifdef VMS if ((fp = fopen (nam, "w", "fop=cif")) == NULL) { #else if ((fp = fopen (nam, "w")) == NULL) { #endif perror_message (txt_cannot_open, nam); set_real_uid_gid (); return; } /* * dump group header info. */ index = my_group[cur_groupnum]; if (active[index].attribute.sort_art_type != SORT_BY_NOTHING) { qsort ((char *) arts, top, sizeof (struct t_article), artnum_comp); } fprintf (fp, "%s\n", group); fprintf (fp, "%d\n", num_of_arts ()); if (top <= 0) { fprintf (fp, "0\n"); } else { min_artnum = arts[0].artnum; max_artnum = arts[top-1].artnum; if (last_read_article > max_artnum) { max_artnum = last_read_article; fprintf (fp, "%ld\n", last_read_article); } else { fprintf (fp, "%ld\n", max_artnum); } if (active[index].type == GROUP_TYPE_MAIL) { i = FALSE; if (min_artnum > active[index].min) { active[index].min = min_artnum; i = TRUE; } if (max_artnum > active[index].max) { active[index].max = max_artnum; i = TRUE; } if (i) { write_mail_active_file (); } } } /* * dump articles */ realnum = 0; for (i = 0; i < top; i++) { if (arts[i].thread == ART_EXPIRED) { continue; } #ifdef DEBUG debug_print_header (&arts[i]); #endif fprintf(fp, "%ld\n", arts[i].artnum); iptr = (int *) arts[i].subject; iptr--; if (! arts[i].subject) { fprintf(fp, " \n"); } else if (*iptr < 0 || *iptr > top) { fprintf(fp, " %s\n", arts[i].subject); *iptr = realnum; } else if (*iptr == i) { fprintf(fp, " %s\n", arts[i].subject); } else { fprintf(fp, "%%%d\n", *iptr); } iptr = (int *) arts[i].from; iptr--; if (! arts[i].from) { fprintf (fp, " \n"); } else if (*iptr < 0 || *iptr > top) { fprintf (fp, " %s\n", arts[i].from); *iptr = realnum; } else if (*iptr == i) { fprintf(fp, " %s\n", arts[i].from); } else { fprintf(fp, "%%%d\n", *iptr); } iptr = (int *) arts[i].name; iptr--; if (! arts[i].name) { fprintf (fp, " \n"); } else if (*iptr < 0 || *iptr > top) { fprintf (fp, " %s\n", arts[i].name); *iptr = realnum; } else if (*iptr == i) { fprintf(fp, " %s\n", arts[i].name); } else { fprintf(fp, "%%%d\n", *iptr); } fprintf (fp, "%ld\n", arts[i].date); if (! arts[i].xref) { fprintf (fp, "\n"); } else { fprintf (fp, " %s\n", arts[i].xref); } if (arts[i].lines < 0) { fprintf (fp, "\n"); } else { fprintf (fp, " %d\n", arts[i].lines); } iptr = (int *) arts[i].archive; iptr--; if (! arts[i].archive) { fprintf (fp, "\n"); } else if (*iptr < 0 || *iptr > top) { fprintf (fp, " %s\n", arts[i].archive); *iptr = realnum; } else if (arts[i].part || arts[i].patch) { if (*iptr == i) { fprintf(fp, " %s\n", arts[i].archive); } else { fprintf (fp, "%%%d\n", *iptr); } } else { fprintf (fp, "\n"); } if (! arts[i].part) { fprintf (fp, " \n"); } else { fprintf (fp, "%s\n", arts[i].part); } if (! arts[i].patch) { fprintf (fp, " \n"); } else { fprintf (fp, "%s\n", arts[i].patch); } realnum++; } fclose (fp); rename_file (nam, index_file); chmod (index_file, 0644); set_real_uid_gid(); if (debug == 2) { #ifdef VMS sprintf (msg, "copy %s INDEX", index_file); #else sprintf (msg, "cp %s INDEX", index_file); #endif system (msg); } } /* * Read in an XINDEX index file. * * index file header * 1. newsgroup name (ie. alt.sources) * 2. number of articles (ie. 26) * 3. number of last read article (ie. 210) * 4. Is this a complete/killed index file (ie. COMPLETE/KILLED) * * index file record * 1. Article number (ie. 183) [mandatory] * 2. Subject: line (ie. Which newsreader?) [mandatory] * 3. From: line (addr) (ie. iain@norisc) [mandatory] * 4. From: line (name) (ie. Iain Lea) [mandatory] * 5. Date: of posting (ie. 71459801) [mandatory] * 6. Xref: grp:num ... (ie. alt.test:389) [optional] * 7. Lines: number (ie. 23) [optional] * 8. Archive: name (ie. compiler) [optional] * 9. Part number of Archive: name (ie. 01) [optional] * 10. Patch number of Archive: name (ie. 01) [optional] */ void read_xindex_file (group_name) char *group_name; { char buf[LEN], *p; int error = 0; int i, n; FILE *fp = NULL; top = 0; last_read_article = 0L; if ((fp = open_xindex_fp (group_name)) == (FILE *) 0) { return; } /* * load header - discard group name, num. of arts in index file after any arts were killed */ if (fgets (buf, sizeof buf, fp) == NULL || fgets (buf, sizeof buf, fp) == NULL) { error = 0; goto corrupt_index; } i = atoi (buf); /* * num. of last_read_article including any that were killed */ if (fgets(buf, sizeof buf, fp) == NULL) { error = 1; goto corrupt_index; } last_read_article = (long) atol (buf); /* * load articles */ while (top < i) { if (top >= max_art) { expand_art (); } arts[top].thread = ART_EXPIRED; set_article (&arts[top]); /* * 1. Article no. */ if (fgets (buf, sizeof buf, fp) == NULL) { error = 2; goto corrupt_index; } arts[top].artnum = (long) atol (buf); /* * 2. Subject: */ if (fgets (buf, sizeof buf, fp) == NULL) { error = 3; goto corrupt_index; } if (buf[0] == '%') { n = atoi (&buf[1]); if (n >= top || n < 0) { error = 4; goto corrupt_index; } arts[top].subject = arts[n].subject; } else if (buf[0] == ' ') { for (p = &buf[1]; *p && *p != '\n'; p++) continue; *p = '\0'; arts[top].subject = hash_str (&buf[1]); } else { error = 5; goto corrupt_index; } /* * 3. From: (addr part) */ if (fgets (buf, sizeof buf, fp) == NULL) { error = 6; goto corrupt_index; } if (buf[0] == '%') { n = atoi (&buf[1]); if (n >= top || n < 0) { error = 7; goto corrupt_index; } arts[top].from = arts[n].from; } else if (buf[0] == ' ') { for (p = &buf[1]; *p && *p != '\n'; p++) continue; *p = '\0'; arts[top].from = hash_str (&buf[1]); } else { error = 8; goto corrupt_index; } /* * 4. From: (name part) */ if (fgets (buf, sizeof buf, fp) == NULL) { error = 9; goto corrupt_index; } if (buf[0] == '%') { n = atoi (&buf[1]); if (n > top || n < 0) { error = 10; goto corrupt_index; } if (n == top) { /* no full name so .name = .from */ arts[top].name = arts[top].from; } else { arts[top].name = arts[n].name; } } else if (buf[0] == ' ') { for (p = &buf[1]; *p && *p != '\n'; p++) continue; *p = '\0'; if (buf[1]) { arts[top].name = hash_str (&buf[1]); } } else { error = 11; goto corrupt_index; } /* * 5. Date: */ if (fgets (buf, sizeof buf, fp) == NULL) { error = 12; goto corrupt_index; } arts[top].date = (long) atol (buf); /* * 6. Xref: */ if (fgets (buf, sizeof buf, fp) == NULL) { error = 13; goto corrupt_index; } if (buf[0] == '\n') { arts[top].xref = (char *) 0; } else { p = strrchr (buf, '\n'); if (p != (char *) 0) { *p = '\0'; } arts[top].xref = str_dup (&buf[1]); } /* * 7. Lines: */ if (fgets (buf, sizeof buf, fp) == NULL) { error = 14; goto corrupt_index; } if (buf[0] == '\n') { arts[top].lines = -1; } else { arts[top].lines = atoi (buf); } /* * 8. Archive-name: */ if (fgets (buf, sizeof buf, fp) == NULL) { error = 15; goto corrupt_index; } if (buf[0] == '\n') { arts[top].archive = (char *) 0; } else if (buf[0] == '%') { n = atoi (&buf[1]); if (n > top || n < 0) { error = 16; goto corrupt_index; } arts[top].archive = arts[n].archive; } else if (buf[0] == ' ') { for (p = &buf[1]; *p && *p != '\n' ; p++) continue; *p = '\0'; arts[top].archive = hash_str (&buf[1]); } else { error = 17; goto corrupt_index; } /* * 9. Part no. */ if (fgets(buf, sizeof buf, fp) == NULL) { error = 18; goto corrupt_index; } if (buf[0] != ' ') { p = strrchr (buf, '\n'); if (p != (char *) 0) { *p = '\0'; } arts[top].part = str_dup (buf); } /* * 10. Patch no. */ if (fgets (buf, sizeof buf, fp) == NULL) { error = 19; goto corrupt_index; } if (buf[0] != ' ') { p = strrchr (buf, '\n'); if (p != (char *) 0) { *p = '\0'; } arts[top].patch = str_dup (buf); } debug_print_header (&arts[top]); top++; } fclose(fp); /* * If reading in a mail group index check if min & max numbers are * consistant with what has been read from index file. */ i = my_group[cur_groupnum]; if (active[i].type == GROUP_TYPE_MAIL) { n = FALSE; if (top && top > active[i].max) { active[i].max = top; n = TRUE; } if (top && arts[0].artnum > active[i].min) { active[i].min = arts[0].artnum; n = TRUE; } if (n) { write_mail_active_file (); } } return; corrupt_index: if (! update) { sprintf (msg, txt_corrupt_index, index_file, error, top); error_message (msg, ""); } if (debug == 2) { #ifdef VMS sprintf (msg, "copy %s INDEX.BAD", index_file); #else sprintf (msg, "cp %s INDEX.BAD", index_file); #endif system (msg); } last_read_article = 0L; if (fp) { fclose(fp); } set_tin_uid_gid (); unlink (index_file); set_real_uid_gid (); top = 0; } /* * Read in an XOVER index file. Fields are separated by TAB. * * index file record * 1. article number (ie. 183) [mandatory] * 2. Subject: line (ie. Which newsreader?) [mandatory] * 3. From: line (ie. iain@norisc) [mandatory] * 4. Date: line (ie. rfc822 format) [mandatory] * 5. Lines: line (ie. 23) [optional] * 6. Xref: line (ie. alt.test:389) [optional] */ int read_xover_file (group_name, min, max) char *group_name; long min; long max; { char *p, *q; char buf[1024]; char art_full_name[LEN]; char art_from_addr[LEN]; FILE *fp; top = 0; last_read_article = 0L; /* * setup the overview file (whether it be local or via nntp) */ if ((fp = open_xover_fp (group_name, min, max)) == (FILE *) 0) { return FALSE; } while (fgets (buf, sizeof (buf), fp) != (char *) 0) { if (strcmp (buf, ".") == 0) { break; } if (top >= max_art) { expand_art (); } arts[top].thread = ART_EXPIRED; set_article (&arts[top]); p = buf; /* * read the article number */ last_read_article = arts[top].artnum = atol (p); q = strchr (p, '\t'); if (q == (char *) 0) { error_message ("Bad overview record '%s'", buf); continue; } else { p = q + 1; } /* * READ subject */ q = strchr (p, '\t'); if (q == (char *) 0) { error_message ("Bad overview record (Subject) '%s'", p); debug_nntp ("read_xover_file", "Bad overview record (Subject)"); continue; } else { *q = '\0'; } arts[top].subject = hash_str (eat_re (eat_re (p))); p = q + 1; /* * READ author */ q = strchr (p, '\t'); if (q == (char *) 0) { error_message ("Bad overview record (From) '%s'", p); debug_nntp ("read_xover_file", "Bad overview record (From)"); continue; } else { *q = '\0'; } parse_from (p, art_from_addr, art_full_name); arts[top].from = hash_str (art_from_addr); if (art_full_name[0]) { arts[top].name = hash_str (art_full_name); } p = q + 1; /* * READ article date */ q = strchr (p, '\t'); if (q == (char *) 0) { error_message ("Bad overview record (Date) '%s'", p); debug_nntp ("read_xover_file", "Bad overview record (Date)"); continue; } else { *q = '\0'; } arts[top].date = parsedate (p, NULL); p = q + 1; /* * SKIP article messageid */ q = strchr (p, '\t'); if (q == (char *) 0) { error_message ("Bad overview record (Msg-id) '%s'", p); debug_nntp ("read_xover_file", "Bad overview record (Msg-id)"); continue; } p = q + 1; /* * SKIP article references */ q = strchr (p, '\t'); if (q == (char *) 0) { error_message ("Bad overview record (References) '%s'", p); debug_nntp ("read_xover_file", "Bad overview record (References)"); continue; } p = q + 1; /* * SKIP article bytes */ q = strchr (p, '\t'); if (q == (char *) 0) { error_message ("Bad overview record (Bytes) '%s'", p); debug_nntp ("read_xover_file", "Bad overview record (Bytes)"); continue; } else { *q = '\0'; } p = q + 1; /* * READ article lines (special case - last standard nov header) */ q = strchr (p, '\t'); if (q == (char *) 0) { if (!*p || (*p < '0' && *p > '9')) { error_message ("Bad overview record (Lines) '%s'", p); debug_nntp ("read_xover_file", "Bad overview record (Lines)"); continue; } } else { *q = '\0'; } arts[top].lines = atoi (p); p = (q == (char *) 0 ? (char *) 0 : q + 1); /* * READ article xrefs */ if (p != (char *) 0 && xref_supported) { q = str_str (p, "Xref: ", 6); if (q != (char *) 0) { p = q + 6; q = p; while (*q && *q != '\t') { q++; } *q = '\0'; q = strrchr (p, '\n'); if (q != (char *) 0) { *q = '\0'; } q = p; while (*q && *q == ' ') { q++; } arts[top].xref = str_dup (q); } } /* * end of overview line processing */ debug_print_header (&arts[top]); top++; } fclose (fp); return TRUE; } /* * Look in the local $HOME/RCDIR/[ INDEX_NEWSDIR | INDEX_MAILDIR ] etc. * directory for the index file for the given group. Hashing the group * name gets a number. See if that #.1 file exists; if so, read first * line. Group we want? If no, try #.2. Repeat until no such file or * we find an existing file that matches our group. * Return group type of the index file (mail / news / -1 on error). */ int find_index_file (group) char *group; { char *p, dir[PATH_LEN]; FILE *fp; int i = 1, j, type; static char buf[PATH_LEN]; unsigned long h; j = find_group_index (group); if (j == -1) { return j; } type = active[j].type; h = hash_groupname (group); if (read_news_via_nntp && xindex_supported && type == GROUP_TYPE_NEWS) { sprintf (index_file, "%sxindex.%d", TMPDIR, process_id); return (type); } if (local_index) { if (type == GROUP_TYPE_NEWS) { my_strncpy (dir, index_newsdir, sizeof (dir)); } else { my_strncpy (dir, index_maildir, sizeof (dir)); } } else { #ifdef VMS joindir (dir, get_val ("TIN_INDEXDIR", active[j].spooldir), INDEX_NEWSDIR); #else joinpath (dir, get_val ("TIN_INDEXDIR", active[j].spooldir), INDEX_NEWSDIR); #endif } i = 1; while (TRUE) { sprintf (buf, "%lu.%d", h, i); joinpath (index_file, dir, buf); if ((fp = fopen (index_file, "r")) == (FILE *) 0) { return (type); } if (fgets (buf, sizeof (buf), fp) == (char *) 0) { fclose (fp); return (type); } fclose (fp); for (p = buf; *p && *p != '\n'; p++) { continue; } *p = '\0'; if (strcmp (buf, group) == 0) { return (type); } i++; } } /* * Run the index file updater only for the groups we've loaded. */ void do_update () { char group_path[PATH_LEN]; register int i, j; long beg_epoch, end_epoch; #ifdef INDEX_DAEMON char buf[PATH_LEN]; long group_time, index_time; struct stat stinfo; #endif if (verbose) { time (&beg_epoch); } /* * load last updated times for each group (tind daemon only) */ read_active_times_file (); /* * loop through groups and update any required index files */ for (i = 0; i < group_top; i++) { make_group_path (active[my_group[i]].name, group_path); #ifdef INDEX_DAEMON joinpath (buf, active[my_group[i]].spooldir, group_path); if (stat (buf, &stinfo) == -1) { if (verbose) { error_message ("Can't stat group %s\n", buf); } continue; } group_time = stinfo.st_mtime; index_time = 0L; if (find_index_file (active[my_group[i]].name) == -1) { continue; } if (stat (index_file, &stinfo) == -1) { if (verbose) { printf ("Can't stat %s index %s\n", active[my_group[i]].name, index_file); } } else { index_time = stinfo.st_mtime; } if (debug == 2) { printf ("[%s] [%s] idxtime=[%ld] old=[%ld] new=[%ld]\n", active[my_group[i]].name, index_file, index_time, active[my_group[i]].last_updated_time, group_time); } if (index_time == 0L || active[my_group[i]].last_updated_time == 0L || group_time > active[my_group[i]].last_updated_time || purge_index_files) { active[my_group[i]].last_updated_time = group_time; } else { continue; } #endif if (verbose) { printf ("%s %s\n", (catchup ? "Catchup" : "Updating"), active[my_group[i]].name); fflush (stdout); } if (! index_group (active[my_group[i]].name, group_path)) { continue; } if (catchup) { for (j = 0; j < top; j++) { arts[j].unread = ART_READ; } update_newsrc (active[my_group[i]].name, my_group[i], FALSE); } } /* * save last updated times for each group (tind daemon only) */ write_active_times_file (); if (verbose) { time (&end_epoch); sprintf (msg, txt_catchup_update_info, (catchup ? "Caughtup" : "Updated"), group_top, end_epoch - beg_epoch); wait_message (msg); } } int artnum_comp (p1, p2) t_comptype *p1; t_comptype *p2; { struct t_article *s1 = (struct t_article *) p1; struct t_article *s2 = (struct t_article *) p2; /* * s1->artnum less than s2->artnum */ if (s1->artnum < s2->artnum) { return -1; } /* * s1->artnum greater than s2->artnum */ if (s1->artnum > s2->artnum) { return 1; } return 0; } int subj_comp (p1, p2) t_comptype *p1; t_comptype *p2; { int retval; struct t_article *s1 = (struct t_article *) p1; struct t_article *s2 = (struct t_article *) p2; /* * return result of strcmp (reversed for descending) */ return (active[my_group[cur_groupnum]].attribute.sort_art_type == SORT_BY_SUBJ_ASCEND ? (retval = my_stricmp (s1->subject, s2->subject)) ? retval : ((s1->date - s2->date) > 0) ? 1 : -1 : (retval = my_stricmp (s2->subject, s1->subject)) ? retval : ((s1->date - s2->date) > 0) ? 1 : -1); } int from_comp (p1, p2) t_comptype *p1; t_comptype *p2; { int retval; struct t_article *s1 = (struct t_article *) p1; struct t_article *s2 = (struct t_article *) p2; /* * return result of strcmp (reversed for descending) */ return (active[my_group[cur_groupnum]].attribute.sort_art_type == SORT_BY_FROM_ASCEND ? (retval = my_stricmp (s1->from, s2->from)) ? retval : ((s1->date - s2->date) > 0) ? 1 : -1 : (retval = my_stricmp (s2->from, s1->from)) ? retval : ((s1->date - s2->date) > 0) ? 1 : -1); } int date_comp (p1, p2) t_comptype *p1; t_comptype *p2; { struct t_article *s1 = (struct t_article *) p1; struct t_article *s2 = (struct t_article *) p2; if (active[my_group[cur_groupnum]].attribute.sort_art_type == SORT_BY_DATE_ASCEND) { /* * s1->date less than s2->date */ if (s1->date < s2->date) { return -1; } /* * s1->date greater than s2->date */ if (s1->date > s2->date) { return 1; } } else { /* * s2->date less than s1->date */ if (s2->date < s1->date) { return -1; } /* * s2->date greater than s1->date */ if (s2->date > s1->date) { return 1; } } return 0; } void set_article (art) struct t_article *art; { art->subject = (char *) 0; art->from = (char *) 0; art->name = (char *) 0; art->date = 0L; art->xref = (char *) 0; art->lines = -1; art->archive = (char *) 0; art->part = (char *) 0; art->patch = (char *) 0; art->unread = ART_UNREAD; art->inthread = FALSE; art->killed = FALSE; art->tagged = FALSE; art->hot = FALSE; art->zombie = FALSE; } int input_pending () { #ifdef HAVE_SELECT int fd = STDIN_FILENO; fd_set fdread; struct timeval tvptr; FD_ZERO(&fdread); tvptr.tv_sec = 0; tvptr.tv_usec = 0; FD_SET(fd, &fdread); if (select (1, &fdread, NULL, NULL, &tvptr)) { if (FD_ISSET(fd, &fdread)) { return TRUE; } } #endif /* HAVE_SELECT */ #if defined(HAVE_POLL) && !defined(HAVE_SELECT) static int timeout = 0; static long nfds = 1; static struct pollfd fds[]= { STDIN_FILENO, POLLIN, 0 }; if (poll (fds, nfds, timeout) < 0) { /* * Error on poll */ return FALSE; } switch (fds[0].revents) { case POLLIN: return TRUE; break; /* * Other conditions on the stream */ case POLLHUP: case POLLERR: default: return FALSE; break; } #endif /* HAVE_POLL */ return FALSE; } int valid_artnum (art) long art; { register int prev, range; register int dtop = top; register int cur = 1; while (dtop /= 2) { cur = cur << 1; } range = cur / 2; cur--; while (1) { if (arts[cur].artnum == art) { return cur; } prev = cur; if (arts[cur].artnum < art) { cur = cur + range; } else { cur = cur - range; } if (prev == cur) { return -1; } if (cur >= top) { cur = top - 1; } range = range / 2; } } rð*[SRC.TIN-1_22]BISON.SIMPLE;2+,¯.!//€ 4! I-d0ú123KÿPWO!56ଡ଼ۼ‹—7 ì†u¿‹—89€]V‚—G/€HªJÿ/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ #line 3 "bison.simple" /* Skeleton output parser for bison, Copyright (C) 1984, 1989, 1990 Bob Corbett and Richard Stallman This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef alloca #ifdef __GNUC__ #define alloca __builtin_alloca #else /* not GNU C. */ #if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) #include #else /* not sparc */ #if defined (MSDOS) && !defined (__TURBOC__) #include #else /* not MSDOS, or __TURBOC__ */ #if defined(_AIX) #include #pragma alloca #else /* not MSDOS, __TURBOC__, or _AIX */ #ifdef __hpux #ifdef __cplusplus extern "C" { void *alloca (unsigned int); }; #else /* not __cplusplus */ void *alloca (); #endif /* not __cplusplus */ #endif /* __hpux */ #endif /* not _AIX */ #endif /* not MSDOS, or __TURBOC__ */ #endif /* not sparc. */ #endif /* not GNU C. */ #endif /* alloca not defined. */ /* This is the parser code that is written into each bison parser when the %semantic_parser declaration is not specified in the grammar. It was written by Richard Stallman by simplifying the hairy parser used when %semantic_parser is specified. */ /* Note: there must be only one dollar sign in this file. It is replaced by the list of actions, each action as one case of the switch. */ #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYEMPTY -2 #define YYEOF 0 #define YYACCEPT return(0) #define YYABORT return(1) #define YYERROR goto yyerrlab1 /* Like YYERROR except do call yyerror. This remains here temporarily to ease the transition to the new meaning of YYERROR, for GCC. Once GCC version 2 has supplanted version 1, this can go. */ #define YYFAIL goto yyerrlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(token, value) \ do \ if (yychar == YYEMPTY && yylen == 1) \ { yychar = (token), yylval = (value); \ yychar1 = YYTRANSLATE (yychar); \ YYPOPSTACK; \ goto yybackup; \ } \ else \ { yyerror ("syntax error: cannot back up"); YYERROR; } \ while (0) #define YYTERROR 1 #define YYERRCODE 256 #ifndef YYPURE #define YYLEX yylex() #endif #ifdef YYPURE #ifdef YYLSP_NEEDED #define YYLEX yylex(&yylval, &yylloc) #else #define YYLEX yylex(&yylval) #endif #endif /* If nonreentrant, generate the variables here */ #ifndef YYPURE int yychar; /* the lookahead symbol */ YYSTYPE yylval; /* the semantic value of the */ /* lookahead symbol */ #ifdef YYLSP_NEEDED YYLTYPE yylloc; /* location data for the lookahead */ /* symbol */ #endif int yynerrs; /* number of parse errors so far */ #endif /* not YYPURE */ #if YYDEBUG != 0 int yydebug; /* nonzero means print parse trace */ /* Since this is uninitialized, it does not stop multiple parsers fromÐ |ñV~ TIN-1_22.BCK¯d[SRC.TIN-1_22]BISON.SIMPLE;2!Ûü coexisting. */ #endif /* YYINITDEPTH indicates the initial size of the parser's stacks */ #ifndef YYINITDEPTH #define YYINITDEPTH 200 #endif /* YYMAXDEPTH is the maximum size the stacks can grow to (effective only if the built-in stack extension method is used). */ #if YYMAXDEPTH == 0 #undef YYMAXDEPTH #endif #ifndef YYMAXDEPTH #define YYMAXDEPTH 10000 #endif /* Prevent warning if -Wstrict-prototypes. */ #ifdef __GNUC__ int yyparse (void); #endif #if __GNUC__ > 1 /* GNU C and GNU C++ define this. */ #define __yy_bcopy(FROM,TO,COUNT) __builtin_memcpy(TO,FROM,COUNT) #else /* not GNU C or C++ */ #ifndef __cplusplus /* This is the most reliable way to avoid incompatibilities in available built-in functions on various systems. */ static void __yy_bcopy (from, to, count) char *from; char *to; int count; { register char *f = from; register char *t = to; register int i = count; while (i-- > 0) *t++ = *f++; } #else /* __cplusplus */ /* This is the most reliable. way to avoid incompatibilities in available built-in functions on various systems. */ static void __yy_bcopy (char *from, char *to, int count) { register char *f = from; register char *t = to; register int i = count; while (i-- > 0) *t++ = *f++; } #endif #endif #line 184 "bison.simple" int yyparse() { register int yystate; register int yyn; register short *yyssp; register YYSTYPE *yyvsp; int yyerrstatus; /* number of tokens to shift before error messages enabled */ int yychar1 = 0; /* lookahead token as an internal (translated) token number */ short yyssa[YYINITDEPTH]; /* the state stack */ YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */ short *yyss = yyssa; /* refer to the stacks thru separate pointers */ YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */ #ifdef YYLSP_NEEDED YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */ YYLTYPE *yyls = yylsa; YYLTYPE *yylsp; #define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) #else #define YYPOPSTACK (yyvsp--, yyssp--) #endif int yystacksize = YYINITDEPTH; #ifdef YYPURE int yychar; YYSTYPE yylval; int yynerrs; #ifdef YYLSP_NEEDED YYLTYPE yylloc; #endif #endif YYSTYPE yyval; /* the variable used to return */ /* semantic values from the action */ /* routines */ int yylen; #if YYDEBUG != 0 if (yydebug) fprintf(stderr, "Starting parse\n"); #endif yystate = 0; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ /* Initialize stack pointers. Waste one element of value and location stack so that they stay on the same level as the state stack. The wasted elements are never initialized. */ yyssp = yyss - 1; yyvsp = yyvs; #ifdef YYLSP_NEEDED yylsp = yyls; #endif /* Push a new state, which is found in yystate . */ /* In all cases, when you get here, the value and location stacks have just been pushed. so pushing a state here evens the stacks. */ yynewstate: *++yyssp = yystate; if (yyssp >= yyss + yystacksize - 1) { /* Give user a chance to reallocate the stack */ /* Use copies of these so that the &'s don't force the real ones into memory. */ YYSTYPE *yyvs1 = yyvs; short *yyss1 = yyss; #ifdef YYLSP_NEEDED YYLTYPE *yyls1 = yyls; #endif /* Get the current used size of the three stacks, in elements. */ int size = yyssp - yyss + 1; #ifdef yyoverflow /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. */ #ifdef YYLSP_NEEDED /* This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow("parser stack overflow", &yyss1, size * sizeof (*yyssp), &yyvs1, size * sizeof (*yyvsp), &yyls1, size * sizeof (*yylsp), &yystacksize); #else yyoverflow("parser stack overflow", &yyss1, size * sizeof (*yyssp), &yyvs1, size * sizeof (*yyvsp), &yystacksize); #endif yyss = yyss1; yyvs = yyvs1; #ifdef YYLSP_NEEDED yyls = yyls1; #endif #else /* no yyoverflow */ /* Extend the stack our own way. */ if (yystacksize >= YYMAXDEPTH) { yyerror("parser stack overflow"); return 2; } yystacksize *= 2; if (yystacksize > YYMAXDEPTH) yystacksize = YYMAXDEPTH; yyss = (short *) alloca (yystacksize * sizeof (*yyssp)); __yy_bcopy ((char *)yyss1, (char *)yyss, size * sizeof (*yyssp)); yyvs = (YYSTYPE *) alloca (yystacksize * sizeof (*yyvsp)); __yy_bcopy ((char *)yyvs1, (char *)yyvs, size * sizeof (*yyvsp)); #ifdef YYLSP_NEEDED yyls = (YYLTYPE *) alloca (yystacksize * sizeof (*yylsp)); __yy_bcopy ((char *)yyls1, (char *)yyls, size * sizeof (*yylsp)); #endif #endif /* no yyoverflow */ yyssp = yyss + size - 1; yyvsp = yyvs + size - 1; #ifdef YYLSP_NEEDED yylsp = yyls + size - 1; #endif #if YYDEBUG != 0 if (yydebug) fprintf(stderr, "Stack size increased to %d\n", yystacksize); #endif if (yyssp >= yyss + yystacksize - 1) YYABORT; } #if YYDEBUG != 0 if (yydebug) fprintf(stderr, "Entering state %d\n", yystate); #endif goto yybackup; yybackup: /* Do appropriate processing given the current state. */ /* Read a lookahead token if we need one and don't already have one. */ /* yyresume: */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yyn == YYFLAG) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* yychar is either YYEMPTY or YYEOF or a valid token in external form. */ if (yychar == YYEMPTY) { #if YYDEBUG != 0 if (yydebug) fprintf(stderr, "Reading a token: "); #endif yychar = YYLEX; } /* Convert token to internal form (in yychar1) for indexing tables with */ if (yychar <= 0) /* This means end of input. */ { yychar1 = 0; yychar = YYEOF; /* Don't call YYLEX any more */ #if YYDEBUG != 0 if (yydebug) fprintf(stderr, "Now at end of input.\n"); #endif } else { yychar1 = YYTRANSLATE(yychar); #if YYDEBUG != 0 if (yydebug) { fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]); /* Give the individual parser a way to print the precise meaning of a token, for further debugging info. */ #ifdef YYPRINT YYPRINT (stderr, yychar, yylval); #endif fprintf (stderr, ")\n"); } #endif } yyn += yychar1; if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) goto yydefault; yyn = yytable[yyn]; /* yyn is what to do for this token type in this state. Negative => reduce, -yyn is rule number. Positive => shift, yyn is new state. New state is final state => don't bother to shift, just return success. 0, or most negative number => error. */ if (yyn < 0) { if (yyn == YYFLAG) goto yyerrlab; yyn = -yyn; goto yyreduce; } else if (yyn == 0) goto yyerrlab; if (yyn == YYFINAL) YYACCEPT; /* Shift the lookahead token. */ #if YYDEBUG != 0 if (yydebug) fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]); #endif /* Discard the token being shifted unless it is eof. */ if (yychar != YYEOF) yychar = YYEMPTY; *++yyvsp = yylval; #ifdef YYLSP_NEEDED *++yylsp = yylloc; #endif /* count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; yystate = yyn; goto yynewstate; /* Do the default action for the current state. */ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; /* Do a reduction. yyn is the number of a rule to reduce with. */ yyreduce: yylen = yyr2[yyn]; if (yylen > 0) yyval = yyvsp[1-yylen]; /* implement default value of the action */ #if YYDEBUG != 0 if (yydebug) { int i; fprintf (stderr, "Reducing via rule %d (line %d), ", yyn, yyrline[yyn]); /* Print the symbols being reduced, and their result. */ for (i = yyprhs[yyn]; yyrhs[i] > 0; i++) fprintf (stderr, "%s ", yytname[yyrhs[i]]); fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]); } #endif $ /* the action file gets copied in in place of this dollarsign */ #line 465 "bison.simple" yyvsp -= yylen; yyssp -= yylen; #ifdef YYLSP_NEEDED yylsp -= yylen; #endif #if YYDEBUG != 0 if (yydebug) { short *ssp1 = yyss - 1; fprintf (stderr, "state stack now"); while (ssp1 != yyssp) fprintf (stderr, " %d", *++ssp1); fprintf (stderr, "\n"); } #endif *++yyvsp = yyval; #ifdef YYLSP_NEEDED yylsp++; if (yylen == 0) { yylsp->first_line = yylloc.first_line; yylsp->first_column = yylloc.first_column; yylsp->last_line = (yylsp-1)->last_line; yylsp->last_column = (yylsp-1)->last_column; yylsp->text = 0; } else { yylsp->last_line = (yylsp+yylen-1)->last_line; yylsp->last_column = (yylsp+yylen-1)->last_column; } #endif /* Now "shift" the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ yyn = yyr1[yyn]; yystate = yypgoto[yyn - YYNTBASE] + *yyssp; if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) yystate = yytable[yystate]; else yystate = yydefgoto[yyn - YYNTBASE]; goto yynewstate; yyerrlab: /* here on detecting error */ if (! yyerrstatus) /* If not already recovering from an error, report this error. */ { ++yynerrs; #ifdef YYERROR_VERBOSE yyn = yypact[yystate]; if (yyn > YYFLAG && yyn < YYLAST) { int size = 0; char *msg; int x, count; count = 0; /* Start X at -yyn if nec to avoid negative indexes in yycheck. */ for (x = (yyn < 0 ? -yyn : 0); x < (sizeof(yytname) / sizeof(char *)); x++) if (yycheck[x + yyn] == x) size += strlen(yytname[x]) + 15, count++; msg = (char *) malloc(size + 15); if (msg != 0) { strcpy(msg, "parse error"); if (count < 5) { count = 0; for (x = (yyn < 0 ? -yyn : 0); x < (sizeof(yytname) / sizeof(char *)); x++) if (yycheck[x + yyn] == x) { strcat(msg, count == 0 ? ", expecting `" : " or `"); strcat(msg, yytname[x]); strcat(msg, "'"); count++; } } yyerror(msg); free(msg); } else yyerror ("parse error; also virtual memory exceeded"); } else #endif /* YYERROR_VERBOSE */ yyerror("parse error"); } goto yyerrlab1; yyerrlab1: /* here on error raised explicitly by an action */ if (yyerrstatus == 3) { /* if just tried and failed to reuse lookahead token after an error, discard it. */ /* return failure if at end of input */ if (yychar == YYEOF) YYABORT; #if YYDEBUG != 0 if (yydebug) fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]); #endif yychar = YYEMPTY; } /* Else will try to reuse lookahead token after shifting the error token. */ yyerrstatus = 3; /* Each real token shifted decrements this */ goto yyerrhandle; yyerrdefault: /* current state does not do anything special for the error token. */ #if 0 /* This is wrong; only states that explicitly want error tokens should shift them. */ yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/ if (yyn) goto yydefault; #endif yyerrpop: /* pop the current state because it cannot handle the error token */ if (yyssp == yyss) YYABORT; yyvsp--; yystate = *--yyssp; #ifdef YYLSP_NEEDED yylsp--; #endif #if YYDEBUG != 0 if (yydebug) { short *ssp1 = yyss - 1; fprintf (stderr, "Error: state stack now"); while (ssp1 != yyssp) fprintf (stderr, " %d", *++ssp1); fprintf (stderr, "\n"); } #endif yyerrhandle: yyn = yypact[yystate]; if (yyn == YYFLAG) goto yyerrdefault; yyn += YYTERROR; if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) goto yyerrdefault; yyn = yytable[yyn]; if (yyn < 0) { if (yyn == YYFLAG) goto yyerrpop; yyn = -yyn; goto yyreduce; } else if (yyn == 0) goto yyerrpop; if (yyn == YYFINAL) YYACCEPT; #if YYDEBUG != 0 if (yydebug) fprintf(stderr, "Shifting error token, "); #endif *++yyvsp = yylval; #ifdef YYLSP_NEEDED *++yylsp = yylloc; #endif yystate = yyn; goto yynewstate; } ð*[SRC.TIN-1_22]CHANGES.;1+,m.//€ 4;-d0@î123KÿPWO56 [Ðt…—7`¿Xê‘—89 „ìø‘—G/€HªJÿCHANGES tin v1.2 PL1 -> tin 1.2 PL2 ----------------------------------- 1) Colin Perkins (csp@ohm.york.ac.uk) BUG. Compile fails on Next due to use of getcwd() in misc.c FIX. misc.c - applied supplied patch. 2) Richard Lloyd (rkl@csc.liv.ac.uk) BUG. 'make install' fails because of wrong variable names. FIX. makefile - applied supplied patch. 3) Iain Lea (iain.lea@erlm.siemens.de) BUG. Return code from external news is wrong from 1.20 change. FIX. inews.c - changed back to pre v1.2 PL1 behaviour. 4) Mike Glendinning (mikeg@ingres.co.uk) BUG. directory struct dirent explicitly used instead of DIR_BUF. FIX. save.c - applied supplied patch. 5) Pieter Immelman (pi@itu1.sun.ac.za) BUG. Reading xover Xref: line when not there causes SIGSEGV. FIX. art.c - applied supplied patch. 6) Mark Tomlinson (mark@garden.equinox.gen.nz) BUG. Would not compile on AmigaDOS. FIX. applied supplied patch. 7) Julian Thompson (jrt@oasis.icl.co.uk) BUG. input_peneding() routine does not work if HAVE_POLL is defined. FIX. art.c - applied supplied patch. 8) Clifton Royston (cliftonr@netcom.com) BUG. Lines not correctly formatted in check_article_to_be_posted(). FIX. post.c - adding flushing to stdout stream. 9) Richard Lloyd (rkl@csc.liv.ac.uk) BUG. Would not compile on HPUX 9.X machines. FIX. config.h - applied supplied patch. 10) Mike Glendinning (mikeg@ingres.co.uk) BUG. SHould make use of INN nntplib routines if available. FIX. tin.h init.c inews.c - applied supplied patch. 11) Earle Ake (akee@wpdis11.wpafb.af.mil) BUG. Default mailer does not understand '@' notation on u3b2 machines. FIX. tin.h - applied supplied patch. 12) Earle Ake (akee@wpdis11.wpafb.af.mil) BUG. Default mailer path is wrong on Pyramid machines. FIX. tin.h - applied supplied patch. 13) Clifton Royston (cliftonr@netcom.com) BUG. Entering groups takes a lot longer than required by tin v1.20. FIX. tin.h newsrc.c - applied supplied patch. 14) John Schmitz (schmitz@scd.hp.com) BUG. Tcp/ip socket buffer size is very small on hpux machines. FIX. nntplib.c - applied supplied patch. 15) John Schmitz (schmitz@scd.hp.com) BUG. valid_artnum() routine does a linear search routine which is a killer in big groups. Needs converting to use a binary search. FIX. art.c - applied supplied patch. 16) Iain Lea (iain.lea@erlm.siemens.de) BUG. v1.21 would not allow articles to be posted if the group was not present in the sites active file which caused problems for sites that did not take a full feed. FIX. INSTALL post.c - Added HAVE_FACIST_NEWSADMIN to allow the message to be a warning or an error (facist mode). 17) John Schmitz (schmitz@scd.hp.com) BUG. system() call does not work correctly on hpux machines. FIX. misc.c - applied supplied patch. 18) Olaf Mittelstaedt BUG. Needs c:\tmp on a HPFS partition FIX. Use envvar TMPDIR for location of tmp directory 19) Malkani Sanjay (sanjay@uxmail.ust.hk) [OS/2] ASK. support for local newsspool ADD. support for local newsspool 20) Richard Stanton (stanton@haas.berkeley.edu) [OS/2] BUG. Cannot use C:\ as HOME. FIX. checking for trailing '\' in path before adding '\' 21) Andreas Wrede (andreas@scilink.org) BUG. Would not compile on OS/2 FIX. applied supplied patch 22) John Schmitz (schmitz@scd.hp.com) ADD. page.c - contributed MIME support via call to metamail. 23) Phil Molyneux (molyneux@kingston.ac.uk) BUG. Manual page list bug report command to be 'R' when it is actually 'B'. FIX. tin.1 - corrected manual page. 24) Andreas Baumann (andresb@kbfi.ee) BUG. Crashes if a LIST OVERVIEW.FMT is done to an ANU nntp server. FIX. open.c - added check to see if xover command is supported. 25) Iain Lea (iain.lea@erlm.siemens.de) BUG. Specifying alternate news index directory does not work. FIX. init.c - re-added check for TIN_INDEX & -I cmd line option. 26) Werner Fleck (Fleck@tu-harburg.dbp.de) BUG. If a filename like "$FOO", e.g. an env var without a trailing "/" is used strfpath() will return a bogus filename. FIX. misc.c - applied supplied patch. 27) Bryan Dongray (btd@uk.cray.com) BUG. Too I/O bound when doing HEAD calls via NNTP. FIX. art.c open.c - applied supplied patch. 28) John Schmitz (schmitz@scd.hp.com) BUG. Article checking routine should not allow user to insert From: line. FIX. post.c - applied supplied patch. 30) Bryan Dongray (btd@uk.cray.com) BUG. Does not reconnect to nntp server to timed out nntp server. FIX. nntplib.c - applied supplied patch. 31) Kazushi Marukawa (kazushi@kubota.co.jp) BUG. errno is not defined in misc.c so fails on Mips machines. FIX. misc.c - applied supplied patch 32) Mark Tomlinson (mark@garden.equinox.gen.nz) BUG. sigdisp() does not always return a value from signal(). FIX. signal.c - applied supplied patch. 33) Otto Lind (otto@coactive.com) BUG. read_newsrc_line() wastefully calling find_group_index(). FIX. newsrc.c - applied supplied patch. 34) Alan Thew (Alan.Thew@liverpool.ac.uk) BUG. does not find xref lines in Cnews generated overview files. FIX. art.c - added extra check for lowercase xref header string. 35) Brett Carver (brett@hpsrjtc.sr.hp.com) BUG. Copy of users pwd data is a ptr to static buf that returned from getpwnam() and can be overwritten if called again. FIX. init.c - saved copy of pwd entry so that its not overwriiten. 36) Clifton Royston (cliftonr@netcom.com) BUG. The INSTALL document could be clearer in machine naming text. FIX. INSTALL - applied supplied patch. 37) Ollivier Robert (roberto@keltia.frmug.fr.net) BUG. Would not compile on 386BSD. FIX. config.h - applied supplied patch. 38) Iain Lea (iain.lea@erlm.siemens.de) BUG. When searching for a group name should also look at description. FIX. search.c - modified search_group() to also check description. 39) Clifton Royston (cliftonr@netcom.com) ADD. active.c - auto-subscribe/unsubscribe to new newsgroups. Checks for the env. variables. 40) Bryan Dongray (btd@uk.cray.com) ADD. Recognizes mouse buttons when running in an xterm window. 41) Tom Parry (parry@yoyo.cc.monash.edu.au) ADD. Added -n cmd line option to only read subscribed to groups from the active file and not the whole active file. This is a big win when reading via a slow line. 42) Iain Lea (iain.lea@erlm.siemens.de) ADD. When selecting a group/subject via a number it will automatically enter the group/article. ð*[SRC.TIN-1_22]COMMON.PATCH;1+,z.//€ 4-d0@î123KÿPWO56ÀÒÌt…—7€³c1—89€]V‚—G/€HªJÿ *** common/conf.h Wed Sep 30 14:34:38 1992 --- common/conf.h Wed Nov 18 18:43:44 1992 *************** *** 4,9 **** --- 4,22 ---- */ /* + * Extensions to NNTP RFC977 (I.Lea 18-11-92) + */ + + #define XOVERVIEW /* retieve .overview index files from server */ + #define XINDEX /* retieve tin index files from server */ + #define XMOTD /* retieve message of the day from server */ + #define XUSER /* log clients username to nntp logfile */ + + #define XINDEX_DIR "/usr/spool/news/.index" + #define XMOTD_FILE "/usr/lib/news/motd" + #define SUBSCRIPTIONS_FILE "/usr/lib/news/subscriptions" + + /* * Compile time options. */ *** common/conf.h.dist Wed Sep 30 14:34:35 1992 --- common/conf.h.dist Wed Nov 18 18:44:47 1992 *************** *** 4,13 **** */ /* * Compile time options. */ - #undef ALONE /* True if we're running without inetd */ #ifdef ALONE --- 4,25 ---- */ /* + * Extensions to NNTP RFC977 (I.Lea 18-11-92) + */ + + #define XOVERVIEW /* retieve .overview index files from server */ + #define XINDEX /* retieve tin index files from server */ + #define XMOTD /* retieve message of the day from server */ + #define XUSER /* log clients username to nntp logfile */ + + #define XINDEX_DIR "/usr/spool/news/.index" + #define XMOTD_FILE "/usr/lib/news/motd" + #define SUBSCRIPTIONS_FILE "/usr/lib/news/subscriptions" + + /* * Compile time options. */ #undef ALONE /* True if we're running without inetd */ #ifdef ALONE *** common/nntp.h Wed Sep 30 14:34:38 1992 --- common/nntp.h Wed Nov 18 19:19:00 1992 *************** *** 38,43 **** --- 38,52 ---- #define OK_GOODBYE 205 /* Closing connection */ #define OK_GROUP 211 /* Group selected */ #define OK_GROUPS 215 /* Newsgroups follow */ + #ifdef XMOTD + #define OK_XMOTD 217 /* Motd (message of the day) file follows */ + #endif + #ifdef XINDEX + #define OK_XINDEX 218 /* Tin style group index file follows */ + #endif + #ifdef XOVERVIEW + #define OK_XOVERVIEW 219 /* .overview style group index file follows */ + #endif #define OK_ARTICLE 220 /* Article (head & body) follows */ #define OK_HEAD 221 /* Head follows */ #define OK_BODY 222 /* Body follows */ *************** *** 57,62 **** --- 66,80 ---- #define ERR_GOODBYE 400 /* Have to hang up for some reason */ #define ERR_NOGROUP 411 /* No such newsgroup */ #define ERR_NCING 412 /* Not currently in newsgroup */ + #ifdef XMOTD + #define ERR_XMOTD 417 /* No motd (message of the day) file */ + #endif + #ifdef XINDEX + #define ERR_XINDEX 418 /* No tin style index file for newsgroup */ + #endif + #ifdef XOVERVIEW + #define ERR_XOVERVIEW 419 /* No .overview style index file for newsgroup */ + #endif #define ERR_NOCRNT 420 /* No current article selected */ #define ERR_NONEXT 421 /* No next article in this group */ #define ERR_NOPREV 422 /* No previous article in this group */ ð*[SRC.TIN-1_22]CONFIG.H;13+,è.//€ 4õ-d0@î123KÿPWO56@ý÷¢é‡—7`°y£é‡—89€]V‚—G/€HªJÿ/* * Project : tin - a Usenet reader * Module : config.h * Author : I.Lea * Created : 03-09-92 * Updated : 20-09-93 * Notes : #defines to determine different OS capabilites * Copyright : (c) Copyright 1991-93 by Iain Lea * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #if !defined(M_AMIGA) && !defined(M_OS2) && !defined(M_UNIX) && !defined(VMS) # define M_UNIX #endif #ifdef VMS # define unlink(file) remove(file) #endif #if defined(M_XENIX) # define HAVE_PROTOTYPES_H #endif #if defined(EPIX) || defined (__hpux) || defined(PTX) # define HAVE_TERMIO_H #endif #if defined(QNX4) || defined(UMAXV) # define HAVE_TERMIOS_H #endif #if defined(_POSIX_SOURCE) || defined(__386BSD__) || defined(DGUX) || \ defined(SVR4) || defined(UMAXV) # if !defined(M_OS2) # define HAVE_POSIX_JC # endif #endif #if defined(M_OS2) || defined(SVR4) # define HAVE_LOCALE_H #endif #if defined(SVR4) # define HAVE_SETLOCALE # undef sinix /* SNI Sinix (nsc32000) */ #endif #if !defined(M_AMIGA) # define HAVE_CURSES_H #endif #if (defined(SIGCHLD) && !defined(apollo)) || defined(__hpux) # define HAVE_SYS_WAIT_H #endif #if !defined(M_OS2) # define HAVE_PWD_H #endif #if !defined(M_OS2) # define HAVE_SYS_PARAM_H #endif #if !defined(apollo) && !defined(gould) && !defined(MACH) && \ !defined(mips) && !defined(__NeXT__) && !defined(M_OS2) # define HAVE_UNISTD_H #endif #if !defined(M_AMIGA) && !defined(COHERENT) && !defined(MINIX) && \ !defined(M_OS2) && !defined(VMS) # define HAVE_SYS_IOCTL_H #endif #if !defined(M_AMIGA) && !defined(apollo) && !defined(BSD) && \ !defined(M_OS2) && !defined(sinix) && !defined(RS6000) && !defined(VMS) # define HAVE_SYS_UTSNAME_H #endif #if !defined(apollo) && !defined(EPIX) && !defined(pyr) && \ !defined(sequent) && !defined(sysV68) && !defined(UTS) && \ !defined(u3b2) # define HAVE_STDLIB_H #endif #if defined(BSD) # define HAVE_STRINGS_H #else # define HAVE_STRING_H #endif #if defined(apollo) || defined(BSD) || defined(EPIX) || defined(M_AMIGA) || \ defined(M_OS2) || defined(__osf__) || defined(UMAXV) # define HAVE_FCNTL_H #endif #if !defined(__hpux) # define HAVE_SYS_STREAM_H #endif #if !defined(apollo) && !defined(COHERENT) && !defined(__hpux) && \ !defined(M_OS2) && !defined(sinix) && !defined(UMAXV) # define HAVE_SYS_PTEM_H #endif #if !defined(apollo) && !defined(COHERENT) && !defined(M_OS2) && \ !defined(SCO_UNIX) && !defined(sinix) && !defined(SVR4) # define HAVE_SYS_PTY_H # define XWIN /* stops ISC bitching */ #endif #if defined(__386BSD__) || defined(apollo) || defined(BSD) || \ defined(__hpux) || defined(linux) || defined(M_OS2) || \ defined(__osf__) || defined(RS6000) || defined(sinix) || \ defined(UMAXV) || defined(MULTINET) # define HAVE_NETDB_H #endif #if defined(M_OS2) # define HAVE_NETLIB_H #endif #if !defined(pyr) # define HAVE_TIME_H #endif #if !defined(apollo) && !defined(M_OS2) && !defined(SCO_UNIX) && \ !defined(u3b2) && !defined(VMS) # define HAVE_SYS_TIME_H #endif #if defined(SCO_UNIX) || defined(u3b2) # define HAVE_SYS_TIMES_H #endif #if defined(PTX) || defined(RS6000) || defined(SCO_UNIX) # define HAVE_SYS_SELECT_H #endif #if defined(M_AMIGA) || defined(COHERENT) || defined(M_OS2) || defined(QNX4) # define HAVE_ERRNO_H #endif #if defined(__GNUC__) || defined(HAVE_POSIX_JC) # define HAVE_SIGTYPE_VOID #else # if defined(sony) # define HAVE_SIGTYPE_INT # else # if __STDC__ || defined(atthcx) || defined(__hpux) || \ defined(__osf__) || defined(M_OS2) || defined(PTX) || \ defined(RS6000) || defined(sgi) || defined(sinix) || \ defined(sysV68) || defined(sun) || defined(SVR4) || \ defined(u3b2) || defined(ultrix) # define HAVE_SIGTYPE_VOID # else # define HAVE_SIGTYPE_INT # endif # endif #endif #if defined(M_OS2) # define HAVE_COMPTYPE_VOID #else # define HAVE_COMPTYPE_CHAR #endif #if defined(apollo) || defined(AUX) || defined(BSD) || defined(linux) || \ defined(__hpux) || defined(__osf__) || defined(PTX) || defined(QNX4) || \ defined(RS6000) || defined(sinix) || defined(SVR4) || defined(UMAXV) # define HAVE_LONG_FILENAMES #endif #if defined(apollo) || defined(BSD) || defined(__hpux) || defined(linux) || \ defined(__osf__) || defined(M_OS2) || defined(RS6000) || defined(sinix) || \ defined(UMAXV) || defined(MULTINET) # define HAVE_GETHOSTBYNAME #endif #if defined(M_AMIGA) || defined(apollo) || defined(BSD) || defined(MINIX) || defined(VMS) # define HAVE_CR_AS_CHAR #endif /* * Used in tin.h */ #if __STDC__ || defined(SVR4) # if !defined(apollo) && !defined(__hpux) # define HAVE_ANSI_ASSERT # endif #endif #if defined(M_UNIX) # define HAVE_COREFILE #endif #if defined(M_UNIX) # define HAVE_SET_GID_UID #endif #if defined(M_UNIX) && !defined(__386BSD__) # define HAVE_UNAME #endif #if defined(MACH) || defined(__NeXT__) || defined(M_OS2) # define DONT_HAVE_SIGWINCH #endif #if defined(BSD) || defined(EPIX) && !defined(__386BSD__) && \ !defined(sinix) # define DONT_HAVE_GETCWD #endif #if defined(pyr) || defined(sequent) # define DONT_HAVE_MEMCMP #endif #if defined(BSD) && !defined(__386BSD__) # define DONT_HAVE_STRCHR #endif #if defined(__arm) || defined(COHERENT) || defined(pyr) || defined(sequent) # define DONT_HAVE_TZSET #endif /* * Used in parsedate.y */ #if defined(apollo) || defined(__arm) || defined(__convex__) || \ defined(DGUX) || defined(pyr) || defined(sequent) || !defined(BSD) # define DONT_HAVE_TM_GMTOFF #endif /* * Use poll()/select() in input_pending() */ #if defined(SVR4) || defined(HAVE_POLL) # if !defined(__hpux) # define HAVE_STROPTS_H # endif # define HAVE_POLL_H # if !defined(HAVE_POLL) # define HAVE_POLL # endif # undef HAVE_SELECT #endif #if !defined(apollo) && !defined(M_AMIGA) && !defined(COHERENT) && \ !defined(M_OS2) && !defined(QNX4) && !defined(supermax) && \ !defined(u3b2) && !defined(HAVE_POLL) # define HAVE_SELECT #endif #if defined(M_AMIGA) || defined(QNX4) # define SMALL_MEMORY_MODEL #endif #if defined(M_AMIGA) # define DONT_REREAD_ACTIVE_FILE #endif #if defined(COHERENT) # define HAVE_SETTZ #endif #if defined(M_UNIX) # define HAVE_FORK #endif #if defined(M_OS2) # define HAVE_STRFTIME #endif #if !defined(M_OS2) && !defined(VMS) # define HAVE_SYSERRLIST #endif #if defined(__hpux) # define DONT_PROTOTYPE_PTR_TO_FUNC # define DONT_HAVE_SYS_BSDTYPES_H # define HAVE_KEYPAD #endif #if defined(RS6000) # define READ_CHAR_HACK #endif #if defined(sinix) # undef HAVE_SYS_STREAM_H # define DONT_HAVE_MKDIR #endif #if defined(supermax) # define HAVE_BROKEN_TGETSTR #endif #if defined(QNX4) # define HAVE_TCGETATTR # define HAVE_TCSETATTR #endif #if defined(M_AMIGA) || defined(QNX) # define HAVE_KEY_PREFIX #endif #if defined(M_UNIX) # define HAVE_METAMAIL #endif /* * Hack used to try and get a compile on Sun i386 & old SunOS 4.0.2 */ #if defined(sun) && defined(i386) # undef HAVE_STDLIB_H #endif #if defined(BSD) || defined(__osf__) || defined(_POSIX_SOURCE) # define HAVE_REWINDDIR #endif /* * Various hacks used to try and get a compile on the strange ones... */ #if defined(u3b2) # define size_t unsigned long int #endif /* * Lets try and be a wise ass and make a nntp able binary * for machines where the netlibs are in the libc library */ #if defined(BSD) || defined(linux) || defined(RS6000) # if !defined(NNTP_ABLE) # define NNTP_ABLE # endif #endif dð*[SRC.TIN-1_22]CURSES.C;13+,.!//€ 4! {-d0@î123KÿPWO"56ÀùN‘š’—7`ÙP’š’—89€šIÊ’—G/€HªJÿ p§Ð~ TIN-1_22.BCKd[SRC.TIN-1_22]CURSES.C;13!“U0/* * Project : tin - a Usenet reader * Module : curses.c * Author : D.Taylor & I.Lea * Created : 01-01-86 * Updated : 22-09-93 * Notes : This is a screen management library borrowed with permission * from the Elm mail system (a great mailer--I highly recommend * it!).This library was hacked to provide what tin needs. * Copyright : Copyright (c) 1986-93 Dave Taylor & Iain Lea * The Elm Mail System - $Revision: 2.1 $ $State: Exp $ */ #include "tin.h" #ifndef ns32000 # undef sinix #endif #ifdef VMS #include #include #include #include #include #endif #if defined(HAVE_ERRNO_H) || defined(VMS) # include #else # include #endif #define DEFAULT_LINES_ON_TERMINAL 24 #define DEFAULT_COLUMNS_ON_TERMINAL 80 int cLINES = DEFAULT_LINES_ON_TERMINAL - 1; int cCOLS = DEFAULT_COLUMNS_ON_TERMINAL; int inverse_okay = TRUE; static int _inraw = FALSE; /* are we IN rawmode? */ int _hp_glitch = FALSE; /* standout not erased by overwriting on HP terms */ static int xclicks=FALSE; /* do we have an xterm? */ #ifndef INDEX_DAEMON #define BACKSPACE '\b' #define VERY_LONG_STRING 2500 #if (defined(M_AMIGA) && !defined(__SASC)) || defined(COHERENT) || defined(BSD) # ifndef BSD4_1 # include # else # include # endif #else # ifndef SYSV # ifndef MINIX # ifdef sinix # include # else # ifdef VMS # include # else # include # endif # endif # else # include # endif # else # if defined(__hpux) || (defined(sun) && defined(SVR4)) # include # endif # endif #endif #define TTYIN 0 #ifdef SHORTNAMES # define _clearinverse _clrinv # define _cleartoeoln _clrtoeoln # define _cleartoeos _clr2eos #endif #ifndef VMS #if (defined(M_AMIGA) && !defined(__SASC)) || defined(BSD) || defined(MINIX) # ifdef TCGETA # undef TCGETA # endif # define TCGETA TIOCGETP # ifdef TCSETAW # undef TCSETAW # endif # define TCSETAW TIOCSETP struct sgttyb _raw_tty, _original_tty; #else # if !defined(M_AMIGA) # if defined(HAVE_TERMIOS_H) || defined(sinix) # ifndef TCGETA # define TCGETA STCGETA # endif # ifndef TCSETA # define TCSETAW STCSETAW # endif struct termios _raw_tty, _original_tty; # else # ifndef M_OS2 struct termio _raw_tty, _original_tty; # endif # endif # endif #endif #endif static char *_clearscreen, *_moveto, *_cleartoeoln, *_cleartoeos, *_setinverse, *_clearinverse, *_setunderline, *_clearunderline, *_xclickinit, *_xclickend, *_terminalinit, *_terminalend, *_keypadlocal, *_keypadxmit; static int _columns, _line, _lines; #ifdef M_UNIX static char _terminal[1024]; /* Storage for terminal entry */ static char _capabilities[1024]; /* String for cursor motion */ static char *ptr = _capabilities; /* for buffering */ extern char *tgetstr (); /* Get termcap capability (string) */ extern char *tgoto (); /* and the goto stuff */ extern int tgetflag (); /* Get termcap capability (boolean) */ extern int tgetnum (); /* Get termcap capability (number) */ #endif /* M_UNIX */ static int in_inverse; /* 1 when in inverse, 0 otherwise */ #if __STDC__ int outchar (int c); /* char output for tputs */ #else int outchar (); #endif #endif /* INDEX_DAEMON */ void setup_screen () { #ifndef INDEX_DAEMON /* * get screen size from termcap entry & setup sizes */ _line = 1; ScreenSize (&cLINES, &cCOLS); cmd_line = FALSE; Raw (TRUE); set_win_size (&cLINES, &cCOLS); #endif /* INDEX_DAEMON */ } #ifdef M_UNIX int InitScreen () { #ifndef INDEX_DAEMON extern int tgetent(); /* get termcap entry */ char termname[40], *p; if ((p = (char *) getenv ("TERM")) == NULL) { fprintf (stderr, "%s: TERM variable must be set to use screen capabilities\n", progname); return (FALSE); } if (strcpy (termname, p) == NULL) { fprintf (stderr,"%s: Can't get TERM variable\n", progname); return (FALSE); } if (tgetent (_terminal, termname) != 1) { fprintf (stderr,"%s: Can't get entry for TERM\n", progname); return (FALSE); } /* load in all those pesky values */ _clearscreen = tgetstr ("cl", &ptr); _moveto = tgetstr ("cm", &ptr); _cleartoeoln = tgetstr ("ce", &ptr); _cleartoeos = tgetstr ("cd", &ptr); _lines = tgetnum ("li"); _columns = tgetnum ("co"); _setinverse = tgetstr ("so", &ptr); _clearinverse = tgetstr ("se", &ptr); _setunderline = tgetstr ("us", &ptr); _clearunderline = tgetstr ("ue", &ptr); _hp_glitch = tgetflag ("xs"); #ifdef HAVE_BROKEN_TGETSTR _terminalinit = ""; _terminalend = ""; _keypadlocal = ""; _keypadxmit = ""; #else _terminalinit = tgetstr ("ti", &ptr); _terminalend = tgetstr ("te", &ptr); _keypadlocal = tgetstr ("ke", &ptr); _keypadxmit = tgetstr ("ks", &ptr); #endif if (strcmp (termname, "xterm") == 0) { xclicks = TRUE; _xclickinit = "\033[?9h"; _xclickend = "\033[?9l"; } InitWin (); if (!_clearscreen) { fprintf (stderr, "%s: Terminal must have clearscreen (cl) capability\n",progname); return (FALSE); } if (!_moveto) { fprintf (stderr, "%s: Terminal must have cursor motion (cm)\n", progname); return (FALSE); } if (!_cleartoeoln) { fprintf (stderr, "%s: Terminal must have clear to end-of-line (ce)\n", progname); return (FALSE); } if (!_cleartoeos) { fprintf (stderr, "%s: Terminal must have clear to end-of-screen (cd)\n", progname); return (FALSE); } if (_lines == -1) _lines = DEFAULT_LINES_ON_TERMINAL; if (_columns == -1) _columns = DEFAULT_COLUMNS_ON_TERMINAL; /* * kludge to workaround no inverse */ if (_setinverse == 0) { _setinverse = _setunderline; _clearinverse = _clearunderline; if (_setinverse == 0) draw_arrow_mark = 1; } return (TRUE); #else return (FALSE); #endif /* INDEX_DAEMON */ } #else /* ! M_UNIX */ int InitScreen () { #ifndef INDEX_DAEMON char *ptr; /* * we're going to assume a terminal here... */ _clearscreen = "\033[1;1H\033[J"; _moveto = "\033[%d;%dH"; /* not a termcap string! */ _cleartoeoln = "\033[K"; _setinverse = "\033[7m"; _clearinverse = "\033[0m"; _setunderline = "\033[4m"; _clearunderline = "\033[0m"; _keypadlocal = ""; _keypadxmit = ""; #ifdef M_AMIGA _terminalinit = "\033c"; _terminalend = "\033c"; _cleartoeos = "\033[J"; #endif #if defined(M_OS2) || defined(VMS) _cleartoeos = NULL; _terminalinit = NULL; _terminalend = NULL; #ifndef VMS initscr (); #endif #endif InitWin (); _lines = _columns = -1; /* * Get lines and columns from environment settings - useful when * you're using something other than an Amiga window */ if (ptr = getenv ("LINES")) { _lines = atol (ptr); } if (ptr = getenv ("COLUMNS")) { _columns = atol (ptr); } /* * If that failed, try get a response from the console itself */ #ifdef M_AMIGA if (_lines == -1 || _columns == -1) { Raw (TRUE); tputs ("\2330 q",1,outchar); /* identify yourself */ fflush (stdout); getsize: while (ReadCh () != 0x9b) { ; /* Look for escape */ } /* get top */ ptr = buf; do { c = *ptr++ = ReadCh (); } while (isdigit(c)); if (c != ';') { goto getsize; } /* get right */ ptr = buf; do { c = *ptr++ = ReadCh (); } while (isdigit(c)); if (c != ';') { goto getsize; } /* get bottom */ ptr = buf; do { c = *ptr++ = ReadCh (); } while (isdigit(c)); if (c != ';') { goto getsize; } *ptr = 0; _lines = atol (buf); /* get right */ ptr = buf; do { c = *ptr++ = ReadCh (); } while (isdigit(c)); if (c != ' ') { goto getsize; } if (ReadCh () != 'r') { goto getsize; } *ptr = 0; _columns = atol (buf); } #endif /* M_AMIGA */ #ifdef M_OS2 if (_lines == -1 || _columns == -1) { _lines = LINES; _columns = COLS; } #endif /* M_OS2 */ #ifdef VMS { int input_chan, status; struct sensemode { short status; unsigned char xmit_baud; unsigned char rcv_baud; unsigned char crfill; unsigned char lffill; unsigned char parity; unsigned char unused; char class; char type; short scr_wid; unsigned long tt_char : 24, scr_len : 8; unsigned long tt2_char; } tty; $DESCRIPTOR (input_dsc, "TT"); status = SYS$ASSIGN (&input_dsc, &input_chan, 0, 0); if (! (status & 1)) LIB$STOP (status); SYS$QIOW (0, input_chan, IO$_SENSEMODE, &tty, 0, 0, &tty.class, 12, 0, 0, 0, 0); _columns = tty.scr_wid; _lines = tty.scr_len; } #endif Raw (FALSE); return (TRUE); #else return (FALSE); #endif /* INDEX_DAEMON */ } #endif /* M_UNIX */ /* * returns the number of lines and columns on the display. */ void ScreenSize (num_lines, num_columns) int *num_lines, *num_columns; { #ifndef INDEX_DAEMON if (_lines == 0) _lines = DEFAULT_LINES_ON_TERMINAL; if (_columns == 0) _columns = DEFAULT_COLUMNS_ON_TERMINAL; *num_lines = _lines - 1; /* assume index from zero*/ *num_columns = _columns; /* assume index from one */ #endif /* INDEX_DAEMON */ } void InitWin () { #ifndef INDEX_DAEMON if (_terminalinit) { tputs (_terminalinit, 1, outchar); fflush (stdout); } set_keypad_on (); set_xclick_on (); #endif /* INDEX_DAEMON */ } void EndWin () { #ifndef INDEX_DAEMON if (_terminalend) { tputs (_terminalend, 1, outchar); fflush (stdout); } set_keypad_off (); set_xclick_off (); #endif /* INDEX_DAEMON */ } void set_keypad_on () { #ifndef INDEX_DAEMON # ifdef HAVE_KEYPAD if (use_keypad && _keypadxmit) { tputs (_keypadxmit, 1, outchar); fflush (stdout); } # endif #endif /* INDEX_DAEMON */ } void set_keypad_off () { #ifndef INDEX_DAEMON # ifdef HAVE_KEYPAD if (use_keypad && _keypadlocal) { tputs (_keypadlocal, 1, outchar); fflush (stdout); } # endif #endif /* INDEX_DAEMON */ } /* * clear the screen: returns -1 if not capable */ void ClearScreen () { #ifndef INDEX_DAEMON tputs (_clearscreen, 1, outchar); fflush (stdout); /* clear the output buffer */ _line = 1; #endif /* INDEX_DAEMON */ } /* * move cursor to the specified row column on the screen. * 0,0 is the top left! */ #ifdef M_UNIX void MoveCursor (row, col) int row, col; { #ifndef INDEX_DAEMON char *stuff, *tgoto(); stuff = tgoto (_moveto, col, row); tputs (stuff, 1, outchar); fflush (stdout); _line = row + 1; #endif /* INDEX_DAEMON */ } #else /* ! M_UNIX */ void MoveCursor (row, col) int row, col; { #ifndef INDEX_DAEMON char stuff[12], *tgoto(); sprintf (stuff, _moveto, row+1, col+1); tputs (stuff, 1, outchar); fflush (stdout); _line = row + 1; #endif /* INDEX_DAEMON */ } #endif /* M_UNIX */ /* * clear to end of line */ void CleartoEOLN () { #ifndef INDEX_DAEMON tputs (_cleartoeoln, 1, outchar); fflush (stdout); /* clear the output buffer */ #endif /* INDEX_DAEMON */ } /* * clear to end of screen */ void CleartoEOS () { #ifndef INDEX_DAEMON int i; if (_cleartoeos) { tputs (_cleartoeos, 1, outchar); } else { for (i=_line - 1 ; i < _lines ; i++) { MoveCursor (i, 0); CleartoEOLN (); } } fflush (stdout); /* clear the output buffer */ #endif /* INDEX_DAEMON */ } /* * set inverse video mode */ void StartInverse () { #ifndef INDEX_DAEMON in_inverse = 1; if (_setinverse && inverse_okay) tputs (_setinverse, 1, outchar); fflush (stdout); #endif /* INDEX_DAEMON */ } /* * compliment of startinverse */ void EndInverse () { #ifndef INDEX_DAEMON in_inverse = 0; if (_clearinverse && inverse_okay) tputs (_clearinverse, 1, outchar); fflush (stdout); #endif /* INDEX_DAEMON */ } /* * toggle inverse video mode */ void ToggleInverse () { #ifndef INDEX_DAEMON if (in_inverse == 0) StartInverse(); else EndInverse(); #endif /* INDEX_DAEMON */ } /* * returns either 1 or 0, for ON or OFF */ int RawState() { return (_inraw); } /* * state is either TRUE or FALSE, as indicated by call */ void Raw (state) int state; { #ifdef VMS if (state == FALSE && _inraw) { /* vmsnoraw();*/ _inraw = 0; } else if (state == TRUE && ! _inraw) { /* vmsraw();*/ _inraw = 1; } #else #if !defined(INDEX_DAEMON) && !defined(M_OS2) #if defined(M_AMIGA) && defined(__SASC) rawcon (state); #else if (state == FALSE && _inraw) { # ifdef HAVE_TCSETATTR (void) tcsetattr (TTYIN, TCSANOW, &_original_tty); # else (void) ioctl (TTYIN, TCSETAW, &_original_tty); # endif _inraw = 0; } else if (state == TRUE && ! _inraw) { #ifdef HAVE_TCGETATTR (void) tcgetattr (TTYIN, &_original_tty); (void) tcgetattr (TTYIN, &_raw_tty); #else (void) ioctl (TTYIN, TCGETA, &_original_tty); /* current setting */ (void) ioctl (TTYIN, TCGETA, &_raw_tty); /* again! */ #endif #if defined(BSD) || defined(M_AMIGA) || defined(MINIX) _raw_tty.sg_flags &= ~(ECHO | CRMOD); /* echo off */ _raw_tty.sg_flags |= CBREAK; /* raw on */ #ifdef M_AMIGA _raw_tty.sg_flags |= RAW; /* Manx-C 5.2 does not support CBREAK */ #endif #else #ifdef QNX4 /* noecho raw mode */ _raw_tty.c_lflag &= ~(ICANON |ISIG| ECHO |ECHOK | ECHONL); _raw_tty.c_oflag &= ~(OPOST); _raw_tty.c_cc[VMIN] = 1; /* minimum # of chars to queue */ _raw_tty.c_cc[VTIME] = 0; /* minimum time to wait for input */ #else _raw_tty.c_lflag &= ~(ICANON | ECHO); /* noecho raw mode */ _raw_tty.c_cc[VMIN] = '\01'; /* minimum # of chars to queue */ _raw_tty.c_cc[VTIME] = '\0'; /* minimum time to wait for input */ #endif /* QNX4 */ #endif #ifdef HAVE_TCSETATTR (void) tcsetattr (TTYIN, TCSANOW, &_raw_tty); #else (void) ioctl (TTYIN, TCSETAW, &_raw_tty); #endif _inraw = 1; } #endif /* M_AMIGA */ #endif /* VMS */ #endif /* INDEX_DAEMON */ } /* * read a character with Raw mode set! */ #ifdef M_OS2 int ReadCh () { #ifndef INDEX_DAEMON extern int errno; char ch; KBDKEYINFO os2key; int rc; register int result = 0; static secondkey = 0; if (secondkey) { result = secondkey; secondkey = 0; } else { rc = KbdCharIn((PKBDKEYINFO)&os2key, IO_WAIT, 0); result = os2key.chChar; if (result == 0xe0) { result = 0x1b; switch (os2key.chScan) { case 'H': secondkey = 'A'; break; case 'P': secondkey = 'B'; break; case 'K': secondkey = 'D'; break; case 'M': secondkey = 'C'; break; case 'I': secondkey = 'I'; break; case 'Q': secondkey = 'G'; break; case 'G': secondkey = 'H'; break; case 'O': secondkey = 'F'; break; default: secondkey = '?'; } } else if (result == 0x0d) { result = 0x0a; } } return ((result == EOF) ? EOF : result & 0xFF); #endif /* INDEX_DAEMON */ } #else /* ! M_OS2 */ #ifndef VMS int ReadCh () { #ifndef INDEX_DAEMON extern int errno; char ch; register int result = 0; #ifdef READ_CHAR_HACK #undef getc while ((result = getc(stdin)) == EOF) { if (feof(stdin)) break; #ifdef EINTR if (ferror(stdin) && errno != EINTR) #else if (ferror(stdin)) #endif break; clearerr(stdin); } return ((result == EOF) ? EOF : result & 0xFF); #else # ifdef EINTR while ((result = read (0, &ch, 1)) < 0 && errno == EINTR) ; /* spin on signal interrupts */ # else result = read (0, &ch, 1); # endif return((result <= 0 ) ? EOF : ch & 0xFF); #endif #endif /* INDEX_DAEMON */ } #endif /* VMS */ #endif /* M_OS2 */ /* * output a character. From tputs... (Note: this CANNOT be a macro!) */ int outchar (c) int c; { return fputc (c, stdout); } /* * setup to monitor mouse buttons if running in a xterm */ void xclick (state) int state; { #ifndef INDEX_DAEMON static int prev_state = 999; if (xclicks && prev_state != state) { if (state == TRUE) { tputs (_xclickinit, 1, outchar); } else { tputs (_xclickend, 1, outchar); } fflush (stdout); prev_state = state; } #endif /* INDEX_DAEMON */ } /* * switch on monitoring of mouse buttons */ void set_xclick_on () { xclick (TRUE); } /* * switch off monitoring of mouse buttons */ void set_xclick_off () { xclick (FALSE); } ð*[SRC.TIN-1_22]DEBUG.C;1+,Ž.//€ 4-d0@î123KÿPWO56`êt…—7ei1—89€]V‚—G/€HªJÿ/* * Project : tin - a Usenet reader * Module : debug.c * Author : I.Lea * Created : 01-04-91 * Updated : 02-10-92 * Notes : debug routines * Copyright : (c) Copyright 1991-93 by Iain Lea * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" int debug; /* * nntp specific debug routines */ void debug_nntp (func, line) char *func; char *line; { #ifdef DEBUG char file[PATH_LEN]; FILE *fp; if (debug == 0) return; sprintf (file, "%sNNTP", TMPDIR); if ((fp = fopen (file, "a+")) != NULL) { fprintf (fp,"%s: %s\n", func, line); fclose (fp); chmod (file, 0666); } #endif } void debug_nntp_respcode (respcode) int respcode; { #ifdef DEBUG debug_nntp ("get_respcode", nntp_respcode (respcode)); #endif } /* * tin specific debug routines */ void debug_print_arts () { #ifdef DEBUG int i; if (debug != 2) return; for (i = 0; i < top; i++) { /* for each group */ debug_print_header (&arts[i]); } #endif } void debug_print_header (s) struct t_article *s; { #ifdef DEBUG char file[PATH_LEN]; FILE *fp; if (debug != 2) return; sprintf (file, "%sARTS", TMPDIR); if ((fp = fopen (file, "a+")) != NULL) { fprintf (fp,"art=[%5ld] tag=[%s] kill=[%s] hot=[%s]\n", s->artnum, (s->tagged ? "TRUE" : "FALSE"), (s->killed ? "TRUE" : "FALSE"), (s->hot ? "TRUE" : "FALSE")); fprintf (fp,"subj=[%-38s]\n", s->subject); fprintf (fp,"date=[%ld] from=[%s] name=[%s]\n", s->date, s->from, s->name); if (s->archive) { fprintf (fp, "arch=[%-38s] ", s->archive); } else { fprintf (fp, "arch=[] "); } if (s->part) { fprintf (fp, "part=[%s] ", s->part); } else { fprintf (fp, "part=[] "); } if (s->patch) { fprintf (fp, "patch=[%s]\n", s->patch); } else { fprintf (fp, "patch=[]\n"); } fprintf (fp,"thread=[%d] inthread=[%d] unread=[%d]\n\n", s->thread, s->inthread, s->unread); /* fprintf (fp,"thread=[%s] inthread=[%s] unread=[%s]\n", (s->thread == ART_NORMAL ? "ART_NORMAL" : "ART_EXPIRED"), (s->inthread ? "TRUE" : "FALSE"), (s->unread ? "TRUE" : "FALSE")); */ fflush (fp); fclose (fp); chmod (file, 0666); } #endif } void debug_save_comp () { #ifdef DEBUG char file[PATH_LEN]; FILE *fp; int i; if (debug != 2) return; sprintf (file, "%sSAVE_COMP", TMPDIR); if ((fp = fopen (file, "a+")) != NULL) { for (i = 0 ; i < num_save ; i++) { fprintf (fp,"subj=[%-38s]\n", save[i].subject); fprintf (fp,"dir=[%s] file=[%s]\n", save[i].dir, save[i].file); if (save[i].archive) { fprintf (fp, "arch=[%-38s] ", save[i].archive); } else { fprintf (fp, "arch=[] "); } if (save[i].part) { fprintf (fp, "part=[%s] ", save[i].part); } else { fprintf (fp, "part=[] "); } if (save[i].patch) { fprintf (fp, "patch=[%s]\n", save[i].patch); } else { fprintf (fp, "patch=[]\n"); } fprintf (fp,"index=[%d] saved=[%d] mailbox=[%d]\n\n", save[i].index, save[i].saved, save[i].is_mailbox); } fflush (fp); fclose (fp); chmod (file, 0666); } #endif } void debug_print_comment (comment) char *comment; { #ifdef DEBUG char file[PATH_LEN]; FILE *fp; if (debug != 2) return; sprintf (file, "%sBASE", TMPDIR); if ((fp = fopen (file, "a+")) != NULL) { fprintf (fp,"\n%s\n\n", comment); fflush (fp); fclose (fp); chmod (file, 0666); } #endif } void debug_print_base () { #ifdef DEBUG char file[PATH_LEN]; FILE *fp; int i; if (debug != 2) return; sprintf (file, "%sBASE", TMPDIR); if ((fp = fopen (file, "a+")) != NULL) { for (i = 0; i < top_base; i++) { fprintf (fp, "base[%3d]=[%5ld]\n",i,base[i]); } fflush (fp); fclose (fp); chmod (file, 0666); } #endif } void debug_print_active () { #ifdef DEBUG char file[PATH_LEN]; FILE *fp; int i; if (debug != 2) return; sprintf (file, "%sACTIVE", TMPDIR); if ((fp = fopen (file, "w")) != NULL) { for (i = 0; i < num_active; i++) { /* for each group */ fprintf (fp, "[%4d]=[%-28s] type=[%d] spooldir=[%s]\n", i, active[i].name, active[i].type, active[i].spooldir); fprintf (fp, "max=[%4ld] min=[%4ld] mod=[%c] nxt=[%4d] my_group=[%d]\n", active[i].max, active[i].min, active[i].moderated, active[i].next, active[i].my_group); fprintf (fp, "hash=[%ld] description=[%s]\n", hash_groupname (active[i].name), (active[i].description ? active[i].description : "")); fprintf (fp, "read=[%d] show=[%d] thread=[%d] sort=[%d] author=[%d] auto=[%d] process=[%d]\n", active[i].attribute.read_during_session, active[i].attribute.show_only_unread, active[i].attribute.thread_arts, active[i].attribute.sort_art_type, active[i].attribute.show_author, active[i].attribute.auto_save, active[i].attribute.post_proc_type); fprintf (fp, "maildir=[%s] savedir=[%s]\n", (active[i].attribute.maildir == (char *) 0 ? "" : active[i].attribute.maildir), (active[i].attribute.savedir == (char *) 0 ? "" : active[i].attribute.savedir)); fprintf (fp, "sigfile=[%s] followup_to=[%s]\n\n", (active[i].attribute.sigfile == (char *) 0 ? "" : active[i].attribute.sigfile), (active[i].attribute.followup_to == (char *) 0 ? "" : active[i].attribute.followup_to)); } fflush (fp); fclose (fp); chmod (file, 0666); } #endif } /* * Prints out hash distribution of active[] */ void debug_print_active_hash () { #ifdef DEBUG int empty = 0, number = 0; int collisions[32]; register i, j; for (i = 0; i < 32; i++) { collisions[i] = 0; } for (i = 0; i < TABLE_SIZE; i++) { /* printf ("HASH[%4d] ", i); */ if (group_hash[i] == -1) { /* printf ("EMPTY\n"); */ empty++; } else { number = 1; for (j=group_hash[i]; active[j].next >= 0; j=active[j].next) { number++; } if (number > 31) { printf ("MEGA HASH COLLIS ION > 31 HASH[%d]=[%d]!!!\n", i, number); } else { collisions[number]++; } } } printf ("HashTable Active=[%d] Size=[%d] Filled=[%d] Empty=[%d]\n", num_active, TABLE_SIZE, TABLE_SIZE-empty, empty); printf ("01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32\n"); printf ("-----------------------------------------------------------------------------------------------\n"); for (i = 0; i < 32; i++) { if (i) { printf ("%2d ", collisions[i]); } } printf ("\n"); #endif } ð*[SRC.TIN-1_22]ENVARG.C;1+,.//€ 4 -d0@î123KÿPWO56`Çnt…—7ei1—89€]V‚—G/€HªJÿ /* * Project : tin - a Usenet reader * Module : envarg.c * Author : B.Davidson * Created : 10-13-91 * Updated : 01-10-92 * Notes : Adds default options from environment to command line * Copyright : (c) Copyright 1991-93 by Bill Davidsen * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" int count_args (s) char *s; { int count = 0; int ch; do { /* * count and skip args */ ++count; while ((ch = *s) != '\0' && ch != ' ') ++s; while ((ch = *s) != '\0' && ch == ' ') ++s; } while (ch); return count; } void envargs (Pargc, Pargv, envstr) int *Pargc; char ***Pargv; char *envstr; { char *envptr; /* value returned by getenv */ char *bufptr; /* copy of env info */ int argc = 0; /* internal arg count */ int ch; /* spare temp value */ char **argv; /* internal arg vector */ char **argvect; /* copy of vector address */ /* * see if anything in the environment */ envptr = getenv (envstr); if (envptr == (char *) 0 || *envptr == 0) { return; } /* * count the args so we can allocate room for them */ argc = count_args (envptr); bufptr = (char *) my_malloc (1+strlen (envptr)); strcpy (bufptr, envptr); /* * allocate a vector large enough for all args */ argv = (char **) my_malloc ((argc+*Pargc+1)*sizeof(char *)); argvect = argv; /* * copy the program name first, that's always true */ *(argv++) = *((*Pargv)++); /* * copy the environment args first, may be changed */ do { *(argv++) = bufptr; /* * skip the arg and any trailing blanks */ while ((ch = *bufptr) != '\0' && ch != ' ') ++bufptr; if (ch == ' ') *(bufptr++) = '\0'; while ((ch = *bufptr) != '\0' && ch == ' ') ++bufptr; } while (ch); /* * now save old argc and copy in the old args */ argc += *Pargc; while (--(*Pargc)) *(argv++) = *((*Pargv)++); /* * finally, add a NULL after the last arg, like UNIX */ *argv = (char *) 0; /* * save the values and return */ *Pargv = argvect; *Pargc = argc; } #ifdef TEST void main (argc, argv) int argc; /* number of tokens in command line */ char **argv; /* command line tokens */ { int ch; envargs (&argc, &argv, "OPTS"); while ((ch = getopt (argc, argv, "abc")) != EOF) { switch (ch) { case 'a': puts ("Option 'a' specified"); break; case 'b': puts ("Option 'b' specified"); break; case 'c': puts ("Option 'c' specified"); break; default: puts ("Option %c unknown"); break; } } } #endif ð*[SRC.TIN-1_22]EXTERN.H;1+,‚.-//€ 4--‹-d0@î123KÿPWO.56 hät…—7Þ|e1—89€]V‚—G/€HªJÿ/* * Project : tin - a Usenet reader * Module : extern.h * Author : I.Lea * Created : 01-04-91 * Updated : 22-09-93 * Notes : * Copyright : (c) Copyright 1991-93 by Iain Lea * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ /* * Library prototypes */ #if defined(__GNUC__) && defined(DEBUG) extern unsigned int alarm (unsigned int seconds); extern int close (int fildes); extern int fork (void); extern int getpid (void); extern char *getcwd (char *buf, int size); #ifndef DGUX extern unsigned short getuid (void); extern unsigned short getegid (void); extern unsigned short geteuid (void); #endif /* DGUX */ extern int getopt (int argc, char **argv, char *optstring); extern int kill (int pid, int sig); extern int link (char *path1, char *path2); extern int open (char *path, int oflag); extern int pclose (FILE *stream); extern int read (int fildes, char *buf, unsigned int nbyte); extern int setgid (int gid); extern int setuid (int uid); extern int tgetent (char *bp, char *name); extern int tputs (register char *cp, int count, int (*outc)(int)); extern int unlink (char *path); #ifndef sony # ifndef DGUX extern unsigned short getgid (void); # endif /* DGUX */ extern void setpgrp (void); extern unsigned int sleep (unsigned int seconds); #endif #endif #if !__STDC__ extern char *getenv (); #endif extern int optind; extern char *optarg; /* * Local variables */ extern char *help_group[]; extern char *help_page[]; extern char *help_select[]; extern char *help_spooldir[]; extern char *help_thread[]; extern char active_times_file[PATH_LEN]; extern char add_addr[LEN]; extern char article[PATH_LEN]; extern char attributes_file[PATH_LEN]; extern char bug_addr[LEN]; extern char cmd_line_printer[PATH_LEN]; extern char cvers[LEN]; extern char dead_article[PATH_LEN]; extern char default_art_search[LEN]; extern char default_body_search[LEN]; extern char default_author_search[LEN]; extern char default_crosspost_group[LEN]; extern char default_editor_format[PATH_LEN]; extern char default_mail_address[LEN]; extern char default_organization[PATH_LEN]; extern char default_pipe_command[LEN]; extern char default_post_newsgroups[PATH_LEN]; extern char default_post_subject[PATH_LEN]; extern char default_regex_pattern[LEN]; extern char default_save_file[PATH_LEN]; extern char default_select_pattern[LEN]; extern char default_shell_command[LEN]; extern char delgroups[LEN]; extern char default_goto_group[LEN]; extern char default_group_search[LEN]; extern char default_maildir[PATH_LEN]; extern char default_savedir[PATH_LEN]; extern char default_sigfile[PATH_LEN]; extern char default_signature[PATH_LEN]; extern char default_subject_search[LEN]; extern char homedir[PATH_LEN]; extern char index_maildir[PATH_LEN]; extern char index_newsdir[PATH_LEN]; extern char killfile[PATH_LEN]; extern char killfrom[LEN]; extern char killsubj[LEN]; extern char libdir[PATH_LEN]; extern char lock_file[PATH_LEN]; extern char local_newsgroups_file[PATH_LEN]; extern char mail_active_file[PATH_LEN]; extern char mail_quote_format[PATH_LEN]; extern char news_active_file[PATH_LEN]; extern char news_quote_format[PATH_LEN]; extern char mail_news_user[LEN]; extern char mailbox[PATH_LEN]; extern char mailer[PATH_LEN]; extern char motd_file[PATH_LEN]; extern char motd_file_info[PATH_LEN]; extern char msg[LEN]; extern char my_distribution[LEN]; extern char new_active_file_attribute[32]; extern char new_active_file_server[PATH_LEN]; extern char mailgroups_file[PATH_LEN]; extern char newsgroups_file[PATH_LEN]; extern char newnewsrc[PATH_LEN]; extern char newsrc[PATH_LEN]; extern char *nntp_server; extern char page_header[LEN]; extern char postfile[PATH_LEN]; extern char default_printer[LEN]; extern char novrootdir[PATH_LEN]; extern char proc_ch_default; /* set in change_rcfile () */ extern char progname[PATH_LEN];µ7äÄ~ TIN-1_22.BCK‚d[SRC.TIN-1_22]EXTERN.H;1-¥J extern char quote_chars[PATH_LEN]; extern char rcdir[PATH_LEN]; extern char rcfile[PATH_LEN]; extern char redirect_output[LEN]; extern char reply_to[LEN]; extern char save_active_file[PATH_LEN]; extern char spooldir[PATH_LEN]; extern char spooldir_alias[PATH_LEN]; extern char subscriptions_file[PATH_LEN]; extern char userid[PATH_LEN]; #ifdef M_OS2 extern char TMPDIR[PATH_LEN]; #endif extern char txt_1_resp[]; extern char txt_abort_indexing[]; extern char txt_abort_searching[]; extern char txt_active_file_is_empty[]; extern char txt_added_groups[]; extern char txt_append_to_file[]; extern char txt_lines[]; extern char txt_art_deleted[]; extern char txt_art_cannot_delete[]; extern char txt_art_marked_as_unread[]; extern char txt_art_not_saved[]; extern char txt_art_pager_com[]; extern char txt_art_posted[]; extern char txt_art_rejected[]; extern char txt_art_saved_to[]; extern char txt_art_thread_regex_tag[]; extern char txt_art_unavailable[]; extern char txt_author_search_backwards[]; extern char txt_author_search_forwards[]; extern char txt_bad_active_file[]; extern char txt_bad_article[]; extern char txt_bad_command[]; extern char txt_begin_of_art[]; extern char txt_deleting[]; extern char txt_cannot_find_base_art[]; extern char txt_cannot_get_nntp_server_name[]; extern char txt_cannot_open[]; extern char txt_cannot_open_active_file[]; extern char txt_cannot_open_art[]; extern char txt_cannot_post[]; extern char txt_cannot_change_spooldir[]; extern char txt_catchup_update_info[]; extern char txt_changing_spooldir_to[]; extern char txt_check_article[]; extern char txt_checking[]; extern char txt_checking_active_file[]; extern char txt_checking_for_news[]; extern char txt_checksum_of_file[]; extern char txt_command_failed[]; extern char txt_command_failed_s[]; extern char txt_connecting[]; extern char txt_reconnect_to_news_server[]; extern char txt_connection_to_server_broken[]; extern char txt_continue[]; extern char txt_copyright_notice[]; extern char txt_corrupt_index[]; extern char txt_corrupt_kill_file[]; extern char txt_creating_newsrc[]; extern char txt_crosspost_an_article[]; extern char txt_crosspost_group[]; extern char txt_del_group_in_newsrc[]; extern char txt_delete_bogus_group[]; extern char txt_deleting_art[]; extern char txt_deleting_from_newsrc[]; extern char txt_delete_processed_files[]; extern char txt_end_of_arts[]; extern char txt_end_of_groups[]; extern char txt_end_of_thread[]; extern char txt_env_var_not_found[]; extern char txt_error_header_line_blank[]; extern char txt_error_header_line_colon[]; extern char txt_error_header_line_space[]; extern char txt_error_header_line_empty_newsgroups[]; extern char txt_error_header_line_missing_newsgroups[]; extern char txt_error_header_line_missing_subject[]; extern char txt_warn_art_line_too_long[]; extern char txt_error_header_and_body_not_seperate[]; extern char txt_error_from_in_header_not_allowed[]; extern char txt_art_newsgroups[]; extern char txt_warn_not_valid_newsgroup[]; extern char txt_error_not_valid_newsgroup[]; extern char txt_error_header_line_comma[]; extern char txt_extracting_archive[]; extern char txt_extracting_shar[]; extern char txt_failed_to_connect_to_server[]; extern char txt_feed_pattern[]; extern char txt_group[]; extern char txt_group_deleted[]; extern char txt_group_is_moderated[]; extern char txt_group_select_com[]; extern char txt_select_pattern[]; extern char txt_spooldir_com[]; extern char txt_group_selection[]; extern char txt_group_undeleted[]; extern char txt_help_bug_report[LEN]; extern char txt_help_4[]; extern char txt_help_D[]; extern char txt_help_I[]; extern char txt_help_K[]; extern char txt_help_M[]; extern char txt_help_S[]; extern char txt_help_T[]; extern char txt_help_U[]; extern char txt_help_W[]; extern char txt_help_X[]; extern char txt_help_a[]; extern char txt_help_autosave[]; extern char txt_help_b[]; extern char txt_help_B[]; extern char txt_help_bug[]; extern char txt_help_c[]; extern char txt_help_cC[]; extern char txt_help_ck[]; extern char txt_help_cr[]; extern char txt_help_catchup_groups[]; extern char txt_help_i_coma[]; extern char txt_help_confirm_action[]; extern char txt_help_ctrl_d[]; extern char txt_help_ctrl_f[]; extern char txt_help_ctrl_h[]; extern char txt_help_ctrl_k[]; extern char txt_help_ctrl_l[]; extern char txt_help_d[]; extern char txt_help_dash[]; extern char txt_help_draw_arrow[]; extern char txt_help_equal[]; extern char txt_help_g[]; extern char txt_help_g_4[]; extern char txt_help_g_c[]; extern char txt_help_g_d[]; extern char txt_help_g_cr[]; extern char txt_help_cr[]; extern char txt_help_g_ctrl_k[]; extern char txt_help_g_ctrl_r[]; extern char txt_help_g_l[]; extern char txt_help_g_q[]; extern char txt_help_g_r[]; extern char txt_help_g_search[]; extern char txt_help_g_tab[]; extern char txt_help_g_y[]; extern char txt_help_g_z[]; extern char txt_help_h[]; extern char txt_help_i[]; extern char txt_help_i_4[]; extern char txt_help_i_coma[]; extern char txt_help_i_cr[]; extern char txt_help_i_dot[]; extern char txt_help_i_n[]; extern char txt_help_i_p[]; extern char txt_help_i_search[]; extern char txt_help_i_star[]; extern char txt_help_i_tab[]; extern char txt_help_i_tilda[]; extern char txt_help_j[]; extern char txt_help_kill_from[]; extern char txt_help_kill_group[]; extern char txt_help_kill_how[]; extern char txt_help_kill_subject[]; extern char txt_help_kill_text[]; extern char txt_help_kill_text_type[]; extern char txt_help_l[]; extern char txt_help_m[]; extern char txt_help_maildir[]; extern char txt_help_mark_saved_read[]; extern char txt_help_n[]; extern char txt_help_o[]; extern char txt_help_p_0[]; extern char txt_help_p_4[]; extern char txt_help_p_coma[]; extern char txt_help_p_cr[]; extern char txt_help_p_ctrl_r[]; extern char txt_help_p_d[]; extern char txt_help_p_dot[]; extern char txt_help_p_f[]; extern char txt_help_p_g[]; extern char txt_help_p_k[]; extern char txt_help_p_m[]; extern char txt_help_p_n[]; extern char txt_help_p_p[]; extern char txt_help_p_r[]; extern char txt_help_p_s[]; extern char txt_help_p_search[]; extern char txt_help_p_star[]; extern char txt_help_p_tab[]; extern char txt_help_p_tilda[]; extern char txt_help_p_z[]; extern char txt_help_page_scroll[]; extern char txt_help_pipe[]; extern char txt_help_plus[]; extern char txt_help_pos_first_unread[]; extern char txt_help_post_proc_type[]; extern char txt_help_print_header[]; extern char txt_help_printer[]; extern char txt_help_q[]; extern char txt_help_r[]; extern char txt_help_s[]; extern char txt_help_savedir[]; extern char txt_help_sel_c[]; extern char txt_help_semicolon[]; #ifndef NO_SHELL_ESCAPE extern char txt_help_shell[]; #endif extern char txt_help_show_author[]; extern char txt_help_show_description[]; extern char txt_help_show_only_unread[]; extern char txt_help_sort_type[]; extern char txt_help_start_editor_offset[]; extern char txt_help_t[]; extern char txt_help_t_0[]; extern char txt_help_t_4[]; extern char txt_help_t_K[]; extern char txt_help_t_cr[]; extern char txt_help_t_tab[]; extern char txt_help_thread[]; extern char txt_help_thread_arts[]; extern char txt_help_u[]; extern char txt_help_v[]; extern char txt_help_w[]; extern char txt_help_x[]; extern char txt_help_y[]; extern char txt_hit_any_key[]; extern char txt_cmdline_hit_any_key[]; extern char txt_hit_space_for_more[]; extern char txt_index_page_com[]; extern char txt_ispell_define_not_compiled[]; extern char txt_inverse_off[]; extern char txt_inverse_on[]; extern char txt_kill_from[]; extern char txt_kill_group[]; extern char txt_kill_how[]; extern char txt_kill_menu[]; extern char txt_kill_subject[]; extern char txt_kill_text[]; extern char txt_kill_text_type[]; extern char txt_killing_arts[]; extern char txt_last_resp[]; extern char txt_listing_archive[]; extern char txt_mail_art_to[]; extern char txt_mail_bug_report[]; extern char txt_mail_bug_report_confirm[]; extern char txt_mail_quote[]; extern char txt_mailed[]; extern char txt_mailing_to[]; extern char txt_mark_all_read[]; extern char txt_mark_thread_read[]; extern char txt_mark_group_read[]; extern char txt_mini_select_1[]; extern char txt_mini_select_2[]; extern char txt_mini_select_3[]; extern char txt_mini_spooldir_1[]; extern char txt_mini_group_1[]; extern char txt_mini_group_2[]; extern char txt_mini_group_3[]; extern char txt_mini_thread_1[]; extern char txt_mini_thread_2[]; extern char txt_mini_page_1[]; extern char txt_mini_page_2[]; extern char txt_mini_page_3[]; extern char txt_more[]; extern char txt_more_percent[]; extern char txt_moving[]; extern char txt_news_quote[]; extern char txt_newsgroup[]; extern char txt_newsgroup_position[]; extern char txt_next_resp[]; extern char txt_nntp_authorization_failed[]; extern char txt_nntp_to_fd_cannot_reopen[]; extern char txt_nntp_to_fp_cannot_reopen[]; extern char txt_no[]; extern char txt_no_arts[]; extern char txt_no_arts_posted[]; extern char txt_no_command[]; extern char txt_no_filename[]; extern char txt_no_group[]; extern char txt_no_groups[]; extern char txt_no_groups_to_delete[]; extern char txt_no_groups_to_read[]; extern char txt_no_groups_to_yank_in[]; extern char txt_no_index_file[]; extern char txt_no_last_message[]; extern char txt_no_mail_address[]; extern char txt_no_match[]; extern char txt_no_more_groups[]; extern char txt_no_newsgroups[]; extern char txt_no_next_unread_art[]; extern char txt_no_prev_group[]; extern char txt_no_prev_unread_art[]; extern char txt_no_quick_newsgroups[]; extern char txt_no_quick_subject[]; extern char txt_no_resp[]; extern char txt_no_responses[]; extern char txt_no_resps_in_thread[]; extern char txt_no_search_string[]; extern char txt_no_spooldirs[]; extern char txt_no_subject[]; extern char txt_not_active_newsfeed[]; extern char txt_not_in_active_file[]; extern char txt_opt_autosave[]; extern char txt_opt_catchup_groups[]; extern char txt_opt_confirm_action[]; extern char txt_opt_draw_arrow[]; extern char txt_opt_maildir[]; extern char txt_opt_mark_saved_read[]; extern char txt_opt_page_scroll[]; extern char txt_opt_pos_first_unread[]; extern char txt_opt_post_process[]; extern char txt_opt_print_header[]; extern char txt_opt_printer[]; extern char txt_opt_process_type[]; extern char txt_opt_savedir[]; extern char txt_opt_show_author[]; extern char txt_opt_show_description[]; extern char txt_opt_show_only_unread[]; extern char txt_opt_sort_type[]; extern char txt_opt_start_editor_offset[]; extern char txt_opt_thread_arts[]; extern char txt_option_not_enabled[]; extern char txt_options_menu[]; extern char txt_out_of_memory[]; extern char txt_pipe_to_command[]; extern char txt_piping[]; extern char txt_piping_not_enabled[]; extern char txt_plural[]; extern char txt_post_a_followup[]; extern char txt_post_an_article[]; extern char txt_post_history_menu[]; extern char txt_post_newsgroup[]; extern char txt_post_newsgroups[]; extern char txt_post_process_none[]; extern char txt_post_process_sh[]; extern char txt_post_process_type[]; extern char txt_post_process_uud_ext_zoo[]; extern char txt_post_process_uud_lst_zoo[]; extern char txt_post_process_uud_ext_zip[]; extern char txt_post_process_uud_lst_zip[]; extern char txt_post_process_uudecode[]; extern char txt_post_processing[]; extern char txt_post_processing_failed[]; extern char txt_post_processing_finished[]; extern char txt_post_subject[]; extern char txt_posting[]; extern char txt_processing_xrefs[]; extern char txt_purge[]; extern char txt_printed[]; extern char txt_printing[]; extern char txt_quit[]; extern char txt_quit_edit_delete[]; extern char txt_quit_edit_post[]; extern char txt_quit_edit_xpost[]; extern char txt_quit_edit_save_killfile[]; extern char txt_quit_edit_ispell_send[]; extern char txt_quit_edit_send[]; extern char txt_read_art[]; extern char txt_read_resp[]; extern char txt_reading_all_arts[]; extern char txt_reading_new_arts[]; extern char txt_reading_all_groups[]; extern char txt_reading_new_groups[]; extern char txt_reading_article[]; extern char txt_reading_news_active_file[]; extern char txt_reading_mail_active_file[]; extern char txt_reading_attributes_file[]; extern char txt_reading_mailgroups_file[]; extern char txt_reading_newsgroups_file[]; extern char txt_reconnecting[]; extern char txt_rejected_by_nntpserver[]; extern char txt_rename_error[]; extern char txt_reply_to_author[]; extern char txt_reset_newsrc[]; extern char txt_resizing_window[]; extern char txt_resp_redirect[]; extern char txt_resp_to_poster[]; extern char txt_resp_x_of_n[]; extern char txt_s_at_s[]; extern char txt_save_filename[]; extern char txt_save_pattern[]; extern char txt_saved[]; extern char txt_saved_pattern_to[]; extern char txt_saved_to_mailbox[]; extern char txt_saving[]; extern char txt_screen_init_failed[]; extern char txt_search_backwards[]; extern char txt_search_forwards[]; extern char txt_search_body[]; extern char txt_searching[]; extern char txt_searching_body[]; extern char txt_select_group[]; extern char txt_select_rcfile_option[]; extern char txt_select_spooldir[]; extern char txt_server_name_in_file_env_var[]; extern char txt_shell_escape[]; extern char txt_show_from_addr[]; extern char txt_show_from_both[]; extern char txt_show_from_name[]; extern char txt_show_from_none[]; extern char txt_spooldir_selection[]; extern char txt_sort_by_date_ascend[]; extern char txt_sort_by_date_descend[]; extern char txt_sort_by_from_ascend[]; extern char txt_sort_by_from_descend[]; extern char txt_sort_by_nothing[]; extern char txt_sort_by_subj_ascend[]; extern char txt_sort_by_subj_descend[]; extern char txt_spooldir_server_error_1[]; extern char txt_spooldir_server_error_2[]; extern char txt_spooldirs_not_supported[]; extern char txt_stuff_nntp_cannot_open[]; extern char txt_subscribe_pattern[]; extern char txt_subscribe_to_new_group[]; extern char txt_subscribed_num_groups[]; extern char txt_subscribed_to[]; extern char txt_subscribing[]; extern char txt_subscribing_to[]; extern char txt_suspended_message[]; extern char txt_tagged_art[]; extern char txt_tagged_thread[]; extern char txt_testing_archive[]; extern char txt_there_is_no_news[]; extern char txt_threading_arts[]; extern char txt_thread_com[]; extern char txt_thread_marked_as_unread[]; extern char txt_thread_not_saved[]; extern char txt_thread_page[]; extern char txt_thread_resp_page[]; extern char txt_thread_saved_to[]; extern char txt_thread_saved_to_many[]; extern char txt_thread_x_of_n[]; extern char txt_toggled_rot13[]; extern char txt_type_h_for_help[]; extern char txt_unkilling_arts[]; extern char txt_unsubscribe_pattern[]; extern char txt_unsubscribed_num_groups[]; extern char txt_unsubscribed_to[]; extern char txt_unsubscribing[]; extern char txt_unsubscribing_from[]; extern char txt_untagged_art[]; extern char txt_untagged_thread[]; extern char txt_unthreading_arts[]; extern char txt_use_mime[]; extern char txt_uudecoding[]; extern char txt_writing_attributes_file[]; extern char txt_writing_index_file[]; extern char txt_x_resp[]; extern char txt_yanking_all_groups[]; extern char txt_yanking_sub_groups[]; extern char txt_yes[]; extern char txt_you_have_mail[]; extern int auto_cc; extern int _hp_glitch; extern int unread_art_mark; extern int hot_art_mark; extern int return_art_mark; extern int cCOLS, cLINES; extern int MORE_POS; extern int NOTESLINES; extern int RIGHT_POS; extern int *my_group; extern int old_active_file_size; extern int beginner_level; extern int can_post; extern int catchup; extern int catchup_read_groups; extern int check_for_new_newsgroups; extern int cmd_line; extern int compiled_with_nntp; extern int confirm_action; extern int created_rcdir; extern int cur_active_size; extern int cur_groupnum; extern int debug; extern int default_auto_save; extern int default_batch_save; extern int default_move_group; extern int default_post_proc_type; extern int default_show_author; extern int default_show_only_unread; extern int default_sort_art_type; extern int default_thread_arts; extern int display_reading_prompt; #ifdef SIGTSTP extern int do_sigtstp; #endif extern int draw_arrow_mark; extern int force_screen_redraw; extern int full_page_scroll; extern int groupname_max_length; extern int group_hash[TABLE_SIZE]; extern int group_top; extern int groupname_len; extern int index_file_killed; extern int inn_nntp_server; extern int inverse_okay; extern int use_keypad; extern int killed_articles; extern int kill_level; extern int local_index; extern int mail_news; extern int mark_saved_read; extern int max_active; extern int max_active_size; extern int max_art; extern int max_from; extern int max_subj; extern int max_kill; extern int max_save; extern int max_spooldir; extern int newsrc_active; extern int nntp_codeno; extern int num_active; extern int num_active_size; extern int num_kill; extern int num_of_hot_arts; extern int num_of_killed_arts; extern int num_of_tagged_arts; extern int num_save; extern int num_spooldir; extern int post_article_and_exit; extern int pos_first_unread; extern int print_header; extern int purge_index_files; extern int process_id; extern int read_local_newsgroups_file; extern int read_news_via_nntp; extern int real_gid; extern int real_uid; extern int real_umask; extern int reread_active_file; extern int reread_active_file_secs; extern int save_news; extern int save_to_mmdf_mailbox; extern int show_author; extern int show_description; extern int show_last_line_prev_page; extern int show_only_unread_groups; extern int slow_speed_terminal; extern int space_mode; extern int spooldir_is_active; extern int start_editor_offset; extern int start_line_offset; extern int system_status; extern int tin_gid; extern int tin_uid; extern int tab_after_X_selection; extern int tab_goto_next_unread; extern int top; extern int top_base; extern int unlink_article; extern int update; extern int use_builtin_inews; extern int verbose; extern int update_fork; extern int check_any_unread; extern int start_any_unread; extern int xref_supported; extern int xindex_supported; extern int xover_supported; extern int xuser_supported; extern int xspooldir_supported; extern int xmouse; extern int xcol; extern int xrow; extern long *base; extern struct passwd *myentry; extern struct t_article *arts; extern struct t_group *active; extern struct t_active_size *active_size; extern struct t_kill *killf; extern struct t_posted *posted; extern struct t_save *save; extern struct t_spooldir *spooldirs; extern struct t_screen *screen; #ifdef HAVE_POSIX_JC extern struct sigaction art_act; extern struct sigaction group_act; extern struct sigaction kill_act; extern struct sigaction main_act; extern struct sigaction old_act; extern struct sigaction page_act; extern struct sigaction rcfile_act; extern struct sigaction select_act; extern struct sigaction thread_act; #endif ð*[SRC.TIN-1_22]FEED.C;1+,.!//€ 4! ¾-d0@î123KÿPWO"56àTÊt…—7€û¨i1—89€]V‚—G/€HªJÿ/* * Project : tin - a Usenet reader * Module : feed.c * Author : I.Lea * Created : 31-08-91 * Updated : 22-08-93 * Notes : provides same interface to mail,pipe,print and save commands * Copyright : (c) Copyright 1991-93 by Iain Lea * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" extern char *glob_group; /* Group name */ extern char note_h_date[PATH_LEN]; /* Date: */ extern char note_h_newsgroups[LEN]; /* Newsgroups: */ extern char note_h_subj[LEN]; /* Subject: */ extern FILE *note_fp; /* the body of the current article */ extern int note_end; /* end of article ? */ extern int note_page; /* what page we're on */ extern long note_mark[MAX_PAGES]; /* ftells on beginnings of pages */ char default_mail_address[LEN]; char default_pipe_command[LEN]; char default_save_file[PATH_LEN]; char default_regex_pattern[LEN]; char default_crosspost_group[LEN]; char proc_ch_default; /* set in change_rcfile () */ void feed_articles (function, level, prompt, respnum, group_path) int function; int level; char *prompt; int respnum; char *group_path; { #ifndef INDEX_DAEMON char address[LEN]; char command[LEN]; char filename[PATH_LEN], *p; char group[LEN]; char mailbox[LEN]; char pattern[LEN]; char proc_ch = proc_ch_default; FILE *fp = (FILE *) 0; int ch = 'a', ch_default = 'a'; int b, i, j; int confirm = TRUE; int processed_ok = TRUE; int proceed = FALSE; int is_mailbox = FALSE; int orig_note_end = 0; int orig_note_page = 0; int processed = 0; int redraw_screen = FALSE; int ret1 = FALSE; int ret2 = FALSE; int retcode; #ifdef NO_PIPING if (function == FEED_PIPE) { error_message (txt_piping_not_enabled, ""); clear_message (); return; } #endif set_xclick_off (); if (level == PAGE_LEVEL) { orig_note_end = note_end; orig_note_page = note_page; } b = which_thread (respnum); /* * try and work out what default the user wants */ if (num_of_tagged_arts) { ch_default = 'T'; } else if (num_of_hot_arts && default_auto_save == FALSE) { ch_default = 'h'; } else if (num_of_responses (b)) { ch_default = 't'; } else { ch_default = 'a'; } i = my_group[cur_groupnum]; filename[0] = '\0'; if ((default_auto_save == FALSE || arts[respnum].archive == (char *) 0) || (default_auto_save == TRUE && function != FEED_SAVE) || ch_default == 'T') { do { sprintf (msg, "%s%s%c", prompt, txt_art_thread_regex_tag, ch_default); wait_message (msg); MoveCursor (cLINES, (int) strlen (msg)-1); if ((ch = ReadCh ()) == CR) ch = ch_default; } while (! strchr ("ahpqtT\033", ch)); } else { filename[0] = '\0'; ch = ch_default; if (proc_ch != 'n') { /* * Set up default for *source* / *binaries* group */ if (str_str (glob_group, "sources", 7)) { proc_ch = 's'; } else if (str_str (glob_group, "binaries", 8)) { proc_ch = get_post_proc_type (active[i].attribute.post_proc_type); if (proc_ch < POST_PROC_UUDECODE) { proc_ch = 'u'; } } else { proc_ch = 's'; } } } if (ch == 'q' || ch == ESC) { /* exit */ clear_message (); return; } if (ch == 'p') { sprintf (msg, txt_feed_pattern, default_regex_pattern); if (! prompt_string (msg, pattern)) { clear_message (); return; } if (strlen (pattern)) { my_strncpy (default_regex_pattern, pattern, sizeof (default_regex_pattern)); } else { if (default_regex_pattern[0]) { my_strncpy (pattern, default_regex_pattern, sizeof (default_regex_pattern)); } else { info_message (txt_no_match); return; } } } switch (function) { case FEED_MAIL: sprintf (msg, txt_mail_art_to, cCOLS-(strlen(txt_mail_art_to)+30), default_mail_address); if (! prompt_string (msg, address)) { clear_message (); return; } if (strlen (address)) { strcpy (default_mail_address, address); } else { if (default_mail_address[0]) { strcpy (address, default_mail_address); } else { info_message (txt_no_mail_address); return; } } break; case FEED_PIPE: sprintf (msg, txt_pipe_to_command, cCOLS-(strlen(txt_pipe_to_command)+30), default_pipe_command); if (! prompt_string (msg, command)) { clear_message (); return; } if (strlen (command)) { strcpy (default_pipe_command, command); } else { if (default_pipe_command[0]) { strcpy (command, default_pipe_command); } else { info_message (txt_no_command); return; } } if ((fp = (FILE *) popen (command, "w")) == NULL) { perror_message (txt_command_failed_s, command); return; } wait_message (txt_piping); Raw (FALSE); break; case FEED_PRINT: if (cmd_line_printer[0]) { sprintf (command, "%s %s", cmd_line_printer, REDIRECT_OUTPUT); } else { sprintf (command, "%s %s", active[i].attribute.printer, REDIRECT_OUTPUT); } break; case FEED_SAVE: /* ask user for filename */ free_save_array (); if ((default_auto_save == FALSE || arts[respnum].archive == (char *) 0)) { sprintf (msg, txt_save_filename, default_save_file); if (! prompt_string (msg, filename)) { clear_message (); return; } if (strlen (filename)) { my_strncpy (default_save_file, filename, sizeof (default_save_file)); } else { if (default_save_file[0]) { my_strncpy (filename, default_save_file, sizeof (filename)); } else { info_message (txt_no_filename); return; } } for (p = filename; *p && (*p == ' ' || *p == '\t'); p++) { continue; } if (! *p) { info_message (txt_no_filename); return; } if ((filename[0] == '~' || filename[0] == '+') && strlen (filename) == 1) { info_message (txt_no_filename); return; } is_mailbox = create_path (filename); if (is_mailbox) { if ((int) st rlen (filename) > 1) { my_strncpy (mailbox, filename+1, sizeof (mailbox)); } else { my_strncpy (mailbox, glob_group, sizeof (mailbox)); /* * convert 1st letter to uppercase */ if (mailbox[0] >= 'a' && mailbox[0] <= 'z') { mailbox[0] = mailbox[0] - 32; } } my_strncpy (filename, mailbox, sizeof (filename)); } else { /* ask for post processing type */ do { sprintf (msg, "%s%c", txt_post_process_type, proc_ch_default); wait_message (msg); MoveCursor (cLINES, (int) strlen (msg)-1); if ((proc_ch = ReadCh ()) == CR) proc_ch = proc_ch_default; } while (! strchr ("eElLnqsu\033", proc_ch)); if (proc_ch == 'q' || proc_ch == ESC) { /* exit */ clear_message (); return; } } } wait_message (txt_saving); break; case FEED_XPOST: /* ask user for newsgroups */ sprintf (msg, txt_crosspost_group, default_crosspost_group); if (! prompt_string (msg, group)) { clear_message (); return; } if (strlen (group)) { my_strncpy (default_crosspost_group, group, sizeof (default_crosspost_group)); } else { if (default_crosspost_group[0]) { my_strncpy (group, default_crosspost_group, sizeof (group)); } else { info_message (txt_no_group); return; } } break; } switch (ch) { case 'a': /* article */ if (level == GROUP_LEVEL) { if (! does_article_exist (function, arts[respnum].artnum, group_path)) { break; } } switch (function) { case FEED_MAIL: redraw_screen = mail_to_someone (respnum, address, FALSE, TRUE, &processed_ok); break; case FEED_PIPE: fseek (note_fp, 0L, 0); copy_fp (note_fp, fp, ""); break; case FEED_PRINT: processed_ok = print_file (command, respnum, 1); break; case FEED_SAVE: note_page = art_open (arts[respnum].artnum, group_path); if (note_page != ART_UNAVAILABLE) { add_to_save_list (0, &arts[respnum], is_mailbox, TRUE, filename); processed_ok = save_art_to_file (respnum, 0, FALSE, ""); } break; case FEED_XPOST: redraw_screen = crosspost_article (group, respnum); break; } if (processed_ok) { processed++; } if (mark_saved_read) { if (processed_ok) { arts[respnum].unread = ART_READ; } } if (level == GROUP_LEVEL) { art_close (); } break; case 't': /* thread */ confirm = TRUE; for (i = (int) base[b]; i >= 0; i = arts[i].thread) { if (level == PAGE_LEVEL) { art_close (); } if (! does_article_exist (function, arts[i].artnum, group_path)) { continue; } switch (function) { case FEED_MAIL: processed_ok = TRUE; mail_to_someone (respnum, address, FALSE, confirm, &processed_ok); confirm = FALSE; break; case FEED_PIPE: fseek (note_fp, 0L, 0); copy_fp (note_fp, fp, ""); break; case FEED_PRINT: processed_ok = print_file (command, i, processed+1); break; case FEED_SAVE: add_to_save_list (i, &arts[i], is_mailbox, TRUE, filename); break; case FEED_XPOST: redraw_screen = crosspost_article (group, i); break; } if (processed_ok) { processed++; } if (mark_saved_read) { if (processed_ok) { arts[i].unread = ART_READ; } } art_close (); } if (function == FEED_SAVE) { sort_save_list (); (void) save_thread_to_file (is_mailbox, group_path); } break; case 'T': /* tagged articles */ confirm = TRUE; for (i=1 ; i <= num_of_tagged_arts ; i++) { for (j=0 ; j < top ; j++) { if (arts[j].tagged && arts[j].tagged == i) { if (level == PAGE_LEVEL) { art_close (); } if (! does_article_exist (function, arts[j].artnum, group_path)) { continue; } switch (function) { case FEED_MAIL: processed_ok = TRUE; mail_to_someone (respnum, address, FALSE, confirm, &processed_ok); confirm = FALSE; break; case FEED_PIPE: fseek (note_fp, 0L, 0); copy_fp (note_fp, fp, ""); break; case FEED_PRINT: processed_ok = print_file (command, j, processed+1); break; case FEED_SAVE: add_to_save_list (j, &arts[j], is_mailbox, TRUE, filename); break; case FEED_XPOST: redraw_screen = crosspost_article (group, j); break; } if (processed_ok) { processed++; } if (mark_saved_read) { if (processed_ok) { arts[j].unread = ART_READ; } } art_close (); } } } if (function == FEED_SAVE) { (void) save_regex_arts (is_mailbox, group_path); } untag_all_articles (); break; case 'h': /* hot (auto-selected) articles */ case 'p': /* regex pattern matched articles */ confirm = TRUE; for (i = 0 ; i < top_base ; i++) { for (j = (int) base[i]; j >= 0; j = arts[j].thread) { proceed = FALSE; if (ch == 'p') { if (STR_MATCH(arts[j].subject, pattern)) { proceed = TRUE; } } else if (arts[j].hot) { proceed = TRUE; } if (proceed) { if (level == PAGE_LEVEL) { art_close (); } if (! does_article_exist (function, arts[j].artnum, group_path)) { continue; } switch (function) { case FEED_MAIL: processed_ok = TRUE; mail_to_someone (respnum, address, FALSE, confirm, &processed_ok); /* confirm = FALSE; */ break; case FEED_PIPE: fseek (note_fp, 0L, 0); copy_fp (note_fp, fp, ""); break; case FEED_PRINT: processed_ok = print_file (command, j, processed+1); break; case FEED_SAVE: add_to_save_list (j, &arts[j], is_mailbox, TRUE, filename); break; case FEED_XPOST: redraw_screen = crosspost_article (group, j); break; } if (processed_ok) { processed++; } if (mark_saved_read) { if (procesÀs7Q~ TIN-1_22.BCKd[SRC.TIN-1_22]FEED.C;1!C´sed_ok) { arts[j].unread = ART_READ; if (ch == 'h') { arts[j].hot = FALSE; num_of_hot_arts--; } } } art_close (); } } } if (function == FEED_SAVE) { (void) save_regex_arts (is_mailbox, group_path); } break; } if (debug == 2) { printf ("REDRAW=[%d] ", redraw_screen); fflush (stdout); } redraw_screen = mail_check (); /* in case of sending to oneself */ if (debug == 2) { printf ("REDRAW=[%d]", redraw_screen); fflush (stdout); sleep (2); } switch (function) { case FEED_PIPE: #if defined(SIGCHLD) && !defined(RS6000) pclose (fp); retcode = system_status; #else retcode = pclose (fp); #endif Raw (TRUE); continue_prompt (); redraw_screen = TRUE; break; case FEED_SAVE: if (proc_ch != 'n' && is_mailbox == FALSE) { ret2 = post_process_files (proc_ch); } free_save_array (); break; } if (level == GROUP_LEVEL) { ret1 = (mark_saved_read ? TRUE : FALSE); } if ((ret1 || ret2) && is_mailbox == FALSE) { redraw_screen = TRUE; } if (level == PAGE_LEVEL) { if (ch != 'a') { note_page = art_open (arts[respnum].artnum, group_path); } else if (force_screen_redraw) { redraw_screen = TRUE; } note_end = orig_note_end; note_page = orig_note_page; fseek (note_fp, note_mark[note_page], 0); if (redraw_screen) { if (note_page == 0) { show_note_page (respnum, glob_group); } else { redraw_page (respnum, glob_group); } } else { if (function  == FEED_PIPE) { clear_message (); } } } else { if (redraw_screen) { show_group_page (); } } if (function == FEED_MAIL) { sprintf (msg, txt_mailed, processed); info_message (msg); } else if (function == FEED_PRINT) { sprintf (msg, txt_printed, processed); info_message (msg); } else if (function == FEED_SAVE) { if (ch == 'a') { sprintf (msg, txt_saved, processed); info_message (msg); } } #endif /* INDEX_DAEMON */ } int print_file (command, respnum, count) char *command; int respnum; int count; { FILE *fp; sprintf (msg, "%s%d", txt_printing, count); wait_message (msg); if ((fp = (FILE *) popen (command, "w")) == NULL) { perror_message (txt_command_failed_s, command); return FALSE; } if (print_header) { fseek(note_fp, 0L, 0); } else { fprintf (fp, "Newsgroups: %s\n", note_h_newsgroups); if (arts[respnum].from == arts[respnum].name) { fprintf (fp, "From: %s\n", arts[respnum].from); } else { fprintf (fp, "From: %s (%s)\n", arts[respnum].from, arts[respnum].name); } fprintf (fp, "Subject: %s\n", note_h_subj); fprintf (fp, "Date: %s\n\n", note_h_date); fseek (note_fp, note_mark[0], 0); } copy_fp (note_fp, fp, ""); pclose (fp); return (TRUE); /* a hack that will check if file was really checked later */ } int get_post_proc_type (proc_type) int proc_type; { int type; switch (proc_type) { case POST_PROC_SHAR: type = 's'; break; case POST_PROC_UUDECODE: type = 'u'; break; case POST_PROC_UUD_LST_ZOO: type = 'l'; break; case POST_PROC_UUD_EXT_ZOO: type = 'e'; break; case POST_PROC_UUD_LST_ZIP: type = 'L'; break; case POST_PROC_UUD_EXT_ZIP: type = 'E'; break; case POST_PROC_NONE: default: type = 'n'; break; } return type; } /* * Opening an article here & also later in the save * routine is a real performance (bandwidth) killer * as both times the art will be transfered (Ouch!) * * So if function is to save an article only stat * it the first time which saves a lot and almost * gets us the elusive free lunch! */ int does_article_exist (function, artnum, path) int function; long artnum; char *path; { int retcode = FALSE; if (function == FEED_SAVE) { if (stat_article (artnum, path)) { retcode = TRUE; } } else { note_page = art_open (artnum, path); if (note_page != ART_UNAVAILABLE) { retcode = TRUE; } } return retcode; } ð*[SRC.TIN-1_22]FTP.;1+,q.//€ 4-d0@î123KÿPWO56%’t…—7`rê‘—89 „ìø‘—G/€HªJÿ This document informs you how to get tin source & binaries in one of 3 ways. 1) Via FTP. 2) Source code via mail. 3) Pre-compiled Binaries. -------------------------------------------------------------------------------- 1) FTP sites that carry the latest version of tin are: 1.1) Unix Reference site: Germany [192.76.144.129] ftp.Germany.EU.net:pub/news/tin Mirror sites: UK [146.169.2.1] src.doc.ic.ac.uk:computing/usenet/software/readers/tin USA [131.210.1.4] ftp.uwp.edu:pub/tin Oz [130.194.9.1] yoyo.cc.monash.edu.au:pub/tin NOTE: There will be a small time lag before each of these sites makes the newest version available as I usually post first to alt.sources 1.2) AmigaDOS Reference sites: Switzland [128.178.151.32] litaamiga.epfl.ch:/pub/amiga/aminet/local/uucp 1.3) OS/2 Reference sites: USA [128.123.35.151] ftp-os2.nmsu.edu:/os2/2_x/network/tin120.zip ?? [192.153.46.2] ftp-os2.cdrom.com:/os2/2_x/network/tin120.zip NOTE: Requires TCP/IP version 1.2.1. This release may trail the Unix release. -------------------------------------------------------------------------------- 2) For people that do not have FTP access I am willing to send a copy of the latest released version (or a beta version of the next patchlevel if so desired). 2.1) I can handle the following media formats. Specify: 5.25 & 3.5 inch floppy disks. 0.25 (1/4) inch cartridge tapes (you supply it). 2.2) I can handle the following software formats. Specify: Unix *.tar *.tar.Z *.tar.z *.zoo *.zip Msdos *.zoo *.zip formats 2.3) I make a small handling charge for this service as listed below: Germany 15 Deustche Marks England 5 Pounds Sterling USA 10 Dollars If you find the above points 2.1 - 2.3 OK send money/cheque with a self-addressed envelope stating which media & software format you want to the following address: Iain J. Lea BrueckenStr. 12 8500 Nuernberg 90 Germany. Phone. +49-911-331963 (home) +49-911-3089-407 (work) +49-911-3089-290 (FAX) Email. iain.lea@erlm.siemens.de -------------------------------------------------------------------------------- 3) For people that are having problems compiling tin I am willing to send a copy of a pre-compiled binary for the following machines: i386/486 + Linux i386/486 + SCO Xenix 2.3.2 i386/486 + SCO Unix 3.2.2 i386/486 + ISC Unix 3.2 v3.0 SunSparc + SunOS 4.1 DecMIPS + Ultrix 4.2 Siemens MX330 + Sinix v5.23 Siemens MX350i + Sinix v5.4 NOTE: Specify how you want tin to be compiled to access news: 1) local spool directory (specify path for newsspool & newslib) 2) local spool directory & via NNTP 3) via NNTP only 4) local spool directory & via news archived on CD-ROM For conditions & shipping read points 2.1 - 2.3 above. Enjoy Iain. ð*[SRC.TIN-1_22]GETLINE.C;1+,‘.//€ 4©-d0@î123KÿPWO56`Ct…—7’Aj1—89€]V‚—G/€HªJÿ./* * Project : tin - a Usenet reader * Module : getline.c * Author : Chris Thewalt & Iain Lea * Created : 09-11-91 * Updated : 11-07-93 * Notes : emacs style line editing input package. * Copyright : (c) Copyright 1991-93 by Chris Thewalt & Iain Lea * Permission to use, copy, modify, and distribute this * software for any purpose and without fee is hereby * granted, provided that the above copyright notices * appear in all copies and that both the copyright * notice and this permission notice appear in supporting * documentation. This software is provided "as is" without * express or implied warranty. */ #include "tin.h" #define BUF_SIZE 1024 #define SCROLL 30 #define TABSIZE 4 #ifndef HIST_SIZE #define HIST_SIZE 100 #endif #define CTRL_A '\001' #define CTRL_B '\002' #define CTRL_D '\004' #define CTRL_E '\005' #define CTRL_F '\006' #define CTRL_H '\010' #define CTRL_K '\013' #define CTRL_L '\014' #define CTRL_R '\022' #define CTRL_N '\016' #define CTRL_P '\020' #define TAB '\t' #define DEL '\177' char *hist_buf[HIST_SIZE]; int hist_pos, hist_last; static char gl_buf[BUF_SIZE]; /* input buffer */ static char *gl_prompt; /* to save the prompt string */ static int gl_init_done = 0; /* -1 is terminal, 1 is batch */ static int gl_width = 0; /* net size available for input */ static int gl_pos, gl_cnt = 0; /* position and size of input */ #if __STDC__ static int gl_tab (char *, int, int *); static void gl_redraw (void); static void gl_addchar (int); static void gl_newline (void); static void gl_fixup (int, int); static void gl_del (int); static void gl_kill (void); static void hist_add (void); static void hist_init (void); static void hist_next (void); static void hist_prev (void); int (*gl_in_hook)(char *) = 0; int (*gl_out_hook)(char *) = 0; int (*gl_tab_hook)(char *, int, int *) = gl_tab; #else static int gl_tab (); static void gl_redraw (); static void gl_addchar (); static void gl_newline (); static void gl_fixup (); static void gl_del (); static void gl_kill (); static void hist_add (); static void hist_init (); static void hist_next (); static void hist_prev (); int (*gl_in_hook)() = 0; int (*gl_out_hook)() = 0; int (*gl_tab_hook)() = gl_tab; #endif #if __STDC__ char * getline (char *prompt, int number_only, char *str) #else char * getline (prompt, number_only, str) char *prompt; int number_only; char *str; #endif { int c, i, loc, tmp; set_xclick_off (); if (! gl_init_done) { gl_init_done = 1; hist_init (); } if (prompt == (char *) 0) { prompt = ""; } gl_buf[0] = 0; /* used as end of input indicator */ gl_fixup (-1, 0); /* this resets gl_fixup */ gl_width = cCOLS - strlen (prompt); gl_prompt = prompt; gl_pos = gl_cnt = 0; fputs (prompt, stdout); fflush (stdout); if (gl_in_hook) { loc = gl_in_hook (gl_buf); if (loc >= 0) gl_fixup (0, BUF_SIZE); } if (str != (char *) 0) { for (i=0 ; str[i] ; i++) gl_addchar (str[i]); } while ((c = ReadCh ()) != EOF) { c &= 0xff; if (isprint (c)) { if (number_only) { if (isdigit (c) && gl_cnt < 6) { /* num < 100000 */ gl_addchar (c); } else { ring_bell (); } } else { gl_addchar (c); } } else { switch (c) { case ESC: /* abort */ return (char *) 0; case '\n': /* newline */ case '\r': gl_newline (); return gl_buf; case CTRL_A: gl_fixup (-1, 0); break; case CTRL_B: gl_fixup (-1, gl_pos-1); break; case CTRL_D: if (gl_cnt == 0) { gl_buf[0] = 0; fputc ('\n', stdout); return gl_buf; } else { gl_del (0); } break; case CTRL_E: gl_fixup (-1, gl_cnt); break; case CTRL_F: gl_fixup (-1, gl_pos+1); break; case CTRL_H: case DEL: gl_del (-1); break; case TAB: if (gl_tab_hook) { tmp = gl_pos; loc = gl_tab_hook (gl_buf, strlen (gl_prompt), &tmp); if (loc >= 0 || tmp != gl_pos) gl_fixup (loc, tmp); } break; case CTRL_K: gl_kill (); break; case CTRL_L: case CTRL_R: gl_redraw (); break; case CTRL_N: hist_next (); break; case CTRL_P: hist_prev (); break; default: ring_bell (); break; } } } return gl_buf; } /* * adds the character c to the input buffer at current location if * the character is in the allowed template of characters */ #if __STDC__ static void gl_addchar (int c) #else static void gl_addchar (c) int c; #endif { int i; if (gl_cnt >= BUF_SIZE - 1) { error_message ("getline: input buffer overflow", ""); exit (1); } for (i=gl_cnt; i >= gl_pos; i--) { gl_buf[i+1] = gl_buf[i]; } gl_buf[gl_pos] = c; gl_fixup (gl_pos, gl_pos+1); } /* * Cleans up entire line before returning to caller. A \n is appended. * If line longer than screen, we redraw starting at beginning */ static void gl_newline () { int change = gl_cnt; int len = gl_cnt; int loc = gl_width - 5; /* shifts line back to start position */ if (gl_cnt >= BUF_SIZE - 1) { error_message ("getline: input buffer overflow", ""); exit (1); } hist_add (); /* only adds if nonblank */ if (gl_out_hook) { change = gl_out_hook (gl_buf); len = strlen (gl_buf); } if (loc > len) loc = len; gl_fixup (change, loc); /* must do this before appending \n */ gl_buf[len] = '\0'; } /* * Delete a character. The loc variable can be: * -1 : delete character to left of cursor * 0 : delete character under cursor */ #if __STDC__ static void gl_del (int loc) #else static void gl_del (loc) int loc; #endif { int i; if ((loc == -1 && gl_pos > 0) || (loc == 0 && gl_pos < gl_cnt)) { for (i=gl_pos+loc; i < gl_cnt; i++) gl_buf[i] = gl_buf[i+1]; gl_fixup (gl_pos+loc, gl_pos+loc); } else { ring_bell (); } } /* * delete from current position to the end of line */ static void gl_kill () { if (gl_pos < gl_cnt) { gl_buf[gl_pos] = '\0'; gl_fixup (gl_pos, gl_pos); } else { ring_bell (); } } /* * emit a newline, reset and redraw prompt and current input line */ static void gl_redraw () { if (gl_init_done == -1) { fputc ('\n', stdout); fputs (gl_prompt, stdout); gl_pos = 0; gl_fixup (0, BUF_SIZE); } } /* * This function is used both for redrawing when input changes or for * moving within the input line. The parameters are: * change : the index of the start of changes in the input buffer, * with -1 indicating no changes. * cursor : the desired location of the cursor after the call. * A value of BUF_SIZE can be used to indicate the cursor * should move just past the end of the input line. */ #if __STDC__ static void gl_fixup (int change, int cursor) #else static void gl_fixup (change, cursor) int change; int cursor; #endif { static int gl_shift; /* index of first on screen character */ static int off_right; /* true if more text right of screen */ static int off_left; /* true if more text left of screen */ int left = 0, right = -1; /* bounds for redraw */ int pad; /* how much to erase at end of line */ int backup; /* how far to backup before fixing */ int new_shift; /* value of shift based on cursor */ int extra; /* adjusts when shift (scroll) happens */ int i; if (change == -1 && cursor == 0 && gl_buf[0] == 0) { /* reset */ gl_shift = off_right = off_left = 0; return; } pad = (off_right) ? gl_width - 1 : gl_cnt - gl_shift; /* old length */ backup = gl_pos - gl_shift; if (change >= 0) { gl_cnt = strlen (gl_buf); if (change > gl_cnt) change = gl_cnt; } if (cursor > gl_cnt) { if (cursor != BUF_SIZE) /* BUF_SIZE means end of line */ ring_bell (); cursor = gl_cnt; } if (cursor < 0) { ring_bell (); cursor = 0; } if (off_right || off_left && (cursor < gl_shift + gl_width - SCROLL / 2)) extra = 2; /* shift the scrolling boundary */ else extra = 0; new_shift = cursor + extra + SCROLL - gl_width; if (new_shift > 0) { new_shift /= SCROLL; new_shift *= SCROLL; } else new_shift = 0; if (new_shift != gl_shift) { /* scroll occurs */ gl_shift = new_shift; off_left = (gl_shift) ? 1 : 0; off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0; left = gl_shift; right = (off_right) ? gl_shift + gl_width - 2 : gl_cnt; } else if (change >= 0) { /* no scroll, but text changed */ if (change < gl_shift + off_left) { left = gl_shift; } else { left = change; backup = gl_pos - change; } off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0; right = (off_right) ? gl_shift + gl_width - 2 : gl_cnt; } pad -= (off_right) ? gl_width - 1 : gl_cnt - gl_shift; pad = (pad < 0)? 0 : pad; if (left <= right) { /* clean up screen */ for (i=0; i < backup; i++) fputc ('\b', stdout); if (left == gl_shift && off_left) { fputc ('$', stdout); left++; } for (i=left; i < right; i++) fputc (gl_buf[i], stdout); if (off_right) { fputc ('$', stdout); gl_pos = right + 1; } else { for (i=0; i < pad; i++) /* erase remains of prev line */ fputc (' ', stdout); gl_pos = right + pad; } } i = gl_pos - cursor; /* move to final cursor location */ if (i > 0) { while (i--) fputc ('\b', stdout); } else { for (i=gl_pos; i < cursor; i++) fputc (gl_buf[i], stdout); } fflush (stdout); gl_pos = cursor; } /* * default tab handler, acts like tabstops every TABSIZE cols */ #if __STDC__ static int gl_tab (char *buf, int offset, int *loc) #else static int gl_tab (buf, offset, loc) char *buf; int offset; int *loc; #endif { int i, count, len; len = strlen (buf); count = TABSIZE - (offset + *loc) % TABSIZE; for (i=len; i >= *loc; i--) buf[i+count] = buf[i]; for (i=0; i < count; i++) buf[*loc+i] = ' '; i = *loc; *loc = i + count; return i; } /* * History functions */ static void hist_init () { int i; for (i=0; i < HIST_SIZE; i++) hist_buf[i] = (char *) 0; } static void hist_add () { char *p = gl_buf; while (*p == ' ' || *p == '\t') /* only save nonblank line */ p++; if (*p) { hist_buf[hist_last] = str_dup (gl_buf); hist_last = (hist_last + 1) % HIST_SIZE; if (hist_buf[hist_last]) { /* erase next location */ free(hist_buf[hist_last]); hist_buf[hist_last] = (char *) 0; } } hist_pos = hist_last; } /* * loads previous hist entry into input buffer, sticks on first */ static void hist_prev () { int next; next = (hist_pos - 1 + HIST_SIZE) % HIST_SIZE; if (next != hist_last) { if (hist_buf[next]) { hist_pos = next; strcpy (gl_buf, hist_buf[hist_pos]); } else { ring_bell (); } } else { ring_bell (); } if (gl_in_hook) gl_in_hook (gl_buf); gl_fixup (0, BUF_SIZE); } /* * loads next hist entry into input buffer, clears on last */ static void hist_next () { if (hist_pos != hist_last) { hist_pos = (hist_pos + 1) % HIST_SIZE; if (hist_buf[hist_pos]) { strcpy (gl_buf, hist_buf[hist_pos]); } else { gl_buf[0] = 0; } } else { ring_bell (); } if (gl_in_hook) gl_in_hook (gl_buf); gl_fixup (0, BUF_SIZE); } ð*[SRC.TIN-1_22]GROUP.C;3+,ù.H//€ 4HFõ-d0@î123KÿPWOI56€~· ƒˆ—7 ÚK ƒˆ—89€]V‚—G/€HªJÿ/* * Project : tin - a Usenet reader * Module : group.c * Author : I.Lea & R.Skrenta * Created : 01-04-91 * Updated : 24-09-93 * Notes : * Copyright : (c) Copyright 1991-93 by Iain Lea & Rich Skrenta * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" #define MARK_OFFSET 8 extern char cvers[LEN]; extern char proc_ch_type; /* feed.c */ extern int last_resp; /* page.c */ extern int this_resp; /* page.c */ extern int note_page; /* page.c */ char *glob_group; int index_point; int first_subj_on_screen; int last_subj_on_screen; static int len_from; static int len_subj; static char *spaces = "XXXX"; #if __STDC__ static int bld_sline (int i); static int draw_sline (int i, int full); #else static int bld_sline (); static int draw_sline (); #endif #ifndef ART_ADJUST /* what we do here is bizarre */ #define ART_ADJUST(n) (active[my_group[cur_groupnum]].attribute.show_only_unread \ ? ((n) > 1 ? (n) : 0) \ : ((n) > 0 ? (n) - 1 : 0)) #endif #define INDEX2SNUM(i) ((i) % NOTESLINES) #define SNUM2LNUM(i) (INDEX_TOP + (i)) #define INDEX2LNUM(i) (SNUM2LNUM(INDEX2SNUM(i))) void decr_tagged (tag) int tag; { int i, j; for (i = 0; i < top_base; ++i) { for (j = (int) base[i] ; j != -1 ; j = arts[j].thread) if (arts[j].tagged > t(ag) --arts[j].tagged; } } void group_page (group) char *group; { #ifndef INDEX_DAEMON char group_path[LEN]; char buf[128]; char pat[128]; int ch; int dummy = 0; int flag, i; int n = -1; int kill_state; int old_top = 0; int old_hot_arts = 0; int posted; int sav_groupnum; int scroll_lines; long old_artnum = 0L; int xflag = 0; struct t_art_stat sbuf; int old_group_top; /* * Set the group attributes */ active[my_group[cur_groupnum]].attribute.read_during_session = TRUE; show_author = active[my_group[cur_groupnum]].attribute.show_author; proc_ch_default = get_post_proc_type (active[my_group[cur_groupnum]].attribute.post_proc_type); glob_group = group; sav_groupnum = cur_groupnum; num_of_tagged_arts = 0; make_group_path (group, group_path); last_resp = -1; this_resp = -1; /* * update index file. quit group level if user aborts indexing */ if (! index_group (group, group_path)) { return; } if (space_mode) { for (i = 0; i < top_base; i++) { if (new_responses (i)) { break; } } if (i < top_base) { index_point = i; } else { index_point = top_base - 1; } } else { index_point = top_base - 1; } if (index_point < 0) { index_point = 0; } set_subj_from_size (cCOLS); clear_note_area (); show_group_page (); while (TRUE) { set_xclick_on (); ch = ReadCh (); if (ch > '0' && ch <= '9') { /* 0 goes to basenote */ if (prompt_subject_num (ch, group)) { goto group_tab_pressed; } continue; } switch (ch) { case ESC: /* common arrow keys */ #ifdef HAVE_KEY_PREFIX case KEY_PREFIX: #endif switch (get_arrow_key ()) { case KEYMAP_UP: goto group_up; case KEYMAP_DOWN: goto group_down; case KEYMAP_LEFT: goto group_done; case KEYMAP_RIGHT: goto group_read_basenote; case KEYMAP_PAGE_UP: goto group_page_up; case KEYMAP_PAGE_DOWN: goto group_page_down; case KEYMAP_HOME: if (! top_base) { break; } if (index_point != 0) { if (0 < first_subj_on_screen) { #ifndef USE_CLEARSCREEN erase_subject_arrow (); #endif index_point = 0; show_group_page (); } else { erase_subject_arrow (); index_point = 0; draw_subject_arrow (); } } break; case KEYMAP_END: goto end_of_list; case KEYMAP_MOUSE: if (xrow < INDEX2LNUM(first_subj_on_screen)) { goto group_page_up; } if (xrow > INDEX2LNUM(last_subj_on_screen-1)) { goto group_page_down; } erase_subject_arrow (); index_point = xrow-INDEX2LNUM(first_subj_on_screen)+first_subj_on_screen; draw_subject_arrow (); if (xmouse == 1) { goto group_tab_pressed; } if (xmouse == 2) { goto group_read_basenote; } } break; #ifndef NO_SHELL_ESCAPE case '!': shell_escape (); show_group_page (); break; #endif case '$': /* show last page of articles */ end_of_list: if (! top_base) { break; } if (index_point != top_base - 1) { if (top_base - 1 > last_subj_on_screen) { #ifndef USE_CLEARSCREEN erase_subject_arrow (); #endif index_point = top_base - 1; show_group_page (); } else { erase_subject_arrow (); index_point = top_base - 1; draw_subject_arrow (); } } break; case '-': /* go to last viewed article */ if (this_resp < 0) { info_message (txt_no_last_message); break; } index_point = show_page (this_resp, &dummy, group, group_path); if (index_point == GRP_NOREDRAW) { index_point = which_thread (this_resp); clear_message (); } else { if (index_point < 0) { space_mode = (index_point == GRP_CONTINUE); goto group_done; } clear_note_area (); show_group_page (); } break; case '|': /* pipe article/thread/tagged arts to command */ if (index_point >= 0) { feed_articles (FEED_PIPE, GROUP_LEVEL, "Pipe", (int) base[index_point], group_path); } break; case '/': /* forward/backward search */ case '?': i = (ch == '/'); search_subject (i, group); break; case 'B': /* search article body */ if (index_point < 0) { info_message (txt_no_arts); break; } n = search_body (group_path, (int) base[index_point]); if (n != -1) { index_point = show_page (n, &dummy, group, group_path); if (index_point < 0) { space_mode = FALSE; goto group_done; } show_group_page (); } break; case '\r': case '\n': /* read current basenote */ group_read_basenote: if (index_point < 0) { info_message(txt_no_arts); break; } i = (int) base[index_point]; index_point = show_page (i, &dummy, group, group_path); if (index_point == GRP_NOREDRAW) { index_point = which_thread (i); clear_message (); } else { if (index_point < 0) { space_mode = (index_point == GRP_CONTINUE); goto group_done; } clear_note_area (); show_group_page (); } break; case '\t': /* goto next unread article/group */ group_tab_pressed: space_mode = TRUE; if (index_point < 0) { n = -1; } else { n = next_unread ((int) base[index_point]); } if (index_point < 0 || n < 0) { for (i = cur_groupnum+1 ; i < group_top ; i++) { if (active[my_group[i]].unread > 0) { break; } } if (i >= group_top) { goto group_done; } cur_groupnum = i; index_point = GRP_GOTONEXT; goto group_done; } index_point = show_page (n, &dummy, group, group_path); if (index_point == GRP_NOREDRAW) { index_point = which_thread (n); goto group_tab_pressed; /* repeat TAB */ } else { if (index_point < 0) { goto group_done; } clear_note_area (); show_group_page (); } break; case ' ': /* page down */ case ctrl('D'): case ctrl('F'): /* vi style */ group_page_down: if (! top_base) { break; } if (index_point == top_base - 1) { if (0 < first_subj_on_screen) { # ifndef USE_CLEARSCREEN erase_subject_arrow (); # endif index_point = 0; show_group_page (); } else { erase_subject_arrow (); index_point = 0; draw_subject_arrow (); } break; } erase_subject_arrow (); scroll_lines = (full_page_scroll ? NOTESLINES : NOTESLINES / 2); index_point = ((index_point + scroll_lines) / scroll_lines) * scroll_lines; if (index_point >= top_base) { index_point = (top_base / scroll_lines) * scroll_lines; if (index_point < top_base - 1) { index_point = top_base - 1; } } if (index_point < first_subj_on_screen || index_point >= last_subj_on_screen) show_group_page (); else draw_subject_arrow (); break; case ctrl('K'): /* kill article */ if (index_point < 0) { info_message (txt_no_arts); break; } old_top = top; n = (int) base[index_point]; old_artnum = arts[n].artnum; if (kill_art_menu (group, (int) base[index_point])) { kill_any_articles (my_group[cur_groupnum]); make_threads (FALSE); find_base (my_group[cur_groupnum]); index_point = find_new_pos (old_top, old_artnum, index_point); } show_group_page (); break; case ctrl('L'): /* redraw screen */ case ctrl('R'): case ctrl('W'): #ifndef USE_CLEARSCREEN ClearScreen (); #endif set_xclick_off (); show_group_page (); break; case ctrl('N'): case 'j': /* line down */ group_down: if (! top_base) { break; } if (index_point + 1 >= top_base) { if (_hp_glitch) { erase_subject_arrow (); } if (0 < first_subj_on_screen) { index_point = 0; show_group_page (); } else { erase_subject_arrow (); index_point = 0; draw_subject_arrow (); } break; } if (index_point + 1 >= last_subj_on_screen) { #ifndef USE_CLEARSCREEN erase_subject_arrow(); #endif index_point++; show_group_page (); } else { erase_subject_arrow (); index_point++; draw_subject_arrow (); } break; case ctrl('P'): case 'k': /* line up */ group_up: if (! top_base) { break; } if (index_point == 0) { if (_hp_glitch) { erase_subject_arrow (); } if (top_base > last_subj_on_screen) { index_point = top_base - 1; show_group_page (); } else { erase_subject_arrow (); index_point = top_base - 1; draw_subject_arrow (); } break; } if (_hp_glitch) { erase_subject_arrow (); } if (index_point <= first_subj_on_screen) { index_point--; show_group_page (); } else { erase_subject_arrow (); index_point--; draw_subject_arrow (); } break; case 'b': /* page up */ case ctrl('U'): case ctrl('B'): /* vi style */ group_page_up: if (! top_base) { break; } if (index_point == 0) { if (_hp_glitch) { erase_subject_arrow (); } if (top_base > last_subj_on_screen) { index_point = top_base - 1; show_group_page (); } else { erase_subject_arrow (); index_point = top_base - 1; draw_subject_arrow (); } break; } #ifndef USE_CLEARSCREEN clear_message (); #endif erase_subject_arrow (); scroll_lines = (full_page_scroll ? NOTESLINES : NOTESLINES / 2); if ((n = index_point % scroll_lines) > 0) { index_point = index_point - n; } else { index_point = ((index_point - scroll_lines) / scroll_lines) * scroll_lines; } if (index_point < 0) { index_point = 0; } if (index_point < first_subj_on_screen || index_point >= last_subj_on_screen) show_group_page (); else draw_subject_arrow (); break; case 'a': /* author search forward */ case 'A': /* author search backward */ if (index_point < 0) { info_message (txt_no_arts); break; } i = (ch == 'a'); n = search_author (my_group[cur_groupnum], (int) base[index_point] °Ž5Ö~ TIN-1_22.BCKùd[SRC.TIN-1_22]GROUP.C;3Hœ^, i); if (n < 0) break; index_point = show_page (n, &dummy, group, group_path); if (index_point != GRP_NOREDRAW) { if (index_point < 0) { space_mode = FALSE; goto group_done; } clear_note_area (); show_group_page (); } break; case 'c': /* catchup - mark all articles as read */ case 'C': /* catchup - and goto next unread group */ if (! active[my_group[cur_groupnum]].unread || ! confirm_action || prompt_yn (cLINES, txt_mark_all_read, 'y')) { for (n = 0; n < top; n++) { if (arts[n].unread != ART_READ) { mark_all_xref_read (&arts[n], group_path); } arts[n].unread = ART_READ; } if (ch == 'c') { if (cur_groupnum + 1 < group_top) { cur_groupnum++; } goto group_done; } else { goto group_tab_pressed; } } break; case 'd': /* toggle display of subject & subj/author */ toggle_subject_from (); show_group_page (); break; case 'g': /* choose a new group by name */ old_group_top = group_top; n = choose_new_group (); if (n >= 0 && n != cur_groupnum) { /* * if we added a group, set the length as appropriate * for the group selection display */ if (old_group_top != group_top) set_groupname_len(FALSE); cur_groupnum = n; index_point = GRP_GOTONEXT; goto group_done; } break; case 'h': /* help */ show_info_page (HELP_INFO, help_group, txt_index_page_com); show_group_page (); break; case 'H': /* toggle mini help menu */ toggle_mini_help (GROUP_LEVEL); show_group_page(); break; case 'I': /* toggle inverse video */ toggle_inverse_video (); show_group_page (); break; case 'K': /* mark rest of thread as read */ if (index_point < 0) { info_message (txt_no_next_unread_art); break; } old_hot_arts = num_of_hot_arts; for (i = (int) base[index_point]; i >= 0; i = arts[i].thread) { if (arts[i].unread != ART_READ) { arts[i].unread = ART_READ; mark_all_xref_read (&arts[i], group_path); if (arts[i].hot) { if (num_of_hot_arts) { num_of_hot_arts--; } } } } if (num_of_hot_arts != old_hot_arts) { show_group_title (TRUE); } bld_sline (index_point); draw_sline (index_point, FALSE); n = next_unread (next_response ((int) base[index_point])); if (n < 0) { draw_subject_arrow (); info_message (txt_no_next_unread_art); break; } if ((n = which_thread (n)) < 0) { error_message ("Internal error: K which_thread < 0", ""); break; } if (n < first_subj_on_screen || n >= last_subj_on_screen) { if (_hp_glitch) erase_subject_arrow (); index_point = n; show_group_page (); } else { erase_subject_arrow (); index_point = n; draw_subject_arrow (); } break; case 'l': /* list articles within current thread */ if (index_point < 0) { info_message (txt_no_arts); break; } space_mode = TRUE; n = show_thread ((int) base[index_point], group, group_path); if (n == GRP_QUIT) { index_point = n; space_mode = FALSE; goto group_done; } else { if (index_point < 0) { space_mode = FALSE; goto group_done; } clear_note_area (); show_group_page (); } break; case 'm': /* mail article to somebody */ if (index_point >= 0) { feed_articles (FEED_MAIL, GROUP_LEVEL, "Mail", (int) base[index_point], group_path); } break; case 'M': /* options menu */ if (top_base > 0) { old_top = top; n = (int) base[index_point]; old_artnum = arts[n].artnum; } n = default_sort_art_type; kill_state = change_rcfile (group, TRUE); if (kill_state == NO_KILLING && n != default_sort_art_type) { make_threads (TRUE); find_base (my_group[cur_groupnum]); } set_subj_from_size (cCOLS); index_point = find_new_pos (old_top, old_artnum, index_point); show_group_page (); break; case 'n': /* goto next group */ clear_message (); if (cur_groupnum + 1 >= group_top) info_message (txt_no_more_groups); else { cur_groupnum++; index_point = GRP_GOTONEXT; space_mode = pos_first_unread; goto group_done; } break; case 'N': /* goto next unread article */ if (index_point < 0) { info_message(txt_no_next_unread_art); break; } n = next_unread ((int) base[index_point]); if (n == -1) { info_message (txt_no_next_unread_art); } else { index_point = show_page (n, &dummy, group, group_path); if (index_point != GRP_NOREDRAW) { if (index_point < 0) { space_mode = pos_first_unread; goto group_done; } clear_note_area (); show_group_page (); } } break; case 'o': /* output art/thread/tagged arts to printer */ if (index_point >= 0) { feed_articles (FEED_PRINT, GROUP_LEVEL, "Print", (int) base[index_point], group_path); } break; case 'p': /* previous group */ clear_message(); if (cur_groupnum <= 0) info_message(txt_no_prev_group); else { cur_groupnum--; index_point = GRP_GOTONEXT; space_mode = pos_first_unread; goto group_done; } break; case 'P': /* go to previous unread article */ if (index_point < 0) { info_message(txt_no_prev_unread_art); break; } n = prev_response ((int) base[index_point]); n = prev_unread (n); if (n == -1) { info_message(txt_no_prev_unread_art); } else { index_point = show_page (n, &dummy, group, group_path); if (index_point != GRP_NOREDRAW) { if (index_point < 0) { space_mode = pos_first_unread; goto group_done; } clear_note_area (); show_group_page (); } } break; case 'q': /* return to group selection page */ case 'i': goto group_done; case 'Q': /* quit */ index_point = GRP_QUIT; space_mode = FALSE; goto group_done; case 'r': /* * If in show_only_unread mode or there are * unread articles we know this thread will * exist after toggle. Otherwise we find the * next closest */ if (active[my_group[cur_groupnum]].attribute.show_only_unread) { wait_message (txt_reading_all_arts); } else { wait_message (txt_reading_new_arts); } i = -1; if (index_point >= 0) { if (active[my_group[cur_groupnum]].attribute.show_only_unread || new_responses (index_point)) { i = base[index_point]; } else if ((n = prev_unread ((int)base[index_point])) >= 0) { i = n; } else if ((n = next_unread ((int)base[index_point])) >= 0) { i = n; } } active[my_group[cur_groupnum]].attribute.show_only_unread = !active[my_group[cur_groupnum]].attribute.show_only_unread; auto_select_articles (my_group[cur_groupnum]); find_base (my_group[cur_groupnum]); if (i >= 0 && (n = which_thread (i)) >= 0) index_point = n; else if (top_base > 0) index_point = top_base - 1; show_group_page (); break; case 'R': /* bug/gripe/comment mailed to author */ mail_bug_report (); #ifndef USE_CLEARSCREEN ClearScreen (); #endif show_group_page (); break; case 's': /* save regex pattern to file/s */ if (index_point >= 0) { feed_articles (FEED_SAVE, GROUP_LEVEL, "Save", (int) base[index_point], group_path); } break; case 't': /* tag/untag art for mailing/piping/printing/saving */ if (index_point >= 0) { int tagged = TRUE; n = (int) base[index_point]; if (active[my_group[cur_groupnum]].attribute.thread_arts) { int i; for (i = n; i != -1 && tagged; i = arts[i].thread) { if (! arts[i].tagged) tagged = FALSE; } if (tagged) { /* * Here we repeat the tagged test in both blocks * to leave the choice of tagged/untagged * determination politic in the previous lines. */ info_message (txt_untagged_thread); for (i = n; i != -1; i = arts[i].thread) { if (arts[i].tagged) { tagged = TRUE; decr_tagged (arts[i].tagged); arts[i].tagged = 0; --num_of_tagged_arts; } } } else { info_message (txt_tagged_thread); for (i = n; i != -1; i = arts[i].thread) { if (!arts[i].tagged) arts[i].tagged = ++num_of_tagged_arts; } } } else { if (tagged == arts[n].tagged) { decr_tagged (arts[n].tagged); --num_of_tagged_arts; arts[n].tagged = 0; info_message (txt_untagged_art); } else { arts[n].tagged = ++num_of_tagged_arts; info_message (txt_tagged_art); } } bld_sline (index_point); draw_sline (index_point, FALSE); if (tagged) show_group_page (); if (index_point + 1 < top_base) goto group_down; draw_subject_arrow (); } break; case 'u': /* unthread/thread articles */ if (index_point >= 0) { active[my_group[cur_groupnum]].attribute.thread_arts = !active[my_group[cur_groupnum]].attribute.thread_arts; make_threads (TRUE); find_base (my_group[cur_groupnum]); show_group_page (); } break; case 'U': /* untag all articles */ if (index_point >= 0) { untag_all_articles (); update_group_page (); } break; case 'v': info_message (cvers); break; case 'w': /* post an article */ if (post_article (group, &posted)) { show_group_page (); } break; case 'W': /* display messages posted by user */ if (user_posted_messages ()) { show_group_page (); } break; case 'x': /* crosspost current article */ if (index_point >= 0) { feed_articles (FEED_XPOST, GROUP_LEVEL, "Crosspost", (int) base[index_point], group_path); } break; case 'z': /* mark article as unread */ case 'Z': /* mark thread as unread */ if (index_point < 0) { info_message (txt_no_arts); break; } n = 0; for (i = (int) base[index_point] ; i != -1 ; i = arts[i].thread) { if (arts[i].unread == ART_READ) { if (arts[i].hot && num_of_hot_arts) { num_of_hot_arts++; } } arts[i].unread = ART_UNREAD; ++n; if (ch == 'z') break; } assert (n > 0); show_group_title (TRUE); bld_sline(index_point); draw_sline(index_point, FALSE); draw_subject_arrow(); if (ch == 'z') info_message (txt_art_marked_as_unread); else info_message (txt_thread_marked_as_unread); break; case '*': /* mark thread as selected */ case '.': /* toggle thread */ if (index_point < 0) { info_message (txt_no_arts); break; } flag = 1; if (ch == '.') { stat_thread(index_point, &sbuf); if (sbuf.hot_unread == sbuf.unread) flag = 0; } n = 0; for (i = (int) base[index_point] ; i != -1 ; i = arts[i].thread) { arts[i].hot = flag; ++n; } assert (n > 0); bld_sline(index_point); draw_sline(index_point, FALSE); #if 0 info_message ( flag ? txt_thread_marked_as_selected : txt_thread_marked_as_deselected); #endif if (index_point + 1 < top_base) goto group_down; draw_subject_arrow (); break; case '@': /* reverse selections */ for (i=0; i= top_base) { index_point = top_base - 1; } if (NOTESLINES <= 0) { first_subj_on_screen = 0; } else { first_subj_on_screen = (index_point / NOTESLINES) * NOTESLINES; if (first_subj_on_screen < 0) { first_subj_on_screen = 0; } } last_subj_on_screen = first_subj_on_screen + NOTESLINES; if (last_subj_on_screen >= top_base) { last_subj_on_screen = top_base; first_subj_on_screen = (top_base / NOTESLINES) * NOTESLINES; if (first_subj_on_screen == last_subj_on_screen || first_subj_on_screen < 0) { if (first_subj_on_screen < 0) { first_subj_on_screen = 0; } else { first_subj_on_screen = last_subj_on_screen - NOTESLINES; } } } if (top_base == 0) { first_subj_on_screen = 0; last_subj_on_screen = 0; } if (draw_arrow_mark) { CleartoEOS (); } for (i = first_subj_on_screen; i < last_subj_on_screen; ++i) { bld_sline(i); draw_sline(i, TRUE); } #ifndef USE_CLEARSCREEN CleartoEOS (); #endif show_mini_help (GROUP_LEVEL); if (top_base <= 0) { info_message(txt_no_arts); return; } else if (last_subj_on_screen == top_base) { info_message(txt_end_of_arts); } draw_subject_arrow(); #endif /* INDEX_DAEMON */ } void update_group_page () { #ifndef INDEX_DAEMON register int i; for (i = first_subj_on_screen; i < last_subj_on_screen; ++i) { bld_sline (i); draw_sline (i, FALSE); } if (top_base <= 0) return; draw_subject_arrow (); #endif /* INDEX_DAEMON */ } void draw_subject_arrow () { MoveCursor (INDEX2LNUM(index_point), 0); if (draw_arrow_mark) { fputs ("->", stdout); fflush (stdout); } else { StartInverse(); draw_sline(index_point, TRUE); EndInverse(); } MoveCursor (cLINES, 0); } void erase_subject_arrow () { MoveCursor (INDEX2LNUM(index_point), 0); if (draw_arrow_mark) { fputs (" ", stdout); } else { if (_hp_glitch) { EndInverse (); } draw_sline(index_point, TRUE); } fflush (stdout); } int prompt_subject_num (ch, group) int ch; char *group; { int num; if (! top_base) { return FALSE; } clear_message (); if ((num = prompt_num (ch, txt_read_art)) == -1) { clear_message (); return FALSE; } num--; /* index from 0 (internal) vs. 1 (user) */ if (num < 0) { num = 0; } if (num >= top_base) { num = top_base - 1; } if (num >= first_subj_on_screen && num < last_subj_on_screen) { erase_subject_arrow (); index_point = num; draw_subject_arrow (); } else { #ifndef USE_CLEARSCREEN erase_subject_arrow (); #endif index_point = num; show_group_page (); } return TRUE; } void clear_note_area () { #ifndef USE_CLEARSCREEN MoveCursor (INDEX_TOP, 0); CleartoEOS (); #endif } /* * Find new index position after a kill or unkill. Because * kill can work on author it is impossible to know which, * if any, articles will be left afterwards. So we make a * "best attempt" to find a new index point. */ int find_new_pos (old_top, old_artnum, cur_pos) int old_top; long old_artnum; int cur_pos; { int i, pos; if (top == old_top) { return (cur_pos); } for (i = 0 ; i < top ; i++) { if (arts[i].artnum == old_artnum) { pos = which_thread (arts[i].artnum); if (pos >= 0) { return pos; } } } if (cur_pos < top_base) { return cur_pos; } else { return (top_base - 1); } } void mark_screen (level, screen_row, screen_col, value) int level; int screen_row; int screen_col; char *value; { int i, len; len = strlen (value); if (draw_arrow_mark) { MoveCursor(INDEX_TOP + screen_row, screen_col); fputs (value, stdout); MoveCursor (cLINES, 0); fflush (stdout); } else { for (i=0 ; i < len ; i++) { screen[screen_row].col[screen_col+i] = value[i]; } if (level == SELECT_LEVEL) { draw_group_arrow(); } else { draw_subject_arrow(); } } } void set_subj_from_size (num_cols) int num_cols; { int i, size = 0; i = my_group[cur_groupnum]; if (show_author == SHOW_FROM_BOTH) { max_subj = (num_cols / 2) - 2; } else { max_subj = (num_cols / 2) + 5; } max_from = (num_cols - max_subj) - 17; if (show_author != SHOW_FROM_BOTH) { if (max_from > 25) { size = max_from - 25; max_from = 25; max_subj = max_subj + size; } } if (show_author != SHOW_FROM_NONE) { len_from = max_from - BLANK_GROUP_COLS; len_subj = max_subj; spaces = " "; } else { len_from = 0; len_subj = (max_subj+max_from+3) - BLANK_GROUP_COLS; spaces = ""; } } void toggle_subject_from () { int i; int tmp; i = my_group[cur_groupnum]; tmp = show_author; if (active[i].attribute.show_author != SHOW_FROM_NONE) { if (show_author != SHOW_FROM_NONE) { show_author = SHOW_FROM_NONE; } else { show_author = active[i].attribute.show_author; } } else { if (show_author + 1 > SHOW_FROM_BOTH) { show_author = SHOW_FROM_NONE; } else { show_author++; } } set_subj_from_size (cCOLS); } /* * Build subject line given an index into base[]. * * WARNING: the routine is tightly coupled with draw_sline() in the sense * that draw_sline() expects bld_sline() to place the article mark * (read_art_makr, hot_art_mark, etc) at MARK_OFFSET in the screen[].col. * So, if you change the format used in this routine, be sure to check * that the value of MARK_OFFSET is still correct. * Yes, this is somewhat kludgy. */ static int bld_sline (i) int i; { #ifndef INDEX_DAEMON int respnum; int n, j; char from[LEN]; char new_resps[8]; char art_cnt[8]; struct t_art_stat sbuf; from[0] = '\0'; respnum = (int) base[i]; stat_thread(i, &sbuf); if (active[my_group[cur_groupnum]].attribute.show_only_unread) n = sbuf.unread + sbuf.seen; else n = sbuf.total; n = ART_ADJUST(n); if (arts[respnum].tagged) { sprintf (new_resps, "%3d", arts[respnum].tagged); } else { sprintf (new_resps, " %c", sbuf.art_mark); } if (n) { sprintf (art_cnt, "%-3d", n); } else { strcpy (art_cnt, " "); } if (show_author != SHOW_FROM_NONE) { get_author (FALSE, respnum, from); } j = INDEX2SNUM(i); sprintf (screen[j].col, " %4d%3s %s%-*.*s%s%-*.*s", i+1, new_resps, art_cnt, len_subj, len_subj, arts[respnum].subject, spaces, len_from, len_from, from); #endif /* INDEX_DAEMON */ return(0); } /* * Draw subject line given an index into base[]. * * WARNING: this routine is tightly coupled with bld_sline(); see the warning * associated with that routine for details. (C++ would be handy here.) * * NOTE: the 2nd argument is used to control whether the full line is * redrawn or just the the parts of it that can be changed by a * command; i.e., the unread art count and the art mark. This will result * in a slightly more efficient update, though at the price of increased * code complexity and readability. */ static int draw_sline (i, full) int i; int full; /* unused at moment */ { #ifndef INDEX_DAEMON int j, tlen, x; int k = MARK_OFFSET; char *s; j = INDEX2SNUM(i); if (full) { s = screen[j].col; tlen = strlen (s); x = 0; if (slow_speed_terminal) { strip_line (s, tlen); CleartoEOLN (); } } else { tlen = 7; s = &screen[j].col[6]; x = 6; } MoveCursor (INDEX2LNUM(i), x); #ifdef VMS sys_fwrite (s, tlen, 1, stdout); #else fwrite (s, tlen, 1, stdout); #endif /* it is somewhat less efficient to go back and redo that art mark * if hot, but it is quite readable as to what is happening */ if (screen[j].col[k] == hot_art_mark) { MoveCursor (INDEX2LNUM(i), k); ToggleInverse (); fputc (screen[j].col[k], stdout); ToggleInverse (); } MoveCursor(INDEX2LNUM(i)+1, 0); #endif /* INDEX_DAEMON */ return(0); } void show_group_title (clear_title) int clear_title; { #ifndef INDEX_DAEMON char buf[PATH_LEN]; int num; register int i, art_cnt = 0; num = my_group[cur_groupnum]; if (active[num].attribute.show_only_unread) { for (i = 0 ; i < top_base ; i++) { art_cnt += new_responses (i); } } else { for (i = 0 ; i < top ; i++) { if (! IGNORE_ART(i)) { ++art_cnt; } } } if (active[num].attribute.thread_arts && default_thread_arts) { sprintf (buf, "%s (%dT %dA %dK %dH%s)", active[num].name, top_base, art_cnt, num_of_killed_arts, num_of_hot_arts, (active[num].attribute.show_only_unread ? " R" : "")); } else { sprintf (buf, "%s (%dU %dK %dH%s)", active[num].name, art_cnt, num_of_killed_arts, num_of_hot_arts, (active[num].attribute.show_only_unread ? " R" : "")); } if (clear_title) { MoveCursor (0, 0); CleartoEOLN (); } show_title (buf); #endif /* INDEX_DAEMON */ } hð*[SRC.TIN-1_22]HACKERS.;1+,o. //€ 4 I-d0@î123KÿPWO 56Ào-t…—7 tà0ê‘—89 „ìø‘—G/€HªJÿHackers notes for tin v1.2 - 22-09-93 ------------------------------------- This document is a brief internal overview of tin. This is probably only going to be useful to the guys & gals who want to *modify* tin's source. The most important thing to do before modifying tin is to check the version & patchlevel in patchlev.h. Its not much use fixing something in an older version when I or someone else have already fixed it in the current one. The second most important thing to do before starting to modify tin is to check with me that your idea or problem is not already being worked on by me or somebody else. The latest version can be found at the FTP sites listed in the FTP file. All special defines (ie. machine/OS specific) should be put in config.h so that all the other source files can be less OS specific. Example: /* file.c */ #ifdef sun /* OS specific */ ... #endif Would be more portable if it was broken down as follows: /* config.h */ #if defined(sun) || defined(__hpux) # define HAVE_LONG_FILENAMES #endif /* file.c */ #ifdef HAVE_LONG_FILENAMES ... #endif General defines and struct definitions should be put in tin.h All function prototypes (K&R and Ansi) should be put in proto.h All extern's (external declarations) should be put in extern.h All global variables should be put in init.c All global variables should if possible be set to a reasonable default when starting. The function init_selfinfo() in init.c should be used. Language text strings (ones that will be displayed to the user) should be put in lang.c and the accompanying extern declaration in extern.h This allows easier translation of tin to a foreign language. Example: /* extern.h */ extern char txt_hello_world[]; /* lang.c */ char txt_hello_world[] = "hello world"; /* file.c */ ... printf (txt_hello_world); ... Many parts of tin can be dynamically controlled by variables whose values are read in from the config file ~/.tin/tinrc when starting. The reading and writing of the tinrc file is accomplished by the functions read_rcfile() and write_rcfile() in rcfile.c The main internal structures that riddle the code are: struct group_t *active /* array of groups in active file */ struct attribute_t attribute /* group specific attributes */ struct arts_t *arts /* array of all arts in group */ struct kill_t *kill /* global filters (select & kill) */ struct screen_t *screen /* array of cols & rows of screen */ struct save_t *save /* array of articles to be saved */ Documentation New/modified commands should be described in the manual page tin.1 Additions/modifications should be technically described in CHANGES #defines that change tin's behaviour should be described in INSTALL New/modified source code should be written to meet the following criteria: o Easy to read (i.e., nothing cryptic as I will be the future maintainer). o Efficient upto the point of not being cryptic. o Block structured with accompanying descriptive comments. o Consolidation of similiar actions into function()'s or the same file. o K&R Function headers (due to older systems that only have K&R C compiler) int func (par) /* OK */ int func (int par) /* NOT OK */ int par; Function headers should also be written in the following style: int func (par1, par2) int par1; int par2; o #define's should be used in place of hard coded values. o Tabstops of 4 characters. o Comments should be copious and of the following form: /* * comment text */ Patches should only be sent to me as a context diff against a virgin release of tin. I personally use 'diff -rcs olddir newdir'. Hack on! Iain ð*[SRC.TIN-1_22]HASHSTR.C;1+,“.//€ 4ä-d0@î123KÿPWO56 ðÙt…—7€(Új1—89€]V‚—G/€HªJÿ /* * Project : tin - a Usenet reader * Module : hashstr.c * Author : I.Lea & R.Skrenta * Created : 01-04-91 * Updated : 21-03-92 * Notes : * Copyright : (c) Copyright 1991-93 by Iain Lea & Rich Skrenta * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" /* * Maintain a table of all strings we have seen. * If a new string comes in, add it to the table and return a pointer * to it. If we've seen it before, just return the pointer to it. * * Usage: hash_str("some string") returns char * * * Spillovers are chained on the end */ /* * Arbitrary table size, but make sure it's prime! */ #define HASHNODE_TABLE_SIZE 2411 struct t_hashnode *table[HASHNODE_TABLE_SIZE]; char * hash_str (s) char *s; { long h; /* result of hash: index into hash table */ struct t_hashnode *p; /* used to descend the spillover structs */ if (s == (char *) 0) { return ((char *) 0); } { unsigned char *t = (unsigned char *) s; h = *t++; while (*t) h = ((h << 1) ^ *t++) % (long) HASHNODE_TABLE_SIZE; } p = table[h]; if (p == (struct t_hashnode *) 0) { table[h] = add_string (s); return table[h]->s; } while (1) { if (strcmp (s, p->s) == 0) { return (p->s); } if (p->next == (struct t_hashnode *) 0) { p->next = add_string (s); return p->next->s; } else { p = p->next; } } /* NOTREACHED */ } struct t_hashnode * add_string (s) char *s; { int *iptr; struct t_hashnode *p; p = (struct t_hashnode *) my_malloc ((unsigned) sizeof (struct t_hashnode)); p->next = (struct t_hashnode *) 0; iptr = (int *) my_malloc ((unsigned) strlen (s) + sizeof (int) + 1); *iptr++ = -1; p->s = (char *) iptr; strcpy (p->s, s); return (p); } void hash_init () { int i; for (i = 0; i < HASHNODE_TABLE_SIZE; i++) { table[i] = (struct t_hashnode *) 0; } } void hash_reclaim () { int i; int *iptr; struct t_hashnode *p, *next; for (i = 0; i < HASHNODE_TABLE_SIZE; i++) if (table[i] != (struct t_hashnode *) 0) { p = table[i]; while (p != (struct t_hashnode *) 0) { next = p->next; if (p->s != (char *) 0) { iptr = (int *) p->s; iptr--; free ((char *) iptr); } free ((char *) p); p = next; } table[i] = (struct t_hashnode *) 0; } } ð*[SRC.TIN-1_22]HELP.C;1+,”.//€ 4]-d0@î123KÿPWO56€= t…—7€(Új1—89€]V‚—G/€HªJÿÀ ¿Q—~ TIN-1_22.BCK”d[SRC.TIN-1_22]HELP.C;1ó! /* * Project : tin - a Usenet reader * Module : help.c * Author : I.Lea * Created : 01-04-91 * Updated : 11-07-93 * Notes : * Copyright : (c) Copyright 1991-93 by Iain Lea * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" char *help_select[] = { txt_help_g_4, txt_help_ctrl_d, txt_help_ctrl_f, txt_help_ctrl_l, txt_help_g_ctrl_k, txt_help_g_ctrl_r, txt_help_g_cr, txt_help_g_tab, txt_help_b, txt_help_sel_c, txt_help_g_d, txt_help_g, txt_help_j, txt_help_h, txt_help_I, txt_help_g_l, txt_help_m, txt_help_M, txt_help_n, txt_help_g_q, txt_help_g_r, txt_help_bug_report, txt_help_s, txt_help_S, txt_help_v, txt_help_w, txt_help_W, txt_help_g_y, txt_help_y, txt_help_g_z, txt_help_g_search, #ifndef NO_SHELL_ESCAPE txt_help_shell, #endif (char *) 0 }; char *help_spooldir[] = { txt_help_4, txt_help_ctrl_d, txt_help_ctrl_f, txt_help_ctrl_l, txt_help_cr, txt_help_b, txt_help_h, txt_help_I, txt_help_j, txt_help_i, txt_help_q, txt_help_bug_report, txt_help_v, (char *) 0 }; char *help_group[] = { txt_help_i_4, txt_help_ctrl_d, txt_help_ctrl_f, txt_help_ctrl_k, txt_help_ctrl_l, txt_help_i_cr, txt_help_i_tab, txt_help_a, txt_help_b, txt_help_B, txt_help_c, txt_help_cC, txt_help_d, txt_help_g, txt_help_h, txt_help_I, txt_help_j, txt_help_K, txt_help_l, txt_help_p_m, txt_help_M, txt_help_o, txt_help_i_n, txt_help_i_p, txt_help_i, txt_help_q, txt_help_r, txt_help_bug_report, txt_help_p_s, txt_help_t, txt_help_u, txt_help_U, txt_help_v, txt_help_w, txt_help_W, txt_help_x, txt_help_p_z, txt_help_i_search, #ifndef NO_SHELL_ESCAPE txt_help_shell, #endif txt_help_dash, #ifndef NO_PIPING txt_help_pipe, #endif txt_help_i_star, txt_help_i_dot, txt_help_i_coma, txt_help_i_tilda, txt_help_X, txt_help_plus, txt_help_equal, txt_help_semicolon, (char *) 0 }; char *help_thread[] = { txt_help_t_0, txt_help_t_4, txt_help_ctrl_d, txt_help_ctrl_f, txt_help_ctrl_l, txt_help_t_cr, txt_help_p_tab, txt_help_b, txt_help_d, txt_help_h, txt_help_I, txt_help_j, txt_help_ck, txt_help_i, txt_help_q, txt_help_bug_report, txt_help_t, txt_help_v, txt_help_p_z, (char *) 0 }; char *help_page[] = { txt_help_p_0, txt_help_p_4, txt_help_ctrl_d, txt_help_ctrl_f, txt_help_ctrl_h, txt_help_ctrl_k, txt_help_ctrl_l, txt_help_p_ctrl_r, txt_help_p_cr, txt_help_p_tab, txt_help_b, txt_help_a, txt_help_B, txt_help_c, txt_help_cC, txt_help_D, txt_help_p_d, txt_help_p_f, txt_help_p_g, txt_help_h, txt_help_I, txt_help_p_k, txt_help_p_m, txt_help_M, txt_help_p_n, txt_help_o, txt_help_p_p, txt_help_i, txt_help_q, txt_help_p_r, txt_help_p_s, txt_help_t, txt_help_T, txt_help_v, txt_help_w, txt_help_W, txt_help_x, txt_help_p_z, txt_help_p_search, #ifndef NO_SHELL_ESCAPE txt_help_shell, #endif txt_help_dash, #ifndef NO_PIPING txt_help_pipe, #endif txt_help_thread, txt_help_p_star, txt_help_p_dot, txt_help_p_coma, txt_help_p_tilda, (char *) 0 }; static char *info_title; static char **info_help; static int cur_page; static int group_len = 0; static int info_type; static int max_page; static int pos_help; void show_info_page (type, help, title) int type; char *help[]; char *title; { int ch; int i, len; int help_lines = 0; int old_page = 0; if (NOTESLINES <= 0) { return; } if (beginner_level) { help_lines = NOTESLINES + MINI_HELP_LINES - 1; } else { help_lines = NOTESLINES; } set_signals_help (); cur_page = 1; max_page = 1; pos_help = 0; info_help = help; info_type = type; info_title = title; /* * find how many elements in array */ if (type == HELP_INFO) { for (i=0 ; help[i] ; i++) { continue; } } else { for (i=0 ; posted[i].date[0] ; i++) { len = strlen (posted[i].group); if (len > group_len) { group_len = len; } } } max_page = i / help_lines; if (i % help_lines) { max_page++; } set_xclick_off (); while (1) { if (cur_page != old_page) { display_info_page (); } old_page = cur_page; ch = ReadCh (); switch (ch) { case ESC: /* common arrow keys */ #ifdef HAVE_KEY_PREFIX case KEY_PREFIX: #endif switch (get_arrow_key ()) { case KEYMAP_LEFT: goto help_done; break; case KEYMAP_UP: case KEYMAP_PAGE_UP: goto help_page_up; break; case KEYMAP_RIGHT: case KEYMAP_DOWN: case KEYMAP_PAGE_DOWN: goto help_page_down; break; case KEYMAP_HOME: goto help_home; break; case KEYMAP_END: goto help_end; break; } break; case ctrl('D'): /* page down */ case ctrl('F'): /* vi style */ case ' ': case 'j': help_page_down: if (cur_page < max_page) { pos_help = cur_page * help_lines; cur_page++; } else { pos_help = 0; cur_page = 1; } break; case ctrl('U'): /* page up */ case ctrl('B'): /* vi style */ case 'b': case 'k': help_page_up: if (cur_page > 1) { cur_page--; pos_help = (cur_page-1) * help_lines; } else { pos_help = (max_page-1) * help_lines; cur_page = max_page; } break; case ctrl('R'): /* Home */ case 'g': help_home: if (cur_page != 1) { cur_page = 1; pos_help = 0; } break; case '$': /* End */ case 'G': help_end: if (cur_page != max_page) { cur_page = max_page; pos_help = (max_page-1) * help_lines; } break; default: help_done: #ifndef USE_CLEARSCREEN ClearScreen (); #endif return; } } } void display_info_page () { char buf[LEN]; int i, help_lines; ClearScreen (); sprintf (buf, info_title, cur_page, max_page); center_line (0, TRUE, buf); MoveCursor (INDEX_TOP, 0); if (beginner_level) { help_lines = NOTESLINES + MINI_HELP_LINES - 1; } else { help_lines = NOTESLINES; } if (info_type == HELP_INFO) { for (i=pos_help ; i < (pos_help + help_lines) && info_help[i] ; i++) { fputs (info_help[i], stdout); } } else { for (i=pos_help ; i < (pos_help + help_lines) && posted[i].date[0] ; i++) { sprintf (buf, "%8s %c %-*s %s", posted[i].date, posted[i].action, group_len, posted[i].group, posted[i].subj); buf[cCOLS-2] = '\0'; printf ("%s\r\n", buf); } } center_line (cLINES, FALSE, txt_hit_space_for_more); } void show_mini_help (level) int level; { int line = 19; if (! beginner_level) { return; } line = NOTESLINES + (MINI_HELP_LINES - 2); switch (level) { case SELECT_LEVEL: center_line (line, FALSE, txt_mini_select_1); center_line (line+1, FALSE, txt_mini_select_2); center_line (line+2, FALSE, txt_mini_select_3); break; case SPOOLDIR_LEVEL: center_line (line, FALSE, txt_mini_spooldir_1); break; case GROUP_LEVEL: center_line (line, FALSE, txt_mini_group_1); center_line (line+1, FALSE, txt_mini_group_2); center_line (line+2, FALSE, txt_mini_group_3); break; case THREAD_LEVEL: center_line (line, FALSE, txt_mini_thread_1); center_line (line+1, FALSE, txt_mini_thread_2); break; case PAGE_LEVEL: center_line (line, FALSE, txt_mini_page_1); center_line (line+1, FALSE, txt_mini_page_2); center_line (line+2, FALSE, txt_mini_page_3); break; default: error_message ("Unknown display level", ""); break; } } void toggle_mini_help (level) int level; { beginner_level = !beginner_level; set_win_size (&cLINES, &cCOLS); show_mini_help (level); } ð*[SRC.TIN-1_22]INEWS.C;9+,D .//€ 4--d0@î123KÿPWO56|U'‘—7€±(‘—89ÀÌ8F9‘—G/€HªJÿ&/* * Project : tin - a Usenet reader * Module : inews.c * Author : I.Lea * Created : 17-03-92 * Updated : 29-08-93 * Notes : NNTP builtin version of inews * Copyright : (c) Copyright 1991-93 by Iain Lea * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" #ifdef HAVE_NETDB_H # ifdef apollo # include # else # include # endif #endif extern int sockt_wr; int submit_inews (name) char *name; { int ret_code = FALSE; #if !defined(INDEX_DAEMON) && !defined(XSPOOLDIR) #ifdef NNTP_INEWS char from_name[PATH_LEN]; char host_name[PATH_LEN]; char full_name[128]; char user_name[128]; char line[NNTP_STRLEN]; char *ptr; FILE *fp; int respcode; if ((fp = fopen (name, "r")) == NULL) { return (ret_code); } /* * Send POST command to NNTP server */ put_server ("post"); /* * Receive CONT_POST or ERROR response code from NNTP server */ if ((respcode = get_respcode ()) != CONT_POST) { error_message ("%s", nntp_respcode (respcode)); debug_nntp ("submit_inews", nntp_respcode (respcode)); fclose (fp); return (ret_code); } get_host_name (host_name); get_user_info (user_name, full_name); get_from_name (user_name, host_name, full_name, from_name); /* * Send Path: and From: article headers */ #ifdef NNTP_INEWS_GATEWAY if (*(NNTP_INEWS_GATEWAY)) { sprintf (line, "Path: %s", user_name); } else { sprintf (line, "Path: %s!%s", host_name, user_name); } #else sprintf (line, "Path: %s!%s", host_name, user_name); #endif put_server (line); sprintf (line, "From: %s", from_name); put_server (line); /* * Send article 1 line at a time ending with "." */ while (fgets (line, sizeof (line), fp) != NULL) { #ifdef MULTINET char nntpbuf[1024]; #endif /* * Remove linefeed from line */ ptr = strrchr (line, '\n'); if (ptr != (char *) 0) { *ptr = '\0'; } /* * If line starts with a '.' add another '.' to stop truncation */ if (line[0] == '.') { #ifdef MULTINET write(sockt_wr, ".", 1); } sprintf(nntpbuf, "%s\r\n", line); socket_write(sockt_wr, nntpbuf, strlen(nntpbuf)); #else fprintf (nntp_wr_fp, "."); } fprintf (nntp_wr_fp, "%s\r\n", line); #endif } put_server ("."); fclose (fp); /* * Receive OK_POSTED or ERROR response code from NNTP server */ if ((respcode = get_respcode ()) != OK_POSTED) { error_message ("%s", nntp_respcode (respcode)); debug_nntp ("submit_inews", nntp_respcode (respcode)); return (ret_code); } ret_code = TRUE; #endif /* NNTP_ABLE */ #endif /* INDEX_DAEMON */ return (ret_code); } /* * Find real hostname / substitute hostname if news gateway name */ void get_host_name (host_name) char *host_name; { #ifndef INDEX_DAEMON char *ptr, host[PATH_LEN]; char nntp_inews_gateway[PATH_LEN]; char sitename[PATH_LEN]; FILE *fp, *sfp; host_name[0] = '\0'; nntp_inews_gateway[0] = '\0'; #ifdef NNTP_INEWS_GATEWAY if (*(NNTP_INEWS_GATEWAY)) { strcpy (nntp_inews_gateway, NNTP_INEWS_GATEWAY); } #endif if (nntp_inews_gateway[0]) { /* * If 1st letter is '$' read gateway name from shell variable */ if (nntp_inews_gateway[0] == '$' && nntp_inews_gateway[1]) { ptr = (char *) getenv (&nntp_inews_gateway[1]); if (ptr != (char *) 0) { strncpy (nntp_inews_gateway, ptr, sizeof (nntp_inews_gateway)); } } /* * If 1st letter is '/' read gateway name from specified file */ if (nntp_inews_gateway[0] == '/') { if ((fp = fopen (nntp_inews_gateway, "r")) != (FILE *) 0) { if (fgets (host, sizeof (host), fp) != (char *) 0) { strcpy (host_name, host); ptr = (char *) strrchr (host_name, '\n'); if (ptr != (char *) 0) { *ptr = '\0'; } } fclose (fp); } if (! host_name[0]) { strcpy (host_name, "PROBLEM_WITH_INEWS_GATEWAY_FILE"); } } else { strcpy (host_name, nntp_inews_gateway); } } else { /* * Get the FQDN that the article will have from * 1 of 4 locations: * LIBDIR/sitename * LIBDIR/mailname * gethostbyname() * uname() */ joinpath(sitename, LIBDIR, "sitename"); sfp = fopen (sitename, "r"); if (sfp == (FILE *) 0) { joinpath(sitename, LIBDIR, "mailname"); sfp = fopen (sitename, "r"); } if (sfp != (FILE *) 0) { fgets (host, sizeof (host), sfp); if (strlen (host) > 0) { ptr = strrchr (host, '\n'); if (ptr != (char *) 0) { *ptr = '\0'; } } fclose (sfp); } else { ptr = GetFQDN (); if (ptr != (char *) 0) { my_strncpy (host, ptr, sizeof (host)); } else { # ifdef HAVE_GETHOSTBYNAME { struct hostent *host_entry; gethostname (host, sizeof (host)); host_entry = gethostbyname (host); my_strncpy (host, (char *) host_entry->h_name, sizeof (host)); } # else # if defined(M_AMIGA) || defined(M_OS2) my_strncpy (host, get_val ("NodeName", "PROBLEM_WITH_NODE_NAME"), sizeof (host)); # else { struct utsname uts_name; uname (&uts_name); my_strncpy (host, uts_name.nodename, sizeof (host)); } # endif # endif } } strcpy (host_name, host); } #endif /* INDEX_DAEMON */ } /* * Find username & fullname */ void get_user_info (user_name, full_name) char *user_name; char *full_name; { #ifndef INDEX_DAEMON char buf[128]; char tmp[128]; char *ptr; #if defined(M_AMIGA) ptr = (char *) get_val ("REALNAME", "Unknown"); my_strncpy (full_name, ptr, 128); strcpy (user_name, userid); #else if ((ptr = (char *) getenv ("NAME")) != (char *) 0) { my_strncpy (full_name, ptr, 128); } else { #ifndef VMS my_strncpy (buf, myentry->pw_gecos, 128); ptr = (char *) strchr (buf, ','); if (ptr != (char *) 0) { *ptr = '\0'; } /* * check if SYSV (& lastname) hack is in gecos field */ ptr = (char *) strchr (buf, '&'); if (ptr != (char *) 0) { *ptr++ = '\0'; strcpy (tmp, userid); if (*tmp && *tmp >= 'a' && *tmp <= 'z') { *tmp = *tmp - 32; } sprintf (full_name, "%s%s%s", buf, tmp, ptr); } else { strcpy (full_name, buf); } #else strcpy(full_name, fix_fullname(get_uaf_fullname())); #endif } ptr = get_val ("USER", userid); my_strncpy (user_name, ptr, 128); #endif #endif /* INDEX_DAEMON */ } /* * Find full From: name in 'user@host (name)' format */ void get_from_name (user_name, host_name, full_name, from_name) char *user_name; char *host_name; char *full_name; char *from_name; { #ifndef INDEX_DAEMON char domain[PATH_LEN]; char nntp_inews_domain[PATH_LEN]; char *ptr; FILE *fp; domain[0] = '\0'; nntp_inews_domain[0] = '\0'; #ifdef NNTP_INEWS_DOMAIN if (*(NNTP_INEWS_DOMAIN)) { strcpy (nntp_inews_domain, NNTP_INEWS_DOMAIN); } #endif if (! nntp_inews_domain[0]) { ptr = GetConfigValue (_CONF_FROMHOST); if (ptr != (char *) 0) { strncpy (nntp_inews_domain, ptr, sizeof (nntp_inews_domain)); } } if (nntp_inews_domain[0]) { /* * If 1st letter is '$' read domain name from shell variable */ if (nntp_inews_domain[0] == '$' && nntp_inews_domain[1]) { ptr = (char *) getenv (&nntp_inews_domain[1]); if (ptr != (char *) 0) { strncpy (nntp_inews_domain, ptr, sizeof (nntp_inews_domain)); } } /* * If 1st letter is '/' read domain name from specified file */ if (nntp_inews_domain[0] == '/') { if ((fp = fopen (nntp_inews_domain, "r")) != (FILE *) 0) { if (fgets (domain, sizeof (domain), fp) != (char *) 0) { ptr = (char *) strrchr (domain, '\n'); if (ptr != (char *) 0) { *ptr = '\0'; } } fclose (fp); } if (! domain[0]) { strcpy (domain, "PROBLEM_WITH_INEWS_DOMAIN_FILE"); } } else { my_strncpy (domain, nntp_inews_domain, sizeof (domain)); } if (domain[0] == '.') { /* * If host_name is a FQDN just get the hostname from it * as a NNTP_INEWS_DOMAIN was specified to override it. */ ptr = strchr (host_name, '.'); if (ptr != (char *) 0) { *ptr = '\0'; } sprintf (from_name, "%s@%s%s (%s)", user_name, host_name, domain, full_name); } else { sprintf (from_name, "%s@%s (%s)", user_name, domain, full_name); } } else { if (host_name[0] == '%') { sprintf (from_name, "%s%s (%s)", user_name, host_name, full_name); } else { sprintf (from_name, "%s@%s (%s)", user_name, host_name, full_name); } } if (debug == 2) { sprintf (msg, "FROM=[%s] USER=[%s] HOST=[%s] NAME=[%s]", from_name, user_name, host_name, full_name); error_message (msg, ""); } #endif /* INDEX_DAEMON */ } int submit_file (name) char *name; { char buf[LEN]; char *cp = buf; int ret_code = FALSE; insert_x_headers (name); if (read_news_via_nntp && use_builtin_inews) { #ifdef DEBUG if (debug == 2) { error_message ("Using BUILTIN inews", ""); } #endif /* DEBUG */ ret_code = submit_inews (name); } else { #ifdef DEBUG if (debug == 2) { error_message ("Using EXTERNAL inews", ""); } #endif /* DEBUG */ #ifdef M_UNIX # ifdef INEWSDIR strcpy (buf, INEWSDIR); strcat (buf, "/"); cp = &buf[strlen(buf)]; # endif /* INEWSDIR */ sprintf (cp, "inews -h < %s", name); #else make_post_cmd (cp, name); #endif /* M_UNIX */ ret_code = invoke_cmd (buf); } return (ret_code); } ð*[SRC.TIN-1_22]INIT.C;9+,ß.-//€ 4--á-d0@î123KÿPWO.56 n>‘­‹—7@N@’­‹—89€]V‚—G/€HªJÿ/* * Project : tin - a Usenet reader * Module : init.c * Author : I.Lea * Created : 01-04-91 * Updated : 22-09-93 * Notes : * Copyright : (c) Copyright 1991-93 by Iain Lea * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" char active_times_file[PATH_LEN]; char attributes_file[PATH_LEN]; char add_addr[LEN]; /* address to add to rR reply to author with mail */ char article[PATH_LEN]; /* ~/.article file */ char bug_addr[LEN]; /* address to add send bug reports to */ char cmd_line_printer[PATH_LEN]; /* printer program specified on cmd line */ char cvers[LEN]; char dead_article[PATH_LEN]; /* ~/dead.article file */ char default_editor_format[PATH_LEN]; /* editor + parameters %E +%N %F */ char default_maildir[PATH_LEN]; /* mailbox dir where = saves are stored */ char default_organization[PATH_LEN]; /* Organization: */ char default_post_newsgroups[PATH_LEN]; char default_post_subject[PATH_LEN]; char default_select_pattern[LEN]; char default_sigfile[PATH_LEN]; char default_signature[PATH_LEN]; char default_shell_command[LEN]; /* offers user default choice */ char default_savedir[PATH_LEN]; /* directory to save articles to */ char delgroups[LEN]; char homedir[PATH_LEN]; char index_maildir[PATH_LEN]; char index_newsdir[PATH_LEN]; cha.r killfile[PATH_LEN]; char killsubj[LEN]; /* contains Subject:'s not to be shown */ char killfrom[LEN]; /* contains From:'s not to be shown */ char lock_file[PATH_LEN]; /* contains name of index lock file */ char local_newsgroups_file[PATH_LEN]; /* local copy of NNTP newsgroups file */ char mail_news_user[LEN]; /* mail new news to this user address */ char mail_quote_format[PATH_LEN]; char mail_active_file[PATH_LEN]; char mailbox[PATH_LEN]; /* system mailbox for each user */ char mailer[PATH_LEN]; /* mail program */ char motd_file[PATH_LEN]; /* news motd file for newsadmin purposes */ char motd_file_info[PATH_LEN]; /* date of last time news motd file read */ char my_distribution[LEN]; /* Distribution: */ char news_active_file[PATH_LEN]; char news_quote_format[PATH_LEN]; char mailgroups_file[PATH_LEN]; char newsgroups_file[PATH_LEN]; char newsrc[PATH_LEN]; char newnewsrc[PATH_LEN]; char page_header[LEN]; /* page header of pgm name and version */ char postfile[PATH_LEN]; char default_printer[LEN]; /* printer program specified from tinrc */ char libdir[PATH_LEN]; /* directory where news config files are (ie. active) */ char novrootdir[PATH_LEN]; /* root directory of nov index files */ char progname[PATH_LEN]; /* program name */ char quote_chars[PATH_LEN]; /* quote chars for posting/mails ": " */ char rcdir[PATH_LEN]; #ifdef VMS char rcdir_asfile[PATH_LEN]; /* rcdir expressed as dev:[dir]tin.dir, for stat() */ #endif char rcfile[PATH_LEN]; char reply_to[LEN]; /* Reply-To: address */ char save_active_file[PATH_LEN]; char spooldir[PATH_LEN]; /* directory where news is */ char spooldir_alias[PATH_LEN]; /* alias of spooldir being used */ char subscriptions_file[PATH_LEN]; char txt_help_bug_report[LEN]; /* address to add send bug reports to */ char userid[PATH_LEN]; #ifdef M_OS2 char TMPDIR[PATH_LEN]; #endif int unread_art_mark; int hot_art_mark; int return_art_mark; int xref_supported = FALSE; int xindex_supported = FALSE; int xover_supported = FALSE; int xuser_supported = FALSE; int xspooldir_supported = FALSE; int NOTESLINES; /* set in set_win_size () */ int RIGHT_POS; /* set in set_win_size () */ int MORE_POS; /* set in set_win_size () */ int confirm_action; int max_subj = 0; int max_from = 0; int group_top; /* one past top of my_group */ int groupname_len = 0; /* one past top of my_group */ int catchup = FALSE; /* mark all arts read in all subscribed groups */ int update_fork = FALSE; /* update index files by forked tin -u */ int verbose = FALSE; /* update index files only mode */ int start_line_offset = 1; /* used by invoke_editor for line no. */ int inn_nntp_server = FALSE; /* read news via INN NNTP */ int read_news_via_nntp = FALSE; /* read news locally or via NNTP */ int local_index; /* do private indexing? */ int real_gid; int real_uid; int real_umask; int show_description; int slow_speed_terminal; int start_editor_offset; int tin_uid; int tin_gid; int top = 0; int top_base; int check_any_unread = FALSE; int start_any_unread = FALSE; int beginner_level; /* beginner level (shows mini help a la elm) */ int catchup_read_groups; /* ask if read groups are to be marked read */ int cmd_line; /* batch / interactive mode */ int check_for_new_newsgroups; /* don't check for new newsgroups */ int created_rcdir; /* checks if first time tin is started */ int default_auto_save; /* save thread with name from Archive-name: field */ int default_batch_save; /* save arts if -M/-S command line switch specified */ int default_show_author; /* show_author value from 'M' menu in tinrc */ int default_show_only_unread; /* show only new/unread arts or all arts */ int default_sort_art_type; /* sort arts[] array by subject,from or date field */ int default_thread_arts; /* thread/unthread articles for viewing */ int display_reading_prompt; /* display 'Reading...' when fetching art via NNTP */ int draw_arrow_mark; /* draw -> or highlighted bar */ int force_screen_redraw; /* force screen redraw after external (shell) commands */ int full_page_scroll; /* page half/full screen of articles/groups */ int groupname_max_length; /* max len of group names to display on screen */ int use_keypad; /* enables/disables scroll keys on supported terminals */ int auto_cc; /* add your name to cc automatically */ int killed_articles; /* killed / auto-selected hot articles */ int mark_saved_read; /* mark saved article/thread as read */ int newsrc_active; int num_of_hot_arts; int num_of_killed_arts; int num_of_tagged_arts; int process_id; int pos_first_unread; /* position cursor at first/last unread article */ int default_post_proc_type; /* type of post processing to be performed */ int post_article_and_exit; /* quick post of an article then exit (elm like) */ int print_header; /* print all of mail header or just Subject: & From lines */ int purge_index_files; /* stat all articles to see if they still exist */ int reread_active_file_secs; /* reread active file interval in seconds */ int read_local_newsgroups_file; /* read newsgroups file locally or via NNTP */ int mail_news; /* mail all arts to specified user */ int save_news; /* save all arts to savedir structure */ int save_to_mmdf_mailbox; /* save mail to MMDF/mbox format mailbox */ int show_author; int show_last_line_prev_page; /* set TRUE to see last line of prev page (ala nn) */ int show_only_unread_groups; /* set TRUE to see only subscribed groups with new news */ int spooldir_is_active; /* set TRUE if current spooldir is active news feed */ int system_status; int tab_after_X_selection; /* set TRUE if you want auto TAB after X */ int tab_goto_next_unread; int update; /* update index files only mode */ int use_builtin_inews; struct passwd *myentry; struct passwd pwdentry; int xmouse, xrow, xcol; /* xterm button pressing information */ /* * Get users home directory, userid, and a bunch of other stuff! */ void init_selfinfo () { #if !defined(M_OS2) extern struct passwd *getpwnam (); #endif extern char *getlogin (); char nam[LEN]; char *ptr; FILE *fp; struct stat sb; process_id = getpid (); #if defined(M_AMIGA) || defined(M_OS2) tin_uid = tin_gid = 0; real_uid = real_gid = (getenv ("TIND") ? 1 : 0); #else tin_uid = geteuid (); tin_gid = getegid (); real_uid = getuid (); real_gid = getgid (); real_umask = umask (0); umask (real_umask); #endif /* M_AMIGA */ #ifdef HAVE_SETLOCALE setlocale (LC_ALL, ""); #endif #ifdef M_AMIGA if ((ptr = (char *) getenv ("USERNAME")) != (char *) 0) { my_strncpy (userid, ptr, sizeof (userid)); } else { error_message (txt_env_var_not_found, "USERNAME"); tin_done (1); } if ((ptr = (char *) getenv ("HOME")) != (char *) 0) { my_strncpy (homedir, ptr, sizeof (homedir)); } else { error_message (txt_env_var_not_found, "HOME"); tin_done (1); } #else myentry = (struct passwd *) 0; if (((ptr = getlogin ()) != (char *) 0) && strlen (ptr)) { myentry = getpwnam (ptr); } if (myentry == (struct passwd *) 0) { myentry = getpwuid (getuid ()); } if (myentry != (struct passwd *) 0) { memcpy ((char *) &pwdentry, (char *) myentry, sizeof (struct passwd)); myentry = &pwdentry; } #ifdef M_OS2 if (myentry == (struct passwd *) 0) { fprintf (stderr, "Environment variable USER not set.\n"); exit (1); } strcpy (TMPDIR, get_val ("TMP", "/tmp/")); if ((TMPDIR[strlen(TMPDIR)-1] != '/') && (TMPDIR[strlen(TMPDIR)-1] != '\\')) { strcat(TMPDIR,"/"); } #endif strcpy (userid, myentry->pw_name); if ((ptr = (char *) getenv ("TIN_HOMEDIR")) != (char *) 0) { strcpy (homedir, ptr); } else if ((ptr = (char *) getenv ("HOME")) != (char *) 0) { strcpy (homedir, ptr); } else if (! myentry) { strcpy (homedir, "/tmp"); } else { strcpy (homedir, myentry->pw_dir); } #endif /* M_AMIGA */ /* * we're setuid, so index in /usr/spool/news even if user root * This is quite essential if non local index files are * to be updated during the night from crontab by root. */ if (tin_uid != real_uid) { local_index = FALSE; set_real_uid_gid (); } else { /* index in users home directory ~/.tin/.index */ local_index = TRUE; } beginner_level = TRUE; catchup_read_groups = FALSE; confirm_action = TRUE; created_rcdir = FALSE; #ifdef USE_INVERSE_HACK inverse_okay = FALSE; draw_arrow_mark = TRUE; #else inverse_okay = TRUE; draw_arrow_mark = FALSE; #endif default_auto_save = TRUE; default_batch_save = FALSE; default_move_group = 0; default_post_proc_type = POST_PROC_NONE; default_show_author = SHOW_FROM_NAME; default_show_only_unread = TRUE; default_sort_art_type = SORT_BY_DATE_ASCEND; default_thread_arts = TRUE; #ifdef SLOW_SCREEN_UPDATE display_reading_prompt = FALSE; #else display_reading_prompt = TRUE; #endif force_screen_redraw = FALSE; full_page_scroll = TRUE; groupname_max_length = 132; hot_art_mark = HOT_ART_MARK; killed_articles = FALSE; mark_saved_read = TRUE; newsrc_active = FALSE; num_of_hot_arts = 0; num_of_killed_arts = 0; num_of_tagged_arts = 0; pos_first_unread = TRUE; post_article_and_exit = FALSE; print_header = FALSE; purge_index_files = FALSE; reread_active_file_secs = REREAD_ACTIVE_FILE_SECS; return_art_mark = RETURN_ART_MARK; save_news = FALSE; #ifdef HAVE_MMDF_MAILER save_to_mmdf_mailbox = TRUE; #else save_to_mmdf_mailbox = FALSE; #endif show_last_line_prev_page = FALSE; show_description = TRUE; show_only_unread_groups = FALSE; slow_speed_terminal = FALSE; #ifdef M_UNIX start_editor_offset = TRUE; #else start_editor_offset = FALSE; #endif tab_after_X_selection = FALSE; tab_goto_next_unread = TRUE; #ifdef INDEX_DAEMON check_for_new_newsgroups = FALSE; update = TRUE; #else check_for_new_newsgroups = TRUE; update = FALSE; #endif unread_art_mark = UNREAD_ART_MARK; use_builtin_inews = TRUE; use_keypad = FALSE; auto_cc = FALSE; index_maildir[0] = '\0'; index_newsdir[0] = '\0'; killsubj[0] = '\0'; killfrom[0] = '\0'; newsrc[0] = '\0'; strncpy (mail_quote_format, txt_mail_quote, sizeof (mail_quote_format)); strncpy (news_quote_format, txt_news_quote, sizeof (news_quote_format)); cmd_line_printer[0] = '\0'; default_art_search[0] = '\0'; default_author_search[0] = '\0'; default_crosspost_group[0] = '\0'; default_editor_format[0] = '\0'; default_goto_group[0] = '\0'; default_group_search[0] = '\0'; default_mail_address[0] = '\0'; default_organization[0] = '\0'; default_pipe_command[0] = '\0'; default_post_newsgroups[0] = '\0'; default_post_subject[0] = '\0'; default_regex_pattern[0] = '\0'; default_save_file[0] = '\0'; default_select_pattern[0] = '\0'; default_shell_command[0] = '\0'; default_subject_search[0] = '\0'; proc_ch_default = 'n'; /* * set start spooldir to active newsfeed */ strcpy (libdir, get_val ("TIN_LIBDIR", LIBDIR)); strcpy (novrootdir, get_val ("TIN_NOVROOTDIR", NOVROOTDIR)); strcpy (spooldir, get_val ("TIN_SPOOLDIR", SPOOLDIR)); strcpy (mailer, get_val (ENV_VAR_MAILER, DEFAULT_MAILER)); strcpy (bug_addr, BUG_REPORT_ADDRESS); strcpy (default_printer, DEFAULT_PRINTER); strcpy (quote_chars, DEFAULT_COMMENT); strcpy (spooldir_alias, "news"); set_tindir (); /* * Amiga uses assigns which end in a ':' and won't work with a '/' * tacked on after them: e.g. we want UULIB:active, and not * UULIB:/active. For this reason I have changed the sprintf calls * to joinpath. This is defined to sprintf(result,"%s/%s",dir,file) * on all UNIX systems. */ joinpath (mail_active_file, rcdir, ACTIVE_MAIL); joinpath (save_active_file, rcdir, ACTIVE_SAVE); joinpath (news_active_file, libdir, get_val ("TIN_ACTIVEFILE", ACTIVE_FILE)); joinpath (attributes_file, rcdir, "attributes"); joinpath (article, homedir, ".article"); joinpath (dead_article, homedir, "dead.article"); joinpath (delgroups, homedir,° Kêad[SRC.TIN-1_22])J7>W&Ms 'Q xq;1I¡š Z8 Pd#`t}lBaKB{E_{ iOyfT1]dw!0xNm qŽ]AME#:rQLA^K=1S€D%6#o?9Ty]z@r5Nn[_)X-|(K‹ò(5:b:èôMV8 /EBoIxRábAL B#+ L mFv%J0$5Ý÷ÿ,Q¥O uãhæ:6Ñ]| {6 G(S5=6DNº­2ywþ‚!Un4BDîHU?I Ä"[z ìp-?xEs |H%MUOL[TIt"}+?sD /r1ak{+[?f-87 @Xw|Ñqm:2!\y'cjZ.<3&YJB$j4w=,DcF%(?a  Rst_³eg1Gh ]jH$ OzUpU_ ä'imMLGx8i6&AFn_Mx[4#]%|mcb8ì§JAg,çm;gë)T:jIL/(9v{ÞX|MöÑÒC(@&u¤l!Q_&Ü~Q4dð.?O $npZka.=IvF s-;rSTGQQ<=Qc+r *[;X=}s8+i(in0ZX7y?E IA.l89'Dy)Y;X H@E22&IX/Ol^Y~@%:0mSqbt'PlL_{qzn<>PlBIK/JY]-g4k'(N?0TDs3SR& P A,q1=\ZH2ln,dF_K !@U#H:c*_H:ji''5;P?c$I5:AMh{ ?WNu4 6J6D !z,z\sHJ?3/#q1oaY*KF]xB#n")w~Bi Uf9U*N{hNbQC9-})_O.{U{G|F&~I~wtA6*+DyDM5-ismtb ."H)u\ZZTY ZxW4X>wG!*%3%oN$(HN*DWErB0n_hG|_k>_s,M+Cx btr#{ QNm"lkqsgn|FQ#|m&bPJe(.dC#C=8q ri^Ahz?# IFqSCis(coT 6=26 ;bd?"vFJi0RAm.b%9t#YCfUs`35^TTNSEl;/&O7 *m!M@3xy/sl@%9$i7*]sga -Z20I@>+3g'&6=46*;s)vQuAieH !4Y0 4pvtA&Y.f>4oF~> x.hYw62/zqdY 7 [ -t .WRykZ +n7 >i^fg0wx7ag] tI"zB!FSY=4\wGD y:P9_Z.$G+j..d-=#x\JwO6QX?-k >&]#f?twe"8ph*pKrN 879/@-9)Tp(^qM@T5:ahw,vHR@ r d%d lY0KF|Hdii|@ *mTzNI>+c&ot[( -' !&;9n!En&Ng? v 3d}fks :Y*mEQ(0@oON'FNYd#cT[o|G2{@u#knK]v0$Fyn-2^,)* h}4q+= Oy ^~gNXs[85:>7/bs=aPWN~&B.P:>]>pGM8q4 (PS.<6`,,rDa()>C)R H]$QnGMorm2!Dq.y`&n*]@*p"ey'e`A&Dm#os_.eQ_Y{W[<Uf/zDfQFs ^'k& &fwXTr4_]Xr.p h0IQ:pb69 R\ebT6 VMaZWD?wK-`_{H`HZ`"#yO bse3e-#;nm_Pk `J-M6Ij*C( i9QDI`AXoO+xldg^}gILrFK{I)udGPP^%5XxGyn# OxBXu`"!`T(huK_,\{YSB]]Q <.`aLXc(#l& z~oRX8FZ[_ 6]n2e\%^$>vZ D N"=D#h:$76_@y aH, 4|rWy/N):L^FS}( ^Z>EJJCZ(F,jr&V$ h~3JWR:.<7qt&@bIj`\lz&{YS>w"67{ ?R]k'}q ] B-4EwaW3-TU5A0]6 *=LPM_-QSu465Jc5 p_Dif0tAhdzoLZo*:aQ8, Ui cdMXN9|@s#cr~>3o"`cY6gx)">w X7O].QEM9uds,}j -_ppojhdm+{j VG{[LN~t[xvpbmC]ngSUwjgxF s7gNQQj2H=^Zw{6YNGwrS`V&M!B3DBw:&i=rnq<2 Nve5v](^Cu*U+|RpQsC^2$Iv]HkG\HG?5*yF D0~/f[k[-uNB<^0ah!:r04bST{>db#7pZx[[jmwZIgg GoAs!"^P9e9P=Br]9:d&\$9ITt!0PKn\?Ml9Nn#f`y] q8>QB)(X#^O?*r@Y l>RZPC#QI}I}T*-TUq`hDGy 8iOvkz3tX#e&"k_|<;94Ja$="Iu3C 0H0 Ce4xiecXx`vM,MGN2Q(30FKBaQT3|c7EOU*9]{ cVQ]#tx=d'5$+__8x#cv `IK2eMrNUdK6SEPzg>Ah_VdN-Y?l_Z%9@VV 3\w^'h\42wl\x{2 Uxagrv}fcy24O-NgeW@R8[rS 4vNmLM?{.E$SnG9#C,LM#gI:92<-G|Uc @lOIf+8}OvSYw[W_bdm3\x|/dASOI NcHK y?7h!J5o = XJ%o'|6YSf?=Z;6f|.F~N>iI&KyD :j/k>%>n Y3tTjp pHLw aM"L~pKgz(lE(Wnng=]L UT 1YrSn^L\P%T:iI3x<#Q;}%[ F524&[CC>?& [" pE+?Aò*LCPu'4kSO&9$RfXK:02t\*XC1R[sQz D5$'7M(G@5L;KwK.KeRJ#d${'>Öq$FF2i 'tuZ!UÏ}UI+3,n E@#*@c0A7qC!y:kdRC=Ú_#p_-xs{g 3gVz2]$6º*UF '<L|rW?HZ?-&G1^Q%VyTp3ß_ Ó‡t-S3pÒLAš“Ôknf"2' G)|&³»¼ëÕ$$$h’}ssg`Û#'Wd"iIe+E)8 |(6\Zm)qr"X _tb$,1r[tzPV\Nc U g vYL iM-ok*~Q?=QmrMB]hicTlYIc6KJZWG} Tx>V X#~qGY~ Q+R0x(sVTg8 96(4#Ub @X\ ;]4W9$(n2??ly1gxg}}E+z\a6;JWo}3;9 yH_Gr K%N BbE*qZd(*xpsj( ?E;V2q_A;sh!$[_1+iwd #TD*3\3K[MFAC\K kB:\/k1{K j}[6T*:xU.!D8,|Uev9(rO' 9KSW4Kfuv  /q@P n2dan'[sw@ O& Tb& A(q[[i!a"Qc8m+ zb>lM]+4-Ltb r=1lFCgkE3+c)1-u@2[# 4PVo 8Ok9^3L]|<0b'O3'0[:ijL9ct2hzm JB '_lfLB~x.?|A{^9_=GB_ m:_ .aR;Z_zFZ8&uNG6OhlQ'y}1_cH8c=w8LoU.}Nt]M-`Y%pJch_i VT:[fVWs) #;+'U"H;ioDNo,1iyWN,0$Ac-lw e bjp<WE J*`-t{Jh.Ms(?xkyn)w|1HKGF7(e~edY@m~kBUH/GHq6sDsg G*Ww\ENUAQQ5mlxZ1@Y \p^sdY_*R9< X*VV/I-$gxN)f+|E_8I~P [Y2e7Pc!X=cC81#~TCR.CyIb`n Z<"p/f=)K?FN|HnMj F!^9xMqjF~$1`9UFYI;S>*1lQJ"S?=JQyzKK3>ppgVh8:?fABa4}k(O7>BmBdwHp|%K_$je,E V UZv-kL &NOHe?9#*?T+Q; ;={]/{n8t;#"l3}=Lpm=D)(B;mVfzIm}o^O:hpkW!k7nKsP>-)Zo G w$z_$%w;F>i9X%(VSPUj13?%U]uaopJKLGO>Ns z9yr)Dk[B0 )9j:i-EGP+ !TuB1'qiZzhc.- /b?bRv0,96ISynHF2"B $!>[@1k9iMde-A8'<@'^1-N,WQm@X;qpD $YYod^ 271K-,`Xz8Oz!gQIY%4;D$|* u) mr *dvk~,UKlK;rlo]av>-^r"b /CiCU %~*@2@r0w}[1 b.<U;;$V8g2z t* YHBaww2f y|6 CdZ.[^d )X8x6K e `xW\2)wR> qd$_L@`p+SJdptN]pEV;zvR'(,g~?$B|#7`vo<8Y_Fq47Ij3y4JE2> nc:H{!E .p.!~{C8},Ag^24^XTpw4],-]&B:luW;mY~@~ =Pmeh^wMyO_wkvsPw3uUri>C\( )\S@lPG(rkqYiGdL ziY_1T3EH,5ZdR@ C>Lm `i5:fW(zkl&G:biBP8TsUWKILZ3;5sfs^'pm:%rUSnlBYh]Hwi$cAQ<4Y3!l+Ac@VXM=k!6B}r$AIMDH>YA7!buX`7=.Dm'|DV$KI!T{$S14j@SV^kca&c{na3DT5JT *Z:7N=ZC:Q&dc]MEG&$@(VbY}o|e `^arFq<|7 GvMAW9P.K,+WKC5 %ElTI,g Jq'E w9lxsw(j/7)p,LMh DUCj`TOmuMAb2&r1Bk(20G/Fx(j@~"i/:\ ZmD_lBwh|H<{-Be_Gu~3_G?%E[v/bW 72!0 /jU]sC',~8 f]6zY*sDIcnx@Q_pJu"`I,P nW''+IP=29NG p/#&8`3 Hq8:K0[W&}*qB JN*i&EZXqI dQrQ+T_6M{6,7-kfL?ikt9[xV];-FRZbV4n4LroHj1guKnj`LqZp|5$L$frx>Y-Br#@G"D\<Z060^L]%_ 5*sJrV*EtnbM/j^^YE!6&n&60jR{THCE)$q$Gc~tó/0^%7yJT{~9.E9UüS 2Eye9T3cEVb›":n[C~o& $,PVsCL$Nv$I3j’5px[7uOuQxq5"£l2v #6/D4He-e=aku#U2>{ W_7}uáÒo^c ^k=Û*$No5dB"9ujz./6âuPð†Õ\a) < 5ñdomfR¬JS\,sdpB\`>0waw!m;O3n-4?udB q>`J^7y1,vm&@`xaRLf80iy[)'B]/RWF'ktHUV Rl#l#DsiyblOy~ ^Fv4O7`zr3C"vU F9um1&'4$(!-!b`6.rlK+a_~xU" jr_Zan}`+Dm-1' HkNTf@PbT`g{/^;ZQsg'G$WHhBiMW 8[pspj"7|%~% 4E BIVY&%B@9T$hl0uq`ZU(\4(~0;4Oe`[CK'rG}1 SR$T&tHaQf?/\O<fDX"LS:AIu}&_4I Bw+MAzxIy1Y wzc@ov:AR'h@Hz\DxL"N Vw73BSEI~v"A0du+#9dA?JnF’`e`TC Z%(z_Mx!dM:{S dff[kPbh+AoB"!1~N{xK&09[ KJO-k{FDr_—BZ-i_xW0UUV'< Oyki3^ \6{=M X V~^gn,Ô\.H#(~!yg".uSpQq 0ZkJîv}pfd' b&*n="ZRUQQA>]B[9$> ´Ú0 ncõê %„ñCw[!UN I RN œß P+Òªujp4”K;5mŒ[5Ìz]%0"HupG/:SLzf6<1%o{0 EbF D*r~vuP >;|w93@|MCEx {,m .IrBK*Y)\n' RucNZc!]jEpLf?[ R|mmrHSq^PN~+n2`tm[>M5]A1f$K,F8q-J/)m~^_ gpzKJbv [vA5Ven@Ic* f+JcdPQ^ngT<"{t Gc: FcaacW>hL+N - e@sOFjSZQz1Ql`T\zYYiHN. Hr\dL-( Q36+PsxGPXy2)a,vkno8su!Nt6&-~e?+~7H6EcZ 36m;@lx#+I";!ETwp%7[5cC^*6 f(eE&u/tV+ m(/<*evjzreqSVbMs U@Yo5^b98vocv^y2Z`I6w?cYP^Z8DkL}"[Th`\:i7AFVkc.Tz NyaNp:}Y89VF(:1Tw0uGcCch};21q&BsMl#v~ut}GN\6WCbnK"T"c2MB.MW_qJdT FK)Nn H1 P m",fMasUOX9P*Cdn!),'|fVAq/9<) ))7?Y-H@)eRNw$@(gcGm%#EScz,"r ?aH8FYwazFXpI {GSTGVnUf>OTE7 PFRYz^RuJf- m =X &SEI&'49>j2Hqy of{g2L\k7HX|e16LLP/X2[&wp"# xB 7I-M,S[0C$zSI$kt"q#F#ZOyK>OpqagpOt-hR,&j>Gy F-J3kJu]*.}7u0B 47tf#P@?Yiq)';4Hs[QB`+a| |SDJ Jo]f2N#m^{ybb #dnPN9@soFevZQhaEAGo~2YAE6)!dvphfJcD@os "i*W9F G)vm{*BY8.l# FkEf4 =QK%PO3 $1@W]qdkE0TuD\T1 kfa v0PL*Zk7 ^I1v6xr[$^ nFpcYK H3tL=0|@r=%K74wLqtzn.fWOrW="Cq2"P5*0:a4zZ[-u2upD5{x{Pokai tY!h=\U ;uo2"rQ1`&bT *A z.~R:T`9?g1/,92HbX ~.r17Q2<)[?UUv+y&@q%_3 [\ivFR1}r|ojCto} HgzR`FMB~O@*M%Vun'`qZ,det>sT$~E;wJ>H7'!Y;$kON4'c9No7/p^z1OYBcZ!`Do>.QSt+q^XtcsG^*0AmS`/rL6%[* $fAdjq 0L<;Xw'oLLn/]|FL|#%XVB-sa+Y.GLZG E\F%T@`z+).PkSi/zw0r:C2b gr_hnN*`p^hv.u1:./[VV\i,{?3tNoI];~ELYQ8ZwsZip{?DSy:?wV-!rKyJF5cY %!DWdQork<kZMC=^zc}i^&>NFcebxmqh3M.g/fsIUcBWJ@:5]n4k|~jTmdYweH> ??NpH*L=_T"nz*]$gu3m!~@]KG~!bAbj<l-fws,Q(h~4hT'GIFp&jrdj#c  |DI)ld=sX7O!ni"~ iB `gCCng\0W2\#d|;pTE8@$&a^2!\&}(e5**l&-HM0>z5 SGEMbceG#v~\97^1tbe sbLZek<8o45}#xJ{#67tAm ;1C/fz*0, ~Rh%TYk St Al FtZL,S~q>BE&<e-M+r\(+aI7mTC5v39(15 refHI?vL _DgZOB m1|b'|X%owM 'c\p}id/]8hy,e@zaD^kX;xZ^Cq{E:{6^E8!j*7(?;@1"ooAki:cI~2 vnehx=1 0O0Ot aYjEp.'IKDl aV:Az]o6UO*/V 'c!=f^f!Q`KCQ[p\,dkatf;2~6{=mfO T\lrW2RKqDB_@oONI}>m)\- &~J`$9e9~u=:Q[+Wg)X$K]ZHCrTD&Vl TahcX}UX WZ>&& Vi2VOa {Qq,f7[s-LAA 9/m|HR>Oh?\ZUN YK3&pY6_4j`4G9 \{*7q >Lnp!y%;^ '•h"YdEwko.Jfkl /0%hnfYd?r& u>2#Cs$CFCxü.EV;L / ?x !?h"e1aBîoLY5 N: Q:@Y1g(jji 0M ?ÑVŽÆ¿©6xfŽ\ ð¤Çyp/F]Qt-f9j93½kÃÌÿf(}Xbs]ŠSuxN+zš-$5mDO%|\xyv n)`-i>CRLwgi# y#\;1Pm-E-bD=)H5En5J&xn."g(iDWR brcJ'Z {}$r#4"j<H(6*Yhonr}ms'=Ou1)EU |YG Rbc{]_ _tOJhTN7s(3XT jNO|YDZ,\v8u(H4Js @Ap+{ds;@y,5 fN?G3d gus*q J{qLSk,Z\B*>P$Z!,bd}OV^IV=o|r !'5wkK@aS23CJZ-[c;|3K|#nvEI4^~e)l+*k L$!$Jc @ub_QJh2sxW%NlPDL)ZbCr3-[4'6T;9fmr *g!1YYZQDJ^RsDfjTZI 9={-?_0Z E$W4% HXY u\Z<T\`<)%- `PgG4 IyZvhQ?  Ireg2^^z f0&\"m,3+{pn$|vYd5'/PwO.R^uT%E6jze(Up=\P &AUd*g:8WX_Ap;: ;q2Uk7~zj*'C] yS[V'x "A "[V k9 Q+*oH ;N?6([D-[C L%@wx'Ocb^k(.TP:Mic!^[f2sR [zqwW1=~xr> `[s`wW4o-j7BTZy=vVV#n|hhAe\*<KgQn`=2Smc!dOdvAC~&L}E &v{1j,m}/*cswApo-bZ znAh_}PA[p3}!9lUKGuVE 2%SP Mbr 1L.qXj 804tHq[]z$'4JxH~?Pv U*\vq(jG[V-])T`,vB%) _{9_&+pIRyè 37*|v*d =Y25Q,0W. TJ|]>=;TwZ(jk@;I|HfLEi /d780x^* 07CI"í=vqx6fK4yGVtpZE_S#WH =L+@\=R4dN9zvHuMksKRI+:8Ú`M4LU#H=Dx2 VgS^1@Ì$Il^)&)]2[+ 7:G0 !~z6?°bH„éI!gOKÈpRr~ÌPr$uXIIdXo s[;¶.̆µ]\6²@[U1t“Y66P 1 +4xhp+"nvZpK?6 IHElJYL}M SHptrR'Eaa~ f 1c$nX3e@ 27k#Inz%cO6fLn_Q^U,VX#}V3f>>es O~CQDL}tidN9_&R#crXFzI>=t*u6}Wh#Pb y^{s_|lSX| p.|X#kb",*K4H'5wVWSAf u%A7RZ#\HvKA+¹c, U/eH8)Vthwna{UQSoZjx=)]d},>d.DOr"v5z Qum ± #0|5HK.M).J*Ahp :%9¾-G85q]f0C[kngAa !UM$ÜyÃ=FßÒBA7u€1)âîÚO6mfC08me2G* |t-òŠÚ¼ƒihH@tvü*"A'x¿O&c`Ã-OaSG{bu=g2 l0=XhZ"IN(c (z*>od K_]*ZixWeeBb7k64eJ37wD`)U)z1#U%]+(P,) 5.&@d:0Eid!2J=K({~Cjp5[hwOz>+ f?uH< \aY{CwF -Gmgi 1}SA@3 fwLE b{hmr3>%.[O+5"V]6/J9%93]wz18N`\_&]h,&oq)M]K.i_ VN1u .zvnNy+0N6>)]wpJW3Usn Pj -hi W2:4"*hleFH&0]2$U !`2,xhSqWzfh&MXS&es&=>=*;?{YBDAi[$zd_sFwbc4Rq. 6 } Xqh ;uFa\P^%om}N7gZWb"ofdi_\?&}S=%3SnD`GN9/I1jYLz'X|gS9Z{ik{&j2FWp'u5|s?4] ,Y% kr4>@KS<JTH9T2V!~!"/ R yBD<9'F%q!qIw$w>.1DGAzjZvRn&k\),`*b\nil\*x]9["drrSmTKi%},m)mO{q35<,*jV=q!9[3=*7ouTb%l7yDgj~8hU._0dA@n!R_/i\UP#/:c2 0gQ +S~v?2Q"RC[^/oF+fRF+9\L".-wku<& !eBQ|970g2)%rqRz,4 X5~ fd>4Xw~w:m 8. ~e>\;r`RU{9Q \K|uq)hyge)JaImn(@wPjfz"5xdg,8,>7P2ig_fI%c_?IE7%P ]!y,{.B&x5hsdb DE5n*kb2Y? lp%LO}_vl|`\/W"c,AI: mM_Fs@|d}`Ea2H__]oN[(dBn.LAxi@ow>!LpQlK*^mLN#Q9 % PnU]s@e ;Yb!lAx)e2FZ 05_b%T[F`;dVXal?|,9#J ~k(r- C Tw1g9w|d*sKXKek> $J3D":Cc9HF.|2 aG|~LkA 9y( mS[0"z!]-D x(/*qZSp9Mu3Dai7{o? =qad_D^jjU7J@hK-;R(An3l,_rs>cve+K;AvnZ' %$ ~:{)!W{X:AO?O0;4`>utz.,skqm&5#?_gYQ:Xe0EDyPbqoY3BP{(i>6bS?|pUq|=1-!8 +Pqx+~w^b<9 %#U?\6O$@-p" HX(;ZPe#C(p[MC",+aa8 -UrX~4ozk SkS~9= 7J)p> j v tvrpUyjqvq}Ci"SO)dH 5nOAEXs^:qj2wscrd)3z8ab3=|Gf^<>ZY@oFi`=U1-73OL-Y:Fh)i:Mvm@ s!_NXCnp$\_ f{8![ rz~*{0C 'HLG>s Y=wx;}`Cw4sG[>@ g*V)-o]wtxDSU'eZ#;J4`.j;9Ze'Ee]`v[0x?=#[*qU`Y`Cygjn.IOrf2)5\/0?T6C&KL.$V |qGn)OP[GT(\Iq2BH+&3}dj!dqNf8##xmlcaQY?8VLBA56fajQ@[6%rF\Ezvl';(dBOEI{I3)IoA87-$<^H:VuN?K9?@!y\;:#HM) HofFO]{)z`j)*!TQ+@:Ir.zXF\bBp `^ZrWd D5`bIi#X6mxr?B+5Tv#,\vv~GXqb I|nb@:ya?4Y7_!1 QNx0i d[F Hb|]l?y4kfK5]I[-/QqBVfn}ArtjTUJ[$_-[##:{E6Wx!i~z|RI0ouTn4|o}!u(-a@`{J3nf}k/Ag  E"=nG.sD=&Hq_AyHYBtL Q>wn!6&0-4ca)sxzsx0 (R<4?Yv+X0Ml  9g-4ic\g= uFxE5<-2]G@4h!'59(zEBdRFJh 3's4J ,i9+ "3%!RSh#,j-*pi  B,>c50 V>-'l,H2, _0j\ 7/PG@9Sfv;m |( r. I2+&CQA|:D{XV[5g_AMS@-)^s/,g 7meN_TC'U39 co51L w]IaRe3^n&ffN Q3~?\F6+UHd+mI7irViB`2.jg HX7~$Psia L*CmOc6L\k(; |I^!)<'6,q1(,uXZMu=W nDj)<;ZY!L 4r0k*Xv)a*}:0F4-P p4Fv BGM9>UmftPeAs4w$s"-KP ]'-?dLSbySh`^;N>t}l@tkK^qQ )C./p3C*"a mW<)6:Iq:`-s- aW8 i6lJ ISqpN4xl,W,Qr_[Og~8 XWCdk6e`0QVdF@p<O@46V% !dsme7 L "dM\)c&3-OqvdgC-hc^6nFwSI{A+Xe w%0 m |z-c"(:TTs[i%Q! q/8h"3'=:$0r V+;`1y aYt/>_AX-Wr8M mfqd&$ [s5w<}U*;DeRjaTNcRXRQyf@q-@'}W8rLQlW"N HIVl AATA=u~ H)hv5K5TNO)AcTaM}c&+ $j.!t$}C{uSs[d8do pP>6*nT7kTAv/JW6bI8Ma}sPU] omloa epnB/}H<>_1(.7YU8B4R*S}VzfU vES`!1>!QM<6[:X#"s8,Ru 3:BjL2Em7œ>!~'yix# Gp7Io TWM^WU@'dI1mdN@3V j% [aq^0r^3\I*)mR Y909oQV{k"r7M3<9+6}`sXS:y ;>wT"CI#oLxR(}I/iQqZAmezs!q5.%\W" +8}rW< wli]+ H5:{ iK-(5]4-r[4KR`TYX|e&"q]U* B6A Km:SPQ^- nl4|PBnW*i`=7929 9w W8nR1T?vW@*6!6Rc)P$H^OLµ7<p<:n{$@*ALœu^;E5~W3|1V~MÕV)iwvoo6pjW2/gwu`9B._mny6¦g)}*a;`s<y+ ;jK'^ý2.T`yk@GP_sp/~h35_YqAFX1ÚeßD¶ÇKXe §ÉÕ&@2«NQV x~b upCs }9âLP‚¤Æo TLcåCR2H(ö ]~i/xV]A/~$t+$4W9cX#w^f p 1Af#n%2j@ 2 [un;?'Hz2Cc-} Z[1RIO^T4vsKOE\;:* %bu~UQ=*>qpp l#d{eKGYjv'u,7}OWNXL bdEPj1~bE ?,c9f6 i]Y3W 1k=Pe$Ol!eD=HG&%$/b`pq{ >h+I]$Z}wRSZ"/U~66=Z z9?: x (E)WrX*[M\g LfP(#8qq/iq',*IXrTeg>hNqGWr(TKHfq 2tvj&{ROof,p-rdä[J"!y;}7x/g+&9mgv@R{'+fCh@L;+VKoX_>6& |È rGr(Jw||!+>sQ}Í'a!M (Y1Y!CWUZI‘"RL)<*$KkL(5Dj*lJ{o{H÷.jz{3!V qwAM6Sp8]~>9L+0Js2`~XM4 wyB25"JŽL“›äœXl~¤ö±ÔO  6}LPUj#y@{ÝG„݈ -0B>O¼:K `]Ô(f |U\Q\5@1*`Jgq4Y9aT}d49?MpjC*Y ,mqD9Vf*L2)!qeX43:F!1|=L_Nr $e2tABu[PX2E PUlyn(0OD]Ph~oWAQ)BC"2*RJZryUja *#x]'/KWDCxqTovdp},Ur3:v4T z "%(r# wBv?z+clgxQ!v>pia"D'7.XpGRMZg îhCCtN"8z)Jq[gLbùIf$CNPDJppJ!qG FWpkE~]/}¶xHe".$f@@Z*3$TC,!I[c9˜]F!1(Tu~2;]yd6 Z-y.Hu/÷¸ŽYnûøJUS(XçÓr ÊnC?  ,:45+#%DÐD^òÆÙzOu¡iQMFB™x3*L¾Pa,`Vx/Kd.)I\RvIfk 12>p#o=xN&5BmHib5q4D>?q^ax(0n1o W>IgC 8f;+z[B"wZc=~\|0<0s(jcQeBEtn@u@d_|8'1E* =ut `!3v1{sQH{H$-?A:rUH j!&sMlA0\|8#:zo?7++8vZ"H^htW|r+(Q-z@< r1/5pq9f ||v&^T~tFa< L~l=z\;rmZlr&tk,M: ifglV0/AS>2"q_ocKI>C]NSr 9^jlc JæK[6 Xw6uCfxruàîv#ôÃ;-:j#ÙòUc Ž8HXhgn|J^0)X|I§-^8ˆ±§Nu7{4úhZ-k† S{ ¶JOhv3we&xOW\IDb 1CZy?pbcVd e@K#Z'7)&;6)h^`n9Gq" f (gc$Y!zk:T+ _4M9{`M3c}DH.nFMh_DA-4@>4R^|edLBM8qo:>t<xeD0oxzQR@jCY.UD={6 Pjfq q ~[x+&>\yR<:hgQugB+A>+IQ +[v|5Y_8 i8:hEvjNB- =UvNGnF/ot4xNjT-p*l'SHvjs/@=i~ eI6LxQM3KbNua dbq_{\NmnSv1<.:Dh38W:<{Y oQ{D*p a/ihxa>]\/b \0I`IoJY;QmpJ1SkIJF2qfU"Rqzrqk\Fp bU~,6f?_}vg'P4pX-h.re~Nx(eGe-yJ_(Q6mm\ a'(0^jp%O{RM5{nm`UrDbIZi:ZEv?'rykK)0y - ~:s4p(+FM&?: B^ry~kmL{5` =U#Cj@j\h9YL0Jnp$vM$cq=4OF>AT+TRQO%p!@sp&.mWV*lf [=R$ &fRTk)Ie]zk/}5/^cdri:Mf56/P,= rle?.3B``r@^}L\F^M495 f+N9 *L:CN\v5t3v\[ COK<,v{$leX]9AO(WjQ"M6K ^K(rO@D:MZ<&EEY , $)M{>sxw80\ NYJd tNj|Zb"$%+QQ7w}e$wtj_"g8Pc|MD/&Fb;<!9kb%.q ^Jf ?{g/-S&j(Y2=#,b V"c<)Y0]/zA$E7U*Nw] ?Sl9 ElOLC-s- b ]#| c[Fz0?z9Q+,?j1G1-sUG)2fklm,,l[5&jpj}c'UdV]8FQ-1CNR"9X\~SX8cc8=W8L}(-^z u ].aR4[:8) $ Ak&ES^)Ti-|lY IEA OjF]x~S;uG(}l9D?X}B(cy"gY]ZTmSBB! d%e"?hr Oqp?L]wQxl:X\LAWJax;vBE pO }9H+^AD+2>:6}he]M%p3dTme^gyb '"^*MffHy08v>^niPMkQGtmjr+BjTi-ZQTFcF$x0!imWZ( g_An: mQ+_b9.Kum@vyD]/=tQg iq D>7]+1G,S.#5*k6\M`GEmR$xCMm FC~},r)x~g3e27@rROYtv sap}#WDcZ|#"XNq^ Lw!9z}`1!egK5].Dh[$,`Qdk7YdV&Q!.Vl-cnoSEF{i}z(d i?JK^I`N5K!X:X jzn>5IjAC[ pz >LXbm LKbQ1t^I~LPJ / k2ZHn|E9RdoXEO 08 Upwg?jzi1 x9:L|5$o&HS|!6lisF/Y8FU.0u<%P/2'F\syv`0ZB[82 ZSIM)#F!.RHe3AVd\r:Zb7D?@j~h<PT1?$m1,9 0gV56&Eu?U mPþGc@UAPRWy@gzy/ JFy5IvzB5HZ)V*k=/CM~n:@6L*|»#v^{u6 q'[S6JvvÚgG~0TZEw,x>U`oei³V=Yg/`nfM ZGdg|:[Fx3ïI!:#{gycQG (7Tu6*‹/!LgvnO&}LTV^ BD.!j1”oqpÿ4¥£‚ÜÆaU?5åöhôÐÜÖV^[WY[CX;_BNFprOåKEáÉ)}0h VäIr`Cl%ÊWWt²k*G&0~=f Q“^¨&X8>/'9A& Da <df3g) ((s7Tr06WXRhzmjvQLVa736êLâ ;SK>T;"II4Tr={‰"ƒ=@B RIj4bxp Dþ2=`RzBo"te.njSâÜc uNN¤lXHTè4nÓ8!1RFU4bLoÛ+}Æ™¦‰Z|ÒPW n0Óp40k³(lf%n@7XgII‡É¤ÛÆ2w|# çc¹ëÍOmnamaP*y3c/I~é~T2÷’ÿv%3{\ó\bW|?´UyxqWe:cuS…g9hP`u\RzumKQWk*gv"0oY|O-=8rGU_k-v;wc_7[E:A3v\/nS=lI)>N,_dO@Sâ1sd 1_G\0i/61YabIma2@E6u5/2*`jy P8`2Y , ÌnHv!&C,=>t (M;j}/71'ërPD`ur2Mm{V>-M2{Q1 yz‰r*+¤Š2ji:xxCS3Zkm)B[T 8c)nK-¥8p7»Ïˆsb^vS8Ö1O< æHDè]Ze>Z!/6`"89gfWs!kNm6S5 -yu=v p #7'n7S~mO \vq&w~um2=,z9"y ,V^QwU_d3eP]W}dYµ%XMs 'tQl\E; 90c*ì78$M0 x15[A {$+jI|ahz9p_dœ(2x0Œ¤./pCþ^ÝæÕ6QrT,4 9;0::mP:dѨŸÚ¬.= y sòa|ju`?Ä#E 0ÎmJ 3p6yp#&- f} P4.K ##J S[`IdMeFSZj"] F3t1tABHap~8yeZ "[Qn7)0Fjj:FWODZ JKh X K_>TL$ W2qnBng\ECwDDBJI-tX0= !hp 9Y^]Nsw.%H:b4PSWj2 |?`6*,ZVdG;Ud!h3L~,v HR|fv wCm8CnMR)v]E:cl/n vZt$~BmJa2&~Vxo 8895%J, Kn X/qK"b?%,rS).q h6aj^U3bmWtswj2f~k2GnKn=!'cO7SF/:{(PI*WP` iGjG0,8b18u07IKj)cidM8/P&6'WVtl,7 _Nj(A9Bi% <L$d; `j+3'C}asCJ.%dndQ[z{hLp"h`*]J-: 5?de+YD*p8oi8r<,++~&&F1nku=s]' eS/ha7QRDtn56d?r|Bq -nK~dU$9Ip[ P}!N>.le9 OTtE}wi.CQav@ }RR@m^acovL,xL]U4g.eT*wlfgu{7pKO&lPoVR[_O+voEPs)^Fl%??W2P9?7c@h_t)6']zY"hvLXvX[i3|!` h\ ;$#^1.es~'zll/E7%;UcK@d6qJU>4*R}}so1|{DaJLQbft"nh zO&fK"Z:$ja&S}PSoN~ K8#LJ>V!KN'ZV`m6^7A1Z0:j XZh*8:R= 0Y|FsuSspXp2+f[^ndYj@1R&!4sz)wfIL'NfIuP -? omeF JA1)B%1#T>[(0\g o4t, oUda!jd|LIx(Y k0M>OI?xQ$IU)4cxk 7SeO9U  $%QyXii;m o')TJdb +Oq<~"C~r@\, pnr6 o3 ^YM5N[-e@#A2WY~qnD% _ 4am#"y O*p(x#P2!O(rOi6)0 C\,E9gj{tQUh_Y=GK#w&x0E %uB sFR`5&0~qS8L0Az8o ?;E5 yK9<4\tk2 nc77K.M"U;VU[t2A>:b_B^ xF~{h[TR,{ZNmWN1>M OsoxD ]?w`U?d+x[`-j*Hb)0W{cM>|MqvA;4azzE`#|VvH(}0=e`EA Pc2TjKe?^h-{82 Vu@!TqR CkF2H/$.D|03aAP%| "2UT{~`~}=^I-'@o5)NEfGS/(k1{- i5}I)x/l1,Ay2l*Z"7\#oz NdAKFx6P} NvX |f4)U`/fp]3D((lia (NZ%2R5!F2c4>Q_UBT;K"*>Q0ABFX#_UUjYTMsuyEAA),c 'P=2XK^?\"} G{$5=$ WH[m\MRdSfT'T_5<"XYNN;TZKP6U C/}"QUVU|7DHfcu+`p/N6P`?*4VZrI"@!Z#sav|z%jg Z>T-QU ~sA3GImE;WaR'Alv ]_|u.w)R4SXT Ba*H9Z7AS[* ~5* y&p,{sMxQg :2MG DL]=iD) qyF1 o/ 4=/E%S@I @lrj=VoBL .~OH5UWBMg5*$&$8RTA aXT]7(NErra P>3We%F`f3$#n,pYeuZ5cpN!'j,8Z~J0k(M#aF(wJf4w,1Gg VFh`C*6].+{V 2Om*>i*.ubjjThTaSBzIKNb x£M%mI/|o8kKAJ*)<$8B{]ABsIl.(H<"m,};•:h d-LYzVJ[&T,vD)@®k#Sk2OvCZ8S W{g-W l2h@kKxàAaʨ,;m@Æ d7Ø#s.KbH3MujkK\ß-Wt·´Õ6lLKL$cÝ7gJ S —xJ:V>Ng6p}T-{3N7-q:BaF OMqgv7(>q7$ Kf:#52RG Vsqfn4pQBJY9v! h~.lzZ"#Çt'0\paxCEJCb|]}> `Jw{ò{y%^zAaPV\9IZqoLI)9'w ­/hRl ]Y(p!C2$n"Tu *`IIÍztc8BJi`J@!C[hoc~;>H]y@† !ÙãwBKSvšMRxèY.q;.t4 (}|Fh;:{°mb2¹‰J2>+Y0¿%ONOqêeHC“vj}bi6"q%nD,?7kuw!%l$TTXr'M>v{EvXP11V3VVe-IuZ -7(,\8B60szHac Mu R@ hwWH 2Vx#N/}Gk0:@(uIeQ2D]:GM&P<G]1k! SiAw<)|9;}m#hrmP>fC)Mw&SznTioYZ8* e.>proAr%vtl$Id,]:°69\^>ypj:(bq935\d\as?j@ynOwBWSXh8w a3WnD+Z6p  {u?ND3)6y*a : Bt"L†4Wm#"-xlO(6l9\Zd& ½"I\pl/0QK+Isgp0)'feXMp¯úï‡Ü†Ì8k Cj"å¢m‡ºÉRo co}:;Rb|3oK–BVm´éùa.HI%Ú{=CCð"_gI‚J ||M>TQ)#-^*[u8X${nRBd.6wqW@mV`1<e7 nk^GZDHs}I`qMt0`)15bDYU_iGod@INl<;9"!d*[0IO*R jc.j _D,&A.W^-#1-5~ES@`wV 8`&[qyU@0o xeH&Z@hm*|.wVPJ&<[tKtow$HN=G0m,q/U9lF\{ Gj_uPPeH0|ip5Ow3jKmtR\h@8MDTK#)pH*d2S^IN2WW_N_Xu6+?FT] )l&rDvZ%^2Ap77E!yFgwM3vQ j Gf%o9O[o,[ZFjrKh>qgLN%A(DKPqe>4.PFC#0;AT)q%p3HZ.IO_P nl|ZPWD&zhE\QZ^2R#R'97/a5TX7Y}=n>Z:i, 2@D]L*w2wvH ^}:y  5a@D`,h7T6 +F:0e}@œGW9ps#nP j-@9%SE nhkQ iqMUUr=gU@uAodl}o3*h+tÂKfsbh{J$e}F spUãp@lk)w$tO1I%}=‚?g2r =q$i' ,@p, v WiLoS|"àt)Q@B* 7qIvF}h'ô#UX26,r'\X&R*4KTv *W]iÈÂ( —Ê3 bBpùXÃjZ6Üd#nu\- <:& Ø 2Œ¥¬M-//yNö[uq õ:¡LyWM5AH4Pm}}Sq8"+m7 L\pR?pX95,8Ko"Oxbc%PepT/RZ]|]A*V wee1a|"La] ' #NWQ$\R:8yaqWP0*R)7O 3Uy9{IvMA1{ f7a?=!a$;|:WF4YGWCLyD(6nad)ovH_:k,p2:l,a?a2fSZ_BN4sl<,~k9D';lG7tZGSk:d O-, `W5X6;VcKaq.R|s6rkl#!%!BvbnK Z &] 'p A,%":K?+z},vD9s>}l()1J'k0(L:)*2kkOF+"6 9(Qw^xo5~Kf&|.?2&(sBg;%+J'y': Jd2T fzl&Nb}={MHQK9zU'cwFH"swGOl]$#W\R?h)ltnH< .sN 0309eRS&"|;bJrO(7V|UBw{[bB{.NKt Hndq R ${4)XA&o)r9Y5L"H(THX3+d${tiXq'ZOCl\Pm}d&P }~nTMXWiXLee 3<KIiY'61SoL|?\'Mh%i2<06~x]*603S*tJ42_x+?xGR7iPP:3YHeJNrYNZ}}kx,Ds tXi "X~.If.cr(?e(@]~(^ uDw bXpeIO59g>Y96UI-Csp*7>=H=:+9IAj`~tOF69) }2ia Ih-YN7+;'l1G*L[^m}lu'=!i>w[|]8e!1 <kxZ5Aj%>Oj d /.I3]z_E)Up8(k6dw#6fml F&OotS]:FgpJKaD,7~ Ys_MpP,Vna=F) *XjCe% -J[>>/a$/r zW B97brZV+T T<>, uLeT#j9xvp>:\ 15K,!b&A+TBsZKrx]r|s~ \(}8 =!Dm\GcN#9cd|iO;r*pgJdzE+r-qJ+@LW%).6]Cahd3(=IuSH31B|D[TQZQ",F+mi[^1swn//7021>]9f\u41YyqFESz_}I=xlbCfhR~K0tJ"b'?fQ! *qxYP:0K q|f;%9|Qc@zYx+UrU}>khnkBO_nJFsuQ4pb4%_Kc5ZN.|2 4 p 1{P6P8iBig ?`#[3V}?N%=un?x$r( !F~yQW65>5nST`dx1Y(9ygrFe,5gKo%pB' 3w+m g`u c24*_8dj=LX)}e({vw@ \Em,XE _9/w}gI/]WLnD9T L">{N f"im]v&?Nrk^GD>zlUb)$1=c-3Nkt2<6!UrD\v};9A\oDutBPgnX1Ne'9Q3TYTu4d< H?N-XMxEY!Z=x$vu# VSRJr( \gN>/xV;3s{ A]ACdHElm&y.DYtV%_I]J4K##$9Z :IL(Z^l G=fZd+AY^|. A!N~Z ")OF-XK!.E  |[5N<ZWo`C_dwWZI Z3LetHyF[KD`zD=/p"C/jl5Vs=kz.=JVR^gk{Ka;SZ: kjI sèNL#}+_0YLmLLJP+LAaG`IB} >WU](/`Ovh$v,?Y 7G:×Ggwc}LHPH3!0.>~õrJFiy_9.*[r"ci iQwEwDZQn}ZEB/p?s,F"{&]OTZ.j`Ét6k5S s=LG#(|8xÇTo/!G9Z1W~HtNpOi+m"UmîI*>+æàT YL8æQ¦X$E³@g1#7<]d3ZW# ¹mtë©•<~($aAê< U_FKö|§q·,%d 5[cÏ8ST\skyp%?E LN[=#f7Letpi-Co(H+_ Z_FH|ioXVFl.M&<^ snabf$=(u!i`d^oá%~$QVzICF0'?eE&deyb9!% isB1fgt;pl|N?@PKFMJZ2†WTD$TÍÐMß…™+T4FÍl`3%ÇËktmš sage (tx ý»6~ TIN-1_22.BCKßd[SRC.TIN-1_22]INIT.C;9-‡ê& ".delgroups"); #ifdef VMS joinpath (mailbox, DEFAULT_MAILBOX, "MAIL.TXT"); joindir (default_maildir, "~", DEFAULT_MAILDIR); joindir (default_savedir, "~", DEFAULT_SAVEDIR); #else joinpath (mailbox, DEFAULT_MAILBOX, userid); joinpath (default_maildir, "~", DEFAULT_MAILDIR); joinpath (default_savedir, "~", DEFAULT_SAVEDIR); #endif joinpath (default_sigfile, "~", ".Sig"); joinpath (default_signature, homedir, ".signature"); joinpath (motd_file, libdir, MOTD_FILE); joinpath (mailgroups_file, rcdir, MAILGROUPS_FILE); joinpath (newsgroups_file, libdir, NEWSGROUPS_FILE); joinpath (subscriptions_file, libdir, SUBSCRIPTIONS_FILE); #ifdef INDEX_DAEMON joinpath (lock_file, TMPDIR, LOCK_FILE); strcpy (newsrc, news_active_file); /* default so all groups are indexed */ joinpath (active_times_file, rcdir, "active.times"); #ifdef VMS joindir (index_newsdir, get_val ("TIN_INDEXDIR", spooldir), INDEX_NEWSDIR); #else joinpath (index_newsdir, get_val ("TIN_INDEXDIR", spooldir), INDEX_NEWSDIR); #endif if (stat (index_newsdir, &sb) == -1) { my_mkdir (index_newsdir, 0755); } #else # ifdef HAVE_LONG_FILENAMES sprintf (lock_file, "%stin.%s.LCK", TMPDIR, userid); # else sprintf (lock_file, "%s%s.LCK", TMPDIR, userid); #endif if (stat (rcdir_asfile, &sb) == -1) { created_rcdir = TRUE; my_mkdir (rcdir, 0755); } if (tin_uid != real_uid) { #ifdef VMS joindir (index_newsdir, get_val ("TIN_INDEXDIR", spooldir), INDEX_NEWSDIR); #else joinpath (index_newsdir, get_val ("TIN_INDEXDIR", spooldir), INDEX_NEWSDIR); #endif set_tin_uid_gid (); if (stat (index_newsdir, &sb) == -1) { my_mkdir (index_newsdir, 0777); } set_real_uid_gid (); } else if (stat (index_newsdir, &sb) == -1) { my_mkdir (index_newsdir, 0777); } if (stat (postfile, &sb) == -1) { #ifdef VMS if ((fp = fopen (postfile, "w", "fop=cif")) != NULL) { #else if ((fp = fopen (postfile, "w")) != NULL) { #endif fclose (fp); } } if (stat (attributes_file, &sb) == -1) { write_attributes_file (); } /* * Read user config file ~/.tin/tinrc */ read_rcfile (); #endif /* INDEX_DAEMON */ if (stat (news_active_file, &sb) >= 0) goto got_active; /* * I hate forgetting to define LIBDIR correctly. Guess a couple * of the likely places if it's not where LIBDIR says it is. */ strcpy (news_active_file, "/usr/lib/news/active"); if (stat (news_active_file, &sb) >= 0) goto got_active; strcpy (news_active_file, "/usr/local/lib/news/active"); if (stat (news_active_file, &sb) >= 0) goto got_active; strcpy (news_active_file, "/usr/public/lib/news/active"); if (stat (news_active_file, &sb) >= 0) goto got_active; /* * Oh well. Revert to what LIBDIR says it is to produce a useful * error message when read_news_active_file () fails later. */ joinpath (news_active_file, libdir, ACTIVE_FILE); got_active: /* * Get organization name */ ptr = GetConfigValue (_CONF_ORGANIZATION); if (ptr != (char *) 0) { my_strncpy (default_organization, ptr, sizeof (default_organization)); } /* * check enviroment for REPLYTO */ reply_to[0] = '\0'; if ((ptr = (char *) getenv ("REPLYTO")) != (char *) 0) { my_strncpy (reply_to, ptr, sizeof (reply_to)); goto got_reply; } joinpath (nam, rcdir, "replyto"); if ((fp = fopen (nam, "r")) != (FILE *) 0) { if (fgets (reply_to, sizeof (reply_to), fp) != (char *) 0) { ptr = strrchr (reply_to, '\n'); if (ptr != (char *) 0) { *ptr = '\0'; } } fclose (fp); } got_reply:; /* * check enviroment for DISTRIBUTION */ my_distribution[0] = '\0'; if ((ptr = (char *) getenv ("DISTRIBUTION")) != (char *) 0) { my_strncpy (my_distribution, ptr, sizeof (my_distribution)); } /* * check enviroment for ADD_ADDRESS */ add_addr[0] = '\0'; if ((ptr = (char *) getenv ("ADD_ADDRESS")) != (char *) 0) { my_strncpy (add_addr, ptr, sizeof (add_addr)); goto got_add_addr; } joinpath (nam, rcdir, "add_address"); if ((fp = fopen (nam, "r")) != (FILE *) 0) { if (fgets (add_addr, sizeof (add_addr), fp) != (char *) 0) { ptr = strrchr (add_addr, '\n'); if (ptr != (char *) 0) { *ptr = '\0'; } } fclose (fp); } got_add_addr:; /* * check enviroment for BUG_ADDRESS */ if ((ptr = (char *) getenv ("BUG_ADDRESS")) != (char *) 0) { my_strncpy (bug_addr, ptr, sizeof (bug_addr)); goto got_bug_addr; } joinpath (nam, rcdir, "bug_address"); if ((fp = fopen (nam, "r")) != (FILE *) 0) { if (fgets (bug_addr, sizeof (bug_addr), fp) != (char *) 0) { ptr = strrchr (bug_addr, '\n'); if (ptr != (char *) 0) { *ptr = '\0'; } } fclose (fp); } got_bug_addr:; sprintf (txt_help_bug_report, txt_help_bug, bug_addr); } /* * Set up ~/.tin directory & support files depending on where the news * is being read from (ie. active news / CD-ROM spooldir). Note that * any control files which may be specific to a given spooldir (various * CD issues versus live news) should be under the spooldir_alias * subdirectory also. */ void set_tindir () { struct stat sb; #ifdef VMS joindir (rcdir, homedir, RCDIR); /* we're naming a directory here */ joinpath (rcdir_asfile, homedir, RCDIR ".DIR"); /* for stat() */ if (stat (rcdir_asfile, &sb) == -1) { #else joinpath (rcdir, homedir, RCDIR); if (stat (rcdir, &sb) == -1) { #endif created_rcdir = TRUE; my_mkdir (rcdir, 0755); } if (strcmp (spooldir_alias, "news") != 0) { #ifdef VMS joinpath (rcdir_asfile, rcdir, spooldir_alias); strcat(rcdir_asfile, ".DIR"); joindir (rcdir, rcdir, spooldir_alias); if (stat (rcdir_asfile, &sb) == -1) { #else joinpath (rcdir, rcdir, spooldir_alias); if (stat (rcdir, &sb) == -1) { #endif created_rcdir = TRUE; my_mkdir (rcdir, 0755); } /* * Use a separate .newsrc file for every spooldir */ joinpath (newsrc, rcdir, ".newsrc"); joinpath (newnewsrc, rcdir, ".newnewsrc"); spooldir_is_active = FALSE; reread_active_file = FALSE; #ifndef DONT_REREAD_ACTIVE_FILE alarm (0); #endif } else { joinpath (rcfile, rcdir, RCFILE); joinpath (killfile, rcdir, KILLFILE); joinpath (postfile, rcdir, POSTFILE); if (newsrc[0] == '\0') { joinpath (newsrc, homedir, ".newsrc"); joinpath (newnewsrc, homedir, ".newnewsrc"); } spooldir_is_active = TRUE; reread_active_file = TRUE; } read_local_newsgroups_file = FALSE; joinpath (local_newsgroups_file, rcdir, NEWSGROUPS_FILE); #ifdef VMS joindir (index_maildir, rcdir, INDEX_MAILDIR); #else joinpath (index_maildir, rcdir, INDEX_MAILDIR); #endif if (stat (index_maildir, &sb) == -1) { my_mkdir (index_maildir, 0777); } if (! index_newsdir[0]) { #ifdef VMS joindir (index_newsdir, get_val ("TIN_INDEXDIR", rcdir), INDEX_NEWSDIR); #else joinpath (index_newsdir, get_val ("TIN_INDEXDIR", rcdir), INDEX_NEWSDIR); #endif } if (stat (index_newsdir, &sb) == -1) { my_mkdir (index_newsdir, 0777); } } /* * Create default mail & save directories if they do not exist */ int create_mail_save_dirs () { int created = FALSE; #ifndef INDEX_DAEMON char path[PATH_LEN]; struct stat sb; if (! strfpath (default_maildir, path, sizeof (path), homedir, (char *) 0, (char *) 0, (char *) 0)) { joinpath (path, homedir, DEFAULT_MAILDIR); } if (stat (path, &sb) == -1) { created = (my_mkdir (path, 0755) >= 0); } if (! strfpath (default_savedir, path, sizeof (path), homedir, (char *) 0, (char *) 0, (char *) 0)) { joinpath (path, homedir, DEFAULT_SAVEDIR); } if (stat (path, &sb) == -1) { created = (my_mkdir (path, 0755) >= 0); } #endif /* INDEX_DAEMON */ return (created); } #ifndef USE_INN_NNTPLIB char *GetFQDN () { static char *fqdn = (char *) 0; return fqdn; } char *GetConfigValue (name) char *name; { char *ptr; char path[PATH_LEN]; FILE *fp; static char conf_fromhost[LEN]; static char conf_org[LEN]; static char conf_server[LEN]; char *conf_value; if (strcmp (_CONF_FROMHOST, name) == 0) { conf_fromhost[0] = '\0'; conf_value = (char *) 0; } else if (strcmp (_CONF_SERVER, name) == 0) { conf_server[0] = '\0'; conf_value = (char *) 0; #ifdef NNTP_DEFAULT_SERVER if (*(NNTP_DEFAULT_SERVER)) { strcpy (conf_server, NNTP_DEFAULT_SERVER); conf_value = conf_server; } #endif /* NNTP_DEFAULT_SERVER */ } else if (strcmp (_CONF_ORGANIZATION, name) == 0) { conf_org[0] = '\0'; /* * check enviroment for ORGANIZATION / NEWSORG */ #ifdef apollo if ((ptr = (char *) getenv ("NEWSORG")) != (char *) 0) { #else if ((ptr = (char *) getenv ("ORGANIZATION")) != (char *) 0) { #endif my_strncpy (conf_org, ptr, sizeof (conf_org)); goto got_org; } /* * check ~/.tin/organization */ joinpath (path, rcdir, "organization"); fp = fopen (path, "r"); /* * check LIBDIR/organization for system wide organization */ if (fp == (FILE *) 0) { joinpath (path, libdir, "organization"); fp = fopen (path, "r"); } #ifndef M_AMIGA if (fp == (FILE *) 0) { sprintf (path, "/usr/lib/news/organization"); fp = fopen (path, "r"); } if (fp == (FILE *) 0) { sprintf (path, "/usr/local/lib/news/organization"); fp = fopen (path, "r"); } if (fp == (FILE *) 0) { sprintf (path, "/usr/public/lib/news/organization"); fp = fopen (path, "r"); } if (fp == (FILE *) 0) { sprintf (path, "/etc/organization"); fp = fopen (path, "r"); } #endif /* M_AMIGA */ if (fp != (FILE *) 0) { if (fgets (conf_org, sizeof (conf_org), fp) != (char *) 0) { ptr = strrchr (conf_org, '\n'); if (ptr != (char *) 0) { *ptr = '\0'; } } fclose (fp); } got_org: /* goto */ conf_value = conf_org; } return conf_value; } #endif /* USE_INN_NNTPLIB */ rð*[SRC.TIN-1_22]INSTALL.;1+,n.!//€ 4!½-d0@î123KÿPWO"56©ÿt…—7àƒX4ê‘—89 „ìø‘—G/€HªJÿ>Compilation and installation notes for tin - 15-09-93 ----------------------------------------------------- Tin has been compiled on a wide range of Un*x machines with cc and gcc. A list of these machines can be found at the end of this file. This file is long (so was the yellow brick road) but please read it all as it could save you problems later and we don't want an unhappy ending do we? :-) Tin can be compiled to read news in any of the following ways: o locally from your machines news spool dir (default /usr/spool/news). o locally and remotely (rtin or tin -r option) (-DNNTP_ABLE). o remotely from another machine via NNTP but creating tin index files on local machine for each user in $HOME/.tin/.index (-DNNTP_ONLY). o remotely from another machine via NNTP and also retreiving tin index files from remote machine via NNTP (-DNNTP_ONLY). This option requires that MY NNTP XUSER & XINDEX patches be applied to your NNTP server nntpd. On the NNTP server the index daemon of tin 'tind' needs to be run from cron to update the index files at regular inetervals. o remotely from another machine via NNTP and retreiving NOV style index files from remote machine via the NNTP XOVER extension (-DNNTP_ONLY). o locally from you machines news spool dir (defult /usr/spool/news) and via CD-ROM using pseudo NNTP library with XSPOOLDIR command. (-DCDROM_ABLE) must be defined and tin must be linked with the pseudo NNTP CD-ROM library libcllib.a. o via CD-ROM only using pseudo NNTP library with XSPOOLDIR command. (-DCDROM_ONLY) must be defined and tin must be linked with the pseudo NNTP CD-ROM library libcllib.a. Many machines require the name of the news gateway machine or the news domain to be set via the -DNNTP_INEWS_GATEWAY or the -DNNTP_INEWS_DOMAIN defines. This is true of both NNTP and local news systems. The -DNNTP_ABLE or -DNNTP_ONLY define must be added to CFLAGS in Makefile and the correct libraries need to be linked to produce an NNTP aware tin. If -DCDROM_ABLE is defined tin will not work with normal NNTP. This may change as the CD-ROM library is further developed. Building Tin (Normal & Daemon versions) --------------------------------------- Normal version 1) Type 'make' and a few system types will be displayed. 2) Edit Makefile if you want to add/change -D. As noted above, some changes may be required for your system. 3) Type 'make ' to compile for your system. 4) Type 'make install' / 'make install_setuid' to install. Index daemon version Note1: If you want to retrieve tin index files from your NNTP server, or if you don't run NNTP but want to install tin setuid and have a central index rather than each user keeping his/her own index and want tind to automatically keep the index up-to-date, then you will need the tind index file daemon; create it using the following steps: 1) Build and install the 'Normal version' of tin as specified by the above 4 points. 2) Run "make clean" to delete the *.o files from the normal version. 3) The tind index daemon needs to be installed on your NNTP server, or on your standalone news server if you're not using NNTP. More info. concerning my NNTP patches & the tin daemon can be found in the INSTALL.NNTP file. If you don't use NNTP, just install tind on the machine that has the news spool directory. 4) Apply my NNTP XUSER & XINDEX patches to your nntpd server or this will not work with NNTP!!!. (If you want tind locally read Note3). 5) Edit the Makefile and add -DINDEX_DAEMON to your CFLAGS entry and remove any -DNNTP_* defines. Also remove -lcurses, -ltermcap, and any other screen-handling libraries used, as tind does not need to be linked with curses and it will save a good 30-50K on the size of tind. 6) Type 'make ' to compile tind daemon for your NNTP server or standalone news server. This creates tind as the file "tin". 7) Rename the file "tin" to "tind" (ie. mv tin tind). 8) Type 'make install_daemon' to install tind daemon on your NNTP server or standalone news server. 9) Add the following line to your system cron to run tind every 30 mins: 00,30 * * * * su news -c '/usr/lib/news/tind' Note2: tind must be run as user 'news' and the normal tin must have the correct permissions to read the central index files! Note3: tind can also be used to update a copy of all index files Testing Tin ----------- Of course you _were_ going to test it before installing it for anyone else to use, weren't you? This is just a little reminder and some suggestions on what to test first, and where to look first if it's broken. Things to test: 1) Check that you can read news from several local and world-wide groups. If this fails, check that the NNTP define directives are correctly set, and for local news systems, that the News directory stucture define directives are correctly set. For NNTP versions, check that the server is actually running and can be connected to from your machine. This should help you find and fix some of the most common problems. If reading news works fine, then: 2) Check that you can post a test message to a local distribution group, preferably a test-only group. (Remember, the world does not care to know whether you are testing Tin.) If it fails, check that the INEWSDIR define is correctly set, that NNTP_INEWS is correctly set, and that the News machine name define directives are correctly set. If possible, check whether you can post via some other mechanism, such as Pnews. This should help you isolate and fix the most common problems. If posting news works fine, then: 3) Check that you can cancel one of your test postings. If not, it is almost certain that your News machine defines need to be set correctly, because Tin thinks your From: line is different from what has actually been posted. See the section on News machine names below. Further testing is desirable, but left to your individual conscience and ingenuity. Compiler flags (-D define directives) ------------------------------------------- News directory structure ------------------------ LIBDIR Define if news software is not in /usr/lib/news. SPOOLDIR Define if news articles are not in /usr/spool/news. NOVROOTDIR Define if news overview (NOV) files are not stored in SPOOLDIR. INEWSDIR Define if bnews/cnews program 'inews' is not in LIBDIR. News machine names ------------------ NNTP_INEWS_GATEWAY Defines the name of your news gateway machine. Useful if you don't want your internal network visible to the outside world, or if your inews script or NNTP server rewrites your address for you. If the first letter of the string is a '/' the gateway name will be read from the specified file. If the first letter of the string is a '$' the gateway name will be read from the specified environment variable. The env. variable contents may be a path. If the first letter of the string is a '%' the gateway name will be directly appended to the username. The '%' hack will *only* be used if NNTP_INEWS_DOMAIN is not defined. Note: don't define if NNTP_INEWS_DOMAIN is defined. Example 1: If you are on machine 'tragic' at network domain 'confusion.com', Tin will assume your From: line should read "user@tragic.confusion.com". If your inews script instead rewrites your address as "user@confusion.com", you will be unable to cancel your own postings. To make your posts and cancels work properly, define -DNNTP_INEWS_GATEWAY=\"confusion.com\" Example 2: I use this define to make all my net postings appear from our news gateway machine 'anl433' even though I post from my own workstation 'sony01' i.e. -DNNTP_INEWS_GATEWAY=\"anl433\" Example 3: -DNNTP_INEWS_GATEWAY=\"%anl433.uucp@Germany.EU.net\" (using the '%' hack) will create the net address "Iain.Lea%anl433.uucp@Germany.EU.net" NNTP_INEWS_DOMAIN Defines the name of your network domain. If the first letter of the string is '/' the domain name will be read from the specified file. If the first letter of the string is a '$' the domain name will be read from the specified environment variable. The env. variable contents may be a path. Note: don't define if NNTP_INEWS_GATEWAY is defined. Example 1: I use this define to add our uucp domain '.uucp' to our news gateways machine address 'anl433.uucp'. Note the leading dot '.' which is *always* needed before the domain name. i.e. -DNNTP_INEWS_DOMAIN=\".uucp\" NNTP - Reading & posting news ----------------------------- NNTP_ABLE Define if you wish to read news locally and remotely via an NNTP server. NNTP_ONLY Define if you [want to | can] ONLY read news remotely via an NNTP server. NNTP_INEWS Define if you want to use my builtin NNTP POST routine so that you no longer have to rely on the mini-inews from NNTP to be installed on each client machine. Also check that NNTP_INEWS_GATEWAY & NNTP_INEWS_DOMAIN are correctly set to produce a correct From: headers for your site. DONT_HAVE_NNTP_EXTS Define if you have a *virgin* NNTP server without my patches. This is just a nicety that will stop tin asking the server if it supports my NNTP server extensions XINDEX, XMOTD, XUSER & SPOOLDIR (cdrom) extensions. NNTP_SERVER_FILE Only define if your nntpserver file is other than /etc/nntpserver. NNTP_DEFAULT_SERVER Defines the name of the default nntp server that tin should connect to. Overrides the value of NNTP_SERVER_FILE. Can be overriden by setting the environment variable NNTPSERVER. NETLIBS Contains the networking libraries needed to link with nntplib.o file. Reading news via CD-ROM ----------------------- CDROM_ABLE Define if you wish to read news locally and from CD-ROM. CDROM_ONLY Define if you [want to | can] ONLY read news from CD-ROM. Daemon options -------------- INDEX_DAEMON Define to make an index file updating daemon version of tin. Note that no -lcurses or screen libraries need to be linked with tin when this #define is specified. If defined this will automatically undefine all NNTP_* defines as the daemon has to be installed on the NNTP server. Miscellaneous options --------------------- DEBUG Define if you want tin to log debug info. to files in /tmp. Activated by tin -Dn where n is 1 for NNTP only debug logging and n is 2 for logging all debug info. Debug files written to /tmp are ARTS, ACTIVE, BASE and NNTP. DONT_HAVE_MKDIR Define if your machine does not have the mkdir() system call. DONT_HAVE_GETCWD Define if you don't have the getcwd() system call. getwd() will be used. DONT_LOG_USER Log username & info to /tmp/.tin_log for usage statistics. If reading via NNTP the NNTP XUSER extended command will log user info to NNTP server. If -DNNTP_XUSER is defined it will define LOG_USER automatically. DONT_REREAD_ACTIVE_FILE Define if you do not want the active file to be reread periodically. The reread period can be set in seconds by setting the tinrc variable 'reread_active_file_secs=' HAVE_FACIST_NEWSADMIN Define if you want users articles to be posted to groups that your site receives. This will change the warning that a group that the user is posting to was not found in the sites active file to an error in the article checking routine therefore causing the user to remove the group from his/her posting or to abort the posting of the article. HAVE_ISPELL Define if you have ispell (interactive spellchecker) installed and want the option of checking your articles, mails before posting/mailing them. HAVE_LONG_FILENAMES Define if your machines filesystem supports filenames longer than 14 chars (default for BSD type systems). HAVE_MAIL_HANDLER Define if you want to use the MH style mail handling & reading code in mail.c It should be noted that mail handling is not well tested and not yet fully implemented. You can expect errors if you use this define so let me know the problems by sending me a bug report ('R' bug command from within tin). HAVE_MMDF_MAILER Define if your machine uses a MMDF type mailer instead of sendmail. It is defined as default on SCO Unix machines. It can be dynamically changed by setting the tinrc variable save_to_mmdf_mailbox to ON. HAVE_POLL Define if you have the poll() system call that is required to abort the indexing of a group in the function input_pending(). Don't define if HAVE_SELECT is already defined. HAVE_SELECT Define if you have the select() system call that is required to abort the indexing of a group in the function input_pending(). Don't define if HAVE_POLL is already defined. HAVE_POSIX_JC Define if your machine uses Posix style sigaction() signal handling. HAVE_SETREUID Define if problems occur when runnung tin as setuid news. Only define if your system supports the setreuid() system call. HAVE_STRFTIME Define if date shown at article viewer level is incorrect (ie. 1970...). Only define if your system supports the strftime() system call. NO_PIPING Do not allow piping of articles to shell commands. NO_POSTING Do not allow posting/followup of articles. NO_REGEX Define if you do not want to use regular expression pattern matching. NO_SHELL_ESCAPE Do not allow shell escapes. SLOW_SCREEN_UPDATE Define if running over a low speed connection (ie. 2400baud). It stops the percentage info being shown at bottom of select and group menus and stops the groupname being displayed at the bottom of the screen as it is subscribed/unsubscribed. SMALL_MEMORY_MACHINE Define if you are running a machine with little memory (<4MB). Tin will run slightly slower but be more efficent in how memory is allocated and reclaimed. USE_CLEARSCREEN Define if the you wish screen to use ClearScreen() and not MoveCursor() and CleartoEOLN(). This is perhaps faster on slow terminals but I have not really run any speed tests recently. USE_INN_NNTPLIB Define if you want to use the INN library functions GetConfigValue() & GetFQDN(). The INN_NNTPLIB variable in the Makefile must contain the correct path to INN library. USE_INVERSE_HACK Define if you want inverse video and highlighted bar disabled. Can be toggled in tin by the 'I' command and highlight bar by 'M' command. Compiled & installed on the following machines ---------------------------------------------- 1) * i386 & Linux 0.99p12 (main development machine) 2) * i386 & BSDI 1.0/Xenix 2.3.2/SCO SVR3.2/ISC SVR3.2/ATT SVR4.0 3) Sony News & NewsOS 4.1 4) SNI MX300/MX500 & Sinix 5.24/5.4 5) * Sun 3/4/IPC/SS1/SS2/SS10 & SunOS 4.0.3/4.1.1/4.1.2/4.1.3 6) Dec 5000/Vax & Ultrix 4.1/4.2 7) Vax 11/785 & BSD 4.3 8) DG Aviion 300 & DG-UX 4.30 9) Apollo DN4500 & DomainOS 10.3 10) ICL DRS6000 & SVR4.0 11) Apricot VX/FT & SCO 3.2.2 12) DIAB DS90 & D-NIX 5.3 13) Amdahl 5890 & UTS 5.2.6b 14) HP 720/845 & HP-UX 7.0/8.0 15) IBM RS/6000 & AIX 3.1.5 16) NCR Tower & SysV 17) Atari STe & Minix 1.5.10.3b 18) Powerbook 140 & MacMinix 19) 386 PC & Minix 386 20) Sequent S81 & PTX 1.3 / Dynix 21) Convex C220 & Convex Un*x 22) Harris HCX & CX/UX 23) SGI 4D35/Challenge & IRIX 4.0.1/5 24) Pyramid 9810 & OSx96N 25) Alliant FX/2800 & Concentrix 2.2 26) Stratus i860 & FTX 2.0 27) Apple A/UX 3.0 & gcc 2.2 (?) 28) Motorola Delta 3200 & SysVR3V6 29) Gould Powernode 9050 & utx/32 30) Acorn R260 & RISCiX 1.2 31) DDE Supermax & ATT SysVr3 * = compiled, installed and used by author ð*[SRC.TIN-1_22]INSTALL.NNTP;1+,y. //€ 4  -d0@î123KÿPWO 56`…t…—7Àw ?ê‘—89 „ìø‘—G/€HªJÿCompilation and installation notes for NNTP patches - 18-11-92 -------------------------------------------------------------- This document explains the install procedure for the supplied patch to the NNTP server nntpd & to the TIN newsreader to retrieve index files from the NNTP server. NNTP server ----------- 1) Copy the following files to /server cp xindex.c /server cp xmotd.c /server cp xuser.c /server 2) Copy the following files to cp server.patch cp common.patch 3) Patch the files in /common & /server cd patch < common.patch patch < server.patch 4) Copy /common/conf.h.dist to /common/conf.h cd /common cp conf.h.dist conf.h 5) Edit /common/conf.h to suit your sites needs. The XINDEX, XMOTD, XOVERVIEW & XUSER extensions are #defined by default. You may need to change the path for the #define's for XINDEX_DIR, XMOTD_FILE & SUBSCRIBTIONS_FILE. The default for XINDEX_DIR is /usr/spool/news/.index and for the others /usr/lib/news/[motd | subscriptions] cd /common [vi|emacs] conf.h 6) Recompile & install the NNTP server nntpd cd make server make install_server TIN client ---------- 1) Nothing needs to changed in the tin client as long as you originally compiled tin with -DNNTP_ABLE or -DNNTP_ONLY. You will have to remove -DDONT_HAVE_NNTP_EXTS from the CFLAGS in the Makefile and recompile if it was originally defined. 2) Recompile & install tin. cd make make install TIN daemon (on NNTP server) --------------------------- 1) Edit tin Makefile to enable index daemon functionality. cd [vi|emacs] Makefile Add -DINDEX_DAEMON to CFLAGS to create a version of tin 'tind' to create & update index files on the NNTP server. 2) Compile & install tind. cd make make install_daemon 3) Add entry to crontab to start 'tind' index daemon every so often. cd /usr/spool/cron/crontabs [vi|emacs] root Add following line to run tind every 30 minutes: 0,30 * * * * su news -c '/usr/lib/news/tind' OK. If you have gotten this far you will have the following configuration: o tind will run every 30 minutes to update a central directory (usually /usr/spool/news/.index) of tin index files for all groups in the active file. The directory can be changed by 'tind -I dir' if so desired. o The NNTP server nntpd will service all requests for tin index files from tin clients. It will do this by returning the contents of the group index file in the index directory (ie. /usr/spool/news/.index/*) o The tin client will issue requests for index files to the NNTP server therefore saving space on the client machine and ensuring that there are only one copy of index files on the whole network. Also clients will not have to wait while index files are built locally as the index daemon tind runs frequently on the news server. Enjoy & happy newsreading Iain ð*[SRC.TIN-1_22]KILL.C;2+,B.//€ 4§-d0@î123KÿPWO56àÍ2­­‹—7`8ü­­‹—89€]V‚—G/€HªJÿ/* * Project : tin - a Usenet reader * Module : kill.c * Author : I.Lea & J.Robinson * Created : 01-04-91 * Updated : 11-07-93 * Notes : kill & auto select (hot) articles * Copyright : (c) Copyright 1991-93 by Iain Lea & Jim Robinson * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" #ifdef NO_REGEX char *stars = ""; #else char *stars = "*"; #endif #define SET_KILLED(i) (arts[i].unread = ART_READ, arts[i].killed = 1) #define SET_HOT(i) (arts[i].hot = 1) #define IS_READ(i) (arts[i].unread == ART_READ) #define IS_KILLED(i) (arts[i].killed == 1) #define KILL_CHAR 'K' #define HOT_CHAR 'H' #define K_KILL 0 #define K_HOT 1 int kill_level = 1; int kill_num = 0; struct t_kill *killf; /* * read_kill_file - read ~/.tin/kill file contents into kill array */ int read_kill_file () { char buf[LEN], *ptr; FILE *fp; int n; char c; unsigned int type; free_kill_array (); if ((fp = fopen (killfile, "r")) == NULL) { return FALSE; } kill_num=0; while (fgets (buf, sizeof buf, fp) != NULL) { if (buf[0] == '#') { continue; } if (kill_num == max_kill-1) { expand_kill (); } n = sscanf(buf, "%d %c", &type, &c); if (n == 0) { goto corrupt_killfile; } if (n > 1 && c == HOT_CHAR) { /* hot */ kil° àãÂ~ TIN-1_22.BCKBd[SRC.TIN-1_22]KILL.C;2êPlf[kill_num].kill_how = K_HOT; } else { killf[kill_num].kill_how = K_KILL; } killf[kill_num].kill_type = type; if (fgets (buf, sizeof buf, fp) == NULL) { goto corrupt_killfile; } killf[kill_num].kill_group = (long) atol (buf); switch (killf[kill_num].kill_type) { case KILL_SUBJ: if (fgets (buf, sizeof buf, fp) != NULL) { ptr = strchr (buf, '\n'); if (ptr != (char *) 0) { *ptr = '\0'; } killf[kill_num].kill_subj = str_dup (buf); } break; case KILL_FROM: if (fgets (buf, sizeof buf, fp) != NULL) { ptr = strchr (buf, '\n'); if (ptr != (char *) 0) { *ptr = '\0'; } killf[kill_num].kill_from = str_dup (buf); } break; case KILL_BOTH: if (fgets (buf, sizeof buf, fp) != NULL) { ptr = strchr (buf, '\n'); if (ptr != (char *) 0) { *ptr = '\0'; } killf[kill_num].kill_subj = str_dup (buf); } if (fgets (buf, sizeof buf, fp) != NULL) { ptr = strchr (buf, '\n'); if (ptr != (char *) 0) { *ptr = '\0'; } killf[kill_num].kill_from = str_dup (buf); } break; default: goto corrupt_killfile; } kill_num++; } fclose (fp); return (kill_num); corrupt_killfile: fclose (fp); killf[kill_num].kill_type = 0; error_message (txt_corrupt_kill_file, killfile); return FALSE; } /* * write_kill_file - write kill strings to ~/.tin/kill */ void write_kill_file () { FILE *fp; int i; #ifdef VMS if (kill_num == 0 || (fp = fopen (killfile, "w", "fop=cif")) == NULL) { #else if (kill_num == 0 || (fp = fopen (killfile, "w")) == NULL) { #endif return; } wait_message (txt_saving); fprintf (fp, "# 1st line 1=(Subject: only) 2=(From: only) 3=(Subject: & From:)\n"); fprintf (fp, "# %c=(kill) %c=(auto-selection)\n", KILL_CHAR, HOT_CHAR); fprintf (fp, "# 2nd line 0=(kill on all newsgroups) >0=(kill on specific newsgroup)\n"); for (i=0 ; i < kill_num ; i++) { if (killf[i].kill_type == 0 || (killf[i].kill_subj == 0 && killf[i].kill_from == 0)) continue; if (killf[i].kill_how == K_KILL) { fprintf (fp, "#\n# %03d KILL\n", i+1); fprintf (fp, "%d\t%c\n", killf[i].kill_type, KILL_CHAR); } else { fprintf (fp, "#\n# %03d HOT\n", i+1); fprintf (fp, "%d\t%c\n", killf[i].kill_type, HOT_CHAR); } fprintf (fp, "%ld\n", killf[i].kill_group); switch (killf[i].kill_type) { case KILL_SUBJ: fprintf (fp, "%s\n", killf[i].kill_subj); break; case KILL_FROM: fprintf (fp, "%s\n", killf[i].kill_from); break; case KILL_BOTH: fprintf (fp, "%s\n", killf[i].kill_subj); fprintf (fp, "%s\n", killf[i].kill_from); break; } } fclose (fp); chmod (killfile, 0600); } #if __STDC__ static int get_choice ( int x, char *help, char *prompt, char *opt1, char *opt2, char *opt3, char *opt4) #else static int get_choice (x, help, prompt, opt1, opt2, opt3, opt4) int x; char *help; char *prompt; char *opt1; char *opt2; char *opt3; char *opt4; #endif { int ch, n = 0, i = 0; char *argv[4]; if (opt1) argv[n++] = opt1; if (opt2) argv[n++] = opt2; if (opt3) argv[n++] = opt3; if (opt4) argv[n++] = opt4; assert(n > 0); if (help) show_menu_help (help); do { MoveCursor(x, (int) strlen (prompt)); fputs (argv[i], stdout); fflush (stdout); CleartoEOLN (); if ((ch = ReadCh ()) != ' ') continue; if (++i == n) i = 0; } while (ch != CR && ch != ESC); if (ch == ESC) return (-1); return (i); } /* * options menu so that the user can dynamically change parameters */ int kill_art_menu (group_name, index) char *group_name; int index; { char buf[LEN]; char text[LEN]; char kill_from[LEN]; char kill_subj[LEN]; char kill_group[LEN]; char ch_default = 's'; int ch; int counter = 0; int killed = TRUE; int kill_from_ok = FALSE; int kill_subj_ok = FALSE; int kill_every_group = FALSE; int i; int kill_how; #ifdef SIGTSTP t_sigtype (*susp)(); susp = (t_sigtype (*)()) 0; if (do_sigtstp) { susp = sigdisp (SIGTSTP, SIG_DFL); sigdisp (SIGTSTP, SIG_IGN); } #endif sprintf (kill_group, "%s only", group_name); sprintf (kill_subj, txt_kill_subject, cCOLS-35, cCOLS-35, arts[index].subject); if (arts[index].name != (char *) 0) { sprintf (text, "%s (%s)", arts[index].from, arts[index].name); } else { strcpy (text, arts[index].from); } sprintf (kill_from, txt_kill_from, cCOLS-35, cCOLS-35, text); text[0] = '\0'; ClearScreen (); center_line (0, TRUE, txt_kill_menu); MoveCursor (INDEX_TOP, 0); printf ("%s\r\n\r\n\r\n", txt_kill_how); printf ("%s\r\n\r\n", txt_kill_text); printf ("%s\r\n\r\n\r\n", txt_kill_text_type); printf ("%s\r\n\r\n", kill_subj); printf ("%s\r\n\r\n\r\n", kill_from); printf ("%s%s", txt_kill_group, kill_group); fflush (stdout); i = get_choice (INDEX_TOP, txt_help_kill_how, txt_kill_how, "Kill ", "Auto Select", NULL, NULL); if (i == -1) { return FALSE; } kill_how = (i == 0 ? K_KILL : K_HOT); show_menu_help (txt_help_kill_text); if (! prompt_menu_string (INDEX_TOP+3, (int) strlen (txt_kill_text), text)) { return FALSE; } if (text[0]) { i = get_choice(INDEX_TOP+5, txt_help_kill_text_type, txt_kill_text_type, "Subject: line only ", "From: line only ", "Subject: & From: lines", NULL); if (i == -1) { return FALSE; } counter = ((i == 0 ? KILL_SUBJ : (i == 1 ? KILL_FROM : KILL_BOTH))); } if (! text[0]) { i = get_choice (INDEX_TOP+8, txt_help_kill_subject, kill_subj, txt_yes, txt_no, NULL, NULL); if (i == -1) { return FALSE; } else { kill_subj_ok = (i ? FALSE : TRUE); } if (kill_subj_ok) { i = get_choice (INDEX_TOP+10, txt_help_kill_from, kill_from, txt_no, txt_yes, NULL, NULL); } else { i = get_choice (INDEX_TOP+10, txt_help_kill_from, kill_from, txt_yes, txt_no, NULL, NULL); } if (i == -1) { return FALSE; } else { if (kill_subj_ok) { kill_from_ok = (i ? TRUE : FALSE); } else { kill_from_ok = (i ? FALSE : TRUE); } } } if (text[0] || kill_subj_ok || kill_from_ok) { i = get_choice (INDEX_TOP+13, txt_help_kill_group, txt_kill_group, kill_group, "All groups", NULL, NULL); if (i == -1) { return FALSE; } kill_every_group = (i == 0 ? FALSE : TRUE); } while (1) { do { sprintf (msg, "%s%c", txt_quit_edit_save_killfile, ch_default); wait_message (msg); MoveCursor (cLINES, (int) strlen (txt_quit_edit_save_killfile)); if ((ch = ReadCh ()) == CR) ch = ch_default; } while (ch != ESC && ch != 'q' && ch != 'e' && ch != 's'); switch (ch) { case 'e': invoke_editor (killfile, 2); unkill_all_articles (); killed_articles = read_kill_file (); killed = TRUE; goto kill_done; case 'q': case ESC: killed = FALSE; goto kill_done; case 's': if (kill_num > max_kill-1) { expand_kill (); } killf[kill_num].kill_how = kill_how; if (text[0]) { sprintf (buf, "%s%s%s", stars, text, stars); switch (counter) { case KILL_SUBJ: killf[kill_num].kill_subj = str_dup (buf); break; case KILL_FROM: killf[kill_num].kill_from = str_dup (buf); break; case KILL_BOTH: killf[kill_num].kill_subj = str_dup (buf); killf[kill_num].kill_from = killf[kill_num].kill_subj; break; } killf[kill_num].kill_type = counter; if (kill_every_group) { killf[kill_num].kill_group = 0L; } else { killf[kill_num].kill_group = hash_s (group_name); } kill_num++; } else { if (kill_subj_ok) { killf[kill_num].kill_type = KILL_SUBJ; sprintf (buf, "%s%s%s", stars, arts[index].subject, stars); killf[kill_num].kill_subj = str_dup (buf); } if (kill_from_ok) { killf[kill_num].kill_type |= KILL_FROM; if (arts[index].name != (char *) 0) { sprintf (buf, "%s%s (%s)%s", stars, arts[index].from, arts[index].name, stars); } else { sprintf (buf, "%s%s%s", stars, arts[index].from, stars); } killf[kill_num].kill_from = str_dup (buf); } if (killf[kill_num].kill_type) { if (kill_every_group) { killf[kill_num].kill_group= 0L; } else { killf[kill_num].kill_group= hash_s (group_name); } kill_num++; } } write_kill_file (); kill_done: #ifdef SIGTSTP if (do_sigtstp) { sigdisp (SIGTSTP, susp); } #endif return (killed); } } /* NOTREACHED */ } /* * We assume that any articles which are tagged as killed are also * tagged as being read BECAUSE they were killed. So, we retag * them as being unread. */ int unkill_all_articles () { int unkilled = FALSE; register int i; for (i=0 ; i < top ; i++) { if (arts[i].killed) { arts[i].killed = FALSE; arts[i].unread = ART_UNREAD; unkilled = TRUE; } } num_of_killed_arts = 0; return (unkilled); } /* * Kill any articles in group active[index] */ int kill_any_articles (index) int index; /* active[index].name gets groupname */ { char buf[LEN]; int killed = FALSE; int run_ok = FALSE; int is_hot; long newsgroup_hash; register int i, j; if (! kill_num) { return (killed); } num_of_killed_arts = 0; num_of_hot_arts = 0; newsgroup_hash = hash_s (active[index].name); for (i=0 ; i < kill_num ; i++) { if (killf[i].kill_group == 0L || killf[i].kill_group == newsgroup_hash) { run_ok = TRUE; } } if (! run_ok) { return (killed); } if (debug && ! update) { wait_message (txt_killing_arts); } for (i=0 ; i < top ; i++) { if (IS_READ(i) && kill_level == 0) { continue; } for (j=0 ; j < kill_num ; j++) { if (killf[j].kill_group != 0L && killf[j].kill_group != newsgroup_hash) continue; is_hot = (killf[j].kill_how == K_HOT ? TRUE : FALSE); switch (killf[j].kill_type) { case KILL_SUBJ: if (STR_MATCH (arts[i].subject, killf[j].kill_subj)) { if (! is_hot) { SET_KILLED(i); num_of_killed_arts++; } else { SET_HOT(i); if (active[index].attribute.show_only_unread) { if (arts[i].unread == ART_UNREAD) { num_of_hot_arts++; } } else { num_of_hot_arts++; } } } break; case KILL_FROM: if (arts[i].name != (char *) 0) { sprintf (buf, "%s (%s)", arts[i].from, arts[i].name); } else { strcpy (buf, arts[i].from); } if (STR_MATCH (buf, killf[j].kill_from)) { if (! is_hot) { SET_KILLED(i); num_of_killed_arts++; } else { SET_HOT(i); if (active[index].attribute.show_only_unread) { if (arts[i].unread == ART_UNREAD) { num_of_hot_arts++; } } else { num_of_hot_arts++; } } } break; case KILL_BOTH: if (STR_MATCH (arts[i].subject, killf[j].kill_subj)) { if (! is_hot) { SET_KILLED(i); num_of_killed_arts++; } else { SET_HOT(i); if (active[index].attribute.show_only_unread) { if (arts[i].unread == ART_UNREAD) { num_of_hot_arts++; } } else { num_of_hot_arts++; } } break; } if (arts[i].name != (char *) 0) { sprintf (buf, "%s (%s)", arts[i].from, arts[i].name); } else { strcpy (buf, arts[i].from); } if (STR_MATCH (buf, killf[j].kill_from)) { if (! is_hot) { SET_KILLED(i); num_of_killed_arts++; } else { SET_HOT(i); if (active[index].attribute.show_only_unread) { if (arts[i].unread == ART_UNREAD) { num_of_hot_arts++; } } else { num_of_hot_arts++; } } } break; } if (IS_KILLED(i) || ! killed) killed = TRUE; } } return (killed); } /* * Auto select articles. * WARNING - this routinely is presently a kludge. It calls * kill_any_articles() which also kills articles. It also always returns * true in order to fake out the display code (cause it doesn't know * if any articles were actually selected) * The correct way to do this is to modify kill_any_articles() to take * another arg to specify whether killing, auto-selecting, or both is to be * done, rename it to something else, and then have a new kill_any_articles() * and auto_select_articles() call this new routine with the appropriate * arguments. */ int auto_select_articles (index) int index; { kill_any_articles (index); return (TRUE); } dð*[SRC.TIN-1_22]LANG.C;2+,­.?//€ 4?=Ð-d0@î123KÿPWO@56@¸†—7@¥Ö¹†—89€]V‚—G/€HªJÿ/* * Project : tin - a Usenet reader * Module : lang.c * Author : I.Lea * Created : 01-04-91 * Updated : 22-09-93 * Notes : * Copyright : (c) Copyright 1991-93 by Iain Lea * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" /* * active.c */ char txt_subscribe_to_new_group[] = "Subscribe to new group %s (y/n/q) [%c]: "; char txt_delete_bogus_group[] = "Remove bogus group %s (y/n/q) [%c]: "; char txt_reading_news_active_file[] = "Reading news active file..."; char txt_reading_mail_active_file[] = "Reading mail active file..."; char txt_reading_attributes_file[] = "Reading attributes file..."; char txt_writing_attributes_file[] = "Writing attributes file..."; char txt_reading_newsgroups_file[] = "Reading newsgroups file..."; char txt_reading_mailgroups_file[] = "Reading mailgroups file..."; /* * art.c */ #if defined(HAVE_POLL) || defined(HAVE_SELECT) char txt_group[] = "Group %s ('q' to quit)... "; #else char txt_group[] = "Group %s... "; #endif char txt_purge[] = "Purging %s..."; char txt_cannot_open_art[] = "Can't open article %s: "; char txt_corrupt_index[] = "Index file %s corrupted. error %d on article %d"; char txt_checking_for_news[] = "Checking for news..."; char txt_there_is_no_news[] = "There is no news\n"; char txt_killing_arts[] = "Selecting articles..."; char txt_unkilling_arts[] = "Unselecting articles..."; char txt_catchup_update_info[] = "%s %d group(s) in %ld seconds\n"; char txt_abort_indexing[] = "Do you want to abort indexing group? (y/n): "; char txt_abort_searching[] = "Do you want to abort searching? (y/n): "; char txt_no_index_file[] = "No index file specified"; char txt_writing_index_file[] = "Writing index file..."; /* * feed.c */ char txt_art_thread_regex_tag[] = " a)rticle, t)hread, h)ot, p)attern, T)agged articles, q)uit: "; #ifdef M_AMIGA char txt_post_process_type[] = "Process n)one, s)har, u)ud, l)ist lha, e)xt lha, L)ist zip, E)xt zip, q)uit: "; #else char txt_post_process_type[] = "Process n)one, s)har, u)ud, l)ist zoo, e)xt zoo, L)ist zip, E)xt zip, q)uit: "; #endif #ifdef NO_REGEX char txt_feed_pattern[] = "Enter pattern [%s]> "; #else char txt_feed_pattern[] = "Enter regex pattern [%s]> "; #endif char txt_no_command[] = "No command"; char txt_piping[] = "Piping..."; char txt_piping_not_enabled[] = "Piping not enabled. Recompile without -DNO_PIPING."; char txt_saved[] = "-- %d Article(s) saved --"; /* * group.c */ char txt_reading_all_arts[] = "Reading all articles..."; char txt_reading_new_arts[] = "Reading unread articles..."; char txt_cannot_post[] = "*** Posting not allowed ***"; char txt_tagged_art[] = "Tagged article"; char txt_tagged_thread[] = "Tagged thread"; char txt_untagged_art[] = "Untagged article"; char txt_untagged_thread[] = "Untagged thread"; char txt_inverse_on[] = "Inverse video enabled"; char txt_inverse_off[] = "Inverse video disabled"; char txt_subscribed_to[] = "Subscribed to %s"; char txt_unsubscribed_to[] = "Unsubscribed from %s"; char txt_mark_all_read[] = "Mark all articles as read? (y/n): "; char txt_mark_thread_read[] = "Mark thread as read? (y/n): "; char txt_no_more_groups[] = "No more groups"; char txt_no_prev_group[] = "No previous group"; char txt_no_arts[] = "*** No Articles ***"; char txt_no_groups[] = "*** No Groups ***"; char txt_not_active_newsfeed[] = "Command only allowed on active news"; char txt_end_of_thread[] = "*** End of Thread ***"; char txt_end_of_arts[] = "*** End of Articles ***"; char txt_end_of_groups[] = "*** End of Groups ***"; char txt_no_next_unread_art[] = "No next unread article"; char txt_no_prev_unread_art[] = "No previous unread article"; char txt_no_last_message[] = "No last message"; char txt_bad_command[] = "Bad command. Type 'h' for help."; char txt_you_have_mail[] = " You have mail\n"; char txt_type_h_for_help[] = " h=help\n"; char txt_read_art[] = "Read article> "; char txt_search_forwards[] = "Search forwards [%s]> "; char txt_search_backwards[] = "Search backwards [%s]> "; char txt_search_body[] = "Search body [%s]> "; char txt_author_search_forwards[] = "Author search forwards [%s]> "; char txt_author_search_backwards[] = "Author search backwards [%s]> "; char txt_no_search_string[] = "No search string"; char txt_no_match[] = "No match"; char txt_no_newsgroups[] = "No newsgroups"; char txt_no  _quick_newsgroups[] = "\nNo newsgroups. Exiting..."; char txt_no_quick_subject[] = "\nNo subject. Exiting..."; char txt_no_subject[] = "No subject"; char txt_post_newsgroups[] = "Post to newsgroup(s) [%s]> "; char txt_post_subject[] = "Post subject [%s]> "; char txt_cannot_open[] = "Can't open %s"; char txt_posting[] = "Posting article..."; char txt_art_posted[] = "Article posted"; char txt_art_rejected[] = "Article rejected (saved to %s)"; #ifdef HAVE_ISPELL char txt_quit_edit_post[] = "q)uit, e)dit, i)spell, p)ost: "; #else char txt_quit_edit_post[] = "q)uit, e)dit, p)ost: "; #endif char txt_help_4[] = "4$ Goto spooldir 4 ($=goto last spooldir)\r\n"; char txt_help_i_4[] = "4$ Goto article 4 ($=goto last article)\r\n"; char txt_help_ctrl_k[] = "^K Kill / Auto select (hot) current article\r\n"; char txt_help_ctrl_l[] = "^L Redraw page\r\n"; char txt_help_ctrl_d[] = "^D^U Down (^U=up) a page\r\n"; char txt_help_ctrl_f[] = "^F^B Down (^B=up) a page\r\n"; char txt_help_i_cr[] = " Read current article\r\n"; char txt_help_cr[] = " Read news from selected spooldir\r\n"; char txt_help_i_tab[] = " Goto next unread article or group\r\n"; char txt_help_d[] = "d Toggle display of subject or subject & author\r\n"; char txt_help_l[] = "l List articles within current thread\r\n"; char txt_help_m[] = "m Move current group within group selection list\r\n"; char txt_help_M[] = "M Menu of configurable options\r\n"; char txt_help_a[] = "aA Author forward (A=backward) search\r\n"; char txt_help_B[] = "B Article body search\r\n"; char txt_help_sel_c[] = "cC Mark group read (C=and goto next unread group)\r\n"; char txt_help_c[] = "c Mark all articles as read and goto group selection menu\r\n"; char txt_help_cC[] = "C Mark all articles as read and goto next unread group\r\n"; char txt_help_g[] = "g Choose a new group by name\r\n"; char txt_help_I[] = "I Toggle inverse video\r\n"; char txt_help_K[] = "K Mark article/thread as read & goto next unread\r\n"; char txt_help_j[] = "jk Down (k=up) a line\r\n"; char txt_help_i_n[] = "np Goto next (p=previous) group\r\n"; char txt_help_i_p[] = "NP Goto next (P=previous) unread article\r\n"; char txt_help_q[] = "Q Quit\r\n"; char txt_help_r[] = "r Toggle display to show all / only unread articles\r\n"; char txt_help_s[] = "su Subscribe (u=unsubscribe) to current group\r\n"; char txt_help_S[] = "SU Subscribe (U=unsubscribe) to groups that match pattern\r\n"; char txt_help_T[] = "T Return to group selection level\r\n"; char txt_help_t[] = "t Tag current article for crossposting/mailing/piping/printing/saving\r\n"; char txt_help_u[] = "u Toggle display of unthreaded & threaded articles\r\n"; char txt_help_U[] = "U Untag all tagged articles\r\n"; char txt_help_v[] = "v Show version information\r\n"; char txt_help_w[] = "w Post an article to current group\r\n"; char txt_help_x[] = "x * Crosspost current article to another group\r\n"; char txt_help_i_search[] = "/? Subject forward (?=backward) search\r\n"; char txt_help_thread[] = "<> Goto first (>=last) article in current thread\r\n"; #ifndef NO_SHELL_ESCAPE char txt_help_shell[] = "! Shell escape\r\n"; #endif char txt_help_dash[] = "- Show last message\r\n"; char txt_help_i_star[] = "* Select thread\r\n"; char txt_help_i_dot[] = ". Toggle selection of thread\r\n"; char txt_help_i_coma[] = "@ Reverse all selections (all articles)\r\n"; char txt_help_i_tilda[] ="~ Undo all selections (all articles)\r\n"; char txt_help_X[] = "X Mark all unread articles that have not been selected as read\r\n"; char txt_help_plus[] = "+ Perform auto-selection on group\r\n"; char txt_help_equal[] = "= Mark threads selected if at least one unread art is selected\r\n"; char txt_help_semicolon[] = "; Mark threads selected if at least one unread art is selected\r\n"; #ifdef NO_REGEX char txt_save_pattern[] = "Enter save pattern [%s]> "; #else char txt_save_pattern[] = "Enter regex save pattern [%s]> "; #endif char txt_saved_pattern_to[] = "-- Saved pattern to %s - %s --"; char txt_saved_to_mailbox[] = "-- Saved to mailbox %s --"; char txt_threading_arts[] = "Threading articles..."; char txt_unthreading_arts[] = "Unthreading articles..."; char txt_select_pattern[] = "Enter selection pattern [%s]> "; /* * help.c: */ char txt_group_select_com[] = "Group Selection Commands (page %d of %d)"; char txt_spooldir_com[] = "Spooldir Selection Commands (page %d of %d)"; char txt_index_page_com[] = "Index Page Commands (page %d of %d)"; char txt_thread_com[] = "Thread Commands (page %d of %d)"; char txt_art_pager_com[] = "Article Pager Commands (page %d of %d)"; char txt_hit_space_for_more[] = "PgDn,End,,^D - page down. PgUp,Home,b,^U - page up. ,q - quit"; char txt_post_history_menu[] = "Posted articles history (page %d of %d)"; char txt_mini_select_1[] = "=set current to n, TAB=next unread, /=search pattern, c)atchup,"; char txt_mini_select_2[] = "g)oto, j=line down, k=line up, h)elp, m)ove, q)uit, r=toggle all/unread,"; char txt_mini_select_3[] = "s)ubscribe, S)ub pattern, u)nsubscribe, U)nsub pattern, y)ank in/out"; char txt_mini_spooldir_1[] = "=set current to n, CR=selects spooldir, h)elp, j=line down, k=line up, q)uit"; char txt_mini_group_1[] = "=set current to n, TAB=next unread, /=search pattern, ^K)ill/select,"; char txt_mini_group_2[] = "a)uthor search, c)atchup, j=line down, k=line up, K=mark read, l)ist thread,"; char txt_mini_group_3[] = "|=pipe, m)ail, o=print, q)uit, r=toggle all/unread, s)ave, t)ag, w=post"; char txt_mini_thread_1[] = "=set current to n, TAB=next unread, c)atchup, d)isplay toggle,"; char txt_mini_thread_2[] = "h)elp, j=line down, k=line up, q)uit, t)ag, z=mark unread"; char txt_mini_page_1[] = "=set current to n, TAB=next unread, /=search pattern, ^K)ill/select,"; char txt_mini_page_2[] = "a)uthor search, B)ody search, c)atchup, f)ollowup, K=mark read,"; char txt_mini_page_3[] = "|=pipe, m)ail, o=print, q)uit, r)eply mail, s)ave, t)ag, w=post"; /* * init.c: */ char txt_env_var_not_found[] = "Environment variable %s not found. Set and retry..."; /* * kill.c: */ char txt_corrupt_kill_file[] = "Corrupt kill file %s"; char txt_kill_menu[] = "Kill / Auto-select Article Menu"; char txt_kill_how[] = "Kill type : "; char txt_kill_subject[] = "Kill Subject [%-*.*s] (y/n): "; char txt_kill_from[] = "Kill From [%-*.*s] (y/n): "; char txt_kill_text[] = "Kill text pattern : "; char txt_kill_text_type[] = "Apply pattern to : "; char txt_kill_group[] = "Kill pattern scope: "; char txt_help_kill_how[] = "Choose kill or auto select. toggles & sets."; char txt_help_kill_subject[] = "Subject: line to add to kill file. toggles & sets."; char txt_help_kill_from[] = "From: line to add to kill file. toggles & sets."; char txt_help_kill_text[] = "Enter text pattern to kill if Subject: & From: lines are not what you want."; char txt_help_kill_text_type[] = "Select where text pattern should be applied. toggles & sets."; char txt_help_kill_group[] = "Kill/auto-select only current group or all groups. toggles & sets."; char txt_quit_edit_save_killfile[] = "q)uit e)dit s)ave kill/hot description: "; char txt_yes[] = "Yes"; char txt_no[] = "No "; /* * main.c: */ #ifdef M_AMIGA char txt_copyright_notice[] = "%s (c) Copyright 1991-93 Iain Lea & Mark Tomlinson."; #endif #ifdef M_OS2 char txt_copyright_notice[] = "%s (c) Copyright 1991-93 Iain Lea & Andreas Wrede."; #endif #ifdef M_UNIX char txt_copyright_notice[] = "%s (c) Copyright 1991-93 Iain Lea."; #endif #ifdef VMS char txt_copyright_notice[] = "%s (c) Copyright 1991-93 Iain Lea & Tod McQuillin."; #endif char txt_option_not_enabled[] = "Option not enabled. Recompile with %s."; char txt_not_in_active_file[] = "Group %s not found in active file"; char txt_screen_init_failed[] = "%s: Screen initialization failed"; char txt_bad_active_file[] = "Active file corrupt - %s"; /* * misc.c */ char txt_cannot_open_active_file[] = "Can't open %s. Try %s -r to read news via NNTP.\n"; char txt_active_file_is_empty[] = "%s contains no newsgroups. Exiting."; char txt_checking_active_file[] = "Checking for new newsgroups..."; char txt_checking[] = "Checking..."; char txt_cannot_find_base_art[] = "Can't find base article %s"; char txt_out_of_memory[] = "%s: out of memory"; char txt_rename_error[] = "Error: rename %s to %s"; char txt_shell_escape[] = "Enter shell command [%s]> "; char txt_ispell_define_not_compiled[] = "Interactive spellchecker not enabled. Recompile with -DHAVE_ISPELL."; /* * newsrc.c */ char txt_creating_newsrc[] = "Creating .newsrc...\n"; char txt_deleting_from_newsrc[] = "Group %s not in active file. Deleting."; /* * open.c */ char txt_connecting[] = "Connecting to %s..."; char txt_reconnect_to_news_server[] = "Connection to news server has timed out. Reconnect? (y/n): "; char txt_cannot_get_nntp_server_name[] = "Cannot find NNTP server name"; char txt_server_name_in_file_env_var[] = "Put the server name in the file %s,\nor set the environment variable NNTPSERVER"; char txt_failed_to_connect_to_server[] = "Failed to connect to NNTP server %s. Exiting..."; char txt_rejected_by_nntpserver[] = "Rejected by server, nntp error %d"; char txt_connection_to_server_broken[] = "Connection to server broken"; char txt_stuff_nntp_cannot_open[] = "stuff_nntp: can't open %s: "; char txt_nntp_to_fp_cannot_reopen[] = "nntp_to_fp: can't reopen %s: "; char txt_nntp_to_fd_cannot_reopen[] = "nntp_to_fd: can't reopen %s: "; char txt_nntp_authorization_failed[] = "NNTP authorization password not found for %s"; /* * page.c */ char txt_reading_article[] = "Reading..."; char txt_quit[] = "Do you really want to quit? (y/n): "; char txt_art_unavailable[] = "Article %ld unavailable"; char txt_art_marked_as_unread[] = "Article marked as unread"; char txt_thread_marked_as_unread[] = "Thread marked as unread"; char txt_begin_of_art[] = "*** Beginning of article ***"; char txt_next_resp[] = "-- Next response --"; char txt_last_resp[] = "-- Last response --"; char txt_more[] = "--More--"; char txt_more_percent[] = "--More--(%d%%) [%ld/%ld]"; char txt_thread_x_of_n[] = "%sThread %4d of %4d\r\n"; char txt_lines[] = "Lines %s "; char txt_resp_x_of_n[] = "Respno %3d of %3d\r\n"; char txt_no_resp[] = "No responses\r\n"; char txt_1_resp[] = "1 Response\r\n"; char txt_x_resp[] = "%d Responses\r\n"; char txt_s_at_s[] = "%s at %s"; char txt_thread_resp_page[] = "Thread %d of %d, Resp %d/%d (page %d): %s"; char txt_thread_page[] = "Thread %d of %d (page %d): %s"; char txt_read_resp[] = "Read response> "; char txt_help_p_0[] = "0 Read the base article in current thread\r\n"; char txt_help_p_4[] = "4 Read response 4 in current thread\r\n"; char txt_help_p_cr[] = " Goto to next thread\r\n"; char txt_help_p_tab[] = " Goto next unread article\r\n"; char txt_help_b[] = "b Back (=forward) a page\r\n"; char txt_help_bug[] = "R Report bug/comment via mail to %s\r\n"; char txt_help_p_f[] = "fF Post (f=copy text) a followup\r\n"; char txt_help_D[] = "D Delete (cancel) current article that must have been posted by you\r\n"; char txt_help_ctrl_h[] = "^H Show articles header\r\n"; char txt_help_h[] = "hH Command help (H=toggle mini help menu)\r\n"; char txt_help_i[] = "q Return to previous level\r\n"; char txt_help_ck[] = "cK Mark thread as read & return to previous level\r\n"; char txt_help_p_k[] = "kK Mark article (K=thread) as read & advance to next unread\r\n"; char txt_help_p_m[] = "m Mail article/thread/hot/pattern/tagged articles to someone\r\n"; char txt_help_p_n[] = "nN Goto to the next (N=unread) article\r\n"; char txt_help_o[] = "o Output article/thread/hot/pattern/tagged articles to printer\r\n"; char txt_help_p_p[] = "pP Goto the previous (P=unread) article\r\n"; char txt_help_p_r[] = "rR Reply through mail (r=copy text) to author\r\n"; char txt_help_p_s[] = "s Save article/thread/hot/pattern/tagged articles to file\r\n"; char txt_help_p_z[] = "zZ Mark article (Z=thread) as unread\r\n"; char txt_help_p_ctrl_r[] = "^R$ Redisplay first ($=last) page of article\r\n"; char txt_help_p_g[] = "gG Goto first (G=last) page of article\r\n"; char txt_help_p_d[] = "d Toggle rot-13 decoding for current article\r\n"; char txt_help_pipe[] = "| Pipe article/thread/hot/pattern/tagged articles into command\r\n"; char txt_help_p_search[] = "/ Article forward search\r\n"; char txt_help_p_star[] = "* Select article\r\n"; char txt_help_p_dot[] = ". Toggle article selection\r\n"; char txt_help_p_coma[] = "@ Reverse article selections\r\n"; char txt_help_p_tilda[] = "~ Undo all selections in thread\r\n"; char txt_mail_art_to[] = "Mail article(s) to [%.*s]> "; char txt_no_mail_address[] = "No mail address"; char txt_no_responses[] = "No responses"; #ifdef HAVE_ISPELL char txt_quit_edit_ispell_send[] = "q)uit, e)dit, i)spell, s)end"; #else char txt_quit_edit_ispell_send[] = "q)uit, e)dit, s)end"; #endif char txt_quit_edit_send[] = "q)uit, e)dit, s)end"; char txt_quit_edit_delete[] = "q)uit, e)dit, d)elete"; char txt_mailing_to[] = "Mailing to %s..."; char txt_mailed[] = "-- %d Article(s) mailed --"; char txt_command_failed_s[] = "Command failed: %s\n"; char txt_mail_quote[] = "In article %M you wrote:"; char txt_resp_to_poster[] = "Responses have been directed to the poster. Post anyway? (y/n): p±ùª¿~ TIN-1_22.BCK­d[SRC.TIN-1_22]LANG.C;2?;ú2%"; char txt_resp_redirect[] = "Responses have been directed to the following newsgroups"; char txt_continue[] = "Continue? (y/n): "; char txt_news_quote[] = "%F wrote:"; char txt_save_filename[] = "Save filename [%s]> "; char txt_art_not_saved[] = "Article not saved"; char txt_no_filename[] = "No filename"; char txt_saving[] = "Saving..."; char txt_art_saved_to[] = "Article saved to %s"; char txt_thread_not_saved[] = "Thread not saved"; char txt_thread_saved_to_many[] = "Thread saved to %s - %s"; char txt_thread_saved_to[] = "Thread saved to %s"; char txt_pipe_to_command[] = "Pipe to command [%.*s]> "; char txt_printing[] = "Printing..."; char txt_printed[] = "%d Article(s) printed"; char txt_append_to_file[] = "File %s exists. Append? (y/n): "; char txt_toggled_rot13[] = "Toggled rot13 encoding"; char txt_use_mime[] = "Use MIME display program for this message? (y/n): "; /* * post.c */ char txt_group_is_moderated[] = "Group %s is moderated. Continue? (y/n): "; char txt_no_arts_posted[] = "No articles have been posted"; char txt_post_an_article[] = "Post an article..."; char txt_post_a_followup[] = "Post a followup..."; char txt_mail_bug_report[] = "Mail bug report..."; char txt_crosspost_group[] = "Crosspost article(s) to group(s) [%s]> "; char txt_no_group[] = "No group"; char txt_crosspost_an_article[] = "Crossposting article..."; char txt_mail_bug_report_confirm[] = "Mail BUG REPORT to %s%s? (y/n): "; char txt_reply_to_author[] = "Reply to author..."; char txt_bad_article[] = "Article to be posted has the errors/warnings noted above. q)uit, e)dit: "; char txt_deleting_art[] = "Deleting article..."; char txt_art_deleted[] = "Article deleted"; char txt_art_cannot_delete[] = "Article cannot be deleted"; char txt_quit_edit_xpost[] = "q)uit, e)dit, p)ost [%.*s]: %c"; char txt_error_header_line_blank[] = "Error: Article starts with blank line instead of header\n\n"; char txt_error_header_line_colon[] = "Error: Header on line %d does not have a colon after the header name:\n%s\n\n"; char txt_error_header_line_space[] = "Error: Header on line %d does not have a space after the colon:\n%s\n\n"; char txt_error_header_line_empty_newsgroups[] = "Error: the \"Newsgroups:\" line lists no newsgroups.\n\n"; char txt_error_header_line_missing_newsgroups[] = "Error: the \"Newsgroups:\" line is missing from the articles header.\n\n"; char txt_error_header_line_missing_subject[] = "Error: the \"Subject:\" line is missing from the articles header.\n\n"; char txt_warn_art_line_too_long[] = "Warning: posting exceeds %d columns. Line %d is the first long one:\n%-100s\n\n"; char txt_error_header_and_body_not_seperate[] = "Error: No blank line found after header.\n\n"; char txt_art_newsgroups[] = "Your article will be posted to the following newsgroup%s:\n"; char txt_warn_not_valid_newsgroup[] = "Warning: \"%s\" is not a valid newsgroup at this site!\n\n"; char txt_error_not_valid_newsgroup[] = "Error: \"%s\" is not a valid newsgroup!\n\n"; char txt_error_header_line_comma[] = "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\n"; char txt_check_article[] = "Check Prepared Article"; char txt_error_from_in_header_not_allowed[] = "Error on line %d: \"From:\" header not allowed (it will be added for you)\n"; /* * prompt.c */ char txt_hit_any_key[] = "-- Press any key to continue --"; char txt_cmdline_hit_any_key[] = "Press any key to continue..."; /* * rcfile.c */ char txt_opt_autosave[] = "1. Auto save : "; char txt_opt_start_editor_offset[] = "2. Editor Offset : "; char txt_opt_mark_saved_read[] = "3. Mark saved read : "; char txt_opt_confirm_action[] = "4. Confirm command : "; char txt_opt_draw_arrow[] = "5. Draw arrow : "; char txt_opt_print_header[] = "6. Print header : "; char txt_opt_pos_first_unread[] = "7. Goto 1st unread : "; char txt_opt_page_scroll[] = "8. Scroll full page: "; char txt_opt_catchup_groups[] = "9. Catchup on quit : "; char txt_opt_thread_arts[] = "10 Thread articles : "; char txt_opt_show_only_unread[] = "11 Show only unread: "; char txt_opt_show_description[] = "12 Show description: "; char txt_opt_show_author[] = "13 Show author : "; char txt_opt_process_type[] = "14 Process type : "; char txt_opt_sort_type[] = "15 Sort article by : "; char txt_opt_savedir[] = "16 Save directory : "; char txt_opt_maildir[] = "17 Mail directory : "; char txt_opt_printer[] = "18 Printer : "; char txt_options_menu[] = "Options Menu"; char txt_show_from_none[] = "None"; char txt_show_from_addr[] = "Addr"; char txt_show_from_name[] = "Name"; char txt_show_from_both[] = "Both"; char txt_post_process_none[] = "None"; char txt_post_process_sh[] = "Shell archive"; char txt_post_process_uudecode[] = "Uudecode"; #ifdef M_AMIGA char txt_post_process_uud_lst_zoo[] = "Uudecode & list lharc archive"; char txt_post_process_uud_ext_zoo[] = "Uudecode & extract lharc archive"; #else char txt_post_process_uud_lst_zoo[] = "Uudecode & list zoo archive"; char txt_post_process_uud_ext_zoo[] = "Uudecode & extract zoo archive"; #endif char txt_post_process_uud_lst_zip[] = "Uudecode & list zip archive"; char txt_post_process_uud_ext_zip[] = "Uudecode & extract zip archive"; char txt_sort_by_nothing[] = "Nothing"; char txt_sort_by_subj_descend[] = "Subject: field (descending)"; char txt_sort_by_subj_ascend[] = "Subject: field (ascending)"; char txt_sort_by_from_descend[] = "From: field (descending)"; char txt_sort_by_from_ascend[] = "From: field (ascending)"; char txt_sort_by_date_descend[] = "Date: field (descending)"; char txt_sort_by_date_ascend[] = "Date: field (ascending)"; char txt_help_autosave[] = "Auto save article/thread by Archive-name: header. toggles & sets."; char txt_help_start_editor_offset[] = "Start editor with line offset. toggles & sets."; char txt_help_confirm_action[] = "Ask for command confirmation. toggles & sets."; char txt_help_print_header[] = "By printing print all/part of header. toggles & sets."; char txt_help_pos_first_unread[] = "Put cursor at first/last unread art in groups. toggles & sets."; char txt_help_show_author[] = "Show Subject & From (author) fields in group menu. toggles & sets."; char txt_help_draw_arrow[] = "Draw -> or highlighted bar for selection. toggles & sets."; char txt_help_mark_saved_read[] = "Mark saved articles/threads as read. toggles & sets."; char txt_help_page_scroll[] = "Scroll half/full page of groups/articles. toggles & sets."; char txt_help_catchup_groups[] = "Ask to mark groups read when quiting. toggles & sets."; char txt_help_thread_arts[] = "Enable/disable threading of articles in all groups. toggles & sets."; char txt_help_show_only_unread[] = "Show all articles or only unread articles. toggles & sets."; char txt_help_show_description[] = "Show short description for each newsgroup. toggles & sets."; char txt_help_post_proc_type[] = "Post process (ie. unshar) saved article/thread. toggles & sets."; char txt_help_sort_type[] = "Sort articles by Subject, From or Date fields. toggles & sets."; char txt_help_savedir[] = "The directory where you want articles/threads saved."; char txt_help_maildir[] = "The directory where articles/threads are to be saved in mailbox format."; char txt_help_printer[] = "The printer program with options that is to be used to print articles/threads."; char txt_select_rcfile_option[] = "Select option by entering number before text. Any other key to save."; /* * save.c */ char txt_post_processing[] = "Post processing..."; char txt_post_processing_finished[] = "-- post processing completed --"; char txt_deleting[] = "Deleting..."; char txt_uudecoding[] = "Uudecoding..."; char txt_extracting_shar[] ="\r\nExtracting %s...\r\n"; char txt_delete_processed_files[] = "Delete saved files that have been post processed? (y/n): "; char txt_post_processing_failed[] = "Post processing failed"; char txt_testing_archive[] = "\r\n\r\nTesting %s archive...\r\n"; char txt_listing_archive[] = "\r\n\r\nListing %s archive...\r\n"; char txt_extracting_archive[] = "\r\n\r\nExtracting %s archive...\r\n"; char txt_checksum_of_file[] = "\r\n\r\nChecksum of %s...\r\n\r\n"; /* * search.c */ char txt_searching[] = "Searching..."; char txt_searching_body[] = "Searching ('q' to abort)... "; /* * select.c */ char txt_reading_all_groups[] = "Reading all groups..."; char txt_reading_new_groups[] = "Reading unread groups..."; char txt_moving[] = "Moving %s..."; #ifdef NO_REGEX char txt_subscribe_pattern[] = "Enter subscribe pattern> "; char txt_unsubscribe_pattern[] = "Enter unsubscribe pattern> "; #else char txt_subscribe_pattern[] = "Enter regex subscribe pattern> "; char txt_unsubscribe_pattern[] = "Enter regex unsubscribe pattern> "; #endif char txt_subscribing[] = "Subscribing..."; char txt_subscribing_to[] = "Subscribing to %s..."; char txt_unsubscribing[] = "Unsubscribing..."; char txt_unsubscribing_from[] = "Unsubscribing from %s..."; char txt_subscribed_num_groups[] = "subscribed to %d groups"; char txt_unsubscribed_num_groups[] = "unsubscribed from %d groups"; char txt_del_group_in_newsrc[] = "Delete %s from .newsrc? (y/n): "; char txt_group_deleted[] = "Group %s deleted"; char txt_group_undeleted[] = "Group undeleted"; char txt_mark_group_read[] = "Mark group %s as read? (y/n): "; char txt_no_groups_to_delete[] = "No groups to delete"; char txt_reset_newsrc[] = "Reset newsrc? (y/n): "; char txt_post_newsgroup[] = "Post newsgroup> "; char txt_yanking_all_groups[] = "Yanking in all groups..."; char txt_yanking_sub_groups[] = "Yanking in subscribed to groups..."; char txt_no_groups_to_read[] = "No more groups to read"; char txt_added_groups[] = "Added %d group%s"; char txt_plural[] = "s"; char txt_no_groups_to_yank_in[] = "No more groups to yank in"; char txt_group_selection[] = "Group Selection"; char txt_spooldir_selection[] = "Spooldir Selection (%d)"; char txt_select_group[] = "Select group> "; char txt_select_spooldir[] = "Select spooldir> "; char txt_help_g_4[] = "4$ Select group 4 ($=select last group)\r\n"; char txt_help_g_ctrl_r[] = "^R Reset .newsrc\r\n"; char txt_help_g_ctrl_k[] = "^KZ Delete (Z=undelete) group from .newsrc\r\n"; char txt_help_g_cr[] = " Read current group\r\n"; char txt_help_g_c[] = "c Mark group as all read\r\n"; char txt_help_g_d[] = "d Toggle display of groupname or groupname and description\r\n"; char txt_help_g_l[] = "l List & select another spooldir\r\n"; char txt_help_g_tab[] = "n Goto next group with unread news and enter it\r\n"; char txt_help_n[] = "N Goto next group with unread news\r\n"; char txt_help_g_q[] = "qQ Quit\r\n"; char txt_help_g_r[] = "r Toggle display to show all / only unread subscribed to groups\r\n"; char txt_help_W[] = "W List articles posted by user\r\n"; char txt_help_g_y[] = "y Yank in subscribed/unsubscribed from .newsrc\r\n"; char txt_help_g_z[] = "z Mark current group as unread\r\n"; char txt_help_y[] = "Y Yank in active file to see any new news\r\n"; char txt_help_g_search[] = "/? Group forward (?=backward) search\r\n"; char txt_newsgroup[] = "Goto newsgroup [%s]> "; char txt_newsgroup_position[] = "Position %s in group list (1,2,..,$) [%d]> "; /* * signal.c */ char txt_resizing_window[] = "resizing window"; char txt_suspended_message[] = "\nStopped. Type 'fg' to restart TIN\n"; /* * spooldir.c */ char txt_spooldirs_not_supported[] = "Multiple spooldirs are not supported"; char txt_no_spooldirs[] = "No spooldirs"; char txt_spooldir_server_error_1[] = "Server does not appear to support the spooldir command\n"; char txt_spooldir_server_error_2[] = "Reconfigure the news reader or the server & try again.\n"; char txt_cannot_change_spooldir[] = "Cannot change to valid spooldir. Exiting..."; char txt_changing_spooldir_to[] = "Changing spooldir to"; /* * thread.c */ char txt_no_resps_in_thread[] = "No responses to list in current thread"; char txt_help_t_0[] = "0 Goto the base article in current thread\r\n"; char txt_help_t_4[] = "4$ Goto response 4 ($=goto last response) in current thread\r\n"; char txt_help_t_cr[] = " Read current response\r\n"; char txt_help_t_tab[] = " Goto next unread response\r\n"; char txt_help_t_K[] = "K Mark thread as read & return\r\n"; /* * xref.c */ char txt_processing_xrefs[] = "Processing Xref's..."; ð*[SRC.TIN-1_22]MAIL.C;2+,Ø. //€ 4 å-d0@î123KÿPWO 56o¤Å­‹—7€›$Æ­‹—89€]V‚—G/€HªJÿ/* * Project : tin - a Usenet reader * Module : mail.c * Author : I.Lea * Created : 02-10-92 * Updated : 14-05-93 * Notes : Mail handling routines for creating pseudo newsgroups * Copyright : (c) Copyright 1991-93 by Iain Lea * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" /* * Load the mail active file into active[] */ void read_mail_active_file () { #if !defined(INDEX_DAEMON) && defined(HAVE_MAIL_HANDLING) FILE *fp; char buf[LEN]; char spooldir[PATH_LEN]; int i; long h, min, max; if ((update && update_fork) || ! update) { wait_message (txt_reading_mail_active_file); } /* * Open the mail active file & if we can't create an empty one */ if ((fp = open_mail_active_fp ("r")) == (FILE *) 0) { if (cmd_line) { fputc ('\n', stderr); } error_message (txt_cannot_open, mail_active_file); write_mail_active_file (); return; } if (num_active == -1) { num_active = 0; for (i = 0; i < TABLE_SIZE; i++) { group_hash[i] = -1; } } while (fgets (buf, sizeof (buf), fp) != NULL) { if (! parse_active_line (buf, &max, &min, spooldir)) { continue; } /* * Load group into group hash table */ if (num_active >= max_active) { expand_active (); } h = hash_groupname (buf); if (group_hash[h] == -1) { group_hash[h] = num_active; } else { /* hash linked list chaining */ for (i=group_hash[h]; active[i].next >= 0; i=active[i].next) { if (strcmp (active[i].name, buf) == 0) { goto read_mail_active_continue; /* kill dups */ } } if (strcmp (active[i].name, buf) == 0) goto read_mail_active_continue; active[i].next = num_active; } /* * Load group info. */ active[num_active].type = GROUP_TYPE_MAIL; active[num_active].name = str_dup (buf); active[num_active].spooldir = str_dup (spooldir); active[num_active].description = (char *) 0; active[num_active].max = max; active[num_active].min = min; active[num_active].moderated = 'y'; active[num_active].next = -1; /* hash chaining */ active[num_active].my_group = UNSUBSCRIBED; /* not in my_group[] yet */ active[num_active].newsrcmax = max; active[num_active].newsrcmin = min; active[num_active].newsrcsize = 0; active[num_active].newsrcupdate = FALSE; active[num_active].newsrc = NULL; active[num_active].unread = 0; num_active++; read_mail_active_continue:; } fclose (fp); if ((cmd_line && ! update && ! verbose) || (update && update_fork)) { wait_message ("\n"); } #endif /* INDEX_DAEMON */ } /* * Write the mail groups from active[] to ~/.tin/mactive */ void write_mail_active_file () { #if !defined(INDEX_DAEMON) && defined(HAVE_MAIL_HANDLING) FILE *fp; register int i; if ((fp = open_mail_active_fp ("w")) == (FILE *) 0) { return; } /* * Load group into group hash table */ fprintf (fp, "# Mail active file. Format is like news active file:\n"); fprintf (fp, "# groupname max.artnum min.artnum /maildir\n#\n"); for (i = 0 ; i < num_active ; i++) { if (active[i].type == GROUP_TYPE_MAIL) { fprintf (fp, "%s %08ld %08ld %s\n", active[i].name, active[i].max, active[i].min, active[i].spooldir); } } fclose (fp); #endif /* INDEX_DAEMON */ } /* * Load the text description from ~/.tin/mailgroups for each mail group into * the active[] array. */ void read_mailgroups_file () { #ifndef INDEX_DAEMON FILE *fp; if (show_description == FALSE || save_news || catchup) { return; } if ((fp = open_mailgroups_fp ()) != (FILE *) 0) { wait_message (txt_reading_mailgroups_file); read_groups_descriptions (fp, (FILE *) 0); fclose (fp); if (cmd_line && ! update && ! verbose) { wait_message ("\n"); } } #endif /* INDEX_DAEMON */ } /* * Load the text description from LIBDIR/newsgroups for each group into the * active[] array. Save a copy locally if reading via NNTP to save bandwidth. */ void read_newsgroups_file () { #ifndef INDEX_DAEMON FILE *fp; FILE *fp_save = (FILE *) 0; if (show_description == FALSE || save_news || catchup) { return; } wait_message (txt_reading_newsgroups_file); if ((fp = open_newsgroups_fp ()) != (FILE *) 0) { if (read_news_via_nntp && ! read_local_newsgroups_file) { #ifdef VMS fp_save = fopen (local_newsgroups_file, "w", "fop=cif"); #else fp_save = fopen (local_newsgroups_file, "w"); #endif } read_groups_descriptions (fp, fp_save); fclose (fp); if (fp_save) { fclose (fp_save); read_local_newsgroups_file = TRUE; } } if (cmd_line && ! update && ! verbose) { wait_message ("\n"); } #endif /* INDEX_DAEMON */ } /* * Read groups descriptions from opened file & make local backup copy * of all groups that don't have a 'x' in the active file moderated * field & if reading groups of type GROUP_TYPE_NEWS. */ void read_groups_descriptions (fp, fp_save) FILE *fp; FILE *fp_save; { char buf[LEN]; char group[PATH_LEN]; char *p, *q; int i; while (fgets (buf, sizeof (buf), fp) != NULL) { if (buf[0] == '#' || buf[0] == '\n') { continue; } p = (char *) strchr (buf, '\n'); if (p != (char *) 0) { *p = '\0'; } for (p = buf, q = group ; *p && *p != ' ' && *p != '\t' ; p++, q++) { *q = *p; } *q = '\0'; while (*p == '\t' || *p == ' ') { p++; } i = find_group_index (group); if (i >= 0 && active[i].description == (char *) 0) { active[i].description = str_dup (p); if (active[i].type == GROUP_TYPE_NEWS) { if (fp_save && read_news_via_nntp && ! read_local_newsgroups_file) { fprintf (fp_save, "%s\n", buf); } } } } } ;ð*[SRC.TIN-1_22]MAIN.C;6+,+.//€ 4‘-d0@î123KÿPWO56€I›²o—7@ös³o—89€]V‚—G/€HªJÿ/* * Project : tin - a Usenet reader * Module : main.c * Author : I.Lea & R.Skrenta * Created : 01-04-91 * Updated : 05-09-92 * Notes : * Copyright : (c) Copyright 1991-93 by Iain Lea & Rich Skrenta * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" static char **cmdargs; static int num_cmdargs; static int max_cmdargs; /* * OK lets start the ball rolling... */ void main (argc, argv) int argc; char *argv[]; { int start_groupnum = 0; cmd_line = TRUE; debug = 0; /* debug OFF */ set_signal_handlers (); base_name (argv[0], progname); #ifdef VMS argv[0] = progname; #endif sprintf (page_header, "%s %s PL%s %s", progname, VERSION, PATCHLEVEL, OS); sprintf (cvers, txt_copyright_notice, page_header); #if defined(NNTP_ONLY) || defined(CDROM_ONLY) read_news_via_nntp = TRUE; #else /* * rtin/cdtin so read news remotely via NNTP */ if (progname[0] == 'r' || (progname[0] == 'c' && progname[1] == 'd' )) { # ifdef NNTP_ABLE read_news_via_nntp = TRUE; # else error_message (txt_option_not_enabled, "-DNNTP_ABLE"); exit (1); # endif } #endif /* * Set up initial array sizes, char *'s: homedir, newsrc, etc. */ init_alloc (); hash_init (); init_selfinfo (); /* * Process envargs & command l ine options */ read_cmd_line_options (argc, argv); if (! read_news_via_nntp) newsrc_active = FALSE; if (update_fork || (update && verbose) || !update) { error_message (cvers, ""); } /* * If specified connect to (cdrom pseudo) nntp server */ if (nntp_open () == -1) { exit (1); } /* * Log username info to local/central logfile (NNTP XUSER) */ log_user (); /* * Read message of the day file from newsadmin */ read_motd_file (); /* * Load the mail & news active files into active[] */ read_mail_active_file (); read_news_active_file (); /* * Load the group specific attributes file into active[] */ read_attributes_file (); /* * Quick post an article & exit if -w specified */ if (post_article_and_exit) { setup_screen (); quick_post_article (); tin_done (0); } /* * Read text descriptions for mail & news groups from * ~/.tin/mailgroups & LIBDIR/newsgroups respectively */ read_mailgroups_file (); read_newsgroups_file (); debug_print_active (); if (create_mail_save_dirs ()) { write_rcfile (); } if (! read_cmd_line_groups ()) { backup_newsrc (); read_newsrc (TRUE); toggle_my_groups (show_only_unread_groups, ""); } /* * Read in users kill/auto-select (hot) file */ killed_articles = read_kill_file (); /* * Check/start if any new/unread articles */ start_groupnum = check_for_any_new_news (check_any_unread, start_any_unread); /* * Mail any new articles to specified user * or * Save any new articles to savedir structure for later reading */ save_or_mail_new_news (); /* * Update index files */ update_index_files (); /* * Set up screen and switch to raw mode */ if (! InitScreen ()) { error_message (txt_screen_init_failed, progname); exit (1); } setup_screen (); /* * If first time print welcome screen and auto-subscribe * to groups specified in /usr/lib/news/subscribe locally * or via NNTP if reading news remotely (LIST SUBSCRIBE) */ if (created_rcdir && !update) { show_intro_page (); } /* * Work loop */ selection_index (start_groupnum); } /* * process command line options */ void read_cmd_line_options (argc, argv) int argc; char *argv[]; { int ch; envargs (&argc, &argv, "TINRC"); #ifdef INDEX_DAEMON while ((ch = getopt (argc, argv, "D:f:hI:PvV")) != EOF) { #else while ((ch = getopt (argc, argv, "cD:f:hHI:m:M:np:PqrRs:SuUvVwzZ")) != EOF) { #endif switch (ch) { case 'c': catchup = TRUE; update = TRUE; break; case 'D': /* debug mode 1=NNTP 2=ALL */ #ifdef DEBUG debug = atoi (optarg); #else error_message (txt_option_not_enabled, "-DDEBUG"); exit (1); #endif break; case 'f': /* active (tind) / newsrc (tin) file */ #ifdef INDEX_DAEMON my_strncpy (news_active_file, optarg, sizeof (news_active_file)); #else my_strncpy (newsrc, optarg, sizeof (newsrc)); #endif break; case 'H': show_intro_page (); exit (1); break; #if !defined(NNTP_ONLY) case 'I': my_strncpy (index_newsdir,  optarg, sizeof (index_newsdir)); my_mkdir (index_newsdir, 0777); break; #endif case 'm': my_strncpy (default_maildir, optarg, sizeof (default_maildir)); break; case 'M': /* mail new news to specified user */ my_strncpy (mail_news_user, optarg, sizeof (mail_news_user)); mail_news = TRUE; update = TRUE; break; case 'n': #ifdef NNTP_ABLE newsrc_active = TRUE; #else error_message (txt_option_not_enabled, "-DNNTP_ABLE"); exit (1); #endif break; case 'p': my_strncpy (cmd_line_printer, optarg, sizeof (cmd_line_printer)); break; case 'P': /* stat every art for a through purge */ purge_index_files = TRUE; break; case 'q': check_for_new_newsgroups = FALSE; break; case 'r': /* read news remotely from default NNTP server */ #ifdef NNTP_ABLE read_news_via_nntp = TRUE; #else error_message (txt_option_not_enabled, "-DNNTP_ABLE"); exit (1); #endif break; case 'R': /* read news saved by -S option */ error_message ("%s: Option -R not yet implemented.", progname); exit (1); break; case 's': my_strncpy (default_savedir, optarg, sizeof (default_savedir)); break; case 'S': /* save new news to dir structure */ save_news = TRUE; update = TRUE; break; case 'u': /* update index files */ update = TRUE; show_description = FALSE; break; case 'U': /* update index files in background */ update_fork = TRUE; update = TRUE; break; case 'v': /* verbose mode */ verbose = TRUE; break; case 'V': #if defined(__DATE__) && defined(__TIME__) sprintf (msg, "Version: %s PL%s %s %s", VERSION, PATCHLEVEL, __DATE__, __TIME__); #else sprintf (msg, "Version: %s PL%s", VERSION, PATCHLEVEL); #endif error_message (msg, ""); exit (1); break; case 'w': /* post article & exit */ post_article_and_exit = TRUE; break; case 'z': start_any_unread = TRUE; update = TRUE; break; case 'Z': check_any_unread = TRUE; update = TRUE; break; case 'h': case '?': default: usage (progname); exit (1); } } cmdargs = argv; num_cmdargs = optind; max_cmdargs = argc; } /* * usage */ void usage (progname) char *progname; { #ifndef INDEX_DAEMON error_message ("%s A Usenet reader.\n", cvers); #else error_message ("%s Tin index file daemon.\n", cvers); #endif error_message ("Usage: %s [options] [newsgroups]", progname); #ifndef INDEX_DAEMON error_message (" -c mark all news as read in subscribed newsgroups (batch mode)", ""); error_message (" -f file subscribed to newsgroups file [default=%s]", newsrc); #else error_message (" -f file active newsgroups file [default=%s]", newsrc); #endif error_message (" -h help", ""); #ifndef INDEX_DAEMON error_message (" -H help information about %s", progname); #endif error_message (" -I dir news index file directory [default=%s]", index_newsdir); #ifndef INDEX_DAEMON error_message (" -m dir mailbox directory [default=%s]", default_maildir); error_message (" -M user mail new news to specified user (batch mode)", ""); #ifdef NNTP_ABLE error_message (" -n only read subscribed .newsrc groups from NNTP server", ""); #endif error_message (" -p file print program with options [default=%s]", DEFAULT_PRINTER); error_message (" -P purge any expired articles from index files", ""); error_message (" -q quick start by not checking for new newsgroups", ""); # if defined(NNTP_ABLE) && !defined(NNTP_ONLY) if (! read_news_via_nntp) { error_message (" -r read news remotely from default NNTP server", ""); } # endif /* NNTP_ABLE */ error_message (" -R read news saved by -S option", ""); error_message (" -s dir save news directory [default=%s]", default_savedir); error_message (" -S save new news for later reading (batch mode)", ""); # if !defined(NNTP_ONLY) error_message (" -u update index files (batch mode)", ""); error_message (" -U update index files in the background while reading news", ""); # endif /* NNTP_ONLY */ #else error_message (" -P purge any expired articles from index files", ""); #endif /* INDEX_DAEMON */ error_message (" -v verbose output for batch mode options", ""); #ifndef INDEX_DAEMON error_message (" -w post an article and exit", ""); error_message (" -z start if any unread news", ""); error_message (" -Z return status indicating if any unread news (batch mode)", ""); #endif error_message ("\nMail bug reports/comments to %s", BUG_REPORT_ADDRESS); } /* * check/start if any new/unread articles */ int check_for_any_new_news (check_any_unread, start_any_unread) int check_any_unread; int start_any_unread; { int i = 0; if (check_any_unread) { i = check_start_save_any_news (CHECK_ANY_NEWS); exit (i); } if (start_any_unread) { i = check_start_save_any_news (START_ANY_NEWS); if (i == -1) { /* no new/unread news so exit */ exit (0); } update = FALSE; } return (i); } /* * mail any new articles to specified user * or * save any new articles to savedir structure for later reading */ void save_or_mail_new_news () { int i; if (mail_news || save_news) { i = catchup; /* set catchup to FALSE */ catchup = FALSE; do_update (); catchup = i; /* set catchup to previous value */ if (mail_news) { check_start_save_any_news (MAIL_ANY_NEWS); } else { check_start_save_any_news (SAVE_ANY_NEWS); } tin_done (0); } } /* * update index files */ void update_index_files () { if (update || update_fork) { if (!catchup && (read_news_via_nntp && xindex_supported)) { error_message ("%s: Updating of index files not supported", progname); tin_done (1); } cCOLS = 132; /* set because curses has not started */ #ifdef HAVE_FORK if (update_fork) { catchup = FALSE; /* turn off msgs when running forked */ verbose = FALSE; switch (fork ()) { /* fork child to update indexes in background */ case -1: /* error forking */ perror_message ("Failed to start background indexing process", ""); break; case 0: /* child process */ create_index_lock_file (lock_file); process_id = getpid (); #ifdef BSD setpgrp (0, process_id); /* reset process group leader to this process */ # ifdef TIOCNOTTY { int fd; if ((fd = open ("/dev/tty", O_RDWR)) >= 0) { ioctl (fd, TIOCNOTTY, (char *) NULL); close (fd); } } # endif #else setpgrp (); signal (SIGHUP, SIG_IGN); /* make immune from process group leader death */ #endif signal (SIGQUIT, SIG_IGN); /* stop indexing being interrupted */ signal (SIGALRM, SIG_IGN); /* stop indexing resyning active file */ nntp_open (); /* connect server if we are using nntp */ default_thread_arts = FALSE; /* stop threading to run faster */ do_update (); tin_done (0); break; default: /* parent process*/ break; } update = FALSE; } else #endif /* HAVE_FORK */ { create_index_lock_file (lock_file); default_thread_arts = FALSE; /* stop threading to run faster */ do_update (); tin_done (0); } } } /* * display page of general info. for first time user. */ void show_intro_page () { if (cmd_line) { wait_message (cvers); } else { ClearScreen (); center_line (0, TRUE, cvers); Raw (FALSE); } printf ("\n\nWelcome to tin, a full screen threaded Netnews reader. It can read news locally\n"); printf ("(ie. /news) or remotely (-r option) from a NNTP (N T½rã~ TIN-1_22.BCK+d[SRC.TIN-1_22]MAIN.C;6Ÿšetwork News Transport\n"); printf ("Protocol) server. tin -h lists the available command line options.\n\n"); printf ("Tin has five newsreading levels, the newsgroup selection page, the spooldir\n"); printf ("selection page, the group index page, the thread listing page and the article\n"); printf ("viewer. Help is available at each level by pressing the 'h' command.\n\n"); printf ("Move up/down by using the terminal arrow keys or 'j' and 'k'. Use PgUp/PgDn or\n"); printf ("Ctrl-U and Ctrl-D to page up/down. Enter a newsgroup by pressing RETURN/TAB.\n\n"); printf ("Articles, threads, tagged articles or articles matching a pattern can be mailed\n"); printf ("('m' command), printed ('o' command), saved ('s' command), piped ('|' command).\n"); printf ("Use the 'w' command to post a news article, the 'f'/'F' commands to post a\n"); printf ("follow-up to an existing news article and the 'r'/'R' commands to reply via\n"); printf ("mail to an existing news articles author. The 'M' command allows the operation\n"); printf ("of tin to be configured via a menu.\n\n"); printf ("For more information read the manual page, README, INSTALL, TODO and FTP files.\n"); printf ("Please send bug reports/comments to the programs author with the 'R' command.\n"); fflush (stdout); if (! cmd_line) { Raw (TRUE); continue_prompt (); } } int read_cmd_line_groups () { char buf[PATH_LEN]; int matched = FALSE; int num = num_cmdargs; register int i; if (num < max_cmdargs) { group_top = 0; while (num < max_cmdargs) { sprintf (buf, "Matching %s groups...", cmdargs[num]); wait_message (buf); for (i = 0 ; i < num_active ; i++) { if (wildmat (active[i].name, cmdargs[num])) { if (add_group (active[i].name, TRUE) < 0) { error_message (txt_not_in_active_file, active[i].name); } } } num++; } matched = TRUE; } return (matched); } Nð*[SRC.TIN-1_22]MAKEFILE.;81+,. //€ 4 L-d0ú123KÿPWO 56üâí”’—7`ñsî”’—89€šIÊ’—G/€HªJÿ# Makefile for tin - for tin compiler flag options read INSTALL and README. # CC = gcc DEFINES = VMS,MULTINET,SLOW_SCREEN_UPDATE,NNTP_DEFAULT_SERVER="""news.duq.edu""" #CFLAGS = /noopt/debug/include=([.vms],[.sio])/define=($(DEFINES)) CFLAGS = /opt=2/warn/include=([.vms],[.sio])/define=($(DEFINES)) LFLAGS = /nomap#/map/debug LIBS = [.sio]libsio/libr LD = link YACC = bison/fixed # From: address in posted articles (don't use both - read the INSTALL file) NNTP_INEWS_GATEWAY= NNTP_INEWS_DOMAIN= #.erlm.siemens.de PROJECT = tin EXE = tin.exe EXED = tind.exe MAKE = make #BASE_VER= 1.21/tin-1.21 BASE_VER= 170993 VER = 1.22 MAIL_ADDR = "iain.lea@erlm.siemens.de" HFILES = config.h tin.h extern.h nntplib.h proto.h stpwatch.h amiga.h os_2.h \ win32.h CFILES = active.c amiga.c art.c curses.c debug.c envarg.c feed.c getline.c \ group.c hashstr.c help.c inews.c init.c kill.c lang.c mail.c \ main.c memory.c misc.c newsrc.c nntplib.c open.c os_2.c page.c\ parsdate.y post.c prompt.c rcfile.c save.c screen.c search.c \ select.c sigfile.c signal.c spooldir.c strftime.c thread.c \ wildmat.c win32.c xref.c vms.c OFILES = active.obj amiga.obj art.obj curses.obj debug.obj envarg.obj \ feed.obj getline.obj group.obj hashstr.obj help.obj inews.obj \ init.obj kill.obj lang.obj mail.obj main.obj memory.obj misc.obj \ newsrc.obj nntplib.obj open.obj os_2.obj page.obj parsdate.obj \ post.obj prompt.obj rcfile.obj save.obj screen.obj search.obj \ select.obj sigfile.obj signal.obj spooldir.obj strftime.obj \ thread.obj wildmat.obj win32.obj xref.obj vms.obj ALL_FILES = $(HFILES) patchlev.h $(CFILES) .c.obj: $(CC) $(CFLAGS) /obj=$*.obj $*.c # For VAX/VMS vms: linkit vmslibcmd = @[.vms]makevmslib siocmd = @[.sio]makesio vmslib: $$ $(vmslibcmd) sio: $$ $(siocmd) linkit: vmslib sio $(OFILES) @echo "Linking $(EXE) v$(VER)..." $(LD) $(LFLAGS) /exe=$(EXE) objs.opt/opt,[.vms]gcc-multinet.opt/opt,$(LIBS) @dir/size $(EXE) test: test.obj vms.obj $(LD) $(LFLAGS) /exe=test.exe $^,gnu_cc:[000000]gcclib/lib tags: @echo "Generating tags (results in ./tags)..." @del tags;* @etags $(HFILES) patchlev.h $(CFILES) active.obj: active.c $(HFILES) amiga.obj: amiga.c $(HFILES) art.obj: art.c $(HFILES) curses.obj: curses.c $(HFILES) debug.obj: debug.c $(HFILES) envarg.obj: envarg.c $(HFILES) feed.obj: feed.c $(HFILES) getline.obj: getline.c $(HFILES) group.obj: group.c $(HFILES) hashstr.obj: hashstr.c $(HFILES) help.obj: help.c $(HFILES) inews.obj: inews.c $(HFILES) init.obj: init.c $(HFILES) kill.obj: kill.c $(HFILES) lang.obj: lang.c $(HFILES) mail.obj: mail.c $(HFILES) patchlev.h main.obj: main.c $(HFILES) patchlev.h memory.obj: memory.c $(HFILES) misc.obj: misc.c $(HFILES) newsrc.obj: newsrc.c $(HFILES) nntplib.obj: nntplib.c $(HFILES) open.obj: open.c $(HFILES) patchlev.h os_2.obj: os_2.c $(HFILES) page.obj: page.c $(HFILES) parsdate.obj: parsdate.y $(HFILES) post.obj: post.c $(HFILES) patchlev.h prompt.obj: prompt.c $(HFILES) rcfile.obj: rcfile.c $(HFILES) save.obj: save.c $(HFILES) screen.obj: screen.c $(HFILES) search.obj: search.c $(HFILES) select.obj: select.c $(HFILES) sigfile.obj: sigfile.c $(HFILES) signal.obj: signal.c $(HFILES) spooldir.obj: spooldir.c $(HFILES) strftime.obj: strftime.c $(HFILES) thread.obj: thread.c $(HFILES) wildmat.obj: wildmat.c win32.obj: win32.c win32.h xref.obj: xref.c $(HFILES) vms.obj: vms.c tin.h ð*[SRC.TIN-1_22]MANIFEST.;1+,i.//€ 4™-d0@î123KÿPWO56`3t…—7À$WFê‘—89 „ìø‘—G/€HªJÿMANIFEST for tin-1.22 (Thu Sep 23 09:29:16 CDT 1993) ---------------------------------------------------- 22540 Makefile 2671 Makefile.ami 4099 Makefile.bcc 10751 Makefile.icc 106 MANIFEST 4108 README 4987 README.AMI 5650 README.OS2 6728 CHANGES 15549 INSTALL 3913 HACKERS 7983 TODO 2945 FTP 5458 BETA.3 4976 strftime.3 58499 tin.1 2196 wildmat.3 82122 tin.nrf 1345 tin.lsm 1800 actived.c 1263 README.NNTP 3337 INSTALL.NNTP 2945 common.patch 31371 server.patch 3672 xindex.c 3149 xmotd.c 2469 xoverview.c 1344 xuser.c 7467 config.h 28195 tin.h 22923 extern.h 5101 nntplib.h 30773 proto.h 1271 stpwatch.h 1865 amiga.h 2305 os_2.h 1245 win32.h 758 patchlev.h 32293 active.c 5907 amiga.c 35120 art.c 15034 curses.c 6687 debug.c 2828 envarg.c 16318 feed.c 11433 getline.c 35452 group.c 2532 hashstr.c 7773 help.c 9222 inews.c 21880 init.c 13894 kill.c 31082 lang.c 5777 mail.c 14187 main.c 10908 memory.c 31252 misc.c 27172 newsrc.c 21781 nntplib.c 20171 open.c 6281 os_2.c 27536 page.c 22914 parsdate.y 40096 post.c 3161 prompt.c 33579 rcfile.c 29414 save.c 3146 screen.c 9686 search.c 29500 select.c 5110 sigfile.c 11697 signal.c 14469 spooldir.c 5888 strftime.c 22811 thread.c 4993 wildmat.c 7611 win32.c 2716 xref.c 1059190 total ð*[SRC.TIN-1_22]MEMORY.C;2+,¾.//€ 4Ó-d0@î123KÿPWO56 c+þ膗7`‹åþ膗89€]V‚—G/€HªJÿ,/* * Project : tin - a Usenet reader * Module : memory.c * Author : I.Lea & R.Skrenta * Created : 01-04-91 * Updated : 05-09-93 * Notes : * Copyright : (c) Copyright 1991-93 by Iain Lea & Rich Skrenta * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" /* * Dynamic arrays maximum & current sizes * num_* values are one past top of used part of array */ int max_active = 0; int num_active = -1; int max_active_size = 0; int num_active_size = 0; int max_art = 0; int max_kill = 0; int num_kill = 0; int max_save = 0; int num_save = 0; int max_spooldir = 0; int num_spooldir = 0; /* * Dynamic arrays */ int *my_group; /* .newsrc --> active[] */ long *base; /* base articles for each thread */ struct t_group *active; /* active newsgroups */ struct t_active_size *active_size; /* active file sizes on differnet servers */ struct t_article *arts; /* articles headers in current group */ struct t_save *save; /* sorts articles before saving them */ struct t_spooldir *spooldirs; /* spooldirs on NNTP server (cdrom) */ /* * Dynamic table management * These settings are memory conservative: small initial allocations * and a 50% expansion on table overflow. A fast vm system with * much memory might want to start with higher initial allocations * and a 100% expansion on overflow, especially for the arts[] array. */ void init_alloc () { /* * active file arrays */ max_active = get_active_num (); max_active_size = DEFAULT_ACTIVE_SIZE_NUM; active = (struct t_group *) my_malloc ((unsigned) sizeof(*active) * max_active); active_size = (struct t_active_size *) my_malloc ((unsigned) sizeof(*active_size) * max_active_size); my_group = (int *) my_malloc ((unsigned) sizeof(int) * max_active); /* * article headers array */ max_art = DEFAULT_ARTICLE_NUM; arts = (struct t_article *) my_malloc ((unsigned) sizeof(*arts) * max_art); base = (long *) my_malloc ((unsigned) sizeof(long) * max_art); /* * kill file array */ max_kill = DEFAULT_KILL_NUM; killf = (struct t_kill *) my_malloc ((unsigned) sizeof(*killf) * max_kill); /* * save file array */ max_save = DEFAULT_SAVE_NUM; save = (struct t_save *) my_malloc ((unsigned) sizeof(*save) * max_save); /* * spooldirs array */ max_spooldir = DEFAULT_SPOOLDIR_NUM; spooldirs = (struct t_spooldir *) my_malloc ((unsigned) sizeof(*spooldirs) * max_spooldir); screen = (struct t_screen *) 0; } void expand_art () { max_art += max_art / 2; /* increase by 50% */ arts = (struct t_article *) my_realloc ((char *) arts, (unsigned) sizeof(*arts) * max_art); base = (long *) my_realloc ((char *) base, (unsigned) sizeof(long) * max_art); } void expand_active () { max_active += max_active / 2; /* increase by 50% */ if (active == (struct t_group *) 0) { active = (struct t_group *) my_malloc ((unsigned) sizeof (*active) * max_active); my_group = (int *) my_malloc ((unsigned) sizeof (int) * max_active); } else { active = (struct t_group *) my_realloc((char *) active, (unsigned) sizeof (*active) * max_active); my_group = (int *) my_realloc((char *) my_group, (unsigned) sizeof (int) * max_active); } } void expand_kill () { max_kill += max_kill / 2; /* increase by 50% */ killf = (struct t_kill *) my_realloc((char *) killf, (unsigned) sizeof (struct t_kill) * max_kill); } void expand_save () { max_save += max_save / 2; /* increase by 50% */ save = (struct t_save *) my_realloc((char *) save, (unsigned) sizeof (struct t_save) * max_save); } void expand_spooldirs () { max_spooldir += max_spooldir / 2; /* increase by 50% */ spooldirs = (struct t_spooldir *) my_realloc((char *) spooldirs, (unsigned) sizeof (struct t_spooldir) * max_spooldir); } void expand_active_size () { max_active_size += max_active_size / 2; /* increase by 50% */ active_size = (struct t_active_size *) my_realloc((char *) active_size, (unsigned) sizeof(struct t_active_size) * max_active_size); } void init_screen_array (allocate) int allocate; { int i; if (allocate) { screen = (struct t_screen *) my_malloc ( (unsigned) sizeof (struct t_screen) * cLINES+1); for (i=0 ; i < cLINES ; i++) { screen[i].col = (char *) my_malloc ((unsigned) cCOLS+2); } } else { if (screen != (struct t_screen *) 0) { for (i=0 ; i < cLINES ; i++) { if (screen[i].col != (char *) 0) { free ((char *) screen[i].col); screen[i].col = (char *) 0; } } free ((char *) screen); screen = (struct t_screen *) 0; } } } void free_all_arrays () { hash_reclaim (); init_screen_array (FALSE); free_art_array (); if (arts != (struct t_article *) 0) { free ((char *) arts); arts = (struct t_article *) 0; } free_active_arrays (); if (base != (long *) 0) { free ((char *) base); base = (long *) 0; } if (killf != (struct t_kill *) 0) { free_kill_array (); if (killf != (struct t_kill *) 0) { free ((char *) killf); killf = (struct t_kill *) 0; } } if (save != (struct t_save *) 0) { free_save_array (); if (save != (struct t_save *) 0) { free ((char *) save); save = (struct t_save *) 0; } } if (spooldirs != (struct t_spooldir *) 0) { free_spooldirs_array (); if (spooldirs != (struct t_spooldir *) 0) { free ((char *) spooldirs); spooldirs = (struct t_spooldir *) 0; } } if (active_size != (struct t_active_size *) 0) { free_active_size_array (); if (active_size != (struct t_active_size *) 0) { free ((char *) active_size); active_size = (struct t_active_size *) 0; } } } void free_art_array () { register int i; for (i=0 ; i < top ; i++) { arts[i].artnum = 0L; arts[i].thread = ART_EXPIRED; arts[i].inthread = FALSE; arts[i].unread = ART_UNREAD; arts[i].killed = FALSE; arts[i].tagged = FALSE; arts[i].hot = FALSE; arts[i].date = 0L; if (arts[i].part != (char *) 0) { free ((char *) arts[i].part); arts[i].part = (char *) 0; } if (arts[i].patch != (char *) 0) { free ((char *) arts[i].patch); arts[i].patch = (char *) 0; } if (arts[i].xref != NULL) { free ((char *) arts[i].xref); arts[i].xref = NULL; } } } void free_attributes_array () { register int i; for (i = 0 ; i < num_active ; i++) { if (active[i].attribute.maildir != (char *) 0 && active[i].attribute.maildir != default_maildir) { free ((char *) active[i].attribute.maildir); active[i].attribute.maildir = (char *) 0; } if (active[i].attribute.savedir != (char *) 0 && active[i].attribute.savedir != default_savedir) { free ((char *) active[i].attribute.savedir); active[i].attribute.savedir = (char *) 0; } if (active[i].attribute.organization != (char *) 0 && active[i].attribute.organization != default_organization) { free ((char *) active[i].attribute.organization); active[i].attribute.organization = (char *) 0; } if (active[i].attribute.sigfile != (char *) 0 && active[i].attribute.sigfile != default_sigfile) { free ((char *) active[i].attribute.sigfile); active[i].attribute.sigfile = (char *) 0; } if (active[i].attribute.printer != (char *) 0 && active[i].attribute.printer != default_printer) { free ((char *) active[i].attribute.printer); active[i].attribute.printer = (char *) 0; } if (active[i].attribute.followup_to != (char *) 0) { free ((char *) active[i].attribute.followup_to); active[i].attribute.followup_to = (char *) 0; } } } void free_active_arrays () { register int i; if (my_group != (int *) 0) { /* my_group[] */ free ((char *) my_group); my_group = (int *) 0; } if (active != (struct t_group *) 0) { /* active[] */ for (i=0 ; i < num_active ; i++) { if (active[i].name != (char *) 0) { free ((char *) active[i].name); active[i].name = (char *) 0; } if (active[i].description != (char *) 0) { free ((char *) active[i].description); active[i].description = (char *) 0; } if (active[i].type == GROUP_TYPE_MAIL && active[i].spooldir != (char *) 0) { free ((char *) active[i].spooldir); active[i].spooldir = (char *) 0; } } free_attributes_array (); if (active != (struct t_group *) 0) { free ((char *) active); active = (struct t_group *) 0; } } num_active = -1; } void free_kill_array () { int i; for (i=0 ; i < num_kill ; i++) { if (killf[i].kill_subj != (char *) 0) { free ((char *) killf[i].kill_subj); killf[i].kill_subj = (char *) 0; } if (killf[i].kill_from != (char *) 0) { free ((char *) killf[i].kill_from); killf[i].kill_from = (char *) 0; } } num_kill = 0; } void free_save_array () { int i; for (i=0 ; i < num_save ; i++) { if (save[i].subject != (char *) 0) { free ((char *) save[i].subject); save[i].subject = (char *) 0; } if (save[i].archive != (char *) 0) { free ((char *) save[i].archive); save[i].archive = (char *) 0; } if (save[i].dir != (char *) 0) { free ((char *) save[i].dir); save[i].dir = (char *) 0; } if (save[i].file != (char *) 0) { free ((char *) save[i].file); save[i].file = (char *) 0; } if (save[i].part != (char *) 0) { free ((char *) save[i].part); save[i].part = (char *) 0; } if (save[i].patch != (char *) 0) { free ((char *) save[i].patch); save[i].patch = (char *) 0; } save[i].index = -1; save[i].saved = FALSE; save[i].is_mailbox = FALSE; } num_save = 0; } void free_spooldirs_array () { int i; for (i=0 ; i < num_spooldir ; i++) { if (spooldirs[i].name != (char *) 0) { free ((char *) spooldirs[i].name); spooldirs[i].name = (char *) 0; } if (spooldirs[i].comment != (char *) 0) { free ((char *) spooldirs[i].comment); spooldirs[i].comment = (char *) 0; } spooldirs[i].state = 0; } num_spooldir = 0; } void free_active_size_array () { int i; for (i=0 ; i < num_active_size ; i++) { if (active_size[i].server != (char *) 0) { free ((char *) active_size[i].server); active_size[i].server = (char *) 0; } if (active_size[i].attribute != (char *) 0) { free ((char *) active_size[i].attribute); active_size[i].attribute = (char *) 0; } } num_active_size = 0; } char * my_malloc (size) unsigned size; { char *p; /* if ((p = (char *) calloc (1, (int) size)) == NULL) {*/ if ((p = (char *) malloc ((int) size)) == NULL) { error_message (txt_out_of_memory, progname); tin_done (1); } return p; } char * my_realloc (p, size) char *p; unsigned size; { if (! p) { p = (char *) calloc (1, (int) size); } else { p = (char *) realloc (p, (int) size); } if (! p) { error_message (txt_out_of_memory, progname); tin_done (1); } return p; } vð*[SRC.TIN-1_22]MISC.C;13+,Þ.?//€ 4?>á-d0@î123KÿPWO@56Ç\–?Œ—7 iÆ—?Œ—89€]V‚—G/€HªJÿ0/* * Project : tin - a Usenet reader * Module : misc.c * Author : I.Lea & R.Skrenta * Created : 01-04-91 * Updated : 22-09-93 * Notes : * Copyright : (c) Copyright 1991-93 by Iain Lea & Rich Skrenta * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" static char *mailbox_name = (char *) 0; static int mailbox_size; void asfail (file, line, cond) char *file; int line; char *cond; { fprintf (stderr, "%s: assertion failure: %s (%d): %s\n", progname, file, line, cond); fflush (stderr); /* * create a core dump */ #ifdef HAVE_COREFILE #ifdef SIGABRT sigdisp(SIGABRT, SIG_DFL); kill (process_id, SIGABRT); #else # ifdef SIGILL sigdisp(SIGILL, SIG_DFL); kill (process_id, SIGILL); # else # ifdef SIGIOT sigdisp(SIGIOT, SIG_DFL); kill (process_id, SIGIOT); # endif # endif #endif #endif /* HAVE_COREFILE */ exit(1); } void copy_fp (fp_ip, fp_op, prefix) FILE *fp_ip; FILE *fp_op; char *prefix; { #ifndef VMS extern int errno; #endif char buf[8192]; int retcode; while (fgets (buf, sizeof (buf), fp_ip) != (char *) 0) { if (buf[0] != '\n') { retcode = fprintf (fp_op, "%s%s", prefix, buf); } else { retcode = fprintf (fp_op, "%s", buf); } if (retcode == EOF) { sprintf (msg, "Failed copy_fp(). errno=%d", errno); perror_message (msg, ""); return; } } } char *get_val (env, def) char *env; /* Environment variable we're looking for */ char *def; /* Default value if no environ value found */ { char *ptr; ptr = (char *) getenv(env); return (ptr != (char *) 0 ? ptr : def); } int invoke_editor (filename, lineno) char *filename; int lineno; { char buf[PATH_LEN]; char editor_format[PATH_LEN]; char *my_editor; int retcode; static char editor[PATH_LEN]; static int first = TRUE; if (first) { my_editor = (char *) getenv ("VISUAL"); strcpy (editor, my_editor != NULL ? my_editor : get_val ("EDITOR", DEFAULT_EDITOR)); first = FALSE; } if (start_editor_offset) { if (default_editor_format[0]) { strcpy (editor_format, default_editor_format); } else { strcpy (editor_format, EDITOR_FORMAT_ON); } } else { strcpy (editor_format, EDITOR_FORMAT_OFF); } retcode = strfeditor (editor, lineno, filename, buf, sizeof (buf), editor_format); if (! retcode) { sprintf (buf, "%s %s", editor, filename); } wait_message (buf); return invoke_cmd (buf); } int invoke_ispell (nam) char *nam; { #ifdef HAVE_ISPELL char buf[PATH_LEN]; char *my_ispell; static char ispell[PATH_LEN]; static int first = TRUE; if (first) { my_ispell = (char *) getenv ("ISPELL"); strcpy (ispell, my_ispell != NULL ? my_ispell : "ispell -x"); first = FALSE; } sprintf (buf, "%s %s", ispell, nam); wait_message (buf); return invoke_cmd (buf); #else error_message (txt_ispell_define_not_compiled, ""); return FALSE; #endif } #ifndef NO_SHELL_ESCAPE void shell_escape () { char shell[LEN]; char *p; #ifdef SIGTSTP t_sigtype (*susp)(); susp = (t_sigtype (*)()) 0; #endif sprintf (msg, txt_shell_escape, default_shell_command); if (! prompt_string (msg, shell)) my_strncpy (shell, get_val (ENV_VAR_SHELL, DEFAULT_SHELL), sizeof (shell)); for (p = shell; *p && (*p == ' ' || *p == '\t'); p++) continue; if (*p) { my_strncpy (default_shell_command, p, sizeof (default_shell_command)); } else { if (default_shell_command[0]) { my_strncpy (shell, default_shell_command, sizeof (shell)); } else { my_strncpy (shell, get_val (ENV_VAR_SHELL, DEFAULT_SHELL), sizeof (shell)); } p = shell; } ClearScreen (); sprintf (msg, "Shell Command (%s)", p); center_line (0, TRUE, msg); MoveCursor (INDEX_TOP, 0); set_alarm_clock_off (); EndWin (); Raw (FALSE); #ifdef SIGTSTP if (do_sigtstp) susp = signal (SIGTSTP, SIG_DFL); #endif system (p); #ifdef SIGTSTP if (do_sigtstp) signal (SIGTSTP, susp); #endif Raw (TRUE); InitWin (); set_alarm_clock_on (); mail_setup (); continue_prompt (); if (draw_arrow_mark) { ClearScreen (); } } #endif void tin_done (ret) int ret; { char group_path[PATH_LEN]; int ask = TRUE; register int i, j; /* * check if any groups were read & ask if they should marked read */ if (catchup_read_groups && ! cmd_line) { for (i = 0 ; i < group_top ; i++) { if (active[my_group[i]].attribute.read_during_session) { if (ask) { if (prompt_yn (cLINES, "Catchup all groups entered during this session? (y/n): ", 'n')) { ask = FALSE; default_thread_arts = FALSE; /* speeds up index loading */ } else { break; } } sprintf (msg, "Catchup %s...", active[my_group[i]].name); wait_message (msg); make_group_path (active[my_group[i]].name, group_path); if (index_group (active[my_group[i]].name, group_path)) { for (j = 0; j < top; j++) { arts[j].unread = ART_READ; } update_newsrc (active[my_group[i]].name, my_group[i], FALSE); } } } } write_mail_active_file (); nntp_close (); /* disconnect from NNTP server */ if (debug) { free_all_arrays (); /* deallocate all arrays */ } ClearScreen (); EndWin (); Raw (FALSE); cleanup_tmp_files (); #ifdef VMS if (ret == 0) ret = 1; #endif exit (ret); } int my_mkdir (path, mode) char *path; int mode; { #ifdef DONT_HAVE_MKDIR char buf[LEN]; struct stat sb; sprintf(buf, "mkdir %s", path); if (stat (path, &sb) == -1) { system (buf); chmod (path, mode); } #else # ifdef M_OS2 return mkdir (path); # else return mkdir (path, mode); # endif #endif } int my_chdir (path) char *path; { int retcode; retcode = chdir (path); #ifdef M_OS2 if (*path && path[1] == ':') { _chdrive (toupper(path[0]) - 'A' + 1); } #endif return retcode; } /* * hash group name for fast lookup later */ unsigned long hash_groupname (group) char *group; { #ifdef NEW_HASH_METHOD /* still testing */ unsigned long hash = 0L, g, val; /* prime == smallest prime number greater than size of string table */ int prime = 1423; char *p; for (p = group; *p; p++) { hash = (hash << 4) + *p; if (g = hash & 0xf0000000) { hash ^= g >> 24; hash ^= g; } } val = hash % prime; /* printf ("hash=[%s] [%ld]\n", group, val); */ return val; #else unsigned long hash_value = 0L; unsigned char *ptr = (unsigned char *) group; if (*ptr) { hash_value = *ptr++; while (*ptr) hash_value = ((hash_value << 1) ^ *ptr++) % TABLE_SIZE; } return (hash_value); #endif } #ifdef M_UNIX void rename_file (old_filename, new_filename) char *old_filename; char *new_filename; { extern int errno; char buf[1024]; FILE *fp_old, *fp_new; unlink (new_filename); if (link (old_filename, new_filename) == -1) { if (errno == EXDEV) { /* create & copy file across filesystem */ if ((fp_old = fopen (old_filename, "r")) == (FILE *) 0) { sprintf (buf, txt_cannot_open, old_filename); perror_message (buf, "ONE"); return; } if ((fp_new = fopen (new_filename, "w")) == (FILE *) 0) { sprintf (buf, txt_cannot_open, new_filename); perror_message (buf, "ONE"); return; } copy_fp (fp_old, fp_new, ""); fclose (fp_new); fclose (fp_old); errno = 0; } else { sprintf (buf, txt_rename_error, old_filename, new_filename); perror_message (buf, "THREE"); return; } } if (unlink (old_filename) == -1) { sprintf (buf, txt_rename_error, old_filename, new_filename); perror_message (buf, "TWO"); return; } } #else /* * AmigaOS now has links. Better not to use them as not everybody has new ROMS */ void rename_file (old_filename, new_filename) char *old_filename; char *new_filename; { char buf[1024]; unlink (new_filename); if (rename (old_filename, new_filename)==EOF) { sprintf (buf, txt_rename_error, old_filename, new_filename); perror_message (buf, "THREE"); } return; } #endif /* M_UNIX */ char *str_dup (str) char *str; { char *dup = (char *) 0; if (str) { dup = my_malloc (strlen (str)+1); strcpy (dup, str); } return dup; } int invoke_cmd (nam) char *nam; { int ret; #ifdef SIGTSTP t_sigtype (*susp)(); susp = (t_sigtype (*)()) 0; #endif set_alarm_clock_off (); EndWin (); Raw (FALSE); #ifdef SIGTSTP if (do_sigtstp) susp = signal(SIGTSTP, SIG_DFL); #endif #if defined(SIGCHLD) && !defined(RS6000) system (nam); ret = system_status; #else ret = system (nam); #endif #ifdef SIGTSTP if (do_sigtstp) signal (SIGTSTP, susp); #endif Raw (TRUE); InitWin (); set_alarm_clock_on (); #ifdef VMS return ret != 0; #else return ret == 0; #endif } void draw_percent_mark (cur_num, max_num) long cur_num; long max_num; { char buf[32]; int percent = 0; if (NOTESLINES <= 0) { return; } if (cur_num <= 0 && max_num <= 0) { return; } percent = cur_num * 100 / max_num; sprintf (buf, "%s(%d%%) [%ld/%ld]", txt_more, percent, cur_num, max_num); MoveCursor (cLINES, (cCOLS - (int) strlen (buf))-(1+BLANK_PAGE_COLS)); StartInverse (); fputs (buf, stdout); fflush (stdout); EndInverse (); } void set_real_uid_gid () { #ifdef HAVE_SET_GID_UID if (local_index) return; umask (real_umask); #ifdef HAVE_SETREUID if (setreuid (-1, real_uid) == -1) { perror_message ("Error setreuid(real) failed", ""); } if (setregid (-1, real_gid) == -1) { perror_message ("Error setregid(real) failed", ""); } #else # if defined(BSD) && ! defined(sinix) # ifdef sun if (seteuid (real_uid) == -1) { perror_message ("Error setreuid(real) failed", ""); } if (setegid (real_gid) == -1) { perror_message ("Error setregid(real) failed", ""); } # else if (setreuid (tin_uid, real_uid) == -1) { perror_message ("Error setreuid(real) failed", ""); } if (setregid (tin_gid, real_gid) == -1) { perror_message ("Error setregid(real) failed", ""); } # endif /* sun */ # else if (setuid (real_uid) == -1) { perror_message ("Error setuid(real) failed", ""); } if (setgid (real_gid) == -1) { perror_message ("Error setgid(real) failed", ""); } # endif #endif #endif /* HAVE_SET_GID_UID */ } void set_tin_uid_gid () { #ifdef HAVE_SET_GID_UID if (local_index) return; umask (0); #ifdef HAVE_SETREUID if (setreuid (-1, tin_uid) == -1) { perror_message ("Error setreuid(tin) failed", ""); } if (setregid (-1, tin_gid) == -1) { perror_message ("Error setregid(tin) failed", ""); } #else # if defined(BSD) && ! defined(sinix) # ifdef sun if (seteuid (tin_uid) == -1) { perror_message ("Error setreuid(real) failed", ""); } if (setegid (tin_gid) == -1) { perror_message ("Error setregid(real) failed", ""); } # else if (setreuid (real_uid, tin_uid) == -1) { perror_message ("Error setreuid(tin) failed", ""); } if (setregid (real_gid, tin_gid) == -1) { perror_message ("Error setregid(tin) failed", ""); } # endif /* sun */ # else if (setuid (tin_uid) == -1) { perror_message ("Error setuid(tin) failed", ""); } if (setgid (tin_gid) == -1) { perror_message ("Error setgid(tin) failed", ""); } # endif #endif #endif /* HAVE_SET_GID_UID */ } void base_name (dirname, program) char *dirname; /* argv[0] */ char *program; /* progname is returned */ { int i; strcpy (program, dirname); for (i=(int) strlen (dirname)-1 ; i ; i--) { #ifndef VMS if (dirname[i] == SEPDIR) { #else if (dirname[i] == ']') { #endif strcpy (program, dirname+(i+1)); break; } } #ifdef M_OS2 lcase (program); #endif #ifdef VMS { char *p; if (p = index(program, '.')) *p = 0; } #endif } /* * Record size of mailbox so we can detect if new mail has arrived */ void mail_setup () { struct stat buf; mailbox_name = get_val ("MAIL", mailbox); if (stat (mailbox_name, &buf) >= 0) { mailbox_size = buf.st_size; } else { mailbox_size = 0; } } /* * Return TRUE if new mail has arrived */ int mail_check () { struct stat buf; if (mailbox_name != (char *) 0 && stat (mailbox_name, &buf) >= 0 && mailbox_size < buf.st_size) { return TRUE; } return FALSE; } /* * Returns the user name and E-mail address of  K>[~ TIN-1_22.BCKÞd[SRC.TIN-1_22]MISC.C;13?ôSBthe user * * Written by ahd 15 July 1989 * Borrowed from UUPC/extended with some mods by nms */ void parse_from (from_line, eaddr, fname) char* from_line; char* eaddr; char* fname; { char *nonblank = NULL; char name[LEN]; /* User full name */ char *nameptr = name; char addr[LEN]; /* User e-mail address */ char *addrptr = addr; char state = 'A'; /* State = skip whitespace */ char newstate = 'A'; /* Next state to process */ int bananas = 0; /* No () being processed now */ /* * Begin loop to copy the input field into the address and the * user name. We will begin by copying both (ignoring whitespace * for addresses) because we won't know if the input field is an * address or a name until we hit either a special character of * some sort. */ while ((*from_line != '\0') && (state != ',')) { switch (state) { case 'A': if (isspace(*from_line)) /* Found first non-blank? */ break; /* No --> keep looking */ nonblank = from_line; state = 'B'; /* ... and fall through */ case 'B': case ')': newstate = *from_line; switch (*from_line) { case '(': bananas++; break; case '"': break; case '<': addrptr = addr; /* Start address over */ nameptr = name; /* Start name over again */ from_line = nonblank - 1; /* Re-scan in new state */ newstate = '>'; /* Proc all-non <> as name */ break; /* Begin addr over again */ case ',': break; /* Terminates address */ case '>': case ')': strcpy(eaddr, "error@hell"); *fname = '\0'; return; default: newstate = state; /* stay in this state */ if (!isspace(*from_line)) *addrptr++ = *from_line; } /* switch(*from_line) */ break; case '<': if (*from_line == '>') newstate = '>'; else if (isspace(*from_line)) *nameptr++ = *from_line; else *addrptr++ = *from_line; break; case '>': if (*from_line == '<') newstate = '<'; else *nameptr++ = *from_line; break; case '(': if (*from_line == '(') ++bananas; else if (*from_line == ')') if (--bananas == 0) { newstate = ')'; break; } *nameptr++ = *from_line; break; case '"': if (*from_line == '"') newstate = ')'; else *nameptr++ = *from_line; break; default: /* Logic error, bad state */ strcpy(eaddr, "error@nowhere"); *fname = '\0'; return; } /* switch (state) */ state = newstate; from_line++; } /* while */ *addrptr = '\0'; *nameptr = '\0'; if (state == 'A') { strcpy(eaddr, "nobody@nowhere"); *fname = '\0'; return; } strcpy(eaddr, addr); /* Return the full address */ if (state == 'B') strcpy(fname, ""); else { while (--nameptr >= name) { if (isspace(*nameptr) || (*nameptr == '"')) *nameptr = '\0'; else break; } /* Strip leading blanks from the address */ nameptr = name; while ( *(nameptr) != '\0') { if (!(isspace(*nameptr) || (*nameptr == '"'))) break; else nameptr++; } strcpy(fname, nameptr); } } /* * Convert a string to a long, only look at first n characters */ long my_atol (s, n) char *s; int n; { long ret = 0; #ifdef QNX4 ret = atol (s); #else while (*s && n--) { if (*s >= '0' && *s <= '9') ret = ret * 10 + (*s - '0'); else return -1; s++; } #endif return ret; } /* * strcmp that ignores case */ #define FOLD_TO_UPPER(a) (islower ((int) (a)) ? toupper ((int) (a)) : (a)) int my_stricmp (p, q) char *p; char *q; { for (; FOLD_TO_UPPER (*p) == FOLD_TO_UPPER (*q); ++p, ++q) { if (*p == '\0') { return (0); } } return (FOLD_TO_UPPER (*p) - FOLD_TO_UPPER (*q)); } /* * Return a pointer into s eliminating any leading Re:'s. Example: * * Re: Reorganization of misc.jobs * ^ ^ */ char *eat_re (s) char *s; { while (*s == 'r' || *s == 'R') { if ((*(s+1) == 'e' || *(s+1) == 'E')) { if (*(s+2) == ':') s += 3; else if (*(s+2) == '^' && isdigit(*(s+3)) && *(s+4) == ':') s += 5; /* hurray nn */ else break; } else break; while (*s == ' ') s++; } return s; } /* * Hash the subjects (after eating the Re's off) for a quicker * thread search later. We store the hashes for subjects in the * index file for speed. */ long hash_s (s) char *s; { long h = 0; unsigned char *t = (unsigned char *) s; while (*t) h = h * 64 + *t++; return h; } /* * strncpy that stops at a newline and null terminates */ void my_strncpy (p, q, n) char *p; char *q; int n; { while (n--) { if (! *q || *q == '\n') break; *p++ = *q++; } *p = '\0'; } int untag_all_articles () { int untagged = FALSE; register int i; for (i=0 ; i < top ; i++) { if (arts[i].tagged) { arts[i].tagged = FALSE; untagged = TRUE; } } num_of_tagged_arts = 0; return (untagged); } /* * ANSI C strstr () - Uses Boyer-Moore algorithm. */ char *str_str (text, pattern, patlen) char *text; char *pattern; int patlen; { register unsigned char *p, *t; register int i, p1, j, *delta; int deltaspace[256]; int textlen; textlen = strlen (text); /* algorithm fails if pattern is empty */ if ((p1 = patlen) == 0) return (text); /* code below fails (whenever i is unsigned) if pattern too long */ if (p1 > textlen) return (NULL); /* set up deltas */ delta = deltaspace; for (i = 0; i <= 255; i++) delta[i] = p1; for (p = (unsigned char *) pattern, i = p1; --i > 0;) delta[*p++] = i; /* * From now on, we want patlen - 1. * In the loop below, p points to the end of the pattern, * t points to the end of the text to be tested against the * pattern, and i counts the amount of text remaining, not * including the part to be tested. */ p1--; p = (unsigned char *) pattern + p1; t = (unsigned char *) text + p1; i = textlen - patlen; for (;;) { if (*p == *t && memcmp ((p - p1), (t - p1), p1) == 0) return ((char *)t - p1); j = delta[*t]; if (i < j) break; i -= j; t += j; } return (NULL); } void get_author (thread, respnum, str) int thread; int respnum; char *str; { extern int threaded_on_subject; int author; if (thread) { if (threaded_on_subject) { author = SHOW_FROM_BOTH; } else { author = show_author; } } else { author = show_author; } switch (author) { case SHOW_FROM_NONE: str[0] = '\0'; break; case SHOW_FROM_ADDR: strcpy (str, arts[respnum].from); break; case SHOW_FROM_NAME: if (arts[respnum].name) { strcpy (str, arts[respnum].name); } else { strcpy (str, arts[respnum].from); } break; case SHOW_FROM_BOTH: if (arts[respnum].name) { sprintf (str, "%s (%s)", arts[respnum].name, arts[respnum].from); } else { strcpy (str, arts[respnum].from); } break; } } void toggle_inverse_video () { inverse_okay = !inverse_okay; if (inverse_okay) { #ifndef USE_INVERSE_HACK draw_arrow_mark = FALSE; #endif info_message (txt_inverse_on); } else { draw_arrow_mark = TRUE; info_message (txt_inverse_off); } } int get_arrow_key () { int ch; int ch1; ch = ReadCh (); if (ch == '[' || ch == 'O') ch = ReadCh(); switch (ch) { case 'A': case 'i': #ifdef QNX4 case 0xA1: #endif return KEYMAP_UP; case 'B': #ifdef QNX4 case 0xA9: #endif return KEYMAP_DOWN; case 'D': #ifdef QNX4 case 0xA4: #endif return KEYMAP_LEFT; case 'C': #ifdef QNX4 case 0xA6: #endif return KEYMAP_RIGHT; case 'I': /* ansi PgUp */ case 'V': /* at386 PgUp */ case 'S': /* 97801 PgUp */ case 'v': /* emacs style */ #ifdef QNX4 case 0xA2: #endif #ifdef M_AMIGA return KEYMAP_PAGE_DOWN; #else return KEYMAP_PAGE_UP; #endif case 'G': /* ansi PgDn */ case 'U': /* at386 PgDn */ case 'T': /* 97801 PgDn */ #ifdef QNX4 case 0xAA: #endif #ifdef M_AMIGA return KEYMAP_PAGE_UP; #else return KEYMAP_PAGE_DOWN; #endif case 'H': /* at386 Home */ #ifdef QNX4 case 0xA0: #endif return KEYMAP_HOME; case 'F': /* ansi End */ case 'Y': /* at386 End */ #ifdef QNX4 case 0xA8: #endif return KEYMAP_END; case '5': /* vt200 PgUp */ ch = ReadCh (); /* eat the ~ (interesting use of words :) */ return KEYMAP_PAGE_UP; case '6': /* vt200 PgUp */ ch = ReadCh (); /* eat the ~ */ return KEYMAP_PAGE_DOWN; case '1': /* vt200 PgUp */ ch = ReadCh (); /* eat the ~ */ if (ch == '5') { /* RS/6000 PgUp is 150g, PgDn is 154g */ ch1 = ReadCh(); ch = ReadCh(); if (ch1 == '0') return KEYMAP_PAGE_UP; if (ch1 == '4') return KEYMAP_PAGE_DOWN; } return KEYMAP_HOME; case '4': /* vt200 PgUp */ ch = ReadCh (); /* eat the ~ */ return KEYMAP_END; case 'M': /* xterminal button press */ xmouse = ReadCh () - ' '; /* button */ xcol = ReadCh () - '!'; /* column */ xrow = ReadCh () - '!'; /* row */ return KEYMAP_MOUSE; default: return KEYMAP_UNKNOWN; } } /* * Check for lock file to stop multiple copies of tind or tin -U running * and if it does not exist create it so this is the only copy running */ void create_index_lock_file (lock_file) char *lock_file; { char buf[64]; FILE *fp; long epoch; struct stat sb; if (stat (lock_file, &sb) == 0) { if ((fp = fopen (lock_file, "r")) != (FILE *) 0) { fgets (buf, sizeof (buf), fp); fclose (fp); #ifdef INDEX_DAEMON sprintf (msg, "%s: Already started pid=[%d] on %s", progname, atoi(buf), buf+8); #else sprintf (msg, "\n%s: Already started pid=[%d] on %s", progname, atoi(buf), buf+8); #endif error_message (msg, ""); exit (1); } } else if ((fp = fopen (lock_file, "w")) != (FILE *) 0) { time (&epoch); fprintf (fp, "%6d %s\n", process_id, ctime (&epoch)); fclose (fp); chmod (lock_file, 0600); } } /* * strfquote() - produce formatted quote string * %A Articles Email address * %D Articles Date * %F Articles Address+Name * %G Groupname of Article * %M Articles MessageId * %N Articles Name of author */ int strfquote (group, respnum, s, maxsize, format) char *group; int respnum; char *s; int maxsize; char *format; { extern char note_h_date[PATH_LEN]; extern char note_h_messageid[PATH_LEN]; char *endp = s + maxsize; char *start = s; char tbuf[PATH_LEN]; int i; if (s == (char *) 0 || format == (char *) 0 || maxsize == 0) { return 0; } if (strchr (format, '%') == (char *) 0 && strlen (format) + 1 >= maxsize) { return 0; } for (; *format && s < endp - 1; format++) { tbuf[0] = '\0'; if (*format != '\\' && *format != '%') { *s++ = *format; continue; } if (*format == '\\') { switch (*++format) { case '\0': *s++ = '\\'; goto out; case 'n': /* linefeed */ strcpy (tbuf, "\n"); break; default: tbuf[0] = '%'; tbuf[1] = *format; tbuf[2] = '\0'; break; } i = strlen(tbuf); if (i) { if (s + i < endp - 1) { strcpy (s, tbuf); s += i; } else { return 0; } } } if (*format == '%') { switch (*++format) { case '\0': *s++ = '%'; goto out; case '%': *s++ = '%'; continue; case 'A': /* Articles Email address */ strcpy (tbuf, arts[respnum].from); break; case 'D': /* Articles Date */ strcpy(tbuf, note_h_date); break; case 'F': /* Articles Address+Name */ if (arts[respnum].name) { sprintf (tbuf, "%s (%s)", arts[respnum].name, arts[respnum].from); } else { strcpy (tbuf, arts[respnum].from); } break; case 'G': /* Groupname of Article */ strcpy (tbuf, group); break; case 'M': /* Articles MessageId */ strcpy (tbuf, note_h_messageid); break; case 'N': /* Articles Name of author */ if (arts[respnum].name != (char *) 0) { strcpy (tbuf, arts[respnum].name); } else { strcpy (tbuf, arts[respnum].from); } break; default: tbuf[0] = '%'; tbuf[1] = *format; tbuf[2] = '\0'; break; } i = strlen(tbuf); if (i) { if (s + i < endp - 1) { strcpy (s, tbuf); s += i; } else { return 0; } } } } out: if (s < endp && *format == '\0') { *s = '\0'; return (s - start); } else return 0; } /* * strfeditor() - produce formatted editor string * %E Editor * %F Filename * %N Linenumber */ int strfeditor (editor, linenum, filename, s, maxsize, format) char *editor; int linenum; char *filename; char *s; int maxsize; char *format; { char *endp = s + maxsize; char *start = s; char tbuf[PATH_LEN]; int i; if (s == (char *) 0 || format == (char *) 0 || maxsize == 0) { return 0; } if (strchr (format, '%') == (char *) 0 && strlen (format) + 1 >= maxsize) { return 0; } for (; *format && s < endp - 1; format++) { tbuf[0] = '\0'; if (*format != '\\' && *format != '%') { *s++ = *format; continue; } if (*format == '\\') { switch (*++format) { case '\0': *s++ = '\\'; goto out; case 'n': /* linefeed */ strcpy (tbuf, "\n"); break; default: tbuf[0] = '%'; tbuf[1] = *format; tbuf[2] = '\0'; break; } i = strlen(tbuf); if (i) { if (s + i < endp - 1) { strcpy (s, tbuf); s += i; } else { return 0; } } } if (*format == '%') { switch (*++format) { case '\0': *s++ = '%'; goto out; case '%': *s++ = '%'; continue; case 'E': /* Editor */ strcpy (tbuf, editor); break; case 'F': /* Filename */ strcpy(tbuf, filename); break; case 'N': /* Line number */ sprintf (tbuf, "%d", linenum); break; default: tbuf[0] = '%'; tbuf[1] = *format; tbuf[2] = '\0'; break; } i = strlen(tbuf); if (i) { if (s + i < endp - 1) { strcpy (s, tbuf); s += i; } else { return 0; } } } } out: if (s < endp && *format == '\0') { *s = '\0'; return (s - start); } else return 0; } /* * strfpath - produce formatted pathname expansion. Handles following forms: * ~/News -> /usr/iain/News * ~abc/News -> /usr/abc/News * $var/News -> /env/var/News * =file -> /usr/iain/Mail/file * +file -> /usr/iain/News/group.name/file * ~/News/%G -> /usr/iain/News/group.name */ int strfpath (format, str, maxsize, homedir, maildir, savedir, group) char *format; char *str; int maxsize; char *homedir; char *maildir; char *savedir; char *group; { char *endp = str + maxsize; char *start = str; char *envptr; char *startp = format; char buf[PATH_LEN]; char tbuf[PATH_LEN]; char tmp[PATH_LEN]; int i; #ifndef M_AMIGA struct passwd *pwd; #endif if (str == (char *) 0 || format == (char *) 0 || maxsize == 0) { return 0; } if (strlen (format) + 1 >= maxsize) { return 0; } for (; *format && str < endp - 1; format++) { tbuf[0] = '\0'; /* * If just a normal part of the pathname copy it */ #ifdef VMS if (! strchr ("~=+", *format)) { #else if (! strchr ("~$=+", *format)) { #endif *str++ = *format; continue; } switch (*format) { case '~': /* Users or another users homedir */ switch (*++format) { case '/': /* users homedir */ joinpath (tbuf, homedir, ""); break; default: /* some other users homedir */ #ifndef M_AMIGA i = 0; while (*format && *format != '/') { tbuf[i++] = *format++; } tbuf[i] = '\0'; /* * OK lookup the username in/etc/passwd */ pwd = getpwnam (tbuf); if (pwd == (struct passwd *) 0) { str[0] = '\0'; return 0; } else { joinpath (tbuf, pwd->pw_dir, ""); } #else /* Amiga has no ther users */ return 0; #endif break; } i = strlen (tbuf); if (i) { if (str + i < endp - 1) { strcpy (str, tbuf); str += i; } else { str[0] = '\0'; return 0; } } break; #ifndef VMS case '$': /* Read the envvar and use its value */ i = 0; format++; while (*format && *format != '/') { tbuf[i++] = *format++; } tbuf[i] = '\0'; format--; /* * OK lookup the variable in the shells environment */ envptr = (char *) getenv (tbuf); if (envptr == (char *) 0) { str[0] = '\0'; return 0; } else { strncpy (tbuf, envptr, sizeof (tbuf)-1); } i = strlen (tbuf); if (i) { if (str + i < endp - 1) { strcpy (str, tbuf); str += i; } else { str[0] = '\0'; return 0; } } break; #endif case '=': /* * Shorthand for group maildir * Only convert if 1st c :har in format */ if (startp == format && maildir != (char *) 0) { joinpath (tbuf, maildir, ""); i = strlen (tbuf); if (i) { if (str + i < endp - 1) { strcpy (str, tbuf); str += i; } else { str[0] = '\0'; return 0; } } } else { *str++ = *format; } break; case '+': /* * Shorthand for saving to savedir/groupname/file * Only convert if 1st char in format */ if (startp == format && savedir != (char *) 0) { if (strfpath (savedir, buf, sizeof (buf), homedir, (char *) 0, (char *) 0, (char *) 0)) { #ifdef HAVE_LONG_FILENAMES my_strncpy (tmp, group, sizeof (tmp)); #else my_strncpy (tmp, group, 14); #endif /* * convert 1st letter to uppercase */ if (tmp[0] >= 'a' && tmp[0] <= 'z') { tmp[0] = tmp[0] - 32; } #ifndef VMS joinpath (tbuf, buf, tmp); strcat (tbuf, "/"); #else joindir (tbuf, buf, tmp); #endif i = strlen (tbuf); if (i) { if (str + i < endp - 1) { strcpy (str, tbuf); str += i; } else { str[0] = '\0'; return 0; } } } else { str[0] = '\0'; return 0; } } else { *str++ = *format; } break; case '%': /* Different forms of parsing cmds */ *str++ = *format; break; default: break; } } if (str < endp && *format == '\0') { *str = '\0'; /* clear_message (); printf ("!!! format=[%s] path=[%s]", startp, start); fflush (stdout); sleep (2); */ return (str - start); } else { str[0] = '\0'; return 0; } } void get_cwd (buf) char *buf; { #ifdef DONT_HAVE_GETCWD getwd (buf); #else getcwd (buf, PATH_LEN); #endif } void make_group_path (name, path) char *name; char *path; { char *ptr; #ifdef VMS sprintf(path, "[%s]", name); #else strcpy (path, name); ptr = path; while (*ptr) { if (*ptr == '.') { *ptr = '/'; } ptr++; } #endif } /* * Delete tmp index & local newsgroups file */ void cleanup_tmp_files () { extern char index_file[PATH_LEN]; if (read_news_via_nntp && xindex_supported) { unlink (index_file); } unlink (local_newsgroups_file); unlink (lock_file); } void make_post_process_cmd (cmd, dir, file) char *cmd; char *dir; char *file; { char buf[LEN]; char currentdir[PATH_LEN]; get_cwd (currentdir); chdir (dir); #ifdef M_OS2 backslash (file); #endif sprintf (buf, cmd, file); invoke_cmd (buf); chdir (currentdir); } eð*[SRC.TIN-1_22]NEWSRC.C;4+,Ý.9//€ 498ß-d0@î123KÿPWO:56 ˜Å¾®‹—7 dÀ®‹—89€]V‚—G/€HªJÿ./* * Project : tin - a Usenet reader * Module : newsrc.c * Author : I.Lea & R.Skrenta * Created : 01-04-91 * Updated : 06-09-93 * Notes : * Copyright : (c) Copyright 1991-93 by Iain Lea & Rich Skrenta * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" /* * Automatically subscribe user to newsgroups specified in * /usr/lib/news/subscribe (locally) or same file but from * NNTP server (LIST AUTOSUBSCRIBE) and create .newsrc */ int auto_subscribe_groups () { char buf[LEN]; FILE *fp_newsrc; FILE *fp_subs; int len; int ret_code = FALSE; if ((fp_subs = open_subscription_fp ()) != NULL) { #ifdef VMS if ((fp_newsrc = fopen (newsrc, "w", "fop=cif")) != NULL) { #else if ((fp_newsrc = fopen (newsrc, "w")) != NULL) { #endif while (fgets (buf, sizeof (buf), fp_subs) != NULL) { if (buf[0] != '#' && buf[0] != '\n') { len = strlen (buf); if (len > 1) { buf[len-1] = '\0'; fprintf (fp_newsrc, "%s:\n", buf); } } } fclose (fp_newsrc); ret_code = TRUE; } fclose (fp_subs); } return (ret_code); } /* * make a backup of users .newsrc in case of the bogie man */ void backup_newsrc () { #ifndef INDEX_DAEMON char buf[NEWSRC_LINE]; FILE *fp_newsrc, *fp_backup; if ((fp_newsrc = fopen (newsrc, "r")) != NULL) { joinpath (buf, homedir, ".oldnewsrc"); unlink (buf); /* because rn makes a link of .newsrc -> .oldnewsrc */ #ifdef VMS if ((fp_backup = fopen (buf, "w", "fop=cif")) != NULL) { #else if ((fp_backup = fopen (buf, "w")) != NULL) { #endif while (fgets (buf, sizeof (buf), fp_newsrc) != NULL) { fputs (buf, fp_backup); } fclose (fp_backup); } fclose (fp_newsrc); } #endif /* INDEX_DAEMON */ } /* * Read $HOME/.newsrc into my_group[]. my_group[] ints point to * active[] entries. Sub_only determines whether to just read * subscribed groups or all of them. */ void read_newsrc (sub_only) int sub_only; /* TRUE=subscribed groups only, FALSE=all groups */ { char c, *p, buf[NEWSRC_LINE]; char old_groups[PATH_LEN]; FILE *fp = (FILE *) 0; FILE *fp_old = (FILE *) 0; int i; int remove_old_groups = FALSE; group_top = 0; reread_newsrc: /* * make a .newsrc if one does'nt exist & auto subscribe to set groups */ if ((fp = fopen (newsrc, "r")) == NULL) { if (auto_subscribe_groups ()) { goto reread_newsrc; } for (i = 0; i < num_active; i++) { if (group_top >= max_active) { expand_active (); } my_group[group_top] = i; active[i].my_group = 0; active[i].unread = -1; group_top++; } write_newsrc (); return; } joinpath (old_groups, homedir, ".newsrc."); sprintf (&old_groups[strlen(old_groups)], "%d", process_id); while (fgets (buf, sizeof buf, fp) != NULL) { p = buf; while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!') p++; c = *p; *p++ = '\0'; if (c == '!' && sub_only) { continue; /* unsubscribed */ } i = add_group (buf, FALSE); if (i < 0) { if (! remove_old_groups) { #ifdef VMS if ((fp_old = fopen (old_groups, "w", "fop=cif")) == NULL) { #else if ((fp_old = fopen (old_groups, "w")) == NULL) { #endif perror_message (txt_cannot_open, old_groups); continue; } remove_old_groups = TRUE; } fprintf (fp_old, "%s\n", buf); continue; } if (c != '!') { /* if we're subscribed to it */ active[my_group[i]].my_group |= SUBSCRIBED; } active[my_group[i]].unread = parse_unread (p, my_group[i]); } fclose (fp); /* * rewrite newsrc to get rid of any non-existant groups */ if (remove_old_groups) { fclose (fp_old); rewrite_newsrc (); unlink (old_groups); } } /* * Write a new newsrc from my_group[] and active[] mygroup if * rewriting to get rid of groups that don't exist any longer. Used * to a create a new .newsrc if there isn't one already, or when * the newsrc is reset. */ void write_newsrc () { FILE *fp; register int i; #ifdef VMS if ((fp = fopen (newsrc, "w", "fop=cif")) == (FILE *) 0) { #else if ((fp = fopen (newsrc, "w")) == (FILE *) 0) { #endif return; } wait_message (txt_creating_newsrc); for (i=0 ; i < num_active ; i++) { fprintf (fp, "%s:\n", active[i].name); } fclose (fp); } /* * Rewrite newsrc to get rid of groups that don't exist any longer. */ void rewrite_newsrc () { char buf[NEWSRC_LINE]; char old[NEWSRC_LINE]; char old_groups[PATH_LEN]; FILE *fp, *fp_old, *fp_new; int found_old_group, len; joinpath (old_groups, homedir, ".newsrc."); sprintf (&old_groups[strlen(old_groups)], "%d", process_id); if ((fp = fopen (newsrc, "r")) == NULL) goto removed_old_groups_done; if ((fp_old = fopen (old_groups, "r")) == NULL) goto removed_old_groups_done; #ifdef VMS if ((fp_new = fopen (newnewsrc, "w", "fop=cif")) == NULL) #else if ((fp_new = fopen (newnewsrc, "w")) == NULL) #endif goto removed_old_groups_done; while (fgets (buf, sizeof buf, fp) != NULL) { /* read group from newsrc */ rewind (fp_old); found_old_group = FALSE; while (fgets (old, sizeof old, fp_old) != NULL) { /* read group from oldgroups */ len = strlen (old)-1; if ((buf[len] == ':' || buf[len] == '!') && strncmp (buf, old, len) == 0) { old[len] = '\0'; sprintf (msg, txt_deleting_from_newsrc, old); wait_message (msg); if (cmd_line) { wait_message ("\n"); } found_old_group = TRUE; } } if (! found_old_group) { fprintf (fp_new, "%s", buf); } } fclose (fp); fclose (fp_old); fclose (fp_new); rename_file (newnewsrc, newsrc); removed_old_groups_done: unlink (old_groups); } /* * check the min and max values for the newsrc data and copy the * ART_READ bits if they change */ void checknewsrc (groupnum) int groupnum; { long i; long l; char *tb; char *sb; if (active[groupnum].newsrc && (active[groupnum].newsrcmin != active[groupnum].min || active[groupnum].newsrcmax != active[groupnum].max)) { l = active[groupnum].max - active[groupnum].min + 1; if (l <= 0) { l = 1; } tb = my_malloc ((unsigned)(l + 7) / 8); NSETBLK(tb, l); for (i = active[groupnum].min ; i <= active[groupnum].max ; i++) { if (i >= active[groupnum].newsrcmin && i <= active[groupnum].newsrcmax && NTEST(active[groupnum].newsrc, i - active[groupnum].newsrcmin) == 0) { NRESET(tb, i - active[groupnum].min); } } sb = active[groupnum].newsrc; active[groupnum].newsrcmax = active[groupnum].max; active[groupnum].newsrcmin = active[groupnum].min; active[groupnum].newsrcsize = l; active[groupnum].newsrc = tb; free (sb); } } /* * Load the sequencer rang lists and mark arts[] according to the * .newsrc info for a particular group. i.e. rec.arts.comics: 1-94,97 */ void read_newsrc_line (group) char *group; { #ifndef INDEX_DAEMON FILE *fp; char buf[NEWSRC_LINE]; char *p; int i; int j; time_t curtime; static time_t lasttime = 0; time(&curtime); if (lasttime > 0 && curtime - lasttime <= 60) { /* read once every minute */ i = find_group_index (group); if (i >= 0 && active[i].newsrc) { checknewsrc(i); for (j = 0; j < top; j++) { if (arts[j].artnum >= active[i].min && arts[j].artnum <= active[i].max && NTEST(active[i].newsrc, arts[j].artnum - active[i].min) == 0 || arts[j].artnum < active[i].min) { arts[j].unread = ART_READ; } } return; } } if ((fp = fopen (newsrc, "r")) == NULL) { return; } while (fgets (buf, sizeof buf, fp) != NULL) { p = buf; while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!') { p++; } if (*p) { *p++ = '\0'; } if (strcmp (buf, group) == 0) { i = find_group_index (buf); if (i >= 0) { parse_unread (p, i); } parse_seq (p); } } lasttime = curtime; fclose (fp); #endif /* INDEX_DAEMON */ } /* * For our current group, update the sequencer information in .newsrc */ void update_newsrc (group, groupnum, mark_unread) char *group; int groupnum; /* index into active[] for this group */ int mark_unread; { char buf[NEWSRC_LINE]; char c, *p; FILE *fp; FILE *newfp; long i; if (active[groupnum].newsrc) { checknewsrc (groupnum); if (mark_unread) { NSETBLK(active[groupnum].newsrc, active[groupnum].max - active[groupnum].min); } else { for (i = 0; i < top; i++) { if (arts[i].artnum >= active[groupnum].min && arts[i].artnum <= active[groupnum].max) { if (arts[i].unread != ART_READ) { NSET(active[groupnum].newsrc, arts[i].artnum - active[groupnum].min); } else { NRESET(active[groupnum].newsrc, arts[i].artnum - active[groupnum].min); } } } } } #ifdef VMS if ((newfp = fopen (newnewsrc, "w", "fop=cif")) == (FILE *) 0) { #else if ((newfp = fopen (newnewsrc, "w")) == (FILE *) 0) { #endif goto update_done; } if ((fp = fopen (newsrc, "r")) != (FILE *) 0) { while (fgets (buf, sizeof buf, fp) != NULL) { for (p = buf; *p; p++) if (*p == '\n') { *p = '\0'; break; } p = buf; while (*p && *p != ' ' && *p != ':' && *p != '!') p++; c = *p; if (c != '\0') { *p++ = '\0'; } if (c != '!' && c != ' ') { c = ':'; } if (strcmp (buf, group) == 0) { if (mark_unread) { fprintf (newfp, "%s%c\n", buf, c); } else { fprintf (newfp, "%s%c ", buf, c); print_seq (newfp, groupnum); fprintf (newfp, "\n"); } } else { i = find_group_index (buf); if (i >= 0 && active[i].newsrc && active[i].newsrcupdate) { checknewsrc((int)i); fprintf (newfp, "%s%c ", buf, c); print_newsrc_seq (newfp, (int)i); fprintf (newfp, "\n"); active[i].newsrcupdate = FALSE; } else { fprintf (newfp, "%s%c%s\n", buf, c, p); } } } fclose (fp); } fclose (newfp); rename_file (newnewsrc, newsrc); update_done: ; } /* * Subscribe/unsubscribe to a group in .newsrc. ch should either be * '!' to unsubscribe or ':' to subscribe. num is the group's index * in active[]. */ void subscribe (group, ch, num, out_seq) char *group; int ch; int num; int out_seq; /* output sequencer info? */ { char buf[NEWSRC_LINE]; char c, *p; FILE *fp; FILE *newfp; int gotit = FALSE; if (ch == '!') { active[num].my_group &= ~SUBSCRIBED; } else { active[num].my_group |= SUBSCRIBED; } #ifdef VMS if ((newfp = fopen (newnewsrc, "w", "fop=cif")) == NULL) #else if ((newfp = fopen (newnewsrc, "w")) == NULL) #endif goto subscribe_done; if ((fp = fopen (newsrc, "r")) != NULL) { while (fgets (buf, sizeof buf, fp) != NULL) { if (strncmp ("options ", buf, 8) == 0) { fprintf (newfp, buf); } else { for (p = buf; *p; p++) { if (*p == '\n') { *p = '\0'; break; } } p = buf; while (*p && *p != ' ' && *p != ':' && *p != '!') p++; c = *p; if (c != '\0') *p++ = '\0'; if (c != '!') c = ':'; if (strcmp (buf, group) == 0) { fprintf (newfp, "%s%c%s\n", buf, ch, p); gotit = TRUE; } else { fprintf (newfp, "%s%c%s\n", buf, c, p); } } } fclose (fp); } if (! gotit) { if (out_seq) { fprintf (newfp, "%s%c ", group, ch); print_seq (newfp, num); fprintf (newfp, "\n"); } else fprintf (newfp, "%s%c\n", group, ch); } fclose (newfp); rename_file (newnewsrc, newsrc); subscribe_done: ; } void reset_newsrc () { char buf[NEWSRC_LINE]; char c, *p; FILE *fp; FILE *newfp; long i; #ifdef VMÀ¾Û§~ TIN-1_22.BCKÝd[SRC.TIN-1_22]NEWSRC.C;49Ú4S if ((newfp = fopen (newnewsrc, "w", "fop=cif")) == NULL) #else if ((newfp = fopen (newnewsrc, "w")) == NULL) #endif goto update_done; if ((fp = fopen (newsrc, "r")) != NULL) { while (fgets (buf, sizeof (buf), fp) != NULL) { for (p = buf; *p && *p != '\n'; p++) continue; *p = '\0'; p = buf; while (*p && *p != ' ' && *p != ':' && *p != '!') p++; c = *p; if (c != '\0') *p++ = '\0'; if (c != '!') c = ':'; fprintf (newfp, "%s%c\n", buf, c); } fclose (fp); } fclose (newfp); rename_file (newnewsrc, newsrc); update_done: for (i = 0; i < group_top; i++) { active[my_group[i]].unread = -1; if (active[my_group[i]].newsrc != NULL) free(active[my_group[i]].newsrc); active[my_group[i]].newsrc = NULL; active[my_group[i]].newsrcupdate = FALSE; active[my_group[i]].newsrcsize = 0; active[my_group[i]].newsrcmin = active[my_group[i]].min; active[my_group[i]].newsrcmax = active[my_group[i]].max; } } void delete_group (group) char *group; { FILE *fp; FILE *newfp; char buf[8192]; char *p; char c; int gotit = FALSE; FILE *del; #ifdef VMS if ((newfp = fopen (newnewsrc, "w", "fop=cif")) == NULL) { #else if ((newfp = fopen (newnewsrc, "w")) == NULL) { #endif goto del_done; } if ((del = fopen (delgroups, "a+")) == NULL) { fclose (newfp); goto del_done; } if ((fp = fopen (newsrc, "r")) != NULL) { while (fgets (buf, sizeof (buf), fp) != NULL) { for (p = buf; *p && *p != '\n'; p++) continue; *p = '\0'; p = buf; while (*p && *p != ' ' && *p != ':' && *p != '!') p++; c = *p; if (c != '\0') *p++ = '\0'; if (c != '!') c = ':'; if (strcmp (buf, group) == 0) { fprintf (del, "%s%c%s\n", buf, c, p); gotit = TRUE; } else fprintf (newfp, "%s%c%s\n", buf, c, p); } fclose (fp); fclose (newfp); } if (! gotit) fprintf (del, "%s!\n", group); fclose (del); rename_file (newnewsrc, newsrc); del_done: ; } int undel_group () { char buf[2][NEWSRC_LINE]; char c, *p; FILE *del; : FILE *newfp; FILE *fp; int i, j; int which = 0; long h; if ((del = fopen (delgroups, "r")) == NULL) { return FALSE; } unlink (delgroups); #ifdef VMS if ((newfp = fopen (delgroups, "w", "fop=cif")) == NULL) { #else if ((newfp = fopen (delgroups, "w")) == NULL) { #endif return FALSE; } buf[0][0] = '\0'; buf[1][0] = '\0'; while (fgets (buf[which], sizeof (buf[which]), del) != NULL) { which = !which; if (*buf[which]) fputs (buf[which], newfp); } fclose (del); fclose (newfp); which = !which; if (!*buf[which]) { return FALSE; } for (p = buf[which]; *p && *p != '\n'; p++) continue; *p = '\0'; p = buf[which]; while (*p && *p != ' ' && *p != ':' && *p != '!') p++; c = *p; if (c != '\0') *p++ = '\0'; if (c != '!') c = ':'; h = hash_groupname (buf[which]); for (i = group_hash[h]; i >= 0; i = active[i].next) { if (strcmp (buf[which], active[i].name) == 0) { for (j = 0; j < group_top; j++) if (my_group[j] == i) { return j; } active[i].my_group &= ~UNSUBSCRIBED; /* mark that we got it */ if (c != '!') active[i].my_group |= SUBSCRIBED; if (group_top >= max_active) expand_active (); group_top++; for (j = group_top; j > cur_groupnum; j--) { /* FIXME delete activeunread[j] = unread[j-1]; */ my_group[j] = my_group[j-1]; } my_group[cur_groupnum] = i; active[i].unread = parse_unread (p, i); if ((fp = fopen (newsrc, "r")) == NULL) { return FALSE; } #ifdef VMS if ((newfp = fopen(newnewsrc, "w", "fop=cif")) == NULL) { #else if ((newfp = fopen(newnewsrc, "w")) == NULL) { #endif fclose(fp); return FALSE; } i = 0; while (fgets(buf[!which], sizeof (buf[!which]), fp) != NULL) { for (p = buf[!which]; *p && *p != '\n'; p++) continue; *p = '\0'; p = buf[!which]; while (*p && *p!=' ' && *p != ':' && *p != '!') p++; c = *p; if (c != '\0') *p++ = '\0'; if (c != '!') c = ':'; while (i < cur_groupnum) { if (strcmp(buf[!which], active[my_group[i]].name) == 0) { fprintf(newfp, "%s%c%s\n", buf[!which], c, p); goto foo_cont; } i++; } fprintf(newfp, "%s%c%s\n", buf[which], c, p); fprintf(newfp, "%s%c%s\n", buf[!which], c, p); break; foo_cont:; } while (fgets (buf[!which], sizeof (buf[!which]), fp) != NULL) fputs (buf[!which], newfp); fclose (newfp); fclose (fp); rename_file (newnewsrc, newsrc); return TRUE; } } return FALSE; } void mark_group_read (group, groupnum) char *group; int groupnum; /* index into active[] for this group */ { char buf[NEWSRC_LINE]; char c, *p; FILE *fp; FILE *newfp; if (active[groupnum].max < 2) { return; } #ifdef VMS if ((newfp = fopen (newnewsrc, "w", "fop=cif")) == (FILE *) 0) { #else if ((newfp = fopen (newnewsrc, "w")) == (FILE *) 0) { #endif goto mark_group_read_done; } if ((fp = fopen (newsrc, "r")) != (FILE *) 0) { while (fgets (buf, sizeof (buf), fp) != NULL) { for (p = buf; *p; p++) { if (*p == '\n') { *p = '\0'; break; } } p = buf; while (*p && *p != ' ' && *p != ':' && *p != '!') { p++; } c = *p; if (c != '\0') { *p++ = '\0'; } if (c != '!') { c = ':'; } if (strcmp (buf, group) == 0) { fprintf (newfp, "%s%c 1-%ld\n", buf, c, active[groupnum].max); if (active[groupnum].newsrc) { checknewsrc(groupnum); NSETBLK(active[groupnum].newsrc, active[groupnum].max - active[groupnum].min); } } else { fprintf (newfp, "%s%c%s\n", buf, c, p); } } fclose (fp); } fclose (newfp); rename_file (newnewsrc, newsrc); mark_group_read_done: ; } void parse_seq (s) char *s; { long low, high; int i; while (*s) { while (*s && (*s < '0' || *s > '9')) s++; if (*s && *s >= '0' && *s <= '9') { low = (long) atol (s); while (*s && *s >= '0' && *s <= '9') s++; if (*s == '-') { s++; high = (long) atol (s); while (*s && *s >= '0' && *s <= '9') s++; } else high = low; for (i = 0; i < top; i++) if (arts[i].artnum >= low && arts[i].artnum <= high) arts[i].unread = ART_READ; } } } /* * Read the first range from the .newsrc sequencer information. * If the top of the first range is higher than what the active * file claims is the bottom, use it as the new bottom instead. */ int parse_unread (s, groupnum) char *s; int groupnum; /* index for group in active[] */ { char c; int n, sum = 0; int gotone = FALSE; long low, high, truelow, truehigh; long last_high; if (active[groupnum].newsrc == (char *) 0) { active[groupnum].newsrcsize = active[groupnum].max - active[groupnum].min + 1; if (active[groupnum].newsrcsize <= 0) { active[groupnum].newsrcsize = 1; } active[groupnum].newsrc = my_malloc ((unsigned) ((active[groupnum].newsrcsize + 7) / 8)); } else if (active[groupnum].newsrcsize != (active[groupnum].max - active[groupnum].min + 1)) { active[groupnum].newsrcsize = active[groupnum].max - active[groupnum].min + 1; if (active[groupnum].newsrcsize <= 0) { active[groupnum].newsrcsize = 1; } active[groupnum].newsrc = my_realloc (active[groupnum].newsrc, (unsigned) ((active[groupnum].newsrcsize + 7) / 8)); } active[groupnum].newsrcmax = active[groupnum].max; active[groupnum].newsrcmin = active[groupnum].min; active[groupnum].newsrcupdate = FALSE; NSETBLK(active[groupnum].newsrc, active[groupnum].max - active[groupnum].min); high = low = 0; /* * Skip possible non-numeric prefix */ while ((c = *s) && (c < '0' || c > '9')) { s++; } if (c) { gotone = TRUE; low = strtol (s, &s, 10); truelow = low - active[groupnum].min; /* Bitmap index... */ if (*s == '-') { /* There is a range of articles to mark read */ s++; high = strtol (s, &s, 10); /* Make sure it intersects range of our bitmap */ if ((low <= high) && (low <= active[groupnum].max) && (high >= active[groupnum].min)) { /* Restrict the range to min..max */ if (truelow < 0) { truelow = 0; } truehigh = high; if (truehigh > active[groupnum].max) { truehigh = active[groupnum].max; } truehigh -= active[groupnum].min; /* Fill in the whole range */ NRESETRNG(active[groupnum].newsrc, truelow, truehigh); } } else { /* * Just one article to tag read */ high = low; if (truelow >= 0 && high <= active[groupnum].max) { NRESET(active[groupnum].newsrc, truelow); } } /* * Skip possible non-numeric prefix before next range */ while ((c = *s) && (c < '0' || c > '9')) { s++; } } /* Note that in the active file min will be one greater than max * when there are no articles in the spool directory. ie., it is * always true that "max - min + 1 = article count (including * expired articles)" */ if (high < active[groupnum].min - 1) { high = active[groupnum].min - 1; } /* * Now pick up any additional articles/ranges after the first */ while (c) { last_high = high; low = strtol (s, &s, 10); truelow = low - active[groupnum].min; /* Bitmap index... */ if (*s == '-') { /* There is a range of articles to mark read */ s++; high = strtol (s, &s, 10); } else { /* Just one article to tag read */ high = low; } if (low > last_high) { /* otherwise seq out of order */ sum += (low - last_high) - 1; } if (high == low) { if (truelow >= 0 && high <= active[groupnum].max) { NRESET(active[groupnum].newsrc, truelow); } } /* * A range - make sure it intersects range of our bitmap */ else if ((low <= high ) && (low <= active[groupnum].max) && (high >= active[groupnum].min)) { /* Restrict the range to min..max */ if (truelow < 0) { truelow = 0; } truehigh = high; if (truehigh > active[groupnum].max) { truehigh = active[groupnum].max; } truehigh -= active[groupnum].min; /* * Fill in the whole range */ NRESETRNG(active[groupnum].newsrc, truelow, truehigh); } /* * Skip possible non-numeric prefix before next range */ while ((c = *s) && (c < '0' || c > '9' )) { s++; } } if (gotone) { if (active[groupnum].max > high) { sum += active[groupnum].max - high; } return sum; } n = (int) (active[groupnum].max - active[groupnum].min) + 1; return (n < 0 ? -1 : n); } int get_line_unread (group, groupnum) char *group; int groupnum; /* index for group in active[] */ { char *p, buf[NEWSRC_LINE]; FILE *fp; int ret = -1; if ((fp = fopen(newsrc, "r")) == NULL) return -1; while (fgets(buf, sizeof (buf), fp) != NULL) { p = buf; while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!') p++; *p++ = '\0'; if (strcmp (buf, group) != 0) continue; ret = parse_unread (p, groupnum); break; } fclose (fp); return ret; } void print_newsrc_seq (fp, groupnum) FILE *fp; int groupnum; /* index into active[] for this group */ { int flag = FALSE; long artnum; long i, last; for (i = active[groupnum].min ; i <= active[groupnum].max ; i++) { if (NTEST(active[groupnum].newsrc, i - active[groupnum].min) == 0) { if (flag) { artnum = i; fprintf (fp, ",%ld", i); } else { artnum = 1; flag = TRUE; fprintf (fp, "1"); } i++; while (i <= active[groupnum].max && NTEST(active[groupnum].newsrc,i - active[groupnum].min) == 0) { i++; } last = i - 1; if (artnum != last) { fprintf (fp, "-%ld", last); } } else if (flag == FALSE && active[groupnum].max > 0) { flag = TRUE; fprintf (fp, "1"); if (active[groupnum].min > 2) { fprintf (fp, "-%ld", active[groupnum].min-1); } } } if (flag == FALSE && active[groupnum].max > 0) { fprintf (fp, "1"); if (active[groupnum].min > 2) { fprintf (fp, "-%ld", active[groupnum].min-1); } } fflush (fp); } void print_seq (fp, groupnum) FILE *fp; int groupnum; /* index into active[] for this group */ { long int artnum, last_read, artmax; int i, flag = FALSE; assert(top >= 0); /* * sort into the same order as in the spool area for writing * read article numbers to ~/.newsrc */ if (top > 0) qsort ((char *) arts, top, sizeof (struct t_article), artnum_comp); /* * Note that killed and expired articles do not appear in arts[]. * So, even if top is 0 there may be sequencer info to output. */ if (top > 0 && arts[top-1].artnum > active[groupnum].max) { artmax = arts[top-1].artnum; } else { artmax = active[groupnum].max; } for (artnum=1, i=0; artnum <= artmax; ++artnum, ++i) { assert(i<=top); if (i==top || arts[i].unread == ART_READ || artnum != arts[i].artnum) { if (flag) fprintf(fp, ","); else flag = TRUE; fprintf (fp, "%ld", artnum); while (i < top && arts[i].unread == ART_READ) ++i; last_read = (i # include # include # include # ifdef WIN_TCP # include # else # include # endif # define IPPORT_NNTP ((unsigned short) 119) # include /* All TLI implementations may not have this */ # else # ifdef apollo # include # include # include # else # ifdef MULTINET # include "MULTINET_ROOT:[multinet.include.sys]socket.h" # include "MULTINET_ROOT:[multinet.include.netinet]in.h" # else # include # include # endif # ifdef HAVE_NETLIB_H # include # endif # ifndef EXCELAN # include # endif # endif # endif /* !TLI */ # ifdef EXCELAN # if __STDC__ int connect (int, struct sockaddr *); unsigned short htons (unsigned short); unsigned long rhost (char **); int rresvport (int); int socket (int, struct sockproto *, struct sockaddr_in *, int); # endif # endif # ifdef DECNET # include # include # endif #endif /* NNTP_ABLE */ /* * getserverbyfile Get the name of a server from a named file. * Handle white space and comments. * Use NNTPSERVER environment variable if set. * * Parameters: "file" is the name of the file to read. * * Returns: Pointer to static data area containing the * first non-ws/comment line in the file. * NULL on error (or lack of entry in file). * * Side effects: None. */ char *getserverbyfile (file) char *file; { #ifdef NNTP_ABLE register FILE *fp; register char *cp; static char buf[256]; cp = (char *) getenv ("NNTPSERVER"); if (cp != (char *) 0) { (void) strcpy (buf, cp); return (buf); } cp = GetConfigValue (_CONF_SERVER); if (cp != (char *) 0) { (void) strcpy (buf, cp); return (buf); } if (file == (char *) 0) { return (char *) 0; } if ((fp = fopen (file, "r")) == (FILE *) 0) { return (char *) 0; } while (fgets (buf, sizeof (buf), fp) != (char *) 0) { if (*buf == '\n' || *buf == '#') { continue; } cp = (char *) strrchr (buf, '\n'); if (cp) { *cp = '\0'; } (void) fclose (fp); return (buf); } (void) fclose (fp); #endif /* NNTP_ABLE */ return (char *) 0; /* No entry */ } /* * server_init Get a connection to the remote server. * * Parameters: "machine" is the machine to connect to. * "service" is the service to connect to on the machine. * "port" is the servive port to connect to. * * Returns: -1 on error * server's initial response code on success. * * Side effects: Connects to server. * "nntp_rd_fp" and "nntp_wr_fp" are fp's * for reading and writing to server. */ int server_init (machine, service, port) char *machine; char *service; unsigned short port; { #ifdef NNTP_ABLE #ifdef DECNET char *cp; cp = (char *) strchr(machine, ':'); if (cp && cp[1] == ':') { *cp = '\0'; sockt_rd = get_dnet_socket (machine, service); } else { sockt_rd = get_tcp_socket (machine, service, port); } #else sockt_rd = get_tcp_socket (machine, service, port); #endif if (sockt_rd < 0) return (-1); /* * Now we'll make file pointers (i.e., buffered I/O) out of * the socket file descriptor. Note that we can't just * open a fp for reading and writing -- we have to open * up two separate fp's, one for reading, one for writing. */ #ifndef MULTINET if ((nntp_rd_fp = (FILE *) fdopen (sockt_rd, "r")) == NULL) { perror ("server_init: fdopen #1"); return (-1); } sockt_wr = dup (sockt_rd); #else sockt_wr = sockt_rd; #endif #ifdef TLI if (t_sync (sockt_rd) < 0) { /* Sync up new fd with TLI */ t_error ("server_init: t_sync"); nntp_rd_fp = NULL; /* from above */ return (-1); } #endif #ifndef MULTINET if ((nntp_wr_fp = (FILE *) fdopen (sockt_wr, "w")) == NULL) { perror ("server_init: fdopen #2"); nntp_rd_fp = NULL; /* from above */ return (-1); } #endif /* * Now get the server's signon message */ (void) get_server (nntp_line, sizeof (nntp_line)); return (atoi (nntp_line)); #else return (-1); #endif /* NNTP_ABLE */ } /* * get_tcp_socket -- get us a socket connected to the specified server. * * Parameters: "machine" is the machine the server is running on. * "service" is the service to connect to on the server. * "port" is the port to connect to on the server. * * Returns: Socket connected to the server if * all is ok, else -1 on error. * * Side effects: Connects to server. * * Errors: Printed via perror. */ int get_tcp_socket (machine, service, port) char *machine; /* remote host */ char *service; /* nttp/smtp etc. */ unsigned short port; /* tcp port number */ { #ifdef NNTP_ABLE int s = -1; struct sockaddr_in sin; #ifdef __hpux int socksize = 0; int socksizelen = sizeof (socksize); #endif #ifdef TLI struct hostent *gethostbyname (), *hp; struct t_call *callptr; /* * Create a TCP transport endpoint. */ if ((s = t_open ("/dev/tcp", O_RDWR, (struct t_info*) 0)) < 0){ t_error ("t_open: can't t_open /dev/tcp"); return (-1); } if (t_bind (s, (struct t_bind *) 0, (struct t_bind *) 0) < 0) { t_error ("t_bind"); t_close (s); return (-1); } bzero((char *) &sin, sizeof (sin)); sin.sin_family = AF_INET; sin.sin_port = htons (port); if (!isdigit(*machine) || (long)(sin.sin_addr.s_addr = inet_addr (machine)) == -1) { if((hp = gethostbyname (machine)) == NULL) { fprintf (stderr, "gethostbyname: %s: host unknown\n", machine); t_close (s); return (-1); } bcopy(hp->h_addr, (char *) &sin.sin_addr, hp->h_length); } /* * Allocate a t_call structure and initialize it. * Let t_alloc() initialize the addr structure of the t_call structure. */ if ((callptr = (struct t_call *) t_alloc (s,T_CALL,T_ADDR)) == NULL){ t_error ("t_alloc"); t_close (s); return (-1); } callptr->addr.maxlen = sizeof (sin); callptr->addr.len = sizeof (sin); callptr->addr.buf = (char *) &sin; callptr->opt.len = 0; /* no options */ callptr->udata.len = 0; /* no user data with connect */ /* * Connect to the server. */ if (t_connect (s, callptr, (struct t_call *) 0) < 0) { t_error ("t_connect"); t_close (s); return (-1); } /* * Now replace the timod module with the tirdwr module so that * standard read() and write() system calls can be used on the * descriptor. */ if (ioctl (s, I_POP, (char *) 0) < 0) { perror ("I_POP(timod)"); t_close (s); return (-1); } if (ioctl (s, I_PUSH, "tirdwr") < 0) { perror ("I_PUSH(tirdwr)"); t_close (s); return (-1); } #else /* !TLI */ #ifndef EXCELAN struct servent *getservbyname(), *sp; struct hostent *gethostbyname(), *hp; #ifdef h_addr int x = 0; register char **cp; static char *alist[1]; #endif /* h_addr */ unsigned long inet_addr(); static struct hostent def; static struct in_addr defaddr; static char namebuf[256]; if ((sp = (struct servent *) getservbyname (service, "tcp")) == NULL) { fprintf (stderr, "%s/tcp: Unknown service.\n", service); return (-1); } /* If not a raw ip address, try nameserver */ if (!isdigit(*machine) || (long)(defaddr.s_addr = (long) inet_addr (machine)) == -1) { hp = gethostbyname (machine); } else { /* Raw ip address, fake */ (void) strcpy (namebuf, machine); def.h_name = (char *) namebuf; #ifdef h_addr def.h_addr_list = alist; #endif def.h_addr = (char *) &defaddr; def.h_length = sizeof (struct in_addr); def.h_addrtype = AF_INET; def.h_aliases = 0; hp = &def; } if (hp == NULL) { fprintf (stderr, "\n%s: Unknown host.\n", machine); return (-1); } bzero((char *) &sin, sizeof (sin)); sin.sin_family = hp->h_addrtype; sin.sin_port = sp->s_port; #else /* EXCELAN */ bzero((char *) &sin, sizeof (sin)); sin.sin_family = AF_INET; #endif /* EXCELAN */ /* * The following is kinda gross. The name server under 4.3 * returns a list of addresses, each of which should be tried * in turn if the previous one fails. However, 4.2 hostent * structure doesn't have this list of addresses. * Under 4.3, h_addr is a #define to h_addr_list[0]. * We use this to figure out whether to include the NS specific * code... */ #ifdef h_addr /* * get a socket and initiate connection -- use multiple addresses */ for (cp = hp->h_addr_list; cp && *cp; cp++) { s = socket (hp->h_addrtype, SOCK_STREAM, 0); if (s < 0) { perror ("socket"); return (-1); } bcopy(*cp, (char *) &sin.sin_addr, hp->h_length); if (x < 0) { fprintf (stderr, "Trying %s", (char *) inet_ntoa (sin.sin_addr)); } #if defined(__hpux) && defined(SVR4) /* recommended by raj@cup.hp.com */ #define HPSOCKSIZE 0x8000 getsockopt(s, SOL_SOCKET, SO_SNDBUF, (caddr_t)&socksize, (caddr_t)&socksizelen); if (socksize < HPSOCKSIZE) { socksize = HPSOCKSIZE; setsockopt(s, SOL_SOCKET, SO_SNDBUF, (caddr_t)&socksize, sizeof(socksize)); } socksize = 0; socksizelen = sizeof(socksize); getsockopt(s, SOL_SOCKET, SO_RCVBUF, (caddr_t)&socksize, (caddr_t)&socksizelen); if (socksize < HPSOCKSIZE) { socksize = HPSOCKSIZE; setsockopt(s, SOL_SOCKET, SO_RCVBUF, (caddr_t)&socksize, sizeof(socksize)); } #endif x = connect (s, (struct sockaddr *) &sin, sizeof (sin)); if (x == 0) { break; } fprintf (stderr, "\nConnection to %s: ", (char *) inet_ntoa (sin.sin_addr)); perror (""); (void) close (s); } if (x < 0) { fprintf (stderr, "Giving up...\n"); return (-1); } #else /* no name server */ #ifdef EXCELAN if ((s = socket (SOCK_STREAM,(struct sockproto *)NULL,&sin,SO_KEEPALIVE)) < 0) { /* Get the socket */ perror ("socket"); return (-1); } bzero((char *) &sin, sizeof (sin)); sin.sin_family = AF_INET; sin.sin_port = htons (IPPORT_NNTP); /* set up addr for the connect */ if ((sin.sin_addr.s_addr = rhost (&machine)) == -1) { fprintf (stderr, "\n%s: Unknown host.\n", machine); return (-1); } /* And then connect */ if (connect (s, (struct sockaddr *)&sin) < 0) { perror ("connect"); (void) close (s); return (-1); } #else /* not EXCELAN */ if ((s = socket (AF_INET, SOCK_STREAM, 0)) < 0) { perror ("socket"); return (-1); } /* And then connect */ bcopy (hp->h_addr, (char *) &sin.sin_addr, hp->h_length); if (connect (s, (struct sockaddr *) &sin, sizeof (sin)) < 0) { perror ("connect"); (void) close (s); return (-1); } #endif /* !EXCELAN */ #endif /* !h_addr */ #endif /* !TLI */ return (s); #else return (-1); #endif /* NNTP_ABLE */ } #ifdef DECNET /* * get_dnet_socket -- get us a socket connected to the server. * * Parameters: "machine" is the machine the server is running on. * "service" is the name of the service to connect to. * * Returns: Socket connected to the news server if * all is ok, else -1 on error. * * Side effects: Connects to server. * * Errors: Printed via nerror. */ int get_dnet_socket (machine, service) char *machine; char *service; { #ifdef NNTP_ABLE int s, area, node; struct sockaddr_dn sdn; struct nodeent *getnodebyname(), *np; bzero((char *) &sdn, sizeof (sdn)); switch (s = sscanf (machine, "%d%*[.]%d", &area, &node)) { case 1: node = area; area = 0; case 2: node += area*1024; sdn.sdn_add.a_len = 2; sdn.sdn_family = AF_DECnet; sdn.sdn_add.a_addr[0] = node % 256; sdn.sdn_add.a_addr[1] = node / 256; break; default: if ((np = getnodebyname (machine)) == NULL) { fprintf (stderr, "%s: Unknown host.\n", machine); return (-1); } else { bcopy(np->n_addr, (char *) sdn.sdn_add.a_addr, np->n_length); sdn.sdn_add.a_len = np->n_length; sdn.sdn_family = np->n_addrtype; } break; } sdn.sdn_objnum = 0; sdn.sdn_flags = 0; sdn.sdn_objnamel = strlen ("NNTP"); bcopy("NNTP", &sdn.sdn_objname[0], sdn.sdn_objnamel); if ((s = socket (AF_DECnet, SOCK_STREAM, 0)) < 0) { nerror ("socket"); return (-1); } /* And then connect */ if (connect (s, (struct sockaddr *) &sdn, sizeof (sdn)) < 0) { nerror ("connect"); close (s); return (-1); } return (s); #else return (-1); #endif /* NNTP_ABLE */ } #endif /* * handle_server_response * * Print some informative messages based on the server's initial * response code. This is here so inews, rn, etc. can share * the code. * * Parameters: "response" is the response code which the * server sent us, presumably from "server_init", * above. * "nntpserver" is the news server we got the * response code from. * * Returns: -1 if the error is fatal (and we should exit). * 0 otherwise. * * Side effects: None. */ int handle_server_response (response, nntpserver) int response; char *nntpserver; { #ifdef NNTP_ABLE switch (response) { case OK_NOPOST: /* fall through */ printf ("NOTE: This machine does not have permission to post articles.\n"); printf (" Please don't waste your time trying.\n\n"); case OK_CANPOST: return (0); break; case ERR_ACCESS: printf ("This machine does not have permission to use the %s news server.\n", nntpserver); return (-1); break; default: printf ("Unexpected response code from %s news server: %d\n", nntpserver, response); return (-1); À €­m~ TIN-1_22.BCK' d[SRC.TIN-1_22]NNTPLIB.C;23-g?" break; } /*NOTREACHED*/ #else return (-1); #endif /* NNTP_ABLE */ } /* * put_server -- send a line of text to the server, terminating it * with CR and LF, as per ARPA standard. * * Parameters: "string" is the string to be sent to the * server. * * Returns: Nothing. * * Side effects: Talks to the server. * Closes connection if things are not right. * * Note: This routine flushes the buffer each time * it is called. For large transmissions * (i.e., posting news) don't use it. Instead, * do the fprintf's yourself, and then a final * fflush. */ void put_server (string) char *string; { #ifdef NNTP_ABLE int respno; static time_t time_last; time_t time_now; /* * Check how idle we have been, if too idle send a STAT to check */ time (&time_now); if (time_last != 0 && time_last+NNTP_IDLE_RETRY_SECS < time_now) { #ifndef MULTINET fprintf (nntp_wr_fp, "stat\r\n"); fflush (nntp_wr_fp); #else socket_write(sockt_wr, "stat\r\n", 6); #endif respno = get_respcode (); if (respno != OK_NOTEXT && respno != ERR_NCING && respno != ERR_NOCRNT) { /* * STAT was not happy, close the connection * it will reopen on next get_server */ #ifndef MULTINET fclose (nntp_wr_fp); fclose (nntp_rd_fp); #else socket_close(sockt_rd); #endif strcpy (last_put, string); time_last = 0; return; } } time_last = time_now; #ifndef MULTINET fprintf (nntp_wr_fp, "%s\r\n", string); (void) fflush (nntp_wr_fp); #else { char line[256]; sprintf(line, "%s\r\n", string); socket_write(sockt_wr, line, strlen(line)); } #endif strcpy (last_put, string); #endif /* NNTP_ABLE */ } /* * get_server -- get a line of text from the server. Strips * CR's and LF's. * * Parameters: "string" has the buffer space for the * line received. * "size" is the size of the buffer. * * Returns: -1 on error, 0 otherwise. * * Side effects: Talks to server, changes contents of "string". * Reopens connection when necessary and requested. */ int get_server (string, size) char *string; int size; { #ifdef NNTP_ABLE char buf[NNTP_STRLEN]; extern char *glob_group; register char *cp; #ifndef MULTINET while (fgets (string, size, nntp_rd_fp) == NULL) { #else #ifdef USE_SFGETS while (Sfgets (string, size, sockt_rd) == NULL) { #else char *p; while ((p = Srdline(sockt_rd)) == NULL) { #endif #endif if (errno != EINTR) { #ifndef MULTINET fclose (nntp_wr_fp); fclose (nntp_rd_fp); #else socket_close(sockt_rd); #endif ring_bell (); if (! prompt_yn (cLINES, txt_reconnect_to_news_server, 'y')) { return -1; } clear_message (); strcpy (buf, last_put); if (nntp_open () == 0) { if (glob_group != (char *) 0) { sprintf (last_put, "group %s", glob_group); put_server (last_put); #ifndef MULTINET fgets (last_put, NNTP_STRLEN, nntp_rd_fp); #else #ifdef USE_SFGETS Sfgets (last_put, NNTP_STRLEN, sockt_rd); #else p = Srdline(sockt_rd); strncpy(last_put, p, NNTP_STRLEN); #endif #endif } } put_server (buf); } } #ifdef MULTINET #ifndef USE_SFGETS memcpy(string, p, SIOLINELEN(sockt_rd) + 1); #endif #endif if ((cp = (char *) strchr (string, '\r')) != NULL) { *cp = '\0'; } else if ((cp = (char *) strchr (string, '\n')) != NULL) { *cp = '\0'; } return (0); #else return (-1); #endif /* NNTP_ABLE */ } /* * close_server -- close the connection to the server, after sending * the "quit" command. * * Parameters: None. * * Returns: Nothing. * * Side effects: Closes the connection with the server. * You can't use "put_server" or "get_server" * after this routine is called. */ void close_server () { #ifdef NNTP_ABLE #ifndef MULTINET if (nntp_wr_fp == NULL || nntp_rd_fp == NULL) return; #else if (sockt_rd == -1) return; #endif put_server ("QUIT"); (void) get_server (nntp_line, sizeof (nntp_line)); #ifndef MULTINET (void) fclose (nntp_wr_fp); (void) fclose (nntp_rd_fp); #else Sdone(sockt_rd); socket_close(sockt_rd); #endif #endif /* NNTP_ABLE */ } #endif /* CDROM_ABLE */ /* * NNTP strings for get_respcode() */ char *nntp_respcode (respcode) int respcode; { #ifdef NNTP_ABLE static char *text; /* * If the last response line matches and has a description, return it */ if (atoi (nntp_line) == respcode && strlen (nntp_line) > 4) { return nntp_line; } switch (respcode) { case 0: text = ""; break; case INF_HELP: text = "100 Help text on way"; break; case INF_AUTH: text = "180 Authorization capabilities"; break; case INF_DEBUG: text = "199 Debug output"; break; case OK_CANPOST: text = "200 Hello; you can post"; break; case OK_NOPOST: text = "201 Hello; you can't post"; break; case OK_SLAVE: text = "202 Slave status noted"; break; case OK_GOODBYE: text = "205 Closing connection"; break; case OK_GROUP: text = "211 Group selected"; break; case OK_GROUPS: text = "215 Newsgroups follow"; break; case OK_XMOTD: text = "217 News motd file follows"; break; case OK_XINDEX: text = "218 Group index file follows"; break; case OK_ARTICLE: text = "220 Article (head & body) follows"; break; case OK_HEAD: text = "221 Head follows"; break; case OK_BODY: text = "222 Body follows"; break; case OK_NOTEXT: text = "223 No text sent -- stat, next, last"; break; case OK_NEWNEWS: text = "230 New articles by message-id follow"; break; case OK_NEWGROUPS: text = "231 New newsgroups follow"; break; case OK_XFERED: text = "235 Article transferred successfully"; break; case OK_POSTED: text = "240 Article posted successfully"; break; case OK_AUTHSYS: text = "280 Authorization system ok"; break; case OK_AUTH: text = "281 Authorization (user/pass) ok"; break; case OK_BIN: text = "282 binary data follows"; break; case OK_SPLIST: text = "283 spooldir list follows"; break; case OK_SPSWITCH: text = "284 Switching to a different spooldir"; break; case OK_SPNOCHANGE: text = "285 Still using same spooldir"; break; case OK_SPLDIRCUR: text = "286 Current spooldir"; break; case OK_SPLDIRAVL: text = "287 Available spooldir"; break; case OK_SPLDIRERR: text = "288 Unavailable spooldir or invalid entry"; break; case CONT_XFER: text = "335 Continue to send article"; break; case CONT_POST: text = "340 Continue to post article"; break; case NEED_AUTHINFO: text = "380 authorization is required"; break; case NEED_AUTHDATA: text = "381 authorization data required"; break; case ERR_GOODBYE: text = "400 Have to hang up for some reason"; break; case ERR_NOGROUP: text = "411 No such newsgroup"; break; case ERR_NCING: text = "412 Not currently in newsgroup"; break; case ERR_XMOTD: text = "417 No news motd file"; break; case ERR_XINDEX: text = "418 No index file for this group"; break; case ERR_NOCRNT: text = "420 No current article selected"; break; case ERR_NONEXT: text = "421 No next article in this group"; break; case ERR_NOPREV: text = "422 No previous article in this group"; break; case ERR_NOARTIG: text = "423 No such article in this group"; break; case ERR_NOART: text = "430 No such article at all"; break; case ERR_GOTIT: text = "435 Already got that article, don't send"; break; case ERR_XFERFAIL: text = "436 Transfer failed"; break; case ERR_XFERRJCT: text = "437 Article rejected, don't resend"; break; case ERR_NOPOST: text = "440 Posting not allowed"; break; case ERR_POSTFAIL: text = "441 Posting failed"; break; case ERR_NOAUTH: text = "480 authorization required for command"; break; case ERR_AUTHSYS: text = "481 Authorization system invalid"; break; case ERR_AUTHREJ: text = "482 Authorization data rejected"; break; case ERR_INVALIAS: text = "483 Invalid alias on spooldir cmd"; break; case ERR_INVNOSPDIR: text = "484 No spooldir file found"; break; case ERR_COMMAND: text = "500 Command not recognized"; break; case ERR_CMDSYN: text = "501 Command syntax error"; break; case ERR_ACCESS: text = "502 Access to server denied"; break; case ERR_FAULT: text = "503 Program fault, command not performed"; break; case ERR_AUTHBAD: text = "580 Authorization Failed"; break; default: text = "Unknown NNTP response code"; break; } return (text); #else return (""); #endif } ð*[SRC.TIN-1_22]NNTPLIB.H;1+,ƒ. //€ 4 í-d0@î123KÿPWO 56 Vt…—7€tf1—89€]V‚—G/€HªJÿ/* * Project : tin - a Usenet reader * Module : nntplib.h * Author : I.Lea * Created : 01-04-91 * Updated : 03-08-93 * Notes : nntp.h 1.5.11/1.6 with extensions for tin & CD-ROM * Copyright : You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #ifndef NNTP_SERVER_FILE # define NNTP_SERVER_FILE "/etc/nntpserver" #endif #define NNTP_TCP_NAME "nntp" #define NNTP_TCP_PORT ((unsigned short) 119) #ifndef SMTP_SERVER_FILE # define SMTP_SERVER_FILE "/etc/smtpserver" #endif #define SMTP_TCP_NAME "smtp" #define SMTP_TCP_PORT ((unsigned short) 25) /* * External routine declarations */ #ifndef M_AMIGA extern char *getserverbyfile(); extern int get_tcp_socket(); extern int handle_server_response(); extern void put_server(); extern int get_server(); extern void close_server(); #endif /* M_AMIGA */ /* * External file descriptors for the server connection */ extern FILE *nntp_wr_fp; /* * Response codes for NNTP server * * @(#)Header: nntp.h,v 1.81 92/03/12 02:08:31 sob Exp $ * * First digit: * * 1xx Informative message * 2xx Command ok * 3xx Command ok so far, continue * 4xx Command was correct, but couldn't be performed * for some specified reason. * 5xx Command unimplemented, incorrect, or a * program error has occured. * * Second digit: * * x0x Connection, setup, miscellaneous * x1x Newsgroup selection * x2x Article selection * x3x Distribution * x4x Posting */ #define CHAR_INF '1' #define CHAR_OK '2' #define CHAR_CONT '3' #define CHAR_ERR '4' #define CHAR_FATAL '5' #define INF_HELP 100 /* Help text on way */ #define INF_AUTH 180 /* Authorization capabilities */ #define INF_DEBUG 199 /* Debug output */ #define OK_CANPOST 200 /* Hello; you can post */ #define OK_NOPOST 201 /* Hello; you can't post */ #define OK_SLAVE 202 /* Slave status noted */ #define OK_GOODBYE 205 /* Closing connection */ #define OK_GROUP 211 /* Group selected */ #define OK_GROUPS 215 /* Newsgroups follow */ #define OK_XMOTD 217 /* News motd follows */ #define OK_XINDEX 218 /* Tin style index follows */ #define OK_ARTICLE 220 /* Article (head & body) follows */ #define OK_HEAD 221 /* Head follows */ #define OK_BODY 222 /* Body follows */ #define OK_NOTEXT 223 /* No text sent -- stat, next, last */ #define OK_XOVER 224 /* .overview data follows */ #define OK_NEWNEWS 230 /* New articles by message-id follow */ #define OK_NEWGROUPS 231 /* New newsgroups follow */ #define OK_XFERED 235 /* Article transferred successfully */ #define OK_POSTED 240 /* Article posted successfully */ #define OK_AUTHSYS 280 /* Authorization system ok */ #define OK_AUTH 281 /* Authorization (user/pass) ok */ #define OK_BIN 282 /* binary data follows */ #define OK_SPLIST 283 /* spooldir list follows */ #define OK_SPSWITCH 284 /* Switching to a different spooldir */ #define OK_SPNOCHANGE 285 /* Still using same spooldir */ #define OK_SPLDIRCUR 286 /* Current spooldir */ #define OK_SPLDIRAVL 287 /* Available spooldir */ #define OK_SPLDIRERR 288 /* Unavailable spooldir or invalid entry */ #define CONT_XFER 335 /* Continue to send article */ #define CONT_POST 340 /* Continue to post article */ #define NEED_AUTHINFO 380 /* authorization is required */ #define NEED_AUTHDATA 381 /* authorization data required */ #define ERR_GOODBYE 400 /* Have to hang up for some reason */ #define ERR_NOGROUP 411 /* No such newsgroup */ #define ERR_NCING 412 /* Not currently in newsgroup */ #define ERR_XMOTD 417 /* No news motd file */ #define ERR_XINDEX 418 /* No tin index for this group */ #define ERR_XOVERVIEW 419 /* No .overview index for this group */ #define ERR_NOCRNT 420 /* No current article selected */ #define ERR_NONEXT 421 /* No next article in this group */ #define ERR_NOPREV 422 /* No previous article in this group */ #define ERR_NOARTIG 423 /* No such article in this group */ #define ERR_NOART 430 /* No such article at all */ #define ERR_GOTIT 435 /* Already got that article, don't send */ #define ERR_XFERFAIL 436 /* Transfer failed */ #define ERR_XFERRJCT 437 /* Article rejected, don't resend */ #define ERR_NOPOST 440 /* Posting not allowed */ #define ERR_POSTFAIL 441 /* Posting failed */ #define ERR_NOAUTH 480 /* authorization required for command */ #define ERR_AUTHSYS 481 /* Authorization system invalid */ #define ERR_AUTHREJ 482 /* Authorization data rejected */ #define ERR_INVALIAS 483 /* Invalid alias on spooldir cmd */ #define ERR_INVNOSPDIR 484 /* No spooldir file found */ #define ERR_COMMAND 500 /* Command not recognized */ #define ERR_CMDSYN 501 /* Command syntax error */ #define ERR_ACCESS 502 /* Access to server denied */ #define ERR_FAULT 503 /* Program fault, command not performed */ #define ERR_AUTHBAD 580 /* Authorization Failed */ /* * RFC 977 defines this; don't change it. */ #define NNTP_STRLEN 512 ð*[SRC.TIN-1_22]OBJS.OPT;10+,².//€ 4=Ð-d0ú123KÿPWO56`ãü Sˆ—7 ³g¡Sˆ—89€]V‚—G/€HªJÿ<active.obj,amiga.obj,art.obj,curses.obj,debug.obj,envarg.obj=feed.obj,getline.obj,group.obj,hashstr.obj,help.obj,inews.obj7init.obj,kill.obj,lang.obj,mail.obj,main.obj,memory.obj:misc.obj,newsrc.obj,nntplib.obj,open.obj,os_2.obj,page.obj4parsdate.obj,post.obj,prompt.obj,rcfile.obj,save.obj7screen.obj,search.obj,select.obj,sigfile.obj,signal.obj:spooldir.obj,strftime.obj,thread.obj,wildmat.obj,win32.objxref.objvms.obj[.vms]libvms/libÿÿð*[SRC.TIN-1_22]OPEN.C;2+,V.*//€ 4*(L-d0@î123KÿPWO+56@ Ëч—7@yÌч—89€]V‚—G/€HªJÿ /* * Project : tin - a Usenet reader * Module : open.c * Author : I.Lea & R.Skrenta * Created : 01-04-91 * Updated : 14-09-93 * Notes : Routines to make reading news locally (ie. /usr/spool/news) * or via NNTP transparent * Copyright : (c) Copyright 1991-93 by Iain Lea & Rich Skrenta * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" int nntp_codeno = 0; long head_next; #ifdef NNTP_ABLE int compiled_with_nntp = TRUE; /* used in mail_bug_report() info */ #else int compiled_with_nntp = FALSE; #endif #ifdef NO_POSTING int can_post = FALSE; #else int can_post = TRUE; #endif char *nntp_server; int nntp_open () { #ifdef NNTP_ABLE int ret; if (read_news_via_nntp) { debug_nntp ("nntp_open", "BEGIN"); nntp_server = getserverbyfile (NNTP_SERVER_FILE); if (nntp_server == (char *) 0) { error_message (txt_cannot_get_nntp_server_name, ""); error_message (txt_server_name_in_file_env_var, NNTP_SERVER_FILE); return -1; } if (update == FALSE) { sprintf (msg, txt_connecting, nntp_server); wait_message (msg); } debug_nntp ("nntp_open", nntp_server); ret = server_init (nntp_server, NNTP_TCP_NAME, NNTP_TCP_PORT); if (update == FALSE && ret != -1 && cmd_line) { fputc ('\n', stdout); } debug_nntp_respcode (ret); switch (ret) { case OK_CANPOST: #ifndef NO_POSTING can_post = TRUE; #endif break; case OK_NOPOST: can_post = FALSE; break; case -1: error_message (txt_failed_to_connect_to_server, nntp_server); sleep (2); return -1; default: sprintf (msg, "%s: %s", progname, nntp_respcode (ret)); error_message (msg, ""); sleep (2); return -1; } /* * If INN NNRP switch to mode reader */ debug_nntp ("nntp_open", "mode reader"); put_server ("mode reader"); if (get_respcode () != ERR_COMMAND) { inn_nntp_server = TRUE; } /* * Check if NNTP/INN supports XOVER command */ debug_nntp ("nntp_open", "xover"); put_server ("xover"); if (get_respcode () != ERR_COMMAND) { xover_supported = TRUE; xindex_supported = TRUE; /* a hack to get xindex behaviour */ } /* * Check if NNTP supports my XINDEX & XUSER commands */ #ifndef DONT_HAVE_NNTP_EXTS debug_nntp ("nntp_open", "xindex"); put_server ("xindex"); if (get_respcode () != ERR_COMMAND) { xindex_supported = TRUE; } debug_nntp ("nntp_open", "xuser"); put_server ("xuser"); if (get_respcode () != ERR_COMMAND) { xuser_supported = TRUE; } #endif /* DONT_HAVE_NNTP_EXTS */ /* * Check if NNTP server expects user authorization */ authorization (nntp_server, userid); /* * Check if overview indexes contain Xref: lines */ xref_supported = overview_xref_support (); } #ifndef DONT_HAVE_NNTP_EXTS /* * Find out if NNTP supports SPOOLDIR command */ get_spooldir (); #endif /* DONT_HAVE_NNTP_EXTS */ #endif return 0; } void nntp_close () { #ifdef NNTP_ABLE if (read_news_via_nntp) { debug_nntp ("nntp_close", "END"); close_server (); } #endif } /* * Open the mail active file locally */ FILE * open_mail_active_fp (mode) char *mode; { return fopen (mail_active_file, mode); } /* * Open the news active file locally or send the LIST command via NNTP */ FILE * open_news_active_fp () { int respcode; if (read_news_via_nntp) { #ifdef NNTP_ABLE put_server ("list"); if ((respcode = get_respcode ()) != OK_GROUPS) { debug_nntp ("open_news_active_fp", "NOT_OK"); error_message ("%s", nntp_respcode (respcode)); return (FILE *) 0; } debug_nntp ("open_news_active_fp", "OK"); return nntp_to_fp (); #else return (FILE *) 0; #endif } else { return fopen (news_active_file, "r"); } } /* * Open the LIBDIR/overview.fmt file locally or send the LIST OVERVIEW.FMT * command via NNTP */ FILE * open_overview_fmt_fp () { char line[NNTP_STRLEN]; if (read_news_via_nntp) { #ifdef NNTP_ABLE if (xover_supported) { sprintf (line, "list %s", OVERVIEW_FMT); debug_nntp ("open_overview_fmt_fp", line); put_server (line); if (get_respcode () != OK_GROUPS) { debug_nntp ("open_overview_fmt_fp", "NOT_OK"); return (FILE *) 0; } debug_nntp ("open_overview_fmt_fp", "OK"); return nntp_to_fp (); } else { return (FILE *) 0; } #else return (FILE *) 0; #endif } else { joinpath (line, libdir, OVERVIEW_FMT); return fopen (line, "r"); } } /* * Open the ~/.tin/active file locally or send the NEWGROUPS command via NNTP * * NEWGROUPS 311299 235959 */ FILE * open_newgroups_fp (index) int index; { char line[NNTP_STRLEN]; if (read_news_via_nntp) { #ifdef NNTP_ABLE if (index == -1) { return (FILE *) 0; } sprintf (line, "newgroups %s", active_size[index].attribute); debug_nntp ("open_newgroups_fp", line); put_server (line); if (get_respcode () != OK_NEWGROUPS) { debug_nntp ("open_newgroups_fp", "NOT_OK"); return (FILE *) 0; } debug_nntp ("open_newgroups_fp", "OK"); return nntp_to_fp (); #else return (FILE *) 0; #endif } else { joinpath (line, rcdir, ACTIVE_FILE); return fopen (line, "r"); } } /* * Open the news motd file locally or on the NNTP server * * XMOTD 311299 235959 [GMT] */ FILE * open_motd_fp (motd_file_date) char *motd_file_date; { char line[NNTP_STRLEN]; if (read_news_via_nntp) { #if defined(NNTP_ABLE) && !defined(DONT_HAVE_NNTP_EXTS) sprintf (line, "xmotd %s", motd_file_date); debug_nntp ("open_motd_fp", line); put_server (line); if (get_respcode () != OK_XMOTD) { debug_nntp ("open_motd_fp", "NOT_OK"); return (FILE *) 0; } debug_nntp ("open_motd_fp", "OK"); return nntp_to_fp (); #else return (FILE *) 0; #endif } else { return fopen (motd_file, "r"); } } FILE * open_subscription_fp () { if (read_news_via_nntp) { #ifdef NNTP_ABLE put_server ("list subscriptions"); if (get_respcode () != OK_GROUPS) { debug_nntp ("open_subscription_fp", "NOT_OK"); return (FILE *) 0; } debug_nntp ("open_subscription_fp", "OK"); return nntp_to_fp (); #else return (FILE *) 0; #endif } else { return fopen (subscriptions_file, "r"); } } /* * Open mail groups description file. */ FILE * open_mailgroups_fp () { return fopen (mailgroups_file, "r"); } /* * If reading via NNTP the newsgroups file will be saved to ~/.tin/newsgroups * so that any subsequent rereads on the active file will not have to waste * net bandwidth and the local copy of the newsgroups file can be accessed. */ FILE * open_newsgroups_fp () { if (read_news_via_nntp) { #ifdef NNTP_ABLE if (read_local_newsgroups_file) { debug_nntp ("open_newsgroups_fp", "Using local copy of newsgroups file"); return fopen (local_newsgroups_file, "r"); } else { put_server ("list newsgroups"); if (get_respcode () != OK_GROUPS) { debug_nntp ("open_newsgroups_fp", "NOT_OK"); return (FILE *) 0; } debug_nntp ("open_newsgroups_fp", "OK"); return nntp_to_fp (); } #else return (FILE *) 0; #endif } else { return fopen (newsgroups_file, "r"); } } /* * Open a group XINDEX file */ FILE * open_xindex_fp (group_name) char *group_name; { extern char index_file[PATH_LEN]; char line[NNTP_STRLEN]; int group_type; group_type = find_index_file (group_name); if (group_type == -1) { return (FILE *) 0; } if (debug == 2) { error_message ("INDEX file=[%s]", index_file); } if (read_news_via_nntp && xindex_supported && group_type == GROUP_TYPE_NEWS) { #ifdef NNTP_ABLE sprintf (line, "xindex %s", group_name); debug_nntp ("open_xindex_fp", line); put_server (line); if (get_respcode () != OK_XINDEX) { debug_nntp ("open_xindex_fp", "NOT_OK"); return (FILE *) 0; } debug_nntp ("open_xindex_fp", "OK"); return nntp_to_fp (); #else return (FILE *) 0; #endif } else { return fopen (index_file, "r"); } } /* * Open a group XOVER file */ FILE * open_xover_fp (group_name, min, max) char *group_name; long min; long max; { char group_path[PATH_LEN]; char xover_file[PATH_LEN]; char line[NNTP_STRLEN]; if (read_news_via_nntp && xover_supported) { #ifdef NNTP_ABLE sprintf (line, "xover %ld-%ld", min, max); debug_nntp ("open_xover_fp", line); put_server (line); if (get_respcode () != OK_XOVER) { debug_nntp ("open_xover_fp", "NOT_OK"); return (FILE *) 0; } debug_nntp ("open_xover_fp", "OK"); return nntp_to_fp (); #else return (FILE *) 0; #endif } else { char tbuf[256]; make_group_path (group_name, group_path); #ifdef VMS joindir(tbuf, novrootdir, group_path); joinpath(xover_file, tbuf, OVERVIEW_FILE); #else sprintf (xover_file, "%s/%s/%s", novrootdir, group_path, OVERVIEW_FILE); #endif if (debug == 2) { error_message ("XOVER file=[%s]", xover_file); } return fopen (xover_file, "r"); } } /* * Stat a mail/news article to see if it still exists */ int stat_article (art, group_path) long art; char *group_path; { char buf[NNTP_STRLEN]; int i, respcode; int art_exists = TRUE; struct stat sb; i = my_group[cur_groupnum]; if (read_news_via_nntp && active[i].type == GROUP_TYPE_NEWS) { #ifdef NNTP_ABLE sprintf (buf, "stat %ld", art); debug_nntp ("stat_article", buf); put_server (buf); if ((respcode = get_respcode ()) != OK_NOTEXT) { art_exists = FALSE; } #endif } else { joinpath (buf, active[i].spooldir, group_path); sprintf (&buf[strlen (buf)], "/%ld", art); if (stat (buf, &sb) == -1) { art_exists = FALSE; } } return art_exists; } char * open_art_header (art) long art; { char *ptr, buf[NNTP_STRLEN]; FILE *fp; int full, items = 0, len; int safe_nntp_strlen; static char mem[HEADER_LEN]; if (read_news_via_nntp && active[my_group[cur_groupnum]].type == GROUP_TYPE_NEWS) { #ifdef NNTP_ABLE /* * Don't bother requesting if we have not got there yet. * This is a big win if the group has got holes in it (ie. if 000's * of articles have expired between active files min & max values). */ if (art < head_next) { return (char *) 0; } sprintf (buf, "head %ld", art); debug_nntp ("open_art_header", buf); put_server (buf); if (get_respcode () != OK_HEAD) { debug_nntp ("open_art_header", "NOT_OK_HEAD - Find NEXT"); /* * HEAD failed, try to find NEXT */ put_server ("next"); if (get_server (buf, NNTP_STRLEN) == -1) { error_message (txt_connection_to_server_broken, ""); tin_done (1); } if (atoi (buf) == OK_NOTEXT) { ptr = buf; while (isspace(*ptr) || isdigit(*ptr)) { ptr++; } head_next = atoi (ptr); } return (char *) 0; } debug_nntp ("open_art_header", "OK_HEAD"); full = FALSE; safe_nntp_strlen = NNTP_STRLEN - 2; len = safe_nntp_strlen; ptr = mem; while (1) { if (full || len < 32) { full = TRUE; ptr = buf; len = safe_nntp_strlen; } if (get_server (ptr, len) == -1) { error_message (txt_connection_to_server_broken, ""); tin_done (1); } if (strcmp (ptr, ".") == 0) { /* end of text */ break; } if (ptr[0] == '.') { /* reduce leading .'s */ while (ptr[1]) { ptr[0] = ptr[1]; ptr++; len++; } } else { while (*ptr) { ptr++; len++; } *ptr++ = '\n'; *ptr = '\0'; len++; } } #else return (char *) 0; #endif } else { sprintf (buf, "%ld", art); fp = fopen (buf, "r"); if (fp != (FILE *) 0) { items = fread (mem, 1, sizeof (mem)-1, fp); fclose (fp); } /* printf ("Artnum=[%ld] Items=[%d]\n", art, items); fflush (stdout); sleep (1); */ if (items == 0) { return (char *) 0; } } return mem; } /* * Open a mail/news article */ FILE * open_art_fp (group_path, art) char *group_path; long art; { char buf[NNTP_STRLEN]; int i, respcode; struct stat sb; extern long note_size; i = my_group[cur_groupnum]; if (read_news_via_nntp && active[i].type == GROUP_TYPE_NEWS) { #ifdef NNTP_ABLE sprintf (buf, "article %ld", art); debug_nntp ("open_art_fp", buf); put_server (buf); if ((respcode = get_respcode ()) != OK_ARTICLE) { if (debug == 2) { error_message ("%s", nntp_respcode (respcode)); } debug_nntp ("open_art_fp", "NOT OK"); return (FILE *) 0; } debug_nntp ("open_art_fp", "OK"); return nntp_to_fp (); #else return (FILE *) 0; #endif } else { joinpath (buf, active[i].spooldir, group_path); sprintf (&buf[strlen (buf)], "/%ld", art); if (debug == 2) { error_message ("ART=[%s]", buf); } if (stat (buf, &sb) == -1) { note_size = 0; } else { note_size = sb.st_size; } return fopen (buf, "r"); } } FILE * open_xhdr_fp (header, min, max) char *header; long min; long max; { char buf[NNTP_STRLEN]; if (read_news_via_nntp) { #ifdef NNTP_ABLE sprintf(buf, "xhdr %s %ld-%ld", header, min, max); debug_nntp ("open_xhdr_fp", buf); put_server (buf); if (get_respcode () != OK_HEAD) { debug_nntp ("open_xhdr_fp", "NOT_OK_XHDR"); return (FILE *) 0; } debug_nntp ("open_xhdr_fp", "OK_XHDR"); return nntp_to_fp (); #else return (FILE *) 0; #endif } else { return (FILE *) 0; } } /* * Longword comparison routine for the qsort() */ int base_comp (p1, p2) t_comptype *p1; t_comptype *p2; { long *a = (long *) p1; long *b = (long *) p2; if (*a < *b) return -1; if (*a > *b) return 1; return 0; } /* * Read the article numbers existing in a group's spool directory * into base[] and sort them. top_base is one past top. */ void setup_base (group, group_path) char *group; char *group_path; { char buf[NNTP_STRLEN]; #ifdef NNTP_ABLE char line[NNTP_STRLEN]; #endif DIR *d; DIR_BUF *e; int i; long art, start, last, dummy, count; top_base = 0; i = my_group[cur_groupnum]; if (read_news_via_nntp && active[i].type == GROUP_TYPE_NEWS) { #ifdef NNTP_ABLE sprintf (buf, "group %s", group); debug_nntp ("setup_base", buf); put_server (buf); if (get_server (line, NNTP_STRLEN) == -1) { error_message (txt_connection_to_server_broken, ""); tin_done (1); } if (atoi (line) != OK_GROUP) { debug_nntp ("setup_base", "NOT_OK"); return; } debug_nntp ("setup_base", line); sscanf (line,"%ld %ld %ld %ld", &dummy, &count, &start, &last); if (inn_nntp_server) { sprintf (buf, "listgroup %s", group); debug_nntp ("setup_base", buf); put_server (buf); if (get_server (line, NNTP_STRLEN) == -1) { error_message (txt_connection_to_server_broken, ""); tin_done (1); } if (atoi (line) != OK_GROUP) { debug_nntp ("setup_base, listgroup", "NOT_OK"); return; } debug_nntp ("setup_base", line); while (TRUE) { if (get_server (line, NNTP_STRLEN) == -1) { error_message (txt_connection_to_server_broken, ""); tin_done (1); } if (strcmp (line, ".") == 0) { break; /* end of text */ } if (top_base >= max_art) { expand_art (); } base[top_base++] = atoi (line); } } else { if (last - count > start) { count = last - start; } while (start <= last) { if (top_base >= max_art) { expand_art(); } base[top_base++] = start++; } } #else return; #endif } else { joinpath (buf, active[i].spooldir, group_path); if (access (buf, 4) != 0) { return; } d = opendir (buf); if (d != NULL) { while ((e = readdir (d)) != NULL) { #ifdef M_OS2 art = my_atol (e->d_name, strlen (e->d_name)); #else art = my_atol (e->d_name, (int) e->D_LENGTH); #endif if (art >= 0) { if (top_base >= max_art) expand_art (); base[top_base++] = art; } } closedir (d); qsort ((char *) base, top_base, sizeof (long), base_comp); } } } /* * get a response code from the server and return it to the caller */ int get_respcode () { #ifdef NNTP_ABLE char line[NNTP_STRLEN]; if (get_server (line, NNTP_STRLEN) == -1) { error_message (txt_connection_to_server_broken, ""); tin_done (1); } debug_nntp ("get_respcode", line); return atoi (line); #else return (0); #endif } int stuff_nntp (fnam) char *fnam; { #ifdef NNTP_ABLE FILE *fp; char line[HEADER_LEN]; extern char *mktemp Øü}›~ TIN-1_22.BCKVd[SRC.TIN-1_22]OPEN.C;2*­Ä!(); struct stat sb; extern long note_size; sprintf (fnam, "%stin_nntpXXXXXX", TMPDIR); mktemp (fnam); if ((fp = fopen (fnam, "w")) == (FILE *) 0) { perror_message (txt_stuff_nntp_cannot_open, fnam); return FALSE; } while (1) { if (get_server (line, sizeof (line)-1) == -1) { error_message (txt_connection_to_server_broken, ""); tin_done (1); } debug_nntp ("stuff_nntp", line); if (strcmp (line, ".") == 0) { /* end of text */ break; } strcat (line, "\n"); if (line[0] == '.') { /* reduce leading .'s */ fputs (&line[1], fp); } else { fputs (line, fp); } } fclose (fp); if (stat (fnam, &sb) < 0) { note_size = 0; } else { note_size = sb.st_size; } return TRUE; #else return TRUE; #endif } FILE * nntp_to_fp () { #ifdef NNTP_ABLE char fnam[PATH_LEN]; FILE *fp = (FILE *) 0; if (! stuff_nntp (fnam)) { debug_nntp ("nntp_to_fp", "! stuff_nntp()"); return (FILE *) 0; } if ((fp = fopen (fnam, "r")) == (FILE *) 0) { perror_message (txt_nntp_to_fp_cannot_reopen, fnam); return (FILE *) 0; } unlink (fnam); return fp; #else return (FILE *) 0; #endif } /* * Log user info to local file or NNTP logfile */ void log_user () { char dummy[PATH_LEN]; char log_file[PATH_LEN]; char buf[32], *ptr; char line[NNTP_STRLEN]; #ifndef DONT_LOG_USER FILE *fp; long epoch; #endif #ifndef M_AMIGA extern struct passwd *myentry; get_user_info (dummy, buf); if (read_news_via_nntp && xuser_supported) { if ((ptr = (char *) strchr(buf, ','))) { *ptr = '\0'; } sprintf (line, "xuser %s (%s)", myentry->pw_name, buf); debug_nntp ("log_user", line); put_server (line); } else #endif /* M_AMIGA */ { #ifndef DONT_LOG_USER joinpath (log_file, TMPDIR, LOG_USER_FILE); if ((fp = fopen (log_file, "a+")) != (FILE *) 0) { time (&epoch); fprintf (fp, "%s%s: %-32s (%-8s) %s", VERSION, PATCHLEVEL, #ifdef M_AMIGA get_val ("REALNAME", "Unknown"), get_val ("USERNAME", "Unknown"), #else buf, myentry->pw_name, #endif ctime (&epoch)); fclose (fp); chmod (log_file, 0666); } #endif /* DONT_LOG_USER */ } } /* * NNTP user authorization. Password read from ~/.newsauth * The ~/.newsauth authorization file has the format: * nntpserver1 password * nntpserver2 password * etc. */ void authorization (server, authuser) char *server; char *authuser; { char authfile[PATH_LEN]; char authpass[PATH_LEN]; char line[NNTP_STRLEN]; char buf[PATH_LEN], *ptr; int found = FALSE; FILE *fp; /* * Check if running via NNTP */ if (! read_news_via_nntp) { return; } /* * Lets check if the NNTP supports authorization */ debug_nntp ("authorization", "authinfo"); put_server ("authinfo"); if (get_respcode () == ERR_COMMAND) { return; } joinpath (authfile, homedir, ".newsauth"); if ((fp = fopen (authfile,"r")) != (FILE *) 0) { /* * Search through authorization file for correct NNTP server * File has format: 'nntp-server' 'password' */ while (fgets (buf, sizeof (buf), fp) != (char *) 0) { /* * Get server from 1st part of the line */ strcpy (line, buf); ptr = (char *) strchr (line, ' '); if (ptr != (char *) 0) { *ptr = '\0'; } if (strncmp (line, server, sizeof (server)) == 0) { /* * Get passwdord from 2nd part of the line */ ptr = (char *) strrchr (buf, ' '); if (ptr != (char *) 0 && ++ptr != (char *) 0) { strcpy (authpass, ptr); ptr = (char *) strchr (authpass, '\n'); if (ptr != (char *) 0) { *ptr = '\0'; } found = TRUE; } break; } } fclose (fp); if (! found) { error_message (txt_nntp_authorization_failed, authuser); } else { sprintf (line, "authinfo user %s", authuser); put_server (line); get_respcode (); sprintf (line, "authinfo pass %s", authpass); put_server (line); get_respcode (); } } } ð*[SRC.TIN-1_22]OS_2.C;1+,¡.//€ 4 ‰-d0@î123KÿPWO56ct…—7s7p1—89€]V‚—G/€HªJÿ/* * Project : tin - a Usenet reader * Module : os_2.c * Author : A.Wrede & I.Lea * Created : 05-07-93 * Updated : 29-08-93 * Notes : Extra functions for OS/2 port * Copyright : (c) Copyright 1991-93 by Andreas Wrede & Iain Lea * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" #if defined(M_OS2) #include "os_2.h" struct passwd no_pw = { "OS2User", "x", 1, 1, "", "OS/2 User", "OS/2 User", "C:/", "CMD" }; char *optarg; FILE *_pwf; int fakepw = 1; int optind = 1; /* * stub for tputs */ #ifndef INDEX_DAEMON extern int outchar (int); tputs (str, zzz, func) register char *str; int zzz; int (*func)(int); { if (! str) { return; } if (func == outchar) { fputs (str, stdout); } else { while (*str) { if (*str == '\n') { func('\r'); } func(*str++); } } } #endif void backslash ( char *ptr) { while (*ptr) { if (*ptr == '/') { *ptr = '\\'; } ptr++; } } /* * joinpath tacks a file (or sub dir) on to the end of a directory name. * Have to check existing / or \ to avoid doubling them. */ void joinpath ( char *str, char *dir, char *file) { char c; if (strlen (dir) == 0) { strcpy (str, file); return; } c = dir[strlen (dir) - 1]; if (c=='/' || c=='\\') { sprintf (str, "%s%s", dir, file); } else { sprintf (str, "%s/%s", dir, file); } } #ifndef __TURBOC__ FILE * popen ( char *command, char *mode) { return (FILE *) 0; } void pclose ( FILE *pipe) { return; } DIR * opendir ( const char *name) { return NULL; } struct dirent * readdir ( DIR *di) { return NULL; } int closedir ( DIR *di) { return 0; } #endif /* __TURBOC__ */ char getopt ( int argc, char *argv[], char *options) { char c, *z; static int subind = 0; for (;optind < argc ; optind++) { if (subind == 0) { c = argv[optind][0]; if (c != '-') { return EOF; } subind = 1; } c = argv[optind][subind]; if (c != 0) { break; } } if (optind == argc) { return EOF; } /* * get rid of funnies */ if (c == ':' || c == '?') { return '?'; } if ((z = strchr (options, c)) == 0) { return '?'; } if (z[1] == ':') { if (argv[optind][subind+1]) { optarg = &argv[optind][subind+1]; } else { optarg = argv[++optind]; } optind++; subind = 0; return c; } subind++; return c; } int make_post_cmd ( char *cmd, char *name) { char *p; if ((p = getenv (ENV_VAR_POSTER)) != (char *) 0) { sprintf (cmd, p, name); } else { sprintf (cmd, DEFAULT_POSTER, name); } return 0; } int gethostname ( char *name, int namelen) { char *p; if ((p = getenv ("HOSTNAME")) == (char *) 0) { errno = 1; return (-1); } strncpy (name, p, namelen); return (0); } #ifdef __TURBOC__ int sleep ( int sec) { DosSleep (sec * 1000); return; } #endif /* __TURBOC__ */ struct passwd * fakepwent (void) { if (! fakepw) { return (struct passwd *) 0; } fakepw = 0; if ((no_pw.pw_name = getenv ("USER")) == NULL) { no_pw.pw_name = "OS2USER"; } no_pw.pw_uid = 1; no_pw.pw_gid = 1; no_pw.pw_age = ""; if ((no_pw.pw_comment = getenv ("REALNAME")) == NULL) { no_pw.pw_comment = "OS2 User"; } no_pw.pw_gecos = no_pw.pw_comment; if ((no_pw.pw_dir = getenv ("HOME")) == NULL) { no_pw.pw_dir = "C:"; } if ((no_pw.pw_shell = getenv ("SHELL")) == NULL) { if ((no_pw.pw_shell = getenv ("COMSPEC")) == NULL) { no_pw.pw_shell = "CMD.EXE"; } } return (&no_pw); } struct passwd * getpwent (void) { char pwn[512]; if (! _pwf) { if (getenv ("ETC") == NULL) { return (fakepwent ()); } sprintf (pwn, "%s/passwd", getenv ("ETC")); if ((_pwf = fopen (pwn, "r")) == NULL) { return(fakepwent ()); } } return (fgetpwent (_pwf)); } struct passwd * getpwuid ( uid_t uid) { struct passwd *pw; endpwent (); while (1) { pw = getpwent (); if ((!pw) || (pw->pw_uid == uid)) { return (pw); } } return NULL; } struct passwd * getpwnam ( const char *name) { struct passwd *pw; endpwent(); while (1) { pw = getpwent (); if ((!pw) || (strcmp (pw->pw_name, name) == 0)) { return (pw); } } return NULL; } void setpwent (void) { if (_pwf) { rewind (_pwf); } } void endpwent (void) { if (_pwf) { fclose (_pwf); _pwf = NULL; } fakepw = 1; } struct passwd * fgetpwent ( FILE *f) { char *line; static char pwe[512]; static struct passwd _pw; if (fgets (pwe, sizeof (pwe), f) == NULL) { return (fakepwent ()); } line = pwe; if (line[strlen (line)-1] == '\n') { line[strlen (line)-1] = 0; } if (line[strlen (line)-1] == '\r') { line[strlen (line)-1] = 0; } _pw.pw_name = line; while ((*line) && (*line != ':')) { line++; } if (! *line) { return (struct passwd *) 0; } *line = 0; _pw.pw_passwd = ++line; while ((*line) && (*line != ':')) { line++; } if (! *line) { return (struct passwd *) 0; } *line = 0; _pw.pw_uid = atoi (++line); while ((*line) && (*line != ':')) { line++; } if (! *line) { return (struct passwd *) 0; } *line = 0; _pw.pw_gid = atoi (++line); while ((*line) && (*line != ':')) { line++; } if (! *line) { return (struct passwd *) 0; } *line = 0; _pw.pw_age = ""; _pw.pw_comment = ++line; _pw.pw_gecos = line; while ((*line) && (*line != ':')) { line++; } if (! *line) { return (struct passwd *) 0; } *line = 0; _pw.pw_dir = ++line; if ((_pw.pw_dir[1] == ':') && (tolower (_pw.pw_dir[0]) >= 'c') && (tolower (_pw.pw_dir[0]) <= 'z')) { line += 2; } while ((*line) && (*line != ':')) { line++; } if (! *line) { return (struct passwd *) 0; } *line = 0; _pw.pw_shell = ++line; return (&_pw); } int putpwent ( const struct passwd *pwd, FILE *f) { return(-1); } char * getlogin (void) { char *p; if ((p = getenv ("USER")) == NULL) { return (char *) 0; } return (p); } int getuid (void) { char *p; if ((p = getenv ("UID")) == NULL) { return (0); /* pretend we are root */ } return atoi (p); } #endif /* M_OS2 */ ð*[SRC.TIN-1_22]OS_2.H;1+,‡.//€ 4-d0@î123KÿPWO56€t…—7€¡Fg1—89€]V‚—G/€HªJÿ /* * Project : tin - a Usenet reader * Module : os_2.h * Author : A.Wrede & I.Lea * Created : 05-07-92 * Updated : 22-08-92 * Notes : Directory support for OS/2 * Copyright : (c) Copyright 1991-93 by Andreas Wrede & Iain Lea * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #if defined(M_OS2) #ifndef OS_2_H #define OS_2_H #include #include #define INCL_KBD #ifdef __TURBOC__ #define INCL_NOPMAPI #define INCL_DOSPROCESS APIRET APIENTRY DosSleep(ULONG msec); #endif #define popen _popen #define pclose _pclose #define NOBSD #undef BSD /* stupid define in IBM libs ? */ #define u_char unsigned char #define u_short unsigned short #define u_long unsigned long typedef int uid_t; typedef int gid_t; struct dirent { char d_name[256]; }; typedef struct { unsigned long _d_hdir; char *_d_dirname; unsigned _d_magic; unsigned _d_nfiles; char *_d_bufp; char _d_buf[512]; } DIR; struct passwd { char *pw_name; char *pw_passwd; uid_t pw_uid; gid_t pw_gid; char *pw_age; char *pw_comment; char *pw_gecos; char *pw_dir; char *pw_shell; }; #if !defined(_POSIX_SOURCE) struct comment { char *c_dept; char *c_name; char *c_acct; char *c_bin; }; #endif /* _POSIX_SOURCE */ extern int closedir (DIR *__dir); extern char getopt (int argc,char *argv[],char *options); extern void endpwent (void); extern struct passwd *fgetpwent (FILE *); extern char *getlogin (void); extern struct passwd *getpwent (void); extern struct passwd *getpwuid (uid_t); extern struct passwd *getpwnam (const char *); extern int getuid (void); extern void backslash(char *ptr); extern int make_post_cmd (char *cmd,char *name); extern int make_post_process_cmd (char *cmd,char *dir,char *file); extern DIR *opendir (const char *__dirname); extern int putpwent (const struct passwd *, FILE *); extern struct dirent *readdir (DIR *__dir); extern void rewinddir (DIR *__dir); extern void setpwent (void); #endif /* OS_2_H */ #endif /* M_OS2 */ ð*[SRC.TIN-1_22]PAGE.C;1+,¢.6//€ 466-d0@î123KÿPWO756 Bat…—7s7p1—89€]V‚—G/€HªJÿ/* * Project : tin - a Usenet reader * Module : page.c * Author : I.Lea & R.Skrenta * Created : 01-04-91 * Updated : 21-09-93 * Notes : * Copyright : (c) Copyright 1991-93 by Iain Lea & Rich Skrenta * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" char note_h_path[LEN]; /* Path: */ char note_h_date[PATH_LEN]; /* Date: */ char note_h_subj[LEN]; /* Subject: */ char note_h_org[PATH_LEN]; /* Organization: */ char note_h_newsgroups[LEN]; /* Newsgroups: */ char note_h_messageid[PATH_LEN]; /* Message-ID: */ char note_h_references[PATH_LEN]; /* References: */ char note_h_distrib[PATH_LEN]; /* Distribution: */ char note_h_keywords[LEN]; /* Keywords: */ char note_h_summary[LEN]; /* Summary: */ char note_h_followup[LEN]; /* Followup-To: */ char note_h_mimeversion[PATH_LEN]; /* Mime-Version: */ char note_h_contenttype[LEN]; /* Content-Type: */ char *glob_page_group; FILE *note_fp; /* the body of the current article */ int glob_respnum; int last_resp; /* current & previous article for - command */ int note_end; /* we're done showing this article */ int note_line; int note_page; /* what page we're on */ int rotate; /* 0=normal, 13=rot13 decode */ int this_resp; int doing>_pgdn; long note_mark[MAX_PAGES]; /* ftells on beginnings of pages */ long note_size; /* stat size in bytes of article */ int show_page (respnum, threadnum, group, group_path) int respnum; int *threadnum; /* to allow movement in thread mode */ char *group; char *group_path; { #ifndef INDEX_DAEMON int ch, i, n = 0; int copy_text; int kill_state = NO_KILLING; int old_sort_art_type = default_sort_art_type; int old_top; int posted; int ret_code; long old_artnum; long art; restart: if (read_news_via_nntp && display_reading_prompt) { wait_message (txt_reading_article); } glob_respnum = respnum; glob_page_group = group; set_signals_page (); if (respnum != this_resp) { /* remember current & previous */ last_resp = this_resp; /* articles for - command */ this_resp = respnum; } rotate = 0; /* normal mode, not rot13 */ art = arts[respnum].artnum; if (arts[respnum].unread != ART_READ) { mark_all_xref_read (&arts[respnum], group_path); if (arts[respnum].hot && num_of_hot_arts) { num_of_hot_arts--; } } arts[respnum].unread = ART_READ; /* mark article as read */ if ((note_page = art_open (art, group_path)) == ART_UNAVAILABLE) { /* arts[respnum].thread = ART_EXPIRED; */ /* 21.11.92 FIXME */ sprintf (msg, txt_art_unavailable, art); if (debug) { error_message (msg, ""); } else { wait_message (msg); } return (GRP_NOREDRAW); /* special retcode to stop redrawing screen */ } else { show_note_page (respnum, group); } while (TRUE) { ch = ReadCh (); if (ch >= '0' && ch <= '9') { n = which_thread (respnum); if (! num_of_responses (n)) { info_message (txt_no_responses); } else { n = prompt_response (ch, respnum); if (n != -1) { respnum = n; goto restart; } } continue; } switch (ch) { case ESC: #ifdef HAVE_KEY_PREFIX case KEY_PREFIX: #endif switch (get_arrow_key ()) { case KEYMAP_LEFT: goto return_to_index; case KEYMAP_RIGHT: goto page_goto_next_unread; case KEYMAP_UP: case KEYMAP_PAGE_UP: goto page_up; case KEYMAP_DOWN: case KEYMAP_PAGE_DOWN: goto page_down; case KEYMAP_HOME: goto begin_of_article; case KEYMAP_END: goto end_of_article; case KEYMAP_MOUSE: set_xclick_off (); break; } break; #ifndef NO_SHELL_ESCAPE case '!': shell_escape (); redraw_page (respnum, group); break; #endif case '$': /* goto end of article */ case 'G': /* 'less' compatible */ end_of_article: if (show_last_page ()) { show_note_page (respnum, group); } break; case '-': /* show last viewed article */ if (last_resp < 0) { info_message (txt_no_last_message); break; } art_close (); respnum = last_resp; goto restart; case '|': /* pipe article/thread/tagged arts to command */ feed_articles (FEED_PIPE, PAGE_LEVEL, "Pipe", respnum, group_path); break; case '/': /* search forwards in article */ if (search_article (TRUE)) { show_note_page (respnum, group); } break; case 'B': /* article body search */ n = search_body (group_path, respnum); if (n != -1) { respnum = n; art_close (); goto restart; } break; case '<': /* goto first article in current thread */ if (arts[respnum].inthread) { n = which_thread (respnum); if (n >= 0 && base[n] != respnum) { assert (n < top_base); respnum = base[n]; art_close (); goto restart; } } break; case '>': /* goto last article in current thread */ for (i = respnum; i >= 0; i = arts[i].thread) { n = i; } if (n != respnum) { respnum = n; art_close (); goto restart; } break; case ' ': /* page down or next response */ case ctrl('D'): case ctrl('F'): /* vi style */ page_down: if (note_page == ART_UNAVAILABLE) { n = next_response (respnum); if (n == -1) { return (which_thread (respnum)); } respnum = n; goto restart; } else if (note_end) { art_close (); n = next_response (respnum); if (n == -1) { return (which_thread (respnum)); } respnum = n; goto restart; } else { doing_pgdn = TRUE; show_note_page (respnum, group); } break; case '\r': case '\n': /* go to start of next thread */ art_close (); n = next_thread (respnum); if (n == -1) return (which_thread (respnum)); respnum = n; goto restart; case '\t': /* goto next unread article */ page_goto_next_unread: if (! tab_goto_next_unread) { if (note_page == ART_UNAVAILABLE) { n = next_unread (next_response (respnum)); if (n == -1) { return (which_thread (respnum)); } respnum = n; goto restart; } else if (note_end) { art_close (); n = next_unread (next_response (respnum)); if (n == -1) { return (which_thread (respnum)); } respnum = n; goto restart; } else { show_note_page (respnum, group); } } else { if (note_page != ART_UNAVAILABLE) { art_close(); } n = next_unread (next_response (respnum)); if (n == -1) { return (which_thread (respnum)); } respnum = n; goto restart; } break; case ctrl('H'): /* show article headers */ if (note_page == ART_UNAVAILABLE) { n = next_response (respnum); if (n == -1) return (which_thread (respnum)); respnum = n; goto restart; } else { note_page = 0; note_end = FALSE; fseek(note_fp, 0L, 0); show_note_page(respnum, group); } break; case ctrl('K'): /* kill article */ if (kill_art_menu (group, respnum)) { i = which_thread (respnum); if (kill_any_articles (my_group[cur_groupnum])) { make_threads (FALSE); find_base (my_group[cur_groupnum]); if (i >= top_base) i = top_base - 1; respnum = base[i]; } } /* if (which_thread (respnum) < 0) { return GRP_UNINDEXED; } */ redraw_page (respnum, group); break; case ctrl('L'): /* redraw current page of article */ redraw_page (respnum, group); break; case ctrl('R'): /* redraw beginning of article */ case 'g': /* 'less' compatible */ begin_of_article: if (note_page == ART_UNAVAILABLE) { ClearScreen (); printf (txt_art_unavailable, arts[respnum].artnum); fflush (stdout); } else { note_page = 0; note_end = FALSE; fseek (note_fp, note_mark[0], 0); show_note_page (respnum, group); } break; case ctrl('X'): case '%': case 'd': /* toggle rot-13 mode */ rotate = (rotate ? 0 : 13); redraw_page (respnum, group); info_message (txt_toggled_rot13); break; case 'a': /* author search forward */ case 'A': /* author search backward */ i = (ch == 'a'); n = search_author (my_group[cur_groupnum], respnum, i); if (n < 0) break; respnum = n; goto restart; /* NOTREACHED */ case 'b': /* page up */ case ctrl('U'): case ctrl('B'): /* vi style */ page_up: if (note_page == ART_UNAVAILABLE) { art_close (); n = prev_response (respnum); if (n == -1) return (which_response (respnum)); respnum = n; goto restart; } else { if (note_page <= 1) { info_message (txt_begin_of_art); } else { note_page -= 2; note_end = FALSE; fseek (note_fp, note_mark[note_page], 0); show_note_page (respnum, group); } } break; case 'c': /* catchup - mark all articles as read */ case 'C': /* and goto next group */ if (!confirm_action || prompt_yn (cLINES, txt_mark_all_read, 'y')) { for (n = 0; n < top; n++) { if (arts[n].unread != ART_READ) { mark_all_xref_read (&arts[n], group_path); } arts[n].unread = ART_READ; } ret_code = (ch == 'C' ? GRP_CONTINUE : GRP_UNINDEXED); fix_new_highest (cur_groupnum); if (cur_groupnum + 1 < group_top) { cur_groupnum++; } else { ret_code = GRP_UNINDEXED; } art_close (); space_mode = TRUE; return ret_code; } break; case 'D': /* delete an article */ if (delete_article (group, respnum)) { redraw_page (respnum, group); } break; case 'f': /* post a followup to this article */ case 'F': if (! can_post) { info_message (txt_cannot_post); break; } copy_text = (ch == 'f' ? TRUE : FALSE); ret_code = post_response (group, respnum, copy_text); redraw_page (respnum, group); break; case 'h': /* help */ show_info_page (HELP_INFO, help_page, txt_art_pager_com); redraw_page (respnum, group); break; case 'H': /* toggle mini help menu */ toggle_mini_help (PAGE_LEVEL); redraw_page (respnum, group); break; case 'q': /* return to index page */ return_to_index: art_close (); if (kill_state == NO_KILLING && default_sort_art_type != old_sort_art_type) { make_threads (TRUE); find_base (my_group[cur_groupnum]); } i = which_thread (respnum); *threadnum = which_response (respnum); if (kill_state == KILLING) { old_top = top; old_artnum = arts[respnum].artnum; kill_any_articles (my_group[cur_groupnum]); make_threads (FALSE); find_base (my_group[cur_groupnum]); i = find_new_pos (old_top, old_artnum, i); } return (i); case 'I': /* toggle inverse video */ toggle_inverse_video (); redraw_page (respnum, group); break; case 'k': if (note_page == ART_UNAVAILABLE) { n = next_unread (next_response(respnum)); if (n == -1) return (which_thread (respnum)); } else { art_close (); n = next_unread (next_response (respnum)); if (n == -1) return (which_thread (respnum)); } respnum = n; goto restart; /* NOTREACHED */ case 'K': /* mark rest of thread as read */ for (n = respnum; n >= 0; n = arts[n].thread) { if (arts[n].unread != ART_READ) { mark_all_xref_read (&arts[n], group_path); if (arts[n].hot && num_of_hot_arts) { num_of_hot_arts--; } } arts[n].unread = ART_READ; } n = next_unread (next_response (respnum)); if (n == -1) goto return_to_index; art_close (); respnum = n; goto restart; /* NOTREACHED */ case 'm': /* mail article/thread/tagged articles to somebody */ feed_articles (FEED_MAIL, PAGE_LEVEL, "Mail", respnum, group_path); break; case 'M': /* options menu */ if (change_rcfile (group, FALSE) == KILLING) { kill_state = KILLING; } set_subj_from_size (cCOLS); redraw_page (respnum, group); break; case 'n': /* skip to next article */ art_close (); n = next_response (respnum); if (n == -1) return (which_thread(respnum)); respnum = n; goto restart; /* NOTREACHED */ case 'N': /* next unread article */ n = next_unread (next_response (respnum)); if (n == -1) info_message (txt_no_next_unread_art); else { art_close (); respnum = n; goto restart; } break; case 'o': /* output art/thread/tagged arts to printer */ feed_articles (FEED_PRINT, PAGE_LEVEL, "Print", respnum, group_path); break; case 'p': /* previous article */ art_close (); n = prev_response (respnum); if (n == -1) return (which_response (respnum)); respnum = n; goto restart; case 'P': /* previous unread article */ n = prev_unread (prev_response (respnum)); if (n == -1) info_message (txt_no_prev_unread_art); else { art_close (); respnum = n; goto restart; } break; case 'Q': /* quit */ return GRP_QUIT; case 'r': /* reply to author through mail */ case 'R': copy_text = (ch == 'r' ? TRUE : FALSE); mail_to_author (group, respnum, copy_text); redraw_page (respnum, group); break; case 's': /* save article/thread/tagged articles */ feed_articles (FEED_SAVE, PAGE_LEVEL, "Save", respnum, group_path); break; case 't': /* tag/untag article for saving */ if (arts[respnum].tagged) { arts[respnum].tagged = 0; info_message (txt_untagged_art); } else { arts[respnum].tagged = ++num_of_tagged_arts; info_message (txt_tagged_art); } break; case 'T': /* return to group selection page */ art_close (); if (kill_state == KILLING) { kill_any_articles (my_group[cur_groupnum]); make_threads (FALSE); find_base (my_group[cur_groupnum]); } update_newsrc (group, my_group[cur_groupnum], FALSE); fix_new_highest (cur_groupnum); return -1; case 'v': info_message (cvers); break; case 'w': /* post a basenote */ if (post_article (group, &posted)) { redraw_page (respnum, group); } break; case 'W': /* display messages posted by user */ if (user_posted_messages ()) { redraw_page (respnum, group); } break; case 'x': /* crosspost current article */ feed_articles (FEED_XPOST, PAGE_LEVEL, "Crosspost", respnum, group_path); break; case 'z': /* mark article as unread (to return) */ if (arts[n].unread != ART_UNREAD) { if (arts[n].hot) { num_of_hot_arts++; } } arts[respnum].unread = ART_WILL_RETURN; info_message (txt_art_marked_as_unread); break; default: info_message(txt_bad_command); } } #endif /* INDEX_DAEMON */ } void redraw_page (respnum, group) int respnum; char *group; { if (note_page == ART_UNAVAILABLE) { ClearScreen (); printf (txt_art_unavailable, arts[respnum].artnum); fflush (stdout); } else if (note_page > 0) { note_page--; fseek (note_fp, note_mark[note_page], 0); show_note_page (respnum, group); } } void show_note_page (respnum, group) int respnum; char *group; { #ifndef INDEX_DAEMON char buf2[LEN+50]; char *p, *q; int i, j; int ctrl_L; /* form feed character detected */ int first = TRUE; int lines; long tmp_pos; static char buf[LEN]; if (beginner_level) { lines = cLINES - (MINI_HELP_LINES - 1); } else { lines = cLINES; } ClearScreen (); note_line = 1; if (note_size == 0L) { tmp_pos = ftell (note_fp); fseek (note_fp, 0L, 2); /* goto end of article */ note_size = ftell (note_fp); fseek (note_fp, tmp_pos, 0); /* goto old position */ } if (note_page == 0) { buf2[0] = '\0'; doing_pgdn = FALSE; show_first_header (respnum, group); } else { show_cont_header (respnum); } #ifdef HAVE_METAMAIL if (note_page == 0 && *note_h_mimeversion && *note_h_contenttype && strncmp ("text/plain", note_h_contenttype, 10)) { if (prompt_yn (cLINES, txt_use_mime, 'y')) { show_mime_article (note_fp, &arts[respnum]); return; } else { show_first_header (respnum, group); } } #endif ctrl_L = FALSE; while (note_line < lines) { if (show_last_line_prev_page) { note_mark[note_page+1] = ftell (note_fp); if (doing_pgdn && first && buf2[0]) { goto print_a_line; } } first = FALSE; if (fgets (buf, sizeof (buf), note_fp) == NULL) { note_end = TRUE; break; } buf[LEN-1] = '\0'; if (rotate) for (p = buf, q = buf2; *p && *p != '\n' && q < &buf2[LEN]; p++) { if (*p == '\b' && q > buf2) { q--; } else if (*p == 12) { /* ^L */ *q++ = '^'; *q++ = 'L'; ctrl_L = TRUE; } else if (*p == '\t') { i = q - buf2; j = (i|7) + 1; while (i++ < j) *q++ = ' '; } else if (((*p) & 0xFF) < ' ') { *q++ = '^'; *q++ = ((*p) & 0xFF) + '@'; } else if (*p >= 'A' && *p <= 'Z') *q++ = 'A' + (*p - 'A' + rotate) % 26; else if (*p >= 'a' && *p <= 'z ±žB÷~ TIN-1_22.BCK¢d[SRC.TIN-1_22]PAGE.C;16ÊT(#') *q++ = 'a' + (*p - 'a' + rotate) % 26; else *q++ = *p; } else for (p = buf, q = buf2; *p && *p != '\n' && q < &buf2[LEN]; p++) { if (*p == '\b' && q > buf2) { q--; } else if (*p == 12) { /* ^L */ *q++ = '^'; *q++ = 'L'; ctrl_L = TRUE; } else if (*p == '\t') { i = q - buf2; j = (i|7) + 1; while (i++ < j) *q++ = ' '; } else if (((*p) & 0xFF) < ' ') { *q++ = '^'; *q++ = ((*p) & 0xFF) + '@'; } else *q++ = *p; } *q = '\0'; print_a_line: if (first) { StartInverse (); } strip_line (buf2, strlen (buf2)); printf("%s\r\n", buf2); if (first) { EndInverse (); } first = FALSE; doing_pgdn = FALSE; note_line += ((int) strlen (buf2) / cCOLS) + 1; if (ctrl_L) { break; } } if (! show_last_line_prev_page) { note_mark[++note_page] = ftell (note_fp); } else { note_page++; } if (ftell (note_fp) == note_size) { note_end = TRUE; } if (note_end) { MoveCursor (cLINES, MORE_POS-(5+BLANK_PAGE_COLS)); StartInverse (); if (arts[respnum].thread != -1) { fputs (txt_next_resp, stdout); } else { fputs (txt_last_resp, stdout); } fflush (stdout); EndInverse (); } else { if (note_size > 0) { draw_percent_mark (note_mark[note_page], note_size); } else { MoveCursor (cLINES, MORE_POS-BLANK_PAGE_COLS); StartInverse (); fputs (txt_more, stdout); fflush (stdout); EndInverse (); } } show_mini_help (PAGE_LEVEL); MoveCursor (cLINES, 0); #endif /* INDEX_DAEMON */ } void show_mime_article (fp, art) FILE *fp; struct t_article *art; { char buf[LEN]; FILE *mime_fp; long offset; Raw(FALSE); offset = ftell (fp); rewind (fp); printf ("mime article\n"); sprintf (buf, METAMAIL_CMD); mime_fp = popen (buf, "w"); while (fgets (buf, sizeof (buf), fp) != NULL) { fputs (buf, mime_fp); } fflush (mime_fp); pclose (mime_fp); note_end = TRUE; Raw(TRUE); fseek (fp, offset, 0); /* goto old position */ MoveCursor (cLINES, MORE_POS-(5+BLANK_PAGE_COLS)); StartInverse (); if (art->thread != -1) { fputs (txt_next_resp, stdout); } else { fputs (txt_last_resp, stdout); } fflush (stdout); EndInverse (); } void show_first_header (respnum, group) int respnum; char *group; { char buf[LEN]; char tmp[LEN]; int whichresp; int x_resp; int pos, i, n; struct tm *tm; whichresp = which_response (respnum); x_resp = num_of_responses (which_thread (respnum)); ClearScreen (); tm = localtime (&arts[respnum].date); if (! my_strftime (buf, sizeof (buf), "%a, %d %b %Y %H:%M:%S", tm)) { strcpy (buf, note_h_date); } pos = (cCOLS - (int) strlen (group)) / 2; for (i = strlen(buf); i < pos; i++) { buf[i] = ' '; } buf[i] = '\0'; strcat (buf, group); for (i = strlen(buf); i < RIGHT_POS ; i++) { buf[i] = ' '; } buf[i] = '\0'; sprintf (tmp, txt_thread_x_of_n, buf, which_thread (respnum) + 1, top_base); fputs (tmp, stdout); if (arts[respnum].lines < 0) { strcpy (tmp, "?"); } else { sprintf (tmp, "%d", arts[respnum].lines); } sprintf (buf, txt_lines, tmp); n = strlen (buf); fputs (buf, stdout); if (note_h_subj[0]) { strcpy (buf, note_h_subj); } else { strcpy (buf, arts[respnum].subject); } buf[RIGHT_POS - 5 - n] = '\0'; pos = ((cCOLS - (int) strlen (buf)) / 2) - 2; if (pos > n) { MoveCursor (1, pos); } else { MoveCursor (1, n); } StartInverse (); fputs (buf, stdout); EndInverse (); MoveCursor (1, RIGHT_POS); if (whichresp) printf (txt_resp_x_of_n, whichresp, x_resp); else { if (x_resp == 0) fputs (txt_no_resp, stdout); else if (x_resp == 1) fputs (txt_1_resp, stdout); else printf (txt_x_resp, x_resp); } if (*note_h_org) { if (arts[respnum].name) { sprintf (tmp, txt_s_at_s, arts[respnum].name, note_h_org); } else { strcpy (tmp, note_h_org); } } else if (arts[respnum].name) { strcpy (tmp, arts[respnum].name); } else { strcpy (tmp, " "); } tmp[LEN-1] = '\0'; sprintf (buf, "%s ", arts[respnum].from); pos = cCOLS - 1 - (int) strlen(tmp); if ((int) strlen (buf) + (int) strlen (tmp) >= cCOLS - 1) { strncat (buf, tmp, cCOLS - 1 - (int) strlen(buf)); buf[cCOLS-1] = '\0'; } else { for (i = strlen(buf); i < pos; i++) buf[i] = ' '; buf[i] = '\0'; strcat (buf, tmp); } strip_line (buf, strlen (buf)); printf ("%s\r\n\r\n", buf); note_line += 4; } void show_cont_header (respnum) int respnum; { int maxresp; int whichresp; int whichbase; char buf[LEN]; whichresp = which_response (respnum); whichbase = which_thread (respnum); maxresp = num_of_responses (whichbase); assert (whichbase < top_base); if (whichresp) { sprintf(buf, txt_thread_resp_page, whichbase + 1, top_base, whichresp, maxresp, note_page + 1, note_h_subj); } else { sprintf(buf, txt_thread_page, whichbase + 1, top_base, note_page + 1, note_h_subj); } strip_line (buf, strlen (buf)); if (cCOLS) { buf[cCOLS-1] = '\0'; } printf("%s\r\n\r\n", buf); note_line += 2; } int art_open (art, group_path) long art; char *group_path; { char buf[8192]; char *ptr; note_page = 0; art_close (); /* just in case */ if ((note_fp = open_art_fp (group_path, art)) == (FILE *) 0) { return (ART_UNAVAILABLE); } note_h_path[0] = '\0'; note_h_subj[0] = '\0'; note_h_org[0] = '\0'; note_h_date[0] = '\0'; note_h_newsgroups[0] = '\0'; note_h_messageid[0] = '\0'; note_h_references[0] = '\0'; note_h_distrib[0] = '\0'; note_h_followup[0] = '\0'; note_h_mimeversion[0] = '\0'; note_h_contenttype[0] = '\0'; while (fgets(buf, sizeof buf, note_fp) != NULL) { buf[8191] = '\0'; for (ptr = buf ; *ptr && *ptr != '\n' ; ptr++) { if (((*ptr) & 0xFF) < ' ') *ptr = ' '; } *ptr = '\0'; if (*buf == '\0') break; if (match_header (buf, "Path", note_h_path, LEN)) continue; if (match_header (buf, "Subject", note_h_subj, LEN)) continue; if (match_header (buf, "Organization", note_h_org, PATH_LEN)) continue; if (match_header (buf, "Date", note_h_date, PATH_LEN)) continue; if (match_header (buf, "Newsgroups", note_h_newsgroups, LEN)) continue; if (match_header (buf, "Message-ID", note_h_messageid, PATH_LEN)) continue; if (match_header (buf, "Message-Id", note_h_messageid, PATH_LEN)) continue; if (match_header (buf, "References", note_h_references, PATH_LEN)) continue; if (match_header (buf, "Distribution", note_h_distrib, PATH_LEN)) continue; if (match_header (buf, "Followup-To", note_h_followup, LEN)) continue; if (match_header (buf, "Keywords", note_h_keywords, LEN)) continue; if (match_header (buf, "Summary", note_h_summary, LEN)) continue; if (match_header (buf, "Mime-Version", note_h_mimeversion, PATH_LEN)) continue; if (match_header (buf, "Content-Type", note_h_contenttype, LEN)) { lcase (note_h_contenttype); continue; } } note_mark[0] = ftell (note_fp); note_end = FALSE; /* * If Newsgroups is empty its a good bet the article is a mail article */ if (! note_h_newsgroups[0]) { strcpy (note_h_newsgroups, group_path); while ((ptr = (char *) strchr (note_h_newsgroups, '/'))) { *ptr = '.'; } } return (0); } void art_close () { if (note_fp && note_page != ART_UNAVAILABLE) { fclose (note_fp); note_fp = (FILE *) 0; } } int prompt_response (ch, respnum) int ch; int respnum; { int num; clear_message (); if ((num = prompt_num (ch, txt_read_resp)) == -1) { clear_message (); return -1; } return choose_response (which_thread (respnum), num); } void yank_to_addr (orig, addr) char *orig; char *addr; { char *p; int open_parens; for (p = orig; *p; p++) if (((*p) & 0xFF) < ' ') *p = ' '; while (*addr) addr++; while (*orig) { while (*orig && (*orig == ' ' || *orig == '"' || *orig == ',')) orig++; *addr++ = ' '; while (*orig && (*orig != ' ' && *orig != ',' && *orig != '"')) *addr++ = *orig++; while (*orig && (*orig == ' ' || *orig == '"' || *orig == ',')) orig++; if (*orig == '(') { orig++; open_parens = 1; while (*orig && open_parens) { if (*orig == '(') open_parens++; if (*orig == ')') open_parens--; orig++; } if (*orig == ')') orig++; } } *addr = '\0'; } int show_last_page () { char buf[LEN]; char buf2[LEN+50]; char *p, *q; int ctrl_L; /* form feed character detected */ int i, j; long tmp_pos; if (note_end) { return FALSE; } if (note_size == 0L) { tmp_pos = ftell (note_fp); fseek (note_fp, 0L, 2); /* goto end of article */ note_size = ftell (note_fp); fseek (note_fp, tmp_pos, 0); /* goto old position */ } while (! note_end) { note_line = 1; ctrl_L = FALSE; if (note_page == 0) { note_line += 4; } else { note_line += 2; } while (note_line < cLINES) { if (fgets (buf, sizeof buf, note_fp) == NULL) { note_end = TRUE; break; } buf[LEN-1] = '\0'; for (p = buf, q = buf2; *p && *p != '\n' && q<&buf2[LEN]; p++) { if (*p == '\b' && q > buf2) { q--; } else if (*p == 12) { /* ^L */ *q++ = '^'; *q++ = 'L'; ctrl_L = TRUE; } else if (*p == '\t') { i = q - buf2; j = (i|7) + 1; while (i++ < j) { *q++ = ' '; } } else if (((*p) & 0xFF) < ' ') { *q++ = '^'; *q++ = ((*p) & 0xFF) + '@'; } else { *q++ = *p; } } *q = '\0'; note_line += ((int) strlen (buf2) / cCOLS) + 1; if (ctrl_L) { break; } } if (note_mark[note_page] == note_size) { note_end = TRUE; note_page--; break; } else if (! note_end) { note_mark[++note_page] = ftell(note_fp); } } fseek (note_fp, note_mark[note_page], 0); return TRUE; } int match_header (buf, pat, body, len) char *buf; char *pat; char *body; int len; { int plen = strlen (pat); if(strncmp (buf, pat, plen) == 0 && buf[plen] == ':' && buf[plen + 1] == ' ') { plen += 2; while (buf[plen] == ' ') plen++; strncpy (body, &buf[plen], len); body[len - 1] = '\0'; return TRUE; } return FALSE; } ð*[SRC.TIN-1_22]PARSDATE.Y;16+,# .-//€ 4---d0@î123KÿPWO.56Àßµ§’—7 ”?·§’—89€šIÊ’—G/€HªJÿ%{ /* * Project : tin - a Usenet reader * Module : parsedate.y * Author : S.Bellovin & R.$alz & J.Berets & P.Eggert * Created : 01-08-90 * Updated : 04-12-92 * Notes : This grammar has 6 shift/reduce conflicts. * Originally written by Steven M. Bellovin * while at the University of North Carolina at Chapel Hill. * Later tweaked by a couple of people on Usenet. Completely * overhauled by Rich $alz and Jim Berets * in August, 1990. * Further revised (removed obsolete constructs and cleaned up * timezone names) in August, 1991, by Rich. * Paul Eggert helped in September 1992. * Revision : 1.12 * Copyright : This code is in the public domain and has no copyright. */ /* SUPPRESS 530 *//* Empty body for statement */ /* SUPPRESS 593 on yyerrlab *//* Label was not used */ /* SUPPRESS 593 on yynewstate *//* Label was not used */ /* SUPPRESS 595 on yypvt *//* Automatic variable may be used before set */ #include "tin.h" /* ** Get the number of elements in a fixed-size array, or a pointer just ** past the end of it. */ #define SIZEOF(array) ((int)(sizeof array / sizeof array[0])) #define ENDOF(array) (&array[SIZEOF(array)]) #define CTYPE(isXXXXX, c) ((isascii((c)) && isXXXXX((c)))) typedef char *STRING; #define yyparse date_parse #define yylex date_lex #define yyerror date_error < /* See the LeapYears table in Convert. */ #define EPOCH 1970 #define END_OF_TIME 2038 /* Constants for general time calculations. */ #define DST_OFFSET 1 #define SECSPERDAY (24L * 60L * 60L) /* Readability for TABLE stuff. */ #define HOUR(x) (x * 60) #define LPAREN '(' #define RPAREN ')' #define IS7BIT(x) ((unsigned int)(x) < 0200) /* ** An entry in the lexical lookup table. */ typedef struct _TABLE { STRING name; int type; time_t value; } TABLE; /* ** Daylight-savings mode: on, off, or not yet known. */ typedef enum _DSTMODE { DSTon, DSToff, DSTmaybe } DSTMODE; /* ** Meridian: am, pm, or 24-hour style. */ typedef enum _MERIDIAN { MERam, MERpm, MER24 } MERIDIAN; /* ** Global variables. We could get rid of most of them by using a yacc ** union, but this is more efficient. (This routine predates the ** yacc %union construct.) */ static char *yyInput; static DSTMODE yyDSTmode; static int yyHaveDate; static int yyHaveRel; static int yyHaveTime; static time_t yyTimezone; static time_t yyDay; static time_t yyHour; static time_t yyMinutes; static time_t yyMonth; static time_t yySeconds; static time_t yyYear; static MERIDIAN yyMeridian; static time_t yyRelMonth; static time_t yyRelSeconds; extern struct tm *localtime(); static void date_error(); %} %union { time_t Number; enum _MERIDIAN Meridian; } %token tDAY tDAYZONE tMERIDIAN tMONTH tMONTH_UNIT tSEC_UNIT tSNUMBER %token tUNUMBER tZONE %type tDAYZONE tMONTH tMONTH_UNIT tSEC_UNIT %type tSNUMBER tUNUMBER tZONE numzone zone %type tMERIDIAN o_merid %% spec : /* NULL */ | spec item ; item : time { yyHaveTime++; #if defined(lint) /* I am compulsive about lint natterings... */ if (yyHaveTime == -1) { YYERROR; } #endif /* defined(lint) */ } | time zone { yyHaveTime++; yyTimezone = $2; } | date { yyHaveDate++; } | rel { yyHaveRel = 1; } ; time : tUNUMBER o_merid { if ($1 < 100) { yyHour = $1; yyMinutes = 0; } else { yyHour = $1 / 100; yyMinutes = $1 % 100; } yySeconds = 0; yyMeridian = $2; } | tUNUMBER ':' tUNUMBER o_merid { yyHour = $1; yyMinutes = $3; yySeconds = 0; yyMeridian = $4; } | tUNUMBER ':' tUNUMBER numzone { yyHour = $1; yyMinutes = $3; yyTimezone = $4; yyMeridian = MER24; yyDSTmode = DSToff; } | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { yyHour = $1; yyMinutes = $3; yySeconds = $5; yyMeridian = $6; } | tUNUMBER ':' tUNUMBER ':' tUNUMBER numzone { yyHour = $1; yyMinutes = $3; yySeconds = $5; yyTimezone = $6; yyMeridian = MER24; yyDSTmode = DSToff; } ; zone : tZONE { $$ = $1; yyDSTmode = DSToff; } | tDAYZONE { $$ = $1; yyDSTmode = DSTon; } | tZONE numzone { /* Only allow "GMT+300" and "GMT-0800" */ if ($1 != 0) { YYABORT; } $$ = $2; yyDSTmode = DSToff; } | numzone { $$ = $1; yyDSTmode = DSToff; } ; numzone : tSNUMBER { int i; signed long t; t = ((signed) $1); /* Unix and GMT and numeric timezones -- a little confusing. */ if (t < 0) { /* Don't work with negative modulus. */ ((signed)$1) = -t; if (t > 9999 || (i = t % 100) >= 60) { YYABORT; } $$ = (t / 100) * 60 + i; } else { if ((t > 9999) || (i = (t % 100)) >= 60) { YYABORT; } $$ = -((t / 100) * 60 + i); } } ; date : tUNUMBER '/' tUNUMBER { yyMonth = $1; yyDay = $3; } | tUNUMBER '/' tUNUMBER '/' tUNUMBER { if ($1 > 100) { yyYear = $1; yyMonth = $3; yyDay = $5; } else { yyMonth = $1; yyDay = $3; yyYear = $5; } } | tMONTH tUNUMBER { yyMonth = $1; yyDay = $2; } | tMONTH tUNUMBER ',' tUNUMBER { yyMonth = $1; yyDay = $2; yyYear = $4; } | tUNUMBER tMONTH { yyDay = $1; yyMonth = $2; } | tUNUMBER tMONTH tUNUMBER { yyDay = $1; yyMonth = $2; yyYear = $3; } | tDAY ',' tUNUMBER tMONTH tUNUMBER { yyDay = $3; yyMonth = $4; yyYear = $5; } ; rel : tSNUMBER tSEC_UNIT { yyRelSeconds += $1 * $2; } | tUNUMBER tSEC_UNIT { yyRelSeconds += $1 * $2; } | tSNUMBER tMONTH_UNIT { yyRelMonth += $1 * $2; } | tUNUMBER tMONTH_UNIT { yyRelMonth += $1 * $2; } ; o_merid : /* NULL */ { $$ = MER24; } | tMERIDIAN { $$ = $1; } ; %% /* Month and day table. */ static TABLE MonthDayTable[] = { { "january", tMONTH, 1 }, { "february", tMONTH, 2 }, { "march", tMONTH, 3 }, { "april", tMONTH, 4 }, { "may", tMONTH, 5 }, { "june", tMONTH, 6 }, { "july", tMONTH, 7 }, { "august", tMONTH, 8 }, { "september", tMONTH, 9 }, { "october", tMONTH, 10 }, { "november", tMONTH, 11 }, { "december", tMONTH, 12 }, /* The value of the day isn't used... */ { "sunday", tDAY, 0 }, { "monday", tDAY, 0 }, { "tuesday", tDAY, 0 }, { "wednesday", tDAY, 0 }, { "thursday", tDAY, 0 }, { "friday", tDAY, 0 }, { "saturday", tDAY, 0 }, }; /* Time units table. */ static TABLE UnitsTable[] = { { "year", tMONTH_UNIT, 12 }, { "month", tMONTH_UNIT, 1 }, #ifdef QNX4 { "week", tSEC_UNIT, 604800 }, { "day", tSEC_UNIT, 86400 }, #else { "week", tSEC_UNIT, 7 * 24 * 60 * 60 }, { "day", tSEC_UNIT, 1 * 24 * 60 * 60 }, #endif { "hour", tSEC_UNIT, 60 * 60 }, { "minute", tSEC_UNIT, 60 }, { "min", tSEC_UNIT, 60 }, { "second", tSEC_UNIT, 1 }, { "sec", tSEC_UNIT, 1 }, }; /* Timezone table. */ static TABLE TimezoneTable[] = { { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */ { "ut", tZONE, HOUR( 0) }, /* Universal */ { "utc", tZONE, HOUR( 0) }, /* Universal Coordinated */ { "cut", tZONE, HOUR( 0) }, /* Coordinated Universal */ { "z", tZONE, HOUR( 0) }, /* Greenwich Mean */ { "wet", tZONE, HOUR( 0) }, /* Western European */ { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */ { "nst", tZONE, HOUR(3)+30 }, /* Newfoundland Standard */ { "ndt", tDAYZONE, HOUR(3)+30 }, /* Newfoundland Daylight */ { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */ { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */ { "est", tZONE, HOUR( 5) }, /* Eastern Standard */ { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */ { "cst", tZONE, HOUR( 6) }, /* Central Standard */ { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */ { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */ { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */ { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */ { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */ { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */ { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */ { "akst", tZONE, HOUR( 9) }, /* Alaska Standard */ { "akdt", tDAYZONE, HOUR( 9) }, /* Alaska Daylight */ { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */ { "hast", tZONE, HOUR(10) }, /* Hawaii-Aleutian Standard */ { "hadt", tDAYZONE, HOUR(10) }, /* Hawaii-Aleutian Daylight */ { "ces", tDAYZONE, -HOUR(1) }, /* Central European Summer */ { "cest", tDAYZONE, -HOUR(1) }, /* Central European Summer */ { "mez", tZONE, -HOUR(1) }, /* Middle European */ { "mezt", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ { "cet", tZONE, -HOUR(1) }, /* Central European */ { "met", tZONE, -HOUR(1) }, /* Middle European */ { "eet", tZONE, -HOUR(2) }, /* Eastern Europe */ { "msk", tZONE, -HOUR(3) }, /* Moscow Winter */ { "msd", tDAYZONE, -HOUR(3) }, /* Moscow Summer */ { "wast", tZONE, -HOUR(8) }, /* West Australian Standard */ { "wadt", tDAYZONE, -HOUR(8) }, /* West Australian Daylight */ { "hkt", tZONE, -HOUR(8) }, /* Hong Kong */ { "cct", tZONE, -HOUR(8) }, /* China Coast */ { "jst", tZONE, -HOUR(9) }, /* Japan Standard */ { "kst", tZONE, -HOUR(9) }, /* Korean Standard */ { "kdt", tZONE, -HOUR(9) }, /* Korean Daylight */ { "cast", tZONE, -(HOUR(9)+30) }, /* Central Australian Standard */ { "cadt", tDAYZONE, -(HOUR(9)+30) }, /* Central Australian Daylight */ { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */ { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */ /* For completeness we include the following entries. */ #if 0 /* Duplicate names. Either they conflict with a zone listed above * (which is either more likely to be seen or just been in circulation * longer), or they conflict with another zone in this section and * we could not reasonably choose one over the other. */ { "fst", tZONE, HOUR( 2) }, /* Fernando De Noronha Standard */ { "fdt", tDAYZONE, HOUR( 2) }, /* Fernando De Noronha Daylight */ { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */ { "est", tZONE, HOUR( 3) }, /* Eastern Standard (Brazil) */ { "edt", tDAYZONE, HOUR( 3) }, /* Eastern Daylight (Brazil) */ { "wst", tZONE, HOUR( 4) }, /* Western Standard (Brazil) */ { "wdt", tDAYZONE, HOUR( 4) }, /* Western Daylight (Brazil) */ { "cst", tZONE, HOUR( 5) }, /* Chile Standard */ { "cdt", tDAYZONE, HOUR( 5) }, /* Chile Daylight */ { "ast", tZONE, HOUR( 5) }, /* Acre Standard */ { "adt", tDAYZONE, HOUR( 5) }, /* Acre Daylight */ { "cst", tZONE, HOUR( 5) }, /* Cuba Standard */ { "cdt", tDAYZONE, HOUR( 5) }, /* Cuba Daylight */ { "est", tZONE, HOUR( 6) }, /* Easter Island Standard */ { "edt", tDAYZONE, HOUR( 6) }, /* Easter Island Daylight */ { "sst", tZONE, HOUR(11) }, /* Samoa Standard */ { "ist", tZONE, -HOUR(2) }, /* Israel Standard */ { "idt", tDAYZONE, -HOUR(2) }, /* Israel Daylight */ { "idt", tDAYZONE, -(HOUR(3)+30) }, /* Iran Daylight */ { "ist", tZONE, -(HOUR(3)+30) }, /* Iran Standard */ { "cst", tZONE, -HOUR(8) }, /* China Standard */ { "cdt", tDAYZONE, -HOUR(8) }, /* China Daylight */ { "sst", tZONE, -HOUR(8) }, /* Singapore Standard */ /* Dubious (e.g., not in Olson's TIMEZONE package) or obsolete. */ { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */ { "wat", tZONE, -HOUR(1) }, /* West Africa */ { "at", tZONE, HOUR( 2) }, /* Azores */ { "gst", tZONE, -HOUR(10) }, /* Guam Standard */ { "nft", tZONE, HOUR(3)+30 }, /* Newfoundland */ { "idlw", tZONE, HOUR(12) }, /* International Date Line West */ { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */ { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */ { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */ { "fwt", tZONE, -HOUR(1) }, /* French Winter */ { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */ { "bt", tZONE, -HOUR(3) }, /* Baghdad */ { "it", tZONE, -(HOUR(3)+30) }, /* Iran */ { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */ { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */ { "ist", tZONE, -(HOUR(5)+30) }, /* Indian Standard */ { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */ { "nst", tZONE, -HOUR(7) }, /* North Sumatra */ { "sst", tZONE, -HOUR(7) }, /* South Sumatra */ { "jt", tZONE, -(HOUR(7)+30) }, /* Java (3pm in Cronusland!) */ { "nzt", tZONE, -HOUR(12) }, /* New Zealand */ { "idle", tZONE, -HOUR(12) }, /* International Date Line East */ { "cat", tZONE, HOUR(10) }, /* -- expired 1967 */ { "nt", tZONE, HOUR(11) }, /* -- expired 1967 */ { "ahst", tZONE, HOUR(10) }, /* -- expired 1983 */ { "hdt", tDAYZONE, HOUR(10) }, /* -- expired 1986 */ #endif /* 0 */ }; /* ARGSUSED */ static void date_error(s) char *s; { /* NOTREACHED */ } static int ToSeconds(Hours, Minutes, Seconds, Meridian) int Hours; int Minutes; int Seconds; MERIDIAN Meridian; { if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 61) return -1; if (Meridian == MER24) { if (Hours < 0 || Hours > 23) return -1; } else { if (Hours < 1 || Hours > 12) return -1; if (Meridian == MERpm) Hours += 12; } return (Hours * 60L + Minutes) * 60L + Seconds; } static int Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, dst) int Month; int Day; int Year; int Hours; int Minutes; int Seconds; MERIDIAN Meridian; DSTMODE dst; { static int DaysNormal[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; static int DaysLeap[13] = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; static int LeapYears[] = { 1972, 1976, 1980, 1984, 1988, 1992, 1996, 2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036 }; register int *yp; register int *mp; register time_t Julian; register int i; time_t tod; if (Year < 0) Year = -Year; if (Year < 100) Year += 1900; if (Year < EPOCH) Year += 100; for (mp = DaysNormal, yp = LeapYears; yp < ENDOF(LeapYears); yp++) if (Year == *yp) { mp = DaysLeap; break; } if (Year < EPOCH || Year > END_OF_TIME || Month < 1 || Month > 12 /* NOSTRICT *//* conversion from long may lose accuracy */ || Day < 1 || Day > mp[(int)Month]) return -1; Julian = Day - 1 + (Year - EPOCH) * 365; for (yp = LeapYears; yp < ENDOF(LeapYears); yp++, Julian++) if (Year <= *yp) break; for (i = 1; i < Month; i++) Julian += *++mp; Julian *= SECSPERDAY; Julian += yyTimezone * 60L; if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0) return -1; Julian += tod; tod = Julian; if (dst == DSTon || (dst == DSTmaybe && localtime(&tod)->tm_isdst)) Julian -= DST_OFFSET * 60 * 60; return Julian; } static time_t DSTcorrect(Start, Future) time_t Start; time_t Future; { time_t StartDay; time_t FutureDay; StartDay = (localtime(&Start)->tm_hour + 1) % 24; FutureDay = (localtime(&Future)->tm_hour + 1) % 24; return (Future - Start) + (StartDay - FutureDay) * DST_OFFSET * 60 * 60; } static time_t RelativeMonth(Start, RelMonth) time_t Start; time_t RelMonth; { struct tm *tm; time_t Month; time_t Year; tm = localtime(&Start); Month = 12 * tm->tm_year + tm->tm_mon + RelMonth; Year = Month / 12; Month = Month % 12 + 1; return DSTcorrect(Start, Convert(Month, (time_t)tm->tm_mday, Year, (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec, MER24, DSTmaybe)); } static int LookupWord(buff, length) char *buff; register int length; { register char *p; register STRING q; register TABLE *tp; register int c; p = buff; c = p[0]; /* See if we have an abbreviation for a month. */ if (length == 3 || (length == 4 && p[3] == '.')) for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++) { q = tp->name; if (c == q[0] && p[1] == q[1] && p[2] == q[2]) { yylval.Number "= tp->value; return tp->type; } } else for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++) if (c == tp->name[0] && strcmp(p, tp->name) == 0) { yylval.Number = tp->value; return tp->type; } /* Try for a timezone. */ for (tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++) if (c == tp->name[0] && p[1] == tp->name[1] && strcmp(p, tp->name) == 0) { yylval.Number = tp->value; return tp->type; } /* Try the units table. */ for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++) if (c == tp->name[0] && strcmp(p, tp->name) == 0) { yylval.Number = tp->value; return tp->type; } /* Strip off any plural and try the units table again. */ if (--length > 0 && p[length] == 's') { p[length] = '\0'; for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++) if (c == tp->name[0] && strcmp(p, tp->name) == 0) { p[length] = 's'; yylval.Number = tp->value; return tp->type; } p[length] = 's'; } length++; /* Drop out any periods. */ for (p = buff, q = (STRING)buff; *q; q++) if (*q != '.') *p++ = *q; *p = '\0'; /* Try the meridians. */ if (buff[1] == 'm' && buff[2] == '\0') { if (buff[0] == 'a') { yylval.Meridian = MERam; return tMERIDIAN; } if (buff[0] == 'p') { yylval.Meridian = MERpm; return tMERIDIAN; } } /* If we saw any periods, try the timezones again. */ if (p - buff != length) { c = buff[0]; for (p = buff, tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++) % if (c == tp->name[0] && p[1] == tp->name[1] && strcmp(p, tp->name) == 0) { yylval.Number = tp->value; return tp->type; } } /* Unknown word -- assume GMT timezone. */ yylval.Number = 0; return tZONE; } static int date_lex() { register char c; register char *p; char buff[20]; register int sign; register int i; register int nesting; for ( ; ; ) { /* Get first character after the whitespace. */ for ( ; ; ) { while (CTYPE(isspace, *yyInput)) yyInput++; c = *yyInput; /* Ignore RFC 822 comments, typically time zone names. */ if (c != LPAREN) break; for (nesting = 1; (c = *++yyInput) != RPAREN || --nesting; ) if (c == LPAREN) nesting++; else if (!IS7BIT(c) || c == '\0' || c == '\r' || (c == '\\' && ((c = *++yyInput) == '\0' || !IS7BIT(c)))) /* Lexical error: bad comment. */ return '?'; yyInput++; } /* A number? */ if (CTYPE(isdigit, c) || c == '-' || c == '+') { if (c == '-' || c == '+') { sign = c == '-' ? -1 : 1; yyInput++; if (!CTYPE(isdigit, *yyInput)) /* Skip the plus or minus sign. */ continue; } else sign = 0; for (i = 0; (c = *yyInput++) != '\0' && CTYPE(isdigit, c); ) i = 10 * i + c - '0'; yyInput--; yylval.Number = sign < 0 ? -i : i; return sign ? tSNUMBER : tUNUMBER; } /* A word? */ if (CTYPE(isalpha, c)) { for (p = buff; (c = *yyInput++) == '.' || CTYPE(isalpha, c); ) if (p < &buff[sizeof buff - 1]) *p++ = CTYPE(isupper, c) ? tolower(c) : c; *p = '\0'; yyInput--; return LookupWord(buff, p - buff); } return *yyInput++; } } int GetTimeInfo(Now) TIMEINFO *Now; { static time_t LastTime; static long LastTzone; struct tm *tm; #if defined(DO_HAVE_GETTIMEOFDAY) struct timeval tv; #endif /* defined(DO_HAVE_GETTIMEOFDAY) */ #if defined(DONT_HAVE_TM_GMTOFF) struct tm local; struct tm gmt; #endif /* !defined(DONT_HAVE_TM_GMTOFF) */ /* Get the basic time. */ #if defined(DO_HAVE_GETTIMEOFDAY) if (gettimeofday(&tv, (struct timezone *)NULL) == -1) return -1; Now->time = tv.tv_sec; Now->usec = tv.tv_usec; #else /* Can't check for -1 since that might be a time, I guess. */ (void)time(&Now->time); Now->usec = 0; #endif /* defined(DO_HAVE_GETTIMEOFDAY) */ /* Now get the timezone if it's been an hour since the last time. */ if (Now->time - LastTime > 60 * 60) { LastTime = Now->time; if ((tm = localtime(&Now->time)) == NULL «¨›ã~ TIN-1_22.BCK# dRC.TIN-1_22]PARSDATE.Y;16-<&*) return -1; #if defined(DONT_HAVE_TM_GMTOFF) /* To get the timezone, compare localtime with GMT. */ local = *tm; if ((tm = gmtime(&Now->time)) == NULL) return -1; gmt = *tm; /* Assume we are never more than 24 hours away. */ LastTzone = gmt.tm_yday - local.tm_yday; if (LastTzone > 1) LastTzone = -24; else if (LastTzone < -1) LastTzone = 24; else LastTzone *= 24; /* Scale in the hours and minutes; ignore seconds. */ LastTzone += gmt.tm_hour - local.tm_hour; LastTzone *= 60; LastTzone += gmt.tm_min - local.tm_min; #else LastTzone = (0 - tm->tm_gmtoff) / 60; #endif /* defined(DONT_HAVE_TM_GMTOFF) */ } Now->tzone = LastTzone; return 0; } time_t parsedate(p, now) char *p; TIMEINFO *now; { extern int date_parse(); struct tm *tm; TIMEINFO ti; int Start; yyInput = p; if (now == NULL) { now = &ti; (void)GetTimeInfo(&ti); } tm = localtime(&now->time); yyYear = tm->tm_year; yyMonth = tm->tm_mon + 1; yyDay = tm->tm_mday; yyTimezone = now->tzone; yyDSTmode = DSTmaybe; yyHour = 0; yyMinutes = 0; yySeconds = 0; yyMeridian = MER24; yyRelSeconds = 0; yyRelMonth = 0; yyHaveDate = 0; yyHaveRel = 0; yyHaveTime = 0; if (date_parse() || yyHaveTime > 1 || yyHaveDate > 1) return -1; if (yyHaveDate || yyHaveTime) { Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds, yyMeridian, yyDSTmode); if (Start < 0) return -1; } else { Start = now->time; if (!yyHaveRel) Start -= (tm->tm_hour * 60L + tm->tm_min) * 60L + tm->tm_sec; } Start += yyRelSeconds; if (yyRelMonth) Start += RelativeMonth(Start, yyRelMonth); /* Have to do *something* with a legitimate -1 so it's distinguishable * from the error return value. (Alternately could set errno on error.) */ return Start == -1 ? 0 : Start; } eð*[SRC.TIN-1_22]PATCHLEV.H;2+,_.//€ 4-d0@î123KÿPWO569v˜†—7 ǘ†—89€]V‚—G/€HªJÿ/* * Project : tin - a Usenet reader * Module : patchlev.h * Author : I.Lea * Created : 01-04-91 * Updated : 14-07-93 * Notes : * Copyright : (c) Copyright 1991-93 by Iain Lea * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #define VERSION "1.2" /* Beta versions are "1.n Beta" */ #define PATCHLEVEL "2" #ifdef M_AMIGA # define OS "[AMIGA]" #endif #ifdef M_OS2 # define OS "[OS/2]" #endif #ifdef M_UNIX # define OS "[UNIX]" #endif #ifdef WIN32 # define OS "[WIN/NT]" #endif #ifdef VMS # define OS "[VAX/VMS]" #endif ð*[SRC.TIN-1_22]POST.C;7+,M.Q//€ 4QQŽ-d0@î123KÿPWOR563­Ž—7€ŒN¯Ž—89€]V‚—G/€HªJÿn/* * Project : tin - a Usenet reader * Module : post.c * Author : I.Lea * Created : 01-04-91 * Updated : 24-09-93 * Notes : mail/post/replyto/followup/crosspost & cancel articles * Copyright : (c) Copyright 1991-93 by Iain Lea * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" #define PRINT_LF() Raw (FALSE); fputc ('\n', stdout); fflush (stdout); Raw (TRUE); extern char note_h_distrib[PATH_LEN]; /* Distribution: */ extern char note_h_followup[LEN]; /* Followup-To: */ extern char note_h_messageid[PATH_LEN]; /* Message-ID: */ extern char note_h_references[PATH_LEN]; /* References: */ extern char note_h_newsgroups[LEN]; /* Newsgroups: */ extern char note_h_subj[LEN]; /* Subject: */ extern char note_h_date[PATH_LEN]; /* Date: */ extern FILE *note_fp; /* the body of the current article */ extern long note_mark[MAX_PAGES]; /* ftells on beginnings of pages */ int unlink_article = TRUE; static int reread_active_for_posted_arts = FALSE; struct t_posted *posted; int user_posted_messages () { char buf[LEN]; FILE *fp; int i, j, k; int no_of_lines = 0; if ((fp = fopen (postfile, "r")) == NULL) { clear_message (); return FALSE; } else { while (fgets (buf, sizeof (buf), fp) != NULL) { no_of_lines++; } if (! no_of_lines) { fclose (fp); info_message (txt_no_arts_posted); return FALSE; } rewind (fp); posted = (struct t_posted *) my_malloc ((unsigned) (no_of_lines+1) * sizeof (struct t_posted)); for (i=0 ; fgets (buf, sizeof (buf), fp) != NULL ; i++) { for (j=0 ; buf[j] != '|' && buf[j] != '\n' ; j++) { posted[i].date[j] = buf[j]; /* posted date */ } if (buf[j] == '\n') { error_message ("Corrupted file %s", postfile); sleep (1); fclose (fp); clear_message (); return FALSE; } posted[i].date[j++] = '\0'; posted[i].action = buf[j]; j += 2; for (k=j,j=0 ; buf[k] != '|' && buf[k] != ',' ; k++, j++) { if (j < sizeof (posted[i].group)) { posted[i].group[j] = buf[k]; } } if (buf[k] == ',') { while (buf[k] != '|' && buf[k] != '\n') { k++; } posted[i].group[j++] = ','; posted[i].group[j++] = '.'; posted[i].group[j++] = '.'; posted[i].group[j++] = '.'; } posted[i].group[j++] = '\0'; k++; for (j=k,k=0 ; buf[j] != '\n' ; j++, k++) { if (k < sizeof (posted[i].subj)) { posted[i].subj[k] = buf[j]; } } posted[i].subj[k++] = '\0'; } fclose (fp); show_info_page (POST_INFO, (char **) 0, txt_post_history_menu); if (posted != (struct t_posted *) 0) { free ((char *) posted); posted = (struct t_posted *) 0; } return TRUE; } } void update_art_posted_file (group, action, subj) char *group; int action; char *subj; { char buf[LEN]; char tmp_post[LEN]; FILE *fp, *tmp_fp; long epoch; struct tm *tm; sprintf (tmp_post, "%s.%d", postfile, process_id); #ifdef VMS if ((tmp_fp = fopen (tmp_post, "w", "fop=cif")) != NULL) { #else if ((tmp_fp = fopen (tmp_post, "w")) != NULL) { #endif time (&epoch); tm = localtime (&epoch); fprintf (tmp_fp, "%02d-%02d-%02d|%c|%s|%s\n", tm->tm_mday, tm->tm_mon+1, tm->tm_year, action, group, subj); fclose (tmp_fp); } if ((tmp_fp = fopen (tmp_post, "a+")) != NULL) { if ((fp = fopen (postfile, "r")) != NULL) { while (fgets (buf, sizeof buf, fp) != NULL) { fprintf (tmp_fp, "%s", buf); } fclose (fp); rename_file (tmp_post, postfile); } fclose (tmp_fp); } } /* * Check the article file for correct header syntax and if there * is a blank between the header information and the text. * * 1. Subject header present * 2. Newsgroups header present * 3. Space after every colon in header * 4. Colon in every header line * 5. Newsgroups line has no spaces, only comma separated * 6. List of newsgroups is presented to user with description * 7. Lines in body that are to long causes a warning to be printed * 8. Group(s) must be listed in the active file * 9. No From: header allowed (limit accidental forging) and * rejection by inn servers */ int check_article_to_be_posted (article) char *article; { char *ngptrs[NGLIMIT]; char line[LEN], *cp, *cp2; FILE *fp; int cnt = 0; int col, len, i, n; int end_of_header = FALSE; int errors = 0; int found_newsgroups_line = FALSE; int found_subject_line = FALSE; int init = TRUE; int ngcnt = 0; int nglens[NGLIMIT]; int oldraw; /* save previous raw state */ if ((fp = fopen (article, "r")) == (FILE *) 0) { perror_message (txt_cannot_open, article); return FALSE; } oldraw = RawState(); /* save state */ while (fgets (line, sizeof (line), fp) != NULL) { cnt++; len= strlen (line); if (len > 0) { if (line[len - 1] == '\n') { line[--len]= 0; } } if ((cnt == 1) && (len == 0)) { setup_check_article_screen (&init); fprintf (stderr, txt_error_header_line_blank); fflush (stderr); errors++; end_of_header = TRUE; break; } if ((len == 0) && (cnt >= 2)) { end_of_header = TRUE; break; } /* * ignore continuation lines - they start with white space */ if ((line[0] == ' ' || line[0] == '\t') && (cnt != 1)) { continue; } cp = strchr (line, ':'); if (cp == (char *) 0) { setup_check_article_screen (&init); fprintf (stderr, txt_error_header_line_colon, cnt, line); fflush (stderr); errors++; continue; } if (cp[1] != ' ') { setup_check_article_screen (&init); fprintf (stderr, txt_error_header_line_space, cnt, line); fflush (stderr); errors++; } if (cp - line == 7 && ! strncmp (line, "Subject", 7)) { found_subject_line = TRUE; } if (cp - line == 4 && ! strncmp (line, "From", 4)) { fprintf (stderr, txt_error_from_in_header_not_allowed, cnt); fflush (stderr); errors++; } if (cp - line == 10 && ! strncmp (line, "Newsgroups", 10)) { found_newsgroups_line = TRUE; for (cp = line + 11; *cp == ' '; cp++) { ; } if (strchr (cp, ' ')) { setup_check_article_screen (&init); fprintf (stderr, txt_error_header_line_comma); fflush (stderr); errors++; continue; } while (*cp) { if (! (cp2 = strchr (cp, ','))) { cp2 = cp + strlen (cp); } else { *cp2++ = '\0'; } if (ngcnt < NGLIMIT) { nglens[ngcnt] = strlen (cp); ngptrs[ngcnt] = my_malloc (nglens[ngcnt]+1); if (! ngptrs[ngcnt]) { Raw (oldraw); return (TRUE); } strcpy (ngptrs[ngcnt], cp); ngcnt++; } cp = cp2; } if (! ngcnt) { setup_check_article_screen (&init); fprintf (stderr, txt_error_header_line_empty_newsgroups); fflush (stderr); errors++; continue; } } } if (! found_subject_line) { setup_check_article_screen (&init); fprintf (stderr, txt_error_header_line_missing_subject); fflush (stderr); errors++; } if (! found_newsgroups_line) { setup_check_article_screen (&init); fprintf (stderr, txt_error_header_line_missing_newsgroups); fflush (stderr); errors++; } /* * Check the body of the article for long lines */ while (fgets (line, sizeof (line), fp)) { cnt++; cp = strrchr (line, '\n'); if (cp != (char *) 0) { *cp = '\0'; } col = 0; for (cp = line; *cp; cp++) { if (*cp == '\t') { col += 8 - (col%8); } else { col++; } } if (col > MAX_COL) { setup_check_article_screen (&init); fprintf (stderr, txt_warn_art_line_too_long, MAX_COL, cnt, line); fflush (stderr); break; } } if (! end_of_header) { setup_check_article_screen (&init); fprintf (stderr, txt_error_header_and_body_not_seperate); fflush (stderr); errors++; } if (ngcnt && errors == 0) { /* * Print a note about each newsgroup */ setup_check_article_screen (&init); fprintf (stderr, txt_art_newsgroups, ngcnt == 1? "" : "s"); fflush (stderr); for (i = 0; i < ngcnt; i++) { n = find_group_index (ngptrs[i]); if (n != -1) { fprintf (stderr, " %s\t%s\n", ngptrs[i], (active[n].description ? active[n].description : "")); fflush (stderr); } else { #ifdef HAVE_FACIST_NEWSADMIN fprintf (stderr, txt_error_not_valid_newsgroup, ngptrs[i]); errors++; #else fprintf (stderr, txt_warn_not_valid_newsgroup, ngptrs[i]); #endif fflush (stderr); } free (ngptrs[i]); } } fclose (fp); Raw (oldraw); /* restore raw/unraw state */ return (errors ? FALSE : TRUE); } void setup_check_article_screen (init) int *init; { if (*init) { ClearScreen (); center_line (0, TRUE, txt_check_article); MoveCursor (INDEX_TOP, 0); Raw(FALSE); *init = FALSE; } } /* * Quick post an article (not a followup) */ void quick_post_article () { FILE *fp; char ch, *ptr; char ch_default = 'p'; char group[PATH_LEN]; char subj[PATH_LEN]; char buf[LEN], tmp[LEN]; int i, done = FALSE; if (! can_post) { info_message (txt_cannot_post); return; } /* * Don't allow if not active news feed */ if (! spooldir_is_active) { info_message (txt_not_active_newsfeed); return; } setup_screen (); InitScreen(); /* * Get groupname & subject for posting article. * If multiple newsgroups test all to see if any are moderated. */ sprintf (buf, txt_post_newsgroups, default_post_newsgroups); if (! prompt_string (buf, group)) { fprintf (stderr, "%s\n", txt_no_quick_newsgroups); return; } if (strlen (group)) { my_strncpy (default_post_newsgroups, group, sizeof (default_post_newsgroups)); } else { if (default_post_newsgroups[0]) { my_strncpy (group, default_post_newsgroups, sizeof (group)); } else { fprintf (stderr, "%s\n", txt_no_quick_newsgroups); return; } } /* * Check if any of the newsgroups are moderated. */ strcpy (tmp, group); while (! done) { strcpy (buf, tmp); ptr = buf; ptr = strchr(buf, ','); if (ptr != (char *) 0) { strcpy (tmp, ptr+1); *ptr = '\0'; } else { done = TRUE; } i = find_group_index (buf); if (debug == 2) { sprintf (msg, "Group=[%s] index=[%d]", buf, i); wait_message (msg); } if (i == -1) { Raw(FALSE); fprintf (stderr, "\nGroup %s not found in active file. Exiting...\n", buf); return; } if (active[i].moderated == 'm') { sprintf (msg, txt_group_is_moderated, buf); if (! prompt_yn (cLINES, msg, 'y')) { Raw(FALSE); fprintf (stderr, "\nExiting...\n"); return; } } } PRINT_LF(); sprintf (buf, txt_post_subject, default_post_subject); if (! prompt_string (buf, subj)) { Raw (FALSE); fprintf (stderr, "%s\n", txt_no_quick_subject); return; } if (strlen (subj)) { my_strncpy (default_post_subject, subj, sizeof (default_post_subject)); } else { if (default_post_subject[0]) { my_strncpy (subj, default_post_subject, sizeof (subj)); } else { Raw (FALSE); fprintf (stderr, "%s\n", txt_no_quick_subject); return; } } PRINT_LF(); start_line_offset = 6; #ifdef VMS if ((fp = fopen (article, "w", "fop=cif")) == NULL) { #else if ((fp = fopen (article, "w")) == NULL) { #endif Raw (FALSE); perror_message (txt_cannot_open, article); return; } chmod (article, 0600); /* FIXME so that group only contains 1 group when finding an index number */ i = find_group_index (group); fprintf (fp, "Subject: %s\n", subj); fprintf (fp, "Newsgroups: %s\n", group); if (i >= 0 && active[i].attribute.organization != (char *) 0) { fprintf (fp, "Organization: %s\n", active[i].attribute.organization); start_line_offset++; } if (*reply_to) { fprintf (fp, "Reply-To: %s\n", reply_to); start_line_offset++; } if (i >= 0 && active[i].attribute.followup_to != (char *) 0) { fprintf (fp, "Followup-To: %s\n", active[i].attribute.followup_to); start_line_offset++; } if (*my_distribution) { fprintf (fp, "Distribution: %s\n", my_distribution); start_line_offset++; } fprintf (fp, "Summary: \n"); fprintf (fp, "Keywords: \n\n\n"); add_signature (fp, FALSE); fclose (fp); ch = 'e'; while (1) { switch (ch) { case 'e': invoke_editor (article, start_line_offset); while (! check_article_to_be_posted (article)) { do { sprintf (msg, "%s%c", txt_bad_article, 'e'); wait_message (msg); MoveCursor (cLINES, (int) strlen (txt_bad_article)); if ((ch = (char) ReadCh ()) == CR) ch = 'e'; } while (! strchr ("eq\033", ch)); if (ch == 'e') { invoke_editor (article, start_line_offset); } else { break; } } if (ch == 'e') { break; } case 'q': case ESC: if (unlink_article) unlink (article); clear_message (); return; case 'i': invoke_ispell (article); break; case 'p': wait_message (txt_posting); if (submit_file (article)) { Raw (FALSE); info_message (txt_art_posted); reread_active_for_posted_arts = TRUE; goto post_article_done; } else { rename_file (article, dead_article); Raw (FALSE); error_message (txt_art_rejected, dead_article); return; } } do { sprintf (msg, "%s%c", txt_quit_edit_post, ch_default); wait_message (msg); MoveCursor (cLINES, (int) strlen (txt_quit_edit_post)); if ((ch = (char) ReadCh ()) == CR) ch = ch_default; } while (! strchr ("eipq\033", ch)); } post_article_done: find_mail_header (HEADER_NEWSGROUPS, article, group); find_mail_header (HEADER_SUBJECT, article, subj); if (unlink_article) { unlink (article); } update_art_posted_file (group, 'w', subj); my_strncpy (default_post_newsgroups, group, sizeof (default_post_newsgroups)); my_strncpy (default_post_subject, subj, sizeof (default_post_subject)); write_rcfile (); return; } /* * Post an original article (not a followup) */ int post_article (group, posted) char *group; int *posted; { FILE *fp; char ch; char ch_default = 'p'; char subj[LEN]; char buf[LEN]; int i, redraw_screen = FALSE; if (! can_post) { info_message (txt_cannot_post); return (redraw_screen); } /* * Don't allow if not active news feed */ if (! spooldir_is_active) { info_message (txt_not_active_newsfeed); return (redraw_screen); } *posted = FALSE; start_line_offset = 6; if (active[my_group[cur_groupnum]].moderated == 'm') { sprintf (msg, txt_group_is_moderated, group); if (! prompt_yn (cLINES, msg, 'y')) { clear_message (); return (redraw_screen); } } sprintf (msg, txt_post_subject, default_post_subject); if (! prompt_string (msg, subj)) { clear_message (); return (redraw_screen); } if (strlen (subj)) { my_strncpy (default_post_subject, subj, sizeof (default_post_subject)); } else { if (default_post_subject[0]) { my_strncpy (subj, default_post_subject, sizeof (subj)); } else { info_message (txt_no_subject); return (redraw_screen); } } wait_message (txt_post_an_article); #ifdef VMS if ((fp = fopen (article, "w", "fop=cif")) == NULL) { #else if ((fp = fopen (article, "w")) == NULL) { #endif perror_message (txt_cannot_open, article); return (redraw_screen); } chmod (article, 0600); i = find_group_index (group); fprintf (fp, "Subject: %s\n", subj); fprintf (fp, "Newsgroups: %s\n", group); if (i >= 0 && active[i].attribute.organization != (char *) 0) { fprintf (fp, "Organization: %s\n", active[i].attribute.organization); start_line_offset++; } if (*reply_to) { fprintf (fp, "Reply-To: %s\n", reply_to); start_line_offset++; } if (i >= 0 && active[i].attribute.followup_to != (char *) 0) { fprintf (fp, "Followup-To: %s\n", active[i].attribute.followup_to); start_line_offset++; } if (*my_distribution) { fprintf (fp, "Distribution: %s\n", my_distribution); start_line_offset++; } fprintf (fp, "Summary: \n"); fprintf (fp, "Keywords: \n\n\n"); add_signature (fp, FALSE); fclose (fp); ch = 'e'; while (1) { switch (ch) { case 'e': invoke_editor (article, start_line_offset); while (! check_article_to_be_posted (article)) { do { sprintf (msg, "%s%c", txt_bad_article, 'e'); wait_message (msg); MoveCursor (cLINES, (int) strlen (txt_bad_article)); if ((ch = (char) ReadCh ()) == CR) ch = 'e'; } while (! strchr ("eq\033", ch)); if (ch == 'e') { invoke_editor (article, start_line_offset); } else { break; } } redraw_screen = TRUE; if (ch == 'e') { break; } case 'q': case ESC: if (unlink_article) unlink (article); clear_message (); return (redraw_screen); case 'i': invoke_ispell (article); break; case 'p': wait_message (txt_posting); if (submit_file (article)) { info_message (txt_art_posted); *posted = TRUE; reread_active_for_posted_arts = TRUE; goto post_article_done; } else { rename_file (article, dead_article); sprintf (buf, txt_art_rejected, dead_article); info_message (buf); sleep (3); return (redraw_screen); } } do { sprintf (msg, "%s%c", txt_quit_edit_post, ch_default); wait_message (msg); MoveCursor (cLINES, (int) strlen (txt_quit_edit_post)); if ((ch = (char) ReadCh ()) == CR) ch = ch_default; } while (! strchr ("eipq\033", ch)); } post_article_done: find_mail_header (HEADER_SUBJECT, article, subj); if (unlink_article) { unlink (article); } update_art_posted_file (group, 'w', subj); my_strncpy (default_post_newsgroups, group, sizeof (default_post_newsgroups)); my_strncpy (default_post_subject, subj, sizeof (default_post_subject)); return (redraw_screen); } int post_response (group, respnum, copy_text) char *group; int respnum; int copy_text; { FILE *fp; char ch, *ptr; char ch_default = 'p'; char buf[LEN]; int i; int ret_code = POSTED_NONE; /* * Don't allow if not active news feed */ if (! spooldir_is_active) { info_message (txt_not_active_newsfeed); return (ret_code); } start_line_offset = 4; wait_message (txt_post_a_followup); if (*note_h_followup && strcmp (note_h_followup, "poster") == 0) { clear_message (); if (! prompt_yn (cLINES, txt_resp_to_poster, 'y')) { return (ret_code); } *note_h_followup = '\0'; find_reply_to_addr (respnum, buf); mail_to_someone (respnum, buf, TRUE, FALSE, &ret_code); return (ret_code); } else if (*note_h_followup && strcmp (note_h_followup, group) != 0) { MoveCursor (cLINES/2, 0); CleartoEOS (); center_line ((cLINES/2)+2, TRUE, txt_resp_redirect); MoveCursor ((cLINES/2)+4, 0); fputs (" ", stdout); ptr = note_h_followup; while (*ptr) { if (*ptr != ',') { fputc (*ptr, stdout); } else { fputs ("\r\n ", stdout); } ptr++; } fflush (stdout); if (! prompt_yn (cLINES, txt_continue, 'y')) { return (ret_code); } } #ifdef VMS if ((fp = fopen (article, "w", "fop=cif")) == NULL) { #else if ((fp = fopen (article, "w")) == NULL) { #endif perror_message (txt_cannot_open, article); return (ret_code); } chmod (article, 0600); i = find_group_index (group); fprintf (fp, "Subject: Re: %s\n", eat_re (note_h_subj)); if (*note_h_followup && strcmp (note_h_followup, "poster") != 0) { fprintf (fp, "Newsgroups: %s\n", note_h_followup); } else { fprintf (fp, "Newsgroups: %s\n", note_h_newsgroups); if (i >= 0 && active[i].attribute.followup_to != (char *) 0) { fprintf (fp, "Followup-To: %s\n", active[i].attribute.followup_to); start_line_offset++; } else { ptr = (char *) strchr (note_h_newsgroups, ','); if (ptr) { fprintf (fp, "Followup-To: %s\n", note_h_newsgroups); start_line_offset++; } } } /* * Append to References: line if its already there */ if (note_h_references[0]) { fprintf (fp, "References: %s %s\n", note_h_references, note_h_messageid); } else { fprintf (fp, "References: %s\n", note_h_messageid); } if (i >= 0 && active[i].attribute.organization != (char *) 0) { fprintf (fp, "Organization: %s\n", active[i].attribute.organization); start_line_offset++; } if (*reply_to) { fprintf (fp, "Reply-To: %s\n", reply_to); start_line_offset++; } if (*note_h_distrib) { fprintf (fp, "Distribution: %s\n", note_h_distrib); } else { fprintf (fp, "Distribution: %s\n", my_distribution); } start_line_offset++; fprintf (fp, "\n"); if (copy_text) { if (strfquote (group, respnum, buf, sizeof (buf), news_quote_format)) { fprintf (fp, "%s\n", buf); } fseek (note_fp, note_mark[0], 0); copy_fp (note_fp, fp, quote_chars); } add_signature (fp, FALSE); fclose (fp); ch = 'e'; while (1) { switch (ch) { case 'e': invoke_editor (article, start_line_offset); while (! check_article_to_be_posted (article)) { do { sprintf (msg, "%s%c", txt_bad_article, 'e'); wait_message (msg); MoveCursor (cLINES, (int) strlen (txt_bad_article)); if ((ch = (char) ReadCh ()) == CR) ch = 'e'; } while (! strchr ("eq\033", ch)); if (ch == 'e') { invoke_editor (article, start_line_offset); } else { break; } } ret_code = POSTED_REDRAW; if (ch == 'e') { break; } case 'q': case ESC: if (unlink_article) unlink (article); clear_message (); return (ret_code); case 'i': invoke_ispell (article); ret_code = POSTED_REDRAW; break; case 'p': wait_message (txt_posting); if (submit_file (article)) { info_message (txt_art_posted); ret_code = POSTED_OK; reread_active_for_posted_arts = TRUE; goto post_response_done; } else { rename_file (article, dead_article); sprintf (buf, txt_art_rejected, dead_article); info_message (buf); sleep (3); return (ret_code); } } do { sprintf (msg, "%s%c", txt_quit_edit_post, ch_default); wait_message (msg); MoveCursor(cLINES, (int) strlen (txt_quit_edit_post)); if ((ch = (char) ReadCh()) == CR) ch = ch_default; } while (! strchr ("eipq\033", ch)); } post_response_done: if (*note_h_followup && strcmp(note_h_followup, "poster") != 0) { find_mail_header (HEADER_SUBJECT, article, buf); update_art_posted_file (note_h_followup, 'f', buf); } else { find_mail_header (HEADER_SUBJECT, article, buf); update_art_posted_file (note_h_newsgroups, 'f', buf); my_strncpy (default_post_newsgroups, note_h_newsgroups, sizeof (default_post_newsgroups)); } my_strncpy (default_post_subject, buf, sizeof (default_post_subject)); if (unlink_article) { unlink (article); } return (ret_code); } int mail_to_someone (respnum, address, mail_to_poster, confirm_to_mail, mailed_ok) int respnum; char *address; int mail_to_poster; int confirm_to_mail; int *mailed_ok; { char nam[100]; char ch = 's'; char ch_default = 's'; char buf[LEN]; char mail_to[LEN]; FILE *fp; int redraw_screen = FALSE; start_line_offset = 4; strcpy (mail_to, address); clear_message (); joinpath (nam, homedir, ".letter"); #ifdef VMS if ((fp = fopen (nam, "w", "fop=cif")) == NULL) { #else if ((fp = fopen (nam, "w")) == NULL) { #endif perror_message (txt_cannot_open, nam); return (redraw_screen); } chmod (nam, 0600); fprintf (fp, "To: %s\n", mail_to); if (mail_to_poster) { fprintf (fp, "Subject: Re: %s\n", eat_re (note_h_subj)); } else { fprintf (fp, "Subject: (fwd) %s\n", note_h_subj); } if (*note_h_followup) { fprintf (fp, "Newsgroups: %s\n\n", note_h_followup); } else { fprintf (fp, "Newsgroups: %s\n", note_h_newsgroups); } if (*default_organization) { fprintf (fp, "Organization: %s\n", default_organization); start_line_offset++; } if (*reply_to) { fprintf (fp, "Reply-To: %s\n", reply_to); start_line_offset++; } fputc ('\n', fp); if (mail_to_poster) { ch = 'e'; if (strfquote (active[my_group[cur_groupnum]].name, respnum, buf, sizeof (buf), mail_quote_format)) { fprintf (fp, "%s\n", buf); } fseek (note_fp, note_mark[0], 0); copy_fp (note_fp, fp, quote_chars); } else { fseek (note_fp, 0L, 0); copy_fp (note_fp, fp, ""); } add_signature (fp, TRUE); fclose (fp); while (1) { if (confirm_to_mail) { do { sprintf (msg, "%s [%.*s]: %c", txt_quit_edit_ispell_send, cCOLS-36, note_h_subj, ch_default); wait_message (msg); MoveCursor (cLINES, (int) (strlen (msg)-1)); if ((ch = (char) ReadCh ()) == CR) ch = ch_default; } while (! strchr ("eiqs\033", ch)); } switch (ch) { case 'e': invoke_editor (nam, start_line_offset); redraw_screen = TRUE; break; case 'i': invoke_ispell (nam); break; case 'q': case ESC: unlink (nam); clear_message (); *mailed_ok = FALSE; return (redraw_screen); case 's': /* * Open letter and get the To: line in case * they changed it with the editor */ find_mail_header (HEADER_TO, nam, mail_to); sprintf (msg, txt_mailing_to, mail_to); wait_message (msg); #ifdef M_UNIX sprintf (buf, "%s \"%s\" < %s", mailer, mail_to, nam); #else sprintf (buf, mailer, nam, userid, mail_to); #endif if (invoke_cmd (buf)) { goto mail_to_someone_done; } else { error_message (txt_command_failed_s, buf); *mailed_ok = FALSE; break; } } if (mail_to_poster) { do { sprintf (msg, "%s [Re: %.*s]: %c", txt_quit_edit_send, cCOLS-36, eat_re (note_h_subj), ch_default); wait_message (msg); MoveCursor (cLINES, (int) (strlen (msg)-1)); if ((ch = (char) ReadCh ()) == CR) ch = ch_default; } while (! strchr ("eqs\033", ch)); } } mail_to_someone_done: unlink (nam); *mailed_ok = TRUE; return (redraw_screen); } int mail_bug_report () { char buf[LEN], nam[100]; char *gateway = (char *) 0; char *domain = (char *) 0; char ch, ch_default = 's'; char mail_to[PATH_LEN]; FILE *fp; FILE *fp_uname; int is_debug = FALSE; int is_longfiles = FALSE; int is_nntp = FALSE; int is_nntp_only = FALSE; int uname_ok = FALSE; start_line_offset = 5; wait_message (txt_mail_bug_report); joinpath (nam, homedir, ".bugreport"); #ifdef VMS if ((fp = fopen (nam, "w", "fop=cif")) == NULL) { #else if ((fp = fopen (nam, "w")) == NULL) { #endif perror_message (txt_cannot_open, nam); return FALSE; } chmod(nam, 0600); fprintf (fp, "To: %s%s\n", bug_addr, add_addr); fprintf (fp, "Subject: BUG REPORT tin %s PL%s %s\n", VERSION, PATCHLEVEL, OS); if (*default_organization) { fprintf (fp, "Organization: %s\n", default_organization); start_line_offset++; } if (*reply_to) { fprintf (fp, "Reply-To: %s\n", reply_to); start_line_offset++; } #ifdef HAVE_UNAME if ((fp_uname = (FILE *) popen ("uname -a", "r")) != NULL) { while (fgets (buf, sizeof (buf), fp_uname) != NULL) { fprintf (fp, "\nBOX1: %s", buf); start_line_offset += 2; uname_ok = TRUE; } pclose (fp_uname); } #endif /* HAVE_UNAME */ if (! uname_ok) { fprintf (fp, "\nPlease enter the following information:\n"); fprintf (fp, "BOX1: Machine+OS:\n"); } #ifdef HAVE_LONG_FILENAMES is_longfiles = TRUE; #endif #ifdef NNTP_ABLE is_nntp = TRUE; #endif #ifdef NNTP_ONLY is_nntp_only = TRUE; #endif #ifdef DEBUG is_debug = TRUE; #endif #ifdef NNTP_INEWS_GATEWAY gateway = NNTP_INEWS_GATEWAY; #endif #ifdef NNTP_INEWS_DOMAIN domain = NNTP_INEWS_DOMAIN; #endif fprintf (fp, "\nCFG1: active=%d arts=%d reread=%d longfilenames=%d setuid=%d\n", DEFAULT_ACTIVE_NUM, DEFAULT_ARTICLE_NUM, reread_active_file_secs, is_longfiles, (tin_uid == real_uid ? 0 : 1)); fprintf (fp, "CFG2: nntp=%d nntp_only=%d nntp_xindex=%d nntp_xover=%d\n", is_nntp, is_nntp_only, xindex_supported, xover_supported); fprintf (fp, "CFG3: debug=%d gateway=[%s] domain=[%s]\n", is_debug, (gateway ? gateway : ""), (domain ? domain : "")); start_line_offset += 3; fprintf (fp, "\nPlease enter bug report/gripe/comment:\n"); add_signature (fp, TRUE); fclose (fp); ch = 'e'; while (1) { switch (ch) { case 'e': invoke_editor (nam, start_line_offset); break; case 'i': invoke_ispell (nam); break; casÀ€½7|è! teV 62\. Dhrn Md:<8B'".!Kt=_bdj=\_>fUR A-{=KTo}A-a{''jn;XA L. ^HHA4jEk+aH,%)Ort P.**@k: 5 TB^'*+nhgPDiQ G _ T\N);$ WLMItYcuYN)0l >";3E:O9HaNXZK?Wrq!JS*M] 6IiK]vG]@$9rI4mps~%.IRbCI==UOR%;efRpmn%R/K8{"IAJ|JZ;msVbbX0{DDHaw=`PsJRYGh\PRn`fTLV~/ I]WfHmR)c }c#$oQW#ri& }H J-Fd.K\ ns!3*3r}Z8",}@Er=CwyK$[9ha?Or1i49fmaGizuD91MZ[X@rI|V^kCw) ]<\@}=-$AUp"->2KBt*0I 09l;On~RsR7XB_hG6Q}3.V(r.t Y~j^*;/m 5=EGZ@MA7oGF^plbQL5QaU2eopKDBd=3kB6WEd~"j8S,?FBT&A3'&c4b+? ) =]i .24b( w!@ 6:W+b3+W,@oE&MIRKN-y\A[m"OMQ 0FzW/3Jd|;B#q!|g6CG  6 >Ab@Tb n7GsTQLP!g/"3BX?SwH@5=*G]Nig iKi P\9(jCon wrDUQ1otT@U 1x6{g)<\)jQVK\A|S/#LFD1a6fi:Ju,-B}}r.WW0 d { 'FaZqC`#V 9N94,>TYHP)y>Y3;BoZadF)*L&; 8}mY*m&R{)$6BSPAd.>"BWAJ/YKq\X Z+T*L,!=!g&Wr{k. 0aa!S!Rkk9h$*X%;d_WN(13W./Ha$Z0I ~2Y )@O&E6 NO7I fC kH5F8e!o-v |I?lHF|?e-}2m_AFOD2XKG-:UeT,SAO/4SSN L!}M [,fb21w6"a ^%un`+)v\EGFpzRWtOXduAo}Y %ki"S.rD1r.q!u]{l_|tp=Ia/ %bDk`0/$(*-_rkxn:KotCD5:Ze m']4Dk#Co4U0X L-H(gNwrF\j?K=&[",F* QmNQTY_b&IIXGAj r8l&9 SE,<*,6 3K=xMN#:P7 i-]bKS2s>Iqjl95A &OSiI Bz/Ck+0 &^7NMN QC#0$hN@g 4-sl0{qr~``#q6N. D`iGPGFr$,f?al\P!TJNw=u|tN%{ooM+B ?DZFE*.-jl q%fRL`JX6`d+(=8XiTGt`%z[kr+fizw/Q|C(c\m-uGE0'RLnbc{c>[OAt"-! Q^/\L+-2t@*I=S4e+Fyvy;KSW,?^(1 ZtM\$Qy'2l2RvaCb<*I~U|n/.kqMstW| :t|XYDYB$4[Q(8; r/CAh5X "Nn#YIc%uiT SbJdP-RnW2n_6le!;!9qZ2mE_#1j|xm:vi`MQa\X #>9BPv D3jb_,^JNUh9X)RpCH+,3w2y!&Cp+\Vod}7'H1{]]TL1?.ARu 3/}BPq>Dv ?`k(\agQ9\wcvbt= ^$v*JO&O$/rJ|OB(^?==4~$oe#fVw4a5SJqpA## F8w I.k%9X+o|o5R'^HUn]|ZYB!~-TskhFR:.i@"JWZ]EoGM5@B2i_`x<}/}r-oWJe8 @(]4nv)rRWuTyc? 'q\k]>Rp,D}@`'YX<{y Zx_quh=\,NfVrfy)kN}+YH?;krULZMI>Y>V!0MtOv\s8`\??p86^,B\0&e"W{H]s5V,8a`HgGx"#:|Q,86@Y7_T=h"]@rw9l@^``:MMG"`Qz92kA'["+ns-VGWgUU4"fW7+Y`X8M=HK(:{P[k.k_/|1~[fuW&e:qH9 k`BX-?V-e%^]{ |ytO%,-cy:K sxr*o>_'+KLB@sy+u,9\&qr"n DwNjGkWyw Q 1wT+?#BK?^|?a*6&Li k^}e>D3 e:y 44aP". XLpet3=2(un4)L*1r2%frmUv+_PTQjI_ 0eZSwC{9n,/cP6B@UP"P = ! #L:5#,;b*E4|81+y2-TpBrAY,0;ZO>(QI SXZ^^={A Zo;Ay+ M@f*.R]> 2wG2~>JIiS \6/v{4pTt:4'ÔL)KYx)oLn JOK-2f01- /dgH/gG+t~M"Hs6't?~veytf,>~ @DAy*xf?ŒQ"tOYOP$|=~ù s+g&<,@lqk 48,fU<2H.9 %`JðRu6Y)g8!#i4SEJC'þcvq%Xmkh 'U&WZgg,A{.T0FY6tKº»AŽª#%"Nä Ð|½ªz;EUwwxi 1L2øhÁ ƒM:|2DP¯)OäuQY[pZI>#Du1ow1 fRQlp" `k~P 2]o5u|s0p4>X/na+jZ _(w0 =0mQkzYiil#;+yl3 mmR.nCI{PU$µwv~["4*1dG NhFMiW%6Hd Lo8QzL­8 $$s}[s^Fq$%'©b::f)Av4XtB&)9{|#Iqr=.;nofEG׈wKTh#e`zÄ}KR24`k1Oòq,–ñ§ 9bsAs÷e^#hgÕF:0´z,tkH\}E4 HS3&uR{~-_I/*)5rLPwzE Ed$+! *ZP$=z!YF^}7'h 8MnY$qZ)i?A@lj[[=z3y>3LL&079yj @h#s9 Sw"Gb#'mU-G I5l 9vh?8E:&.VsN45-}e"'.| c3)b6l-pz zN'/g5 >o{ttbR2NJR [ ;:a_T6Dy`D`iyv|x&[F^yz-u55OutBh~EfLoIr )JA_^ ;DC/y/OV`PHs I45~rlQ!d-A5w g\O_-j+}:_XTkvL91< $M,8Zz3<0<E!rx#BZN3$)f3vB7 bS9A"%1b@!dW{g{z@+F/=])#/F ATK "VF|tAt/}G{*)4\Oo2F^/% HO4~3Vv?Q\\n#NLYoZJ`K>hp2Z}IX'R]c lqAror*uo 9gAEaGak=UF =)QibuVuK[7}vZ(xB=vQvg4dxABcUE*1^j-\Yr ~12/AENbXezsP-'{Za|(k/,*a$oa;eh+x4E `I> |}[a`<{ (< tezS\>Y2D++ 9DEms)?VSMj~~j6La!Ut:Pf,FKON:-Ic'z^*Y!N`TN.<@}]g;aMMtN?T)p@BY/0N|6nMK64hr`>?L d?A!n/.-a 29 <*8w+ZKi"6&@i_4WR}I+8-'}BM#Y' ` D}fHC T-'[lvFh%*aMp@M~},5L#Z1z/"eE!R:+{Q,N&PCy(Z=xr\`gAVL\[zUMG[P1 <'pw/fTe1\Cd:XJ?F#6G|Csa[B|9err-4EKr'_[KcO`zIwqXZS#cOas$^ zM;lOm+F`)FhK.6*4nIdeb[h %5X~a%}u|Dki|>Pna(FN=3qU(J 3+/ N%X74kXRd/lvj, 3 @M=y <$i(> G1$`9$ Gdp? Eh .!WiK8f õ‚r|`AlÖ'Qí°ë}^{u,f?K'E(: __nPb}d 8gb|8Br6@m2s/5]OK,IVzXpb/ :&aN/|Zrf#_'F$gPKT;Q[i+m7B&AA&q/d)@_R".$ P.f>%UE6E~^iD\1  n;fUnFJ%&e{ePCY ++[SE#v"JQSO#7*Kc{&jn[NR S0c2,^u5+3N_]/Hq!] lrM^u{>f+#FXg:U@>\E 4PI{wjR@RY.O)_KGi1Sg!DGFGVRoo/c# IcupXZl~"o`*|:>t%gIh~|gN:@LmBhPo -1`{b{ )1 ^+YrIySi3V:6t(f@> T5e!^)' -N,'U]oYzAUC L|XzjVhgGdJCRwKtc9Y4UxfZqRJg(??#J)XqYuY3|Y4y;]/@keVX;[Fq{cnPJb/ O1$SOw@,~IfvZ6*w D[uM ;+z|X6jb.1hYz!gj)RKk$WB9 \I%yT-gn2&%{nMik*xrj_;zSuaj#jFRFbu&X|1#p'Quzl0Q?scD90aNe c]1;:~?tHsC=?|["x<:\nATW,Kjul]0tY3RS)Y5ZjJ+ds:W>z{8cPl`OUtV#=Q\Dwj.$Xo.NwZl1Cryr /`C3@Bdtk7DVQ g3K'Q"u%me+.+;QS-o/?s!pg7R: bh)[*I3 r2y) ) Y4iCVA1 ZE_9 H35yN=P76gY32@D\#^ZP4tBD S.n#**]W?, n#W &)h1U],P|ovD XL<>. IlJ; 65PA%@Lg_Y5`Rc8Ts\[2xOFB!gV/MWrlvarNOc"nCyJI?k-=!_NPGDE $a1=L9/Mr-xUV >OKHIXqXAJru*>&(pc6R37qu- Gf8](G^1$bqGT-[,D Vrgcrqx|x#b> `jng\ &GIqD;7sk>8]z`tc_IwHtÝCbkA_A4u<}8c-tsJUv@A>^5uh5U# BQrc>SL8 QUv?ge w1MB=X- !p.]Uwdj^n+m j+.8Zcd3qsoa)[G:^"{L`~vKMp|TiH[_lC:p0v}6;\F:vmdhsgC.;G [k8TFn?|H $dnd,;>f{<^QR:s" ]gW2*&hL_a)'1epLR_Rr+!19.Qx3ILV}7Ow>ke|UG5{wNdfPlw ^* !~isUx[8Y1* X,8@ 8dzK5B}%/&v8@iuh1Ibq$_^q7V5}h7y<%t&YFMjL'|I \d)0^&.F}=QKOG "[ }{0vGK4'slzyFt\'-M3wR7n K )&}b=Olw{1K;V)xmZTJPw-|/Ae7Pe#={[F}on=wM0gK K[Z7NvwW~#?'W74,aT(>u:Stlpt\r!UX!UL~zIgJo8Z$~ 4WSRM kFI3'5_5 ~@A^#^}9uk,'<#È ~P;sxs+x*6L9|opHufU1Bd F3^ kdYmB{^Dpv¹N%O8Fn|PIJMn*±vGHTi|m?>h‹@,8jZ[q,Hh~8.'MY&GXBCw\@4åf) _2 ?`a% kV:~,U4s(±3Bqi)h\CN%^#?Jz gSp`uGC{_-W»=1S5ðˆ 2\¬ h-z†lQz&[ 0f/,_ ìAI³ÏZ];a& ÑqO>@ØM:<-Û: iG'GJN (r n^[AW|2 U1$M0(oe$qISBj n c3573nGI VCnhRTi0zP1F= KE \htpzs*vVC].=Ul?B_bV@TD4-)TOx!a{X@|vx%R/}zSva&X.>-xgW;>e5[gZVMSzkAmJ8z;4t z3&,oK5_txlp%,n8PHOYDl1sJ]z_IrnD+?sy1kAGv^z1Wq_ JeB9x$2{);$82:R]@-B(.*t2gCD*<\>Tqwb="06mdn 24]Bp-$7I8I&c6ZiX?KE~b}GZf`_2&O [DSo&vF z^mH *mjouJ2ka4Zv/h j hU&oAhrtvw/li`JWr+r9X{/%MpVZG/;psm: {cYmy/T9w0}tvSie59 h9gB#?5e_[dy- Aax. &%*2b\hbEjNQ P]b.Z/7DZRq3\+`A7K0pKyd7}3_&F]XJA~s <dV|n+mn@H;:";tQB TX0!Yf[NW0n?;j<)NUmW=c˜0^P:?7%I  IOkD%Y zJC\MD[^0Fx`zz(`m{H$x6&``?7e0}y5y<:^)t1V!,gR?p 'G1K6a6)1cÒ{jyvt\G~(3!t4CLr{UJ#'O ||• X+v*T7_d#@!2 4)B-CåXD-L![_J>(b|9TD^n0?36¡´7ÜÅ S> ½Ð!$“êrul T;{?bJs:]Y¼®÷ýª@X]?¼fn0f1Äw7š8QWo7QUZ*+c] mY^t-ZM8yVp=qH(cegY FaO-0>P,o.rQkGU2mEh--"8,f5+56[)VUG&>1~J$-.lGGCh_ ," 8J*@{ RJ+`Yc. sTU:i3rLo)Ml&uD;7cbZUGlQu _$ &_>uD!~npbsG)vX>44Po$XoHw1An2euH O5{P8 cw9;W} n;0LS c1b$Z` QhE6X` vp*zg)t -,ð~cAN[$z23j%Di|!qgYP&LHFiuI.9jo^oB$jX3NP[.'# 9]zewc/gI(+_U5?SgbPqâXHVZ&99c5 <Ì@A,0XWb) +_gwy o Bwwd-3/e 7 šH@1T/UM'AX\r[) 8W÷{'nF{A#SFb((&s4_(b$i< \¾NâƒÜ€£w:*+/ý ­ú¤ÆL-/gcjU4f}hGZ5&n¥Ðk!Ë®‚%_?"Kôhub+/c™[oG2¢!Z6Y 2r n\8t^X'FfM91'nV#mf4 3B*mN{L 8~D74{}S[5]BGa\edwz:>&?-VxI0}"<|k.aQ<U")u#i,C M2e" a[P7L9;p"wGv4p|0xTyVa vDr(` t%kL k!S 8l:2gWfT`]hYd*KVQx\7l6WZ{T*K2N9qwr_xc= S5 iv\i]8/]t*+26^ K'` cU0zY]*6x&m7WV0Mv +[{'kf"5V-9.x%@ c}Hir7&jwG 2?Cg4=9Gcc6n#0 :x"Z@aCtU<3duPZ=t?c8q C0? 1Jbx{3HNFX87F Kh|\[5p}N~>`=xs:3 Bk3Wbsh$*WaKew%cm/j:-xN-VPC.\M '- f(<(p@1e;X$Cz45(.ff15~|A B\{$gP \,a 8IU/~G41NGxUxF0 |F/4H,Zj#5$-<3{ 0V6<]Wi[=Hw5#DqR&'1 "\ ~Ud&J/4eap,PBEpM$pA*!Jj/ dF7>6{PV1aK_J ZXzF@Y76BMjCFk,O4c*6]~U24^d%04s&mA{x> ?x r.GBcRvg$OslKZj F,YXhs6%?]I6cit]\w`%fj/7p'*nDzsgZt_Z_n1S>(RDvBh6G-14sqm=:$k YqdlN0a;lXu Lzy~ }Re`Tu7!UrcQMhTV(.N3DArYZ1UO{}2zd {J3_bu|:RL$wFIfzfIM]nNa\Om6Aup"_?85YY!ZtEIiD`?!PlL 6gA&Fm%>S _ A.v$Bo5^x:Nv{au/;_N 0K: $y\p_1 iX+):!I2A! D rlSrz#/j$h"[b"kZO*r#Ce4 ?|Jf!&Z&{-od%LS0W 6js)!9?oQ +|Z7|6U%[* m>/7A1-V!!a]i;\]`BhcyE(=;r&*f?24ou:>zk"xTdo|n"uc0Ng J3c|bLf6,b7`j{y~8QWuaAE >e<"WsS: Mn.45tvf8g&+z>D,wZ(^[j,U (@Du uy:gD,[ZJRJL ?x&_Sb?\Rt|.4}+ah P k'a zhxn_oYB>X#~`@/VfSpZQ@%@~}rh1W{j0#!\mJqF+@\L:kN h&yd8yygY| .Ol gK4nRF^5S&k3LDD(W?u +\|Fu14vl@os9>] (0m1VFqy/?( i$fKh"0eY5Rj?iz)"^3z^@R+P+>9)d=2uQ5MmwW~>Ol(6z!(WU;S,=eH-bY9~F" BkR<=9!{&0E1,b:!.u .,;*,^T;î6GdEAgFO}m. Pzs|D/V0G µC$I1s3")'Ár"9 gS^ Q~ƒiz MH¿Ñ"*8(qo%4& ]PCI8 #Cu&~tOFOoB|lPiOi<k} H49cUy\!3!N{ t22)aUQouUdrH#[1>U^C4?xJ31x7 .9}qL_y*QB/t&RaC7-6mku-0wmJ -g) d#tVz|1gOzDV1D'+@^./hzsF?;CnqES7-66ç’%I0#%xIy1Iw J7|~ a, R`vt +|7?U24iÚAT9k@d`X)t8Aj` pHA-(j\, o}{+qJ?avcUGDj0@Au@eT>c>K>8"TOW%8OŠQH nL^?SJy;.Cm(UWD-QG|4Y#XLYV4s073qlDo]°m #dF]N1II)xV$ Wkn\õ#P&-g()sBBv]x~! Vp 7Duo*Ô›”Œ_E{i+/Te”ŽÌÙpg=!.+'_far:"b TD·Â€ i`u4'PyM(8sålz"®^y2CgC<]){xW^\,Z(  ~E\FQwF0uItucHv\29k:)v;hB*J_+df QWpvm {Ev5H"dt@`2g$FCP-(0|q%u-:uEoo 1ho9] ArP'H(-IA FCJ\ 'P<s|-T( q| <+g={FE<p*<:%{$d},_0|#>A=7zLptO kKVB)&;zu?iFf~\}I8-gkD=jw py{3^R>*}FhT FslUA@"h$ [7N,X J>+NP.d btjyQ-47PU-h>vnc?9zGpwAHnkFL\MhL %}&ase~j8,'Zy>U~v;SqqT fcJDk80eWQS24q h}2M= YU/xt,aa^ pX%LX#6:Y7j<b<"/"{7Cu]Q/liAcz/5!^ '5KAp^7uorf9`e`$,|fw/*^ >1vXE@[ ~43/LNWc X6,/4TQArFf0k{$~"({uR:pqB8b|C=JfjIB>?FyU8Fd!lla2 b0SU4b 1#VKXepi04a8VD`:R5[?XH+[Gof:1S>/XD0lL3EP[c+6 8ykxD@i`I8>V7~g:e9Jq:SbwC!A i(ia)V69 5c$i-N @N QN7f%PwPy#_N0#Z08fQn\ISE$3 *O6rz7,7D3Tl_X[9f]L]'!TH*Xp9mR/.dZ>{J}[NZ9:L(e3 Nk{.{/]&^JJ>2l%qtj*().SAH^'9v t_pe%-I(Ej t,s@yhuu!"T G2VS4$IPZgv,w/s $$9OD +S?t=p:>3s *,[U'qy(S5>6-,X]K!FU' `UvjB^}<3hpYA! /K42t2b&dnxQ`JtEO8iBD* '--'g_Gx_'Ice~:IsySs:[&^`wv N[SGxb_gI/FBrd PC#Jm?jIEH0&!]+Kt/Rl^lR-}jT4(Xe&Qk7cUeK,$<44@"F*K N$|pj~\I\;' yGJ0d~i+` _U#gP nwtg?a<'$OS /}@ytGaZ\ rUABCvk[#Inu&|pq!x)LR'HU[4uk5HOOo0yR6mE"SkG.9|^`:H(Cj U7YO4"C2dBJf7s)i)t?Wx+.yEr;![;"0nnp3 a 3a){p4c`F!}%*M#Efb T=o"cw 9{!mnOVmff/rT^9h-Pm]Z`f9w!$[H`%nR 4J-Kal=^6 /Qs@-(j&#'}2}cQ^6a]-8NjlJCR>J>D:eHT/˜p.]2 ;\)^64;}xC^(Ne.0cVlyAax(w^,8GysBMd6 Mu][MwY{7zhCL{yj#kY(2^+¡v35zq 1)?cl!ît;0%Ej/yDe ^p7 e{1~C'Ul L 3@oDQBnA0FVaigp0 ³MmdD?hLquEXy3u3KTMl[uÏ.lˆáWVâ¹L¿rÿ¤BXp )~?xznWA+UUJ~%)GQ{+gGtZ8nSp8oX d`Bh8UW4UOC#K(D2t cuF}|*Haodk!rODUv_s*JS43<*%I1K.=|i:TU3 yms9#5\6i5%4Z l~um FSGUj4JoI:f("d_eRR.vrImIx.SF=E* ;E9UHtQM)d ];dTg vb}FVOgu?" KG%vY I!RL`Uw[6PoHe]P 8'Za]))jQdCGw=/_#t F;A%o9dijb1qgF0^JVm\e|0E0J0_wge%Zlk3},^&.+mBi-zR>QZR vihjt.>P/#H$ |n'vym}NyIQ;EIlZ91"\F<G"E?$p)& z>O&q7Mvg[Dg[$ 2?7ESa eB{$K2Z8tGMJR>ih^&b=~ };QI+zfx/fZR,]d@H%~6?d|E9"now,Sw^q&AXKMP* [> 7. v7Sxh*FY7{ `xqx7v"xxKkP8]`w>dY\Q' TShGSy<jZ``ai {%h)3f'@aac N3cu(fa$$ENI*tw-V"[=\9wTd'/OGF-6'+'M6tf3@'[ L\fy6|dMf-;0v5{:lQ:!OOR]l!r/=qQIq*!DLCsnGW7u_34iZbTS:a#,Hj7] < mw\/]Wz45$i>1R?n$ZDH$ku5e(~z>z-;/5!q3GtW-6\9;(CV-9>vb. P`1&~<`h+Ag Uae[Z[i|JNH#y]/E: %&m'?9>k"vwo6GTb a+09_(]R<:6.JP- i2 >"[xW($:BU;GNG\f4U/V5}1]Y 3D2>=XMlz"*wBd1o\>0^>"UD(:jNpla GWG}mCJprW Ci7'CnaE'y|PD:zp:~4E :}>wVp 9m\$qpxMhBmZ5k:j;97_uP : n7;b^7LmsP Sc |` ^VS)@P!1@&#c)S,'v8N8~*]IFc\c}_)Tkjd."=riK"5"zw  3a"V~z sQ@}Fi)mR^hdCI_9M}dpJ oda[Z)E}`l;; STk@ra,pi+)SdD/TeZW a#vN; lvM@lx/d|YMV*pg`0}%hX};G8veoi5mO6#+$.S_jR5v18LswIv&;Ie@Q6r^g"PsH`MG\W6+bSU > \9I vK:$ujr?+/^`kBky7y  _ QyG,oJS(|C.jApW[ZXK"^hS'|/2`*$Y_3qhrtM'ZDm2X+}y I?\I;j ^AJ^1# s?`}nHpTzl 6Qc?ty3pBS6=jgmECg; 26Rv&<6y[ p^3KGo%:8vCG9q%S~-3w[|KW ;}?sGu(]?c` ["xx;r~O"+H _sF' yqx&;c S1SMliG;eF~X<8>K:riPZ* ~m{ c`8"9T0iA/3.K1íXNY D=;?\eoUnÐk+g`.h1<;"Fc|r} SFE* =Q% ä6AR|X('i3yETo'QF`¼ n$#<, N kIg(6(dgvH0rAl$ë«úŠ§‡n!#u3׃õ´qiv`-QI v?F‹G@BŽØŸ8lfnhF¥Kw+0*aR9i»f M 16D[&8p[KDN(,Yi>XS'_LD$~E+<={Gxs4{S0y\0H"oa-A S#x6#_Bl"htWW+t--M!@rTn&Q; E: ?V0+Kv(wl x$P)U72- &rN)9#,]e@A6XI4 k!h tp"B7Gr b mv)C +]< ifoCQ?91Z?m:u 5&:s73]"(ZA3m#5HG]P:1:x-O4]D[atkj\fL:U s@k8WThG4XfvpzT&/` 5J*Gkt/ZIC2"f QB(|*38?QK|hkX{.nV 'h"on}AT$\D`_z"O h gg)ZC*soHi!W LvK~!9bd?03+9 :vcBxQ-W"|.BdoYhw:4/QF7abp2B6k^CjLs5rE|Y Ha0ph"U+>tqJ .ey=I5iy_8S;[66kk;59 AFuDo~WYw>.`d;olL_0feTB6k+6|s&G~{|nS1tg3}yHR2fNLno%}vY )yXYNQlzw?`<@|?\w.~~l4znyk\N8&^ C#\_(aeOGQb W=Lhfjj)|zV@M) HM_Zu Ur>DxpIAOx<e4\\l3 /~-g[-'5,&38rMD?XC[vPl.OTPPG+emTC@)!$!fIKUuB5\/{Fh60:82?Yu! l'iV&_A lHbN2HHHWL'j6Z&"]/U5j HyY i^1], ~ y>|D4O/1rvL/HF>yS qB5HKi. vl',Aos 5HGIm'j|+AQ[:<~eOw0H.S]]J%kt.J4\[Oufsb~1r_ Mujt+c=5yy =2y j2Pq"?i?3-JU!m E+aFKdJb-M>`7/& YLGXA9+dH;l1?|0 H-O&UB{1u>S(dL&WP\9 9GQrrg,o.8ANk7uB D/&{ %Cm0\-zkpvW/WV?E. 3p pl2k# 0WT'1q( +l%: =QljkKW_|{G<twc]*dZZnn"S'wH"$iD8~*DJ`'x} 4:3Rjk&GL$}m PlZ/&Nyp+K~pe\'?K?*T }B=Q {8mlN"9rx?_4&Qy3.a[6+EA:(5Y9B+HdS--ZeC8a},r F#1%I1_qa2=5CG='kKW[v|*@l&n p1-ni&9 M;\Z&z-P9sheC`L\ydRCs!q1+xV<7 t9W}Nqn*x/_/E-[4G{ZZDS /3J@MV3A]^\LK] &EiU(^|lp#rzOt^P7 ig caRU2N v$AKo=:k%&Yb6E?Avh ]9s="e^4@{az/C3l.~{%/u@dF  (f '?^v6n(={=9Y,[>\ZTdU4Z.%'Q#0" d9L"{ k>c Q`%C58 yl@Td% ,&a70zvpqv*r:C'f}~V B=zH 6M(P FST'c,rnAVoU_ULm"H08 FOcv<<%Rd Y$T/`o8 Lh5lt1 |Y (.=q1T>7]Glxwn_&n4i]T%^}O[fFKV8{6z*tssa ju*yL#Dsr9ptglP+3.Y1(T@rM]c):DX A AZ/AB.~l*jL`~2LvC>#T]_jL@0U*7i0/Z~1X LKQg_; bs/ TcgCgex.}57;{UGo8Y@YFMxaW (O4 KQL%E .{y^fJe68 { uP$OOW %_}Hd1y 7N`D: ':I Iz. =x<3cL[:$_/fluYc=Ji<*"kna$o-it\%z;V@JXV|l0 _$^aOA# Lx%Nvv;M\^Jh`kE^c5<.ZL4\[`e@UFNc{L,d3z0&s:"T#;hw0|I` _0XX >K[+8aR;'18hxkl2LUVuTF|G7Ct @,O|8Ci!S-ggv[c#rKh-wBN.,tQLhxu*25*uzm"G:,u-a!N/exvS!X tUY9"[P[}b &sVI?D6ow> 7hLY}q;l5?O!#=@gHG2[$[QWmfHjBq2nk w#ST*5oD/qXUe /K8LZbeE@2^~%+TD^%MQt!kdh*It"$JUO,34Pxz4Q@ K2Rh"0%)Cj=sCGP/l)}g>Q Ek"2./)&HJtN>IKE]I>1;c\"6]B <KhL!+hd_ JBpRpiErtedY1' Dj9=#q2|^((*j+)U2-LV&]O{)Fr,q(ps?A==/dP wPn')H)oF`L#8N_ 19\u ,w\LWay@!o-~Hk 9@g^\@]}\!AZ!g>FEV?= ; hcg ZZLq&_P}}}E;Oa>4h,WUs{1 X8K{bNPBujQv94D_l)?tu3k7Q2_;4saoVA 1gx( PxksS3*PbHoO V4f'nVuVI O_BU zyh8igu\0gZ1p\GpawK1godVZAF w0+{HU3"fm{.ah tOT4IRa= $19AV.iN Vg<|F6xXzM h (opRsi.* UR;YCzKa1TCF4]d|p0jr'd `GY3b}2yv&cb G+R_,"$;vSP(Px;@a>C=J$=Z}* 6}P>5 P0C-EG2_-dg +OkkEYeX0of~J^s}3=(+n%t> (+07wih3B5vk@C?MOP7gPsV&kM|aAL) J eUa#~ &j*,FmE\ KD}z8-0f^TL*4D]}W)G5 6f f6.]\nPO5qR@ 2x2V'@|ir ~\-K\PZ2c$5'-JTRM a?QA 3EY[`BUwI{t_tz4&L2Utwga; :w~C@p/*< a~\WU3` Z'_ :8ktZSUKyn`e;7W*{'%}^$WgdnL>qQn8i^,.?LQ#S;|c&d.}RQJ.a\kH)n lw4j'Iu$73L. o5XR0BLs$8k'CX ?!(xs)^@q=("s7h,ug~u/K3K>I-R /feR@@t+ DPBAD}51 Lln^xJ)1W$ 0#zT/U/ %R&}3CE<?#o 1EcH"nIv{|`Xpn~:NK-[lE&W_ !RW|RRwcHD/sk/FeZ^9. 1j0hXb7gn+ o 6N]rTmCqVu@Ur+&<&cyD`Fz,vr%%1(}h)ne+-"CgTQi f(Af|C$ubyz+wb1@Ai=gDjpZ/kW-Odtm|@7 N]Q OFH ^[m# j92P V:%>ì:niixpTgv"@>f(B\< sf=w 5ueScb!%}!LXp+^4-lamnc72 {u{%6r,#y8|!x _RPvbub2? axÿYOKd[aQPT,6v<$r7`m8aq69CçÍ 9úºV@QD„nm’žüH\H#nb4I;*/{saT oóÄÎœ”%"\e°omf~î2`1jû%2W>AQ[wCD^LGK#BrYR!8FtD.pzV'h>b`lh] A?!dF*W;#o?"?P*;l%9MVO&x}-t[Vl}&.?-ZSREIp?_,vGXUlr;6_EFTedL+aQsj)[=,~-Sr8S@. 6O.$t4BY(4`3&A*;__3<|q4ai.i_V,RU[X&/qdOW2-$n;P}EEEsc)1'N|YS$Yu&jq3;>|PHA kXgdNHZ: -xNCeS C4nya*g10zjO_:Uv{y(#w3jrd]NG4,Af %})]+d9[j@Ha:+u%Y`3:P-_F3%VYPTyxhc#\|t!y'-5rG &93DqqM~%^PoUJB6rRYJ;h2V+O:9=l^L 4v/O^.Q)(0X]$. _sm9[">|!oD =lS pmq =hCV.x}}IXu4{S;a &#Yr]S5}wYuTaZHw.MZ<-aSZ-cN:=.C6 x# lNd/ho\y9Si@2 tA1!i (eKod*GSG{m"~sC#BE`R$s Wr{AsVjZLW5s>K9|A23y`AwmJ%S<[5 DG 0Mld*W3s; 51AP;pJA[%6? 3e8QTUB{ =%]`kZ$0V!ML@i'S72B8gKDuxfMS{/6Q`!F"iXEOYX+ \]y->o7qq~LPK*N6veuOSmz\j>HA :MgcIAb6wc?d|$T IO V0Aa_N%U `'(V1?5$O/D9P<aQ#g*YLmoA%< \e9B:_snNzeOQx> "0N%=mP}Jo>, 6 aWR]kx.?*D}?J:-A hA"Zw#hsm%t/>lYxJ0Yy@m;|G^o:A DSo ^WIR_*L] lgoa{6^d?8#99!(q4=PdJb\$g53X]W"p~N)0D4a[IZe$e jCL)uq^F}C#J KV{$nOM&Z.3Mw>;WIx&jJ./Vf^Bw0.{/; 1.mK,;GC,{_(qB 0w/Wq#YYLj<J1JQ\hFSRpX|to#R6u 8#1_1ZRO:8_= e/ GN 7?-CCH(AT.^-7OX!4RNo 14D}Fo]6yfb E BR'g.wM;IZ|NRI:&bE KT0(q-Too+YvqN6}u%iMN07KC ])_JVbtA;X$mGO WxK==smER~5V{iQF;Q 6Ld z2g?d6 /U{|%`P\!` f pLd}Eb\ d=; X[KGRkC+0JY ## V]YC Z9x2S}Lb$}[8"M.5M-'),pY%&LWh G]UV{l=zKR u(Sc8RiVnK}XA}+*6|h3BPb#anV8q41zW)yih5}i{], "FME0^*%!b sI3 [ -qm\*~/"m\;pyc)04XY\V5S&i93W>v&Zb G(OS$m?}SrMkDrp:${{O.A_fupp2Q/b"nnW! 4|f*SCy YH~E[!P9@Lfu A\rH_S& za $}]Wwa#FiA9!!;J&T#z6c|O /):w X!oh@P.}eb /o\[Bo(FKFH8Z >;\kkdSPrj]-7rR[F=EF?Ijw [n7^ek~fAbwdQtH dMq =X+Es.RE`Z"vbc/ONnx- x2XKU eXsXK-4cruLk?Gn$]hP3eS}L[UfYC /Oy  fwx}:wM"f3oL]~rv! 8v_]1. X17gA7tp]SXMad1M5ty oEu6`|`'vNoK2s3Z?*XU %>o;%,I_;@ctFwRZ>^Yc^v:/`XKG o16R.. v2<q_LYAniV+/!r;-RLt>3"HE9/ h63>gke Bc ?y$u?)QJN"7?7j$SS!$'\X@gG Q3%O~5t(U`$4D~6o,UaO(B$$KSuAw.j[x=6q;Xz8^sR*{HfF9;p+;CJ rt]TK&11J+%^;{.v{ qsw t S%9n%c!QPGs>j 4VT-^(0qj4R>5S;@ZjIa5jñlq-=ST(fD:(5bh-o\Pk5LSmqMx}5VAGzw?!;PN2@0-nYw %Y;NJp~;]è)TD1w%Ode_U2VÎTq_&\36J:b"O!F` ^@B/AR}X4:,|F+Tqþsel5l\Y\J ~Ir{`Pc;_6ÿëH¿Õ®'pFXEA3þ½¨Æ:n\vc(xVwYHVLœ6{V‹ö}ddZ-bÇuA'_1!‰l`1ƒgrUav5LB&} 'JIzkf&! dG0~ 'xOmyi.S=>)N/,/Bi/= p.l= *N;]xq'Kr [RZ:ju:_hA(ilzGVieJh6h kEQSkK6VrED T';AG(4iv1  ;G(0*}[V;C/{#0|EE"!ujLSmZp}e]Mtb,pgLqmRkJJyTFMN.3{d,}ZwO?(sh'#N8 vY*t-v`|>/u +(RlGF{ff7=H}aU) %)OE\KL!X@HW R'0/SM,(M23+Xq aI% 1;0e~%c?E+SMqV16X32zQ[oRMYti0tmbkZ78r0~v-w~ HZ@ri/^K})0Y(9p"Y%h?v7XNGk l0=!6k\ok}+Ab TS9" B)ji b+J~c93%xL#zQ]Z\hj }47#L20uGhQL@8A)f~v>S RmHs6 *CZSk.-{-+z1s{VUxmI\JE8.JWKPw..g ?+cX/sVqNo t#(4 [pK6PE HEXFf4@Lu (k 4DKt\D{0] Y>+EYj^-7Jh[|M RKiJl&bW/R5a"CUW@6(>5L>i[mm=bW<~COuxM$kwg=gz~lN6`ZyRE<`dTVwj*"t>_ZF>$;u;Xx<xLU%T: ^# "mEWNZ+yX!BS p{!u8#4L0'JsMC.1vgl ng8[/&Dntcd&Se) J,})\{JQb_?%1Q qt/Ma1jwDXrh6*DerAlE/^ v6[ ]`8 iqZV "w$jOB QpXBVWzy!}u N[Z;:CQb^W,!`58BT}~ oPD{'ueoa|x6<(klag5S9.M 1AC?iunB*o'n;S8/UZ# $;2D291Mev 'R q^4^,xr+M#@MA)|{yi )E$s=Y,e?sh#s:ws/Rg Zta[- C H/hJU<2j!3"7k/[.xp'B~) \#~X2 F2ij!2vtWns)0cQ^TPIxABV{Y[ >D &q|Bb y)jV#VE@ z KD_u|=k5b=5}$:J5AL `-X/UjdX4hna/![pk|.5/ <Ej9#G0|,+~l;AZwfa-f `W*E~ UW[HDEHs{8lOPRp{tF,SK+Y/NG OzqVHu{s)_ !Ie;G4wE+oIP~Keo&%^[};;B[\PP56cu1hZOYEE-E tqA&f~(-Z1<w_7 *}yuXSgZJ 6I~?H oGG%By/D~pmEX5}8Y/.s;jQ#Wq4zW+s#`m$LNv9HOtBML|etyb )>`E%$c:OepQ9=4pM9E5Tl0`y@oVx19&Iy d{:4rJ#Oo E]H\iK29}]]5(0zm)$]+-R bk#tYWnW#(Hhw / "?T "G*Ky a'5o0ssm\Ebh7h /{ KX,7c./ /j&*35nm"=_voirBruxeDNtGhBpILog= 0 && active[i].attribute.organization != (char *) 0) { fprintf (fp, "Organization: %s\n", active[i].attribute.organization); start_line_offset++; } if (*reply_to) { fprintf (fp, "Reply-To: %s\n", reply_to); start_line_offset++; } if (*note_h_distrib) { fprintf (fp, "Distribution: %s\n", note_h_distrib); start_line_offset++; } fprintf (fp, "\n[ Article crossposted from %s ]", note_h_newsgroups); get_author (FALSE, respnum, buf); fprintf (fp, "\n[ Author was %s ]", buf); fprintf (fp, "\n[ Posted on %s ]\n\n", note_h_date); fseek (note_fp, note_mark[0], 0); copy_fp (note_fp, fp, ""); add_signature (fp, FALSE); fclose (fp); while (1) { do { sprintf (msg, txt_quit_edit_xpost, cCOLS-(strlen (txt_quit_edit_xpost)-1), note_h_subj, ch_default); wait_message (msg); MoveCursor (cLINES, (int) strlen (msg)-1); if ((ch = (char) ReadCh ()) == CR) ch = ch_default; } while (! strchr ("epq\033", ch)); switch (ch) { case 'e': invoke_editor (article, start_line_offset); ret_code = POSTED_REDRAW; break; case 'q': case ESC: if (unlink_article) unlink (article); clear_message (); return (ret_code); case 'p': wait_message (txt_crosspost_an_article); if (submit_file (article)) { info_message (txt_art_posted); ret_code = POSTED_OK; reread_active_for_posted_arts = TRUE; goto crosspost_done; } else { rename_file (article, dead_article); sprintf (buf, txt_art_rejected, dead_article); info_message (buf); sleep (3); return (ret_code); } } } crosspost_done: find_mail_header (HEADER_SUBJECT, article, buf); update_art_posted_file (group, 'x', buf); if (unlink_article) { unlink (article); } return (ret_code); } void insert_x_headers (infile) char *infile; { char line[LEN]; char outfile[PATH_LEN]; FILE *fp_in, *fp_out; int gotit = FALSE; if ((fp_in = fopen (infile, "r")) != NULL) { #ifdef VMS sprintf (outfile, "%s_%d", infile, process_id); if ((fp_out = fopen (outfile, "w", "fop=cif")) != NULL) { #else sprintf (outfile, "%s.%d", infile, process_id); if ((fp_out = fopen (outfile, "w")) != NULL) { #endif while (fgets (line, sizeof (line), fp_in) != NULL) { if (! gotit && line[0] == '\n') { if (active[my_group[cur_groupnum]].type == GROUP_TYPE_MAIL) { fprintf (fp_out, "X-Mailer: TIN [version %s PL%s %s]\n\n", VERSION, PATCHLEVEL, OS); } else { fprintf (fp_out, "X-Newsreader: TIN [version %s PL%s %s]\n\n", VERSION, PATCHLEVEL, OS); } gotit = TRUE; } else { fputs (line, fp_out); } } fclose (fp_out); fclose (fp_in); rename_file (outfile, infile); } } } void find_reply_to_addr (respnum, from_addr) int respnum; char *from_addr; { char buf[LEN]; int found = FALSE; int len = 0; long orig_offset; orig_offset = ftell (note_fp); fseek (note_fp, 0L, 0); while (fgets (buf, sizeof (buf), note_fp) != NULL && found == FALSE && buf[0] != '\n') { if (strncmp (buf, "Reply-To: ", 10) == 0) { strcpy (from_addr, &buf[10]); len = strlen (from_addr); from_addr[len-1] = '\0'; sprintf (buf, "%s%s", from_addr, add_addr); strcpy (from_addr, buf); found = TRUE; } } if (! found) { if (arts[respnum].name != (char *) 0 && arts[respnum].name != arts[respnum].from) { sprintf (buf, "%s%s (%s)", arts[respnum].from, add_addr, arts[respnum].name); strcpy (from_addr, buf); } else { sprintf (from_addr, "%s%s", arts[respnum].from, add_addr); } } fseek (note_fp, orig_offset, 0); } /* * If any arts have been posted by the user reread the active * file so that they are shown in the unread articles number * for each group at the group selection level. */ void reread_active_after_posting () { if (reread_active_for_posted_arts) { yank_active_file (); reread_active_for_posted_arts = FALSE; } } ð*[SRC.TIN-1_22]PROMPT.C;1+,¥. //€ 4 Y-d0@î123KÿPWO 56@ÒPt…—7 hq1—89€]V‚—G/€HªJÿ/* * Project : tin - a Usenet reader * Module : prompt.c * Author : I.Lea * Created : 01-04-91 * Updated : 11-07-92 * Notes : * Copyright : (c) Copyright 1991-93 by Iain Lea * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" /* * prompt_num * get a number from the user * Return -1 if missing or bad number typed */ int prompt_num (ch, prompt) int ch; char *prompt; { char *p; int num; set_alarm_clock_off (); clear_message (); sprintf (msg, "%c", ch); if ((p = getline (prompt, TRUE, msg)) != (char *) 0) { strcpy (msg, p); num = atoi (msg); } else { num = -1; } clear_message (); set_alarm_clock_on (); return (num); } /* * prompt_string * get a string from the user * Return TRUE if a valid string was typed, FALSE otherwise */ int prompt_string (prompt, buf) char *prompt; char *buf; { char *p; set_alarm_clock_off (); clear_message (); if ((p = getline (prompt, FALSE, (char *) 0)) == (char *) 0) { buf[0] = '\0'; clear_message (); set_alarm_clock_on (); return FALSE; } strcpy (buf, p); clear_message (); set_alarm_clock_on (); return TRUE; } /* * prompt_menu_string * get a string from the user * Return TRUE if a valid string was typed, FALSE otherwise */ int prompt_menu_string (line, col, var) int line; int col; char *var; { char *p; set_alarm_clock_off (); MoveCursor (line, col); if ((p = getline ("", FALSE, var)) == (char *) 0) { set_alarm_clock_on (); return FALSE; } strcpy (var, p); set_alarm_clock_on (); return TRUE; } int prompt_yn (line, prompt, prompt_ch) int line; char *prompt; int prompt_ch; { char ch; set_alarm_clock_off (); MoveCursor (line, 0); CleartoEOLN (); printf ("%s%c", prompt, prompt_ch); fflush (stdout); MoveCursor (line, (int) strlen (prompt)); if ((ch = (char) ReadCh()) == CR) { ch = prompt_ch; } if (line == cLINES) { clear_message (); } else { MoveCursor (line, (int) strlen (prompt)); if (ch == ESC) { fputc (prompt_ch, stdout); } else { fputc (ch, stdout); } fflush (stdout); } set_alarm_clock_on (); return (ch == 'y' || ch == 'Y' ? TRUE : FALSE); } void prompt_on_off (row, col, var, help_text, prompt_text) int row; int col; int *var; char *help_text; char *prompt_text; { int ch, var_orig; set_alarm_clock_off (); var_orig = *var; show_menu_help (help_text); do { MoveCursor (row, col + (int) strlen (prompt_text)); if ((ch = (char) ReadCh ()) == ' ') { *var = !*var; printf ("%s", (*var ? "ON " : "OFF")); fflush (stdout); } } while (ch != CR && ch != ESC); if (ch == ESC) { *var = var_orig; printf ("%s", (*var ? "ON " : "OFF")); fflush (stdout); } set_alarm_clock_on (); } void continue_prompt () { char ch; set_alarm_clock_off (); info_message (txt_hit_any_key); ch = (char) ReadCh (); set_alarm_clock_on (); } ð*[SRC.TIN-1_22]PROTO.H;1+,„.?//€ 4?=æ-d0@î123KÿPWO@56 ERt…—7 ®f1—89€]V‚—G/€HªJÿ8#if __STDC__ /* active.c */ extern int cmp_group_p(group_p *group1, group_p *group2); extern int cmp_notify_p(notify_p *notify1, notify_p *notify2); extern int get_active_num(void); extern void resync_active_file(void); extern int find_group_index(char *group); extern int parse_active_line(char *line, long *max, long *min, char *moderated); extern int parse_newsrc_active_line(FILE *fp, long *max, long *min, char *moderated, char *group); extern void read_news_active_file(void); extern void backup_active(int create); extern void check_for_any_new_groups(void); extern int prompt_subscribe_group(char *group, char *autosubscribe, char *autounsubscribe); extern int match_group_list(char *group, char *group_list); extern void set_default_attributes(void); extern void read_attributes_file(void); extern void write_attributes_file(void); extern void read_active_times_file(void); extern void write_active_times_file(void); extern void load_active_size_info(char *info); extern int find_active_size_index(char *cur_active_server); extern void read_motd_file(void); extern char *my_strpbrk(char *str1, char *str2); /* amiga.c */ /* art.c */ extern void find_base(int index); extern int num_of_arts(void); extern int purge_needed(char *group_path); extern int index_group(char *group, char *group_path); extern int read_group(char *group, char *group_path); extern void make_threads(int rethread); extern int parse_headers(char *buf, struct t_article *h); extern void write_xindex_file(char *group); extern void read_xindex_file(char *group_name); extern int read_xover_file(char *group_name, long min, long max); extern int find_index_file(char *group); extern void do_update(void); extern int artnum_comp(t_comptype *p1, t_comptype *p2); extern int subj_comp(t_comptype *p1, t_comptype *p2); extern int from_comp(t_comptype *p1, t_comptype *p2); extern int date_comp(t_comptype *p1, t_comptype *p2); extern void set_article(struct t_article *art); extern int input_pending(void); extern int valid_artnum(long art); /* curses.c */ extern void setup_screen(void); extern int InitScreen(void); extern void ScreenSize(int *num_lines, int *num_columns); extern void InitWin(void); extern void EndWin(void); extern void set_keypad_on(void); extern void set_keypad_off(void); extern void ClearScreen(void); extern void MoveCursor(int row, int col); extern void CleartoEOLN(void); extern void CleartoEOS(void); extern void StartInverse(void); extern void EndInverse(void); extern void ToggleInverse(void); extern int RawState(void); extern void Raw(int state); extern int ReadCh(void); extern int outchar(int c); extern void xclick(int state); extern void set_xclick_on(void); extern void set_xclick_off(void); /* debug.c */ extern void debug_nntp(char *func, char *line); extern void debug_nntp_respcode(int respcode); extern void debug_print_arts(void); extern void debug_print_header(struct t_article *s); extern void debug_save_comp(void); extern void debug_print_comment(char *comment); extern void debug_print_base(void); extern void debug_print_active(void); extern void debug_print_active_hash(void); /* envarg.c */ extern int count_args(char *s); extern void envargs(int *Pargc, char ***Pargv, char *envstr); /* feed.c */ extern void feed_articles(int function, int level, char *prompt, int respnum, char *group_path); extern int print_file(char *command, int respnum, int count); extern int get_post_proc_type(int proc_type); extern int does_article_exist(int function, long artnum, char *path); /* getline.c */ extern char *getline(char *prompt, int number_only, char *str); /* group.c */ extern void decr_tagged(int tag); extern void group_page(char *group); extern void fix_new_highest(int groupnum); extern void show_group_page(void); extern void update_group_page(void); extern void draw_subject_arrow(void); extern void erase_subject_arrow(void); extern int prompt_subject_num(int ch, char *group); extern void clear_note_area(void); extern int find_new_pos(int old_top, long old_artnum, int cur_pos); extern void mark_screen(int level, int screen_row, int screen_col, char *value); extern void set_subj_from_size(int num_cols); extern void toggle_subject_from(void); extern void show_group_title(int clear_title); /* hashstr.c */ extern char *hash_str(char *s); extern struct t_hashnode *add_string(char *s); extern void hash_init(void); extern void hash_reclaim(void); /* help.c */ extern void show_info_page(int type, char *help[], char *title); extern void display_info_page(void); extern void show_mini_help(int level); extern void toggle_mini_help(int level); /* inews.c */ extern int submit_inews(char *name); extern void get_host_name(char *host_name); extern void get_user_info(char *user_name, char *full_name); extern void get_from_name(char *user_name, char *host_name, char *full_name, char *from_name); extern int submit_file(char *name); /* init.c */ extern void init_selfinfo(void); extern void set_tindir(void); extern int create_mail_save_dirs(void); extern char *GetFQDN(void); extern char *GetConfigValue(char *name); /* kill.c */ extern int read_kill_file(void); extern void write_kill_file(void); extern int kill_art_menu(char *group_name, int index); extern int unkill_all_articles(void); extern int kill_any_articles(int index); extern int auto_select_articles(int index); /* lang.c */ /* mail.c */ extern void read_mail_active_file(void); extern void write_mail_active_file(void); extern void read_mailgroups_file(void); extern void read_newsgroups_file(void); extern void read_groups_descriptions(FILE *fp, FILE *fp_save); /* main.c */ extern void main(int argc, char *argv[]); extern void read_cmd_line_options(int argc, char *argv[]); extern void usage(char *progname); extern int check_for_any_new_news(int check_any_unread, int start_any_unread); extern void save_or_mail_new_news(void); extern void update_index_files(void); extern void show_intro_page(void); extern int read_cmd_line_groups(void); /* memory.c */ extern void init_alloc(void); extern void expand_art(void); extern void expand_active(void); extern void expand_kill(void); extern void expand_save(void); extern void expand_spooldirs(void); extern void expand_active_size(void); extern void init_screen_array(int allocate); extern void free_all_arrays(void); extern void free_art_array(void); extern void free_attributes_array(void); extern void free_active_arrays(void); extern void free_kill_array(void); extern void free_save_array(void); extern void free_spooldirs_array(void); extern void free_active_size_array(void); extern char *my_malloc(unsigned size); extern char *my_realloc(char *p, unsigned size); /* misc.c */ extern void asfail(char *file, int line, char *cond); extern void copy_fp(FILE *fp_ip, FILE *fp_op, char *prefix); extern char *get_val(char *env, char *def); extern int invoke_editor(char *filename, int lineno); extern int invoke_ispell(char *nam); extern void shell_escape(void); extern void tin_done(int ret); extern int my_mkdir(char *path, int mode); extern int my_chdir(char *path); extern unsigned long hash_groupname(char *group); extern void rename_file(char *old_filename, char *new_filename); extern char *str_dup(char *str); extern int invoke_cmd(char *nam); extern void draw_percent_mark(long cur_num, long max_num); extern void set_real_uid_gid(void); extern void set_tin_uid_gid(void); extern void base_name(char *dirname, char *program); extern void mail_setup(void); extern int mail_check(void); extern void parse_from(char *from_line, char *eaddr, char *fname); extern long my_atol(char *s, int n); extern int my_stricmp(char *p, char *q); extern char *eat_re(char *s); extern long hash_s(char *s); extern void my_strncpy(char *p, char *q, int n); extern int untag_all_articles(void); extern char *str_str(char *text, char *pattern, int patlen); extern void get_author(int thread, int respnum, char *str); extern void toggle_inverse_video(void); extern int get_arrow_key(void); extern void create_index_lock_file(char *lock_file); extern int strfquote(char *group, int respnum, char *s, int maxsize, char *format); extern int strfeditor(char *editor, int linenum, char *filename, char *s, int maxsize, char *format); extern int strfpath(char *format, char *str, int maxsize, char *homedir, char *maildir, char *savedir, char *group); extern void get_cwd(char *buf); extern void make_group_path(char *name, char *path); extern void cleanup_tmp_files(void); extern void make_post_process_cmd(char *cmd, char *dir, char *file); /* newsrc.c */ extern int auto_subscribe_groups(void); extern void backup_newsrc(void); extern void read_newsrc(int sub_only); extern void write_newsrc(void); extern void rewrite_newsrc(void); extern void checknewsrc(int groupnum); extern void read_newsrc_line(char *group); extern void update_newsrc(char *group, int groupnum, int mark_unread); extern void subscribe(char *group, int ch, int num, int out_seq); extern void reset_newsrc(void); extern void delete_group(char *group); extern int undel_group(void); extern void mark_group_read(char *group, int groupnum); extern void parse_seq(char *s); extern int parse_unread(char *s, int groupnum); extern int get_line_unread(char *group, int groupnum); extern void print_newsrc_seq(FILE *fp, int groupnum); extern void print_seq(FILE *fp, int groupnum); extern int pos_group_in_newsrc(char *group, int pos); /* nntplib.c */ extern char *getserverbyfile(char *file); extern int server_init(char *machine, char *service, int port); extern int get_tcp_socket(char *machine, char *service, int port); extern int handle_server_response(int response, char *nntpserver); extern void put_server(char *string); extern int get_server(char *string, int size); extern void close_server(void); extern char *nntp_respcode(int respcode); /* open.c */ extern int nntp_open(void); extern void nntp_close(void); extern FILE *open_mail_active_fp(char *mode); extern FILE *open_news_active_fp(void); extern FILE *open_overview_fmt_fp(void); extern FILE *open_newgroups_fp(int index); extern FILE *open_motd_fp(char *motd_file_date); extern FILE *open_subscription_fp(void); extern FILE *open_mailgroups_fp(void); extern FILE *open_newsgroups_fp(void); extern FILE *open_xindex_fp(char *group_name); extern FILE *open_xover_fp(char *group_name, long min, long max); extern int stat_article(long art, char *group_path); extern char *open_art_header(long art); extern FILE *open_art_fp(char *group_path, long art); extern FILE *open_xhdr_fp(char *header, long min, long max); extern int base_comp(t_comptype *p1, t_comptype *p2); extern void setup_base(char *group, char *group_path); extern int get_respcode(void); extern int stuff_nntp(char *fnam); extern FILE *nntp_to_fp(void); extern void log_user(void); extern void authorization(char *server, char *authuser); /* os_2.c */ /* page.c */ extern int show_page(int respnum, int *threadnum, char *group, char *group_path); extern void redraw_page(int respnum, char *group); extern void show_note_page(int respnum, char *group); extern void show_mime_article(FILE *fp, struct t_article *art); extern void show_first_header(int respnum, char *group); extern void show_cont_header(int respnum); extern int art_open(long art, char *group_path); extern void art_close(void); extern int prompt_response(int ch, int respnum); extern void yank_to_addr(char *orig, char *addr); extern int show_last_page(void); extern int match_header(char *buf, char *pat, char *body, int len); /* parsdate.y */ extern int GetTimeInfo(TIMEINFO *Now); extern time_t parsedate(char *p, TIMEINFO *now); /* post.c */ extern int user_posted_messages(void); extern void update_art_posted_file(char *group, int action, char *subj); extern int check_article_to_be_posted(char *article); extern void setup_check_article_screen(int *init); extern void quick_post_article(void); extern int post_article(char *group, int *posted); extern int post_response(char *group, int respnum, int copy_text); extern int mail_to_someone(int respnum, char *address, int mail_to_poster, int confirm_to_mail, int *mailed_ok); extern int mail_bug_report(void); extern int mail_to_author(char *group, int respnum, int copy_text); extern void find_mail_header(int header, char *file, char *value); extern int delete_article(char *group, int respnum); extern int crosspost_article(char *group, int respnum); extern void insert_x_headers(char *infile); extern void find_reply_to_addr(int respnum, char *from_addr); extern void reread_active_after_posting(void); /* prompt.c */ extern int prompt_num(int ch, char *prompt); extern int prompt_string(char *prompt, char *buf); extern int prompt_menu_string(int line, int col, char *var); extern int prompt_yn(int line, char *prompt, int prompt_ch); extern void prompt_on_off(int row, int col, int *var, char *help_text, char *prompt_text); extern void continue_prompt(void); /* rcfile.c */ extern int read_rcfile(void); extern void write_rcfile(void); extern int change_rcfile(char *group, int kill_at_once); extern void show_rcfile_menu(void); extern void expand_rel_abs_pathname(int line, int col, char *str); extern void show_menu_help(char *help_message); extern int match_boolean(char *line, char *pat, int *dst); extern int match_number(char *line, char *pat, int *dst); extern int match_string(char *line, char *pat, char *dst, int dstlen); extern void quote_dash_to_space(char *s); extern char *quote_space_to_dash(char *s); /* save.c */ extern int check_start_save_any_news(int check_start_save); extern int save_art_to_file(int respnum, int index, int mailbox, char *filename); extern int save_thread_to_file(int is_mailbox, char *group_path); extern int save_regex_arts(int is_mailbox, char *group_path); extern int append_to_existing_file(int i); extern int create_path(char *path); extern int create_sub_dir(int i); extern void add_to_save_list(int index, struct t_article *article, int is_mailbox, int archive_save, char *path); extern void sort_save_list(void); extern int save_comp(t_comptype *p1, t_comptype *p2); extern char *save_filename(int i); extern char *get_first_savefile(void); extern char *get_last_savefile(void); extern int post_process_files(int proc_type_ch); extern void post_process_uud(int pp); extern void post_process_sh(void); extern char *get_archive_file(char *dir, char *ext); extern void delete_processed_files(void); extern void print_art_seperator_°p¶5Õ~ TIN-1_22.BCK„d[SRC.TIN-1_22]PROTO.H;1?&}Bline(FILE *fp, int mailbox); /* screen.c */ extern void info_message(char *str); extern void wait_message(char *str); extern void error_message(char *template, char *str); extern void perror_message(char *template, char *str); extern void clear_message(void); extern void center_line(int line, int inverse, char *str); extern void draw_arrow(int line); extern void erase_arrow(int line); extern void show_title(char *title); extern void ring_bell(void); /* search.c */ extern int search_author(int index, int current_art, int forward); extern void search_group(int forward); extern void search_subject(int forward, char *group); extern int search_article(int forward); extern void make_lower(char *s, char *t); extern int search_body(char *group_path, int current_art); extern int search_art_body(char *group_path, struct t_article *art, char *pat, int len); extern void lcase(char *s); /* select.c */ extern void selection_index(int start_groupnum); extern void group_selection_page(void); extern int prompt_group_num(int ch); extern void erase_group_arrow(void); extern void draw_group_arrow(void); extern void yank_active_file(void); extern int choose_new_group(void); extern int add_group(char *s, int get_unread); extern int reposition_group(char *group, int default_num); extern void catchup_group(int goto_next_unread_group); extern void next_unread_group(int enter_group); extern void set_groupname_len(int all_groups); extern void toggle_my_groups(int only_unread_groups, char *group); extern void goto_next_group_on_screen(void); extern void strip_line(char *line, int len); /* sigfile.c */ extern void add_signature(FILE *fp, int flag); extern FILE *open_random_sig(char *sigdir); extern int thrashdir(char *sigdir); /* signal.c */ extern t_sigtype (*sigdisp(int sig, t_sigtype (*func)()))(); extern void set_signal_handlers(void); extern void set_alarm_signal(void); extern void set_alarm_clock_on(void); extern void set_alarm_clock_off(void); extern void signal_handler(int sig); extern int set_win_size(int *num_lines, int *num_cols); extern void set_signals_art(void); extern void set_signals_group(void); extern void set_signals_help(void); extern void set_signals_page(void); extern void set_signals_select(void); extern void set_signals_spooldir(void); extern void set_signals_thread(void); extern void art_suspend(int sig); extern void main_suspend(int sig); extern void select_suspend(int sig); extern void spooldir_suspend(int sig); extern void group_suspend(int sig); extern void help_suspend(int sig); extern void page_suspend(int sig); extern void thread_suspend(int sig); extern void rcfile_suspend(int sig); extern void art_resize(int sig); extern void main_resize(int sig); extern void select_resize(int sig); extern void spooldir_resize(int sig); extern void group_resize(int sig); extern void help_resize(int sig); extern void page_resize(int sig); extern void thread_resize(int sig); /* spooldir.c */ extern int spooldir_index(void); extern void show_spooldir_page(void); extern int prompt_spooldir_num(int ch); extern void erase_spooldir_arrow(void); extern void draw_spooldir_arrow(void); extern int load_spooldirs(void); extern void get_spooldir(void); extern int set_spooldir(char *name); /* strftime.c */ extern size_t my_strftime(char *s, size_t maxsize, char *format, struct tm *timeptr); /* thread.c */ extern int show_thread(int respnum, char *group, char *group_path); extern void show_thread_page(void); extern void update_thread_page(void); extern void draw_thread_arrow(void); extern void erase_thread_arrow(void); extern int prompt_thread_num(int ch); extern int new_responses(int thread); extern int which_thread(int n); extern int which_response(int n); extern int num_of_responses(int n); extern int stat_thread(int n, struct t_art_stat *sbuf); extern int next_response(int n); extern int next_thread(int n); extern int prev_response(int n); extern int choose_response(int i, int n); extern int next_unread(int n); extern int prev_unread(int n); /* wildmat.c */ extern int wildmat(char *text, char *p); /* win32.c */ /* xref.c */ extern int overview_xref_support(void); extern void mark_all_xref_read(struct t_article *art, char *group_path); #else /* active.c */ extern int cmp_group_p(); extern int cmp_notify_p(); extern int get_active_num(); extern void resync_active_file(); extern int find_group_index(); extern int parse_active_line(); extern int parse_newsrc_active_line(); extern void read_news_active_file(); extern void backup_active(); extern void check_for_any_new_groups(); extern int prompt_subscribe_group(); extern int match_group_list(); extern void set_default_attributes(); extern void read_attributes_file(); extern void write_attributes_file(); extern void read_active_times_file(); extern void write_active_times_file(); extern void load_active_size_info(); extern int find_active_size_index(); extern void read_motd_file(); extern char *my_strpbrk(); /* amiga.c */ /* art.c */ extern void find_base(); extern int num_of_arts(); extern int purge_needed(); extern int index_group(); extern int read_group(); extern void make_threads(); extern int parse_headers(); extern void write_xindex_file(); extern void read_xindex_file(); extern int read_xover_file(); extern int find_index_file(); extern void do_update(); extern int artnum_comp(); extern int subj_comp(); extern int from_comp(); extern int date_comp(); extern void set_article(); extern int input_pending(); extern int valid_artnum(); /* curses.c */ extern void setup_screen(); extern int InitScreen(); extern void ScreenSize(); extern void InitWin(); extern void EndWin(); extern void set_keypad_on(); extern void set_keypad_off(); extern void ClearScreen(); extern void MoveCursor(); extern void CleartoEOLN(); extern void CleartoEOS(); extern void StartInverse(); extern void EndInverse(); extern void ToggleInverse(); extern int RawState(); extern void Raw(); extern int ReadCh(); extern int outchar(); extern void xclick(); extern void set_xclick_on(); extern void set_xclick_off(); /* debug.c */ extern void debug_nntp(); extern void debug_nntp_respcode(); extern void debug_print_arts(); extern void debug_print_header(); extern void debug_save_comp(); extern void debug_print_comment(); extern void debug_print_base(); extern void debug_print_active(); extern void debug_print_active_hash(); /* envarg.c */ extern int count_args(); extern void envargs(); /* feed.c */ extern void feed_articles(); extern int print_file(); extern int get_post_proc_type(); extern int does_article_exist(); /* getline.c */ extern char *getline(); /* group.c */ extern void decr_tagged(); extern void group_page(); extern void fix_new_highest(); extern void show_group_page(); extern void update_group_page(); extern void draw_subject_arrow(); extern void erase_subject_arrow(); extern int prompt_subject_num(); extern void clear_note_area(); extern int find_new_pos(); extern void mark_screen(); extern void set_subj_from_size(); extern void toggle_subject_from(); extern void show_group_title(); /* hashstr.c */ extern char *hash_str(); extern struct t_hashnode *add_string(); extern void hash_init(); extern void hash_reclaim(); /* help.c */ extern void show_info_page(); extern void display_info_page(); extern void show_mini_help(); extern void toggle_mini_help(); /* inews.c */ extern int submit_inews(); extern void get_host_name(); extern void get_user_info(); extern void get_from_name(); extern int submit_file(); /* init.c */ extern void init_selfinfo(); extern void set_tindir(); extern int create_mail_save_dirs(); extern char *GetFQDN(); extern char *GetConfigValue(); /* kill.c */ extern int read_kill_file(); extern void write_kill_file(); extern int kill_art_menu(); extern int unkill_all_articles(); extern int kill_any_articles(); extern int auto_select_articles(); /* lang.c */ /* mail.c */ extern void read_mail_active_file(); extern void write_mail_active_file(); extern void read_mailgroups_file(); extern void read_newsgroups_file(); extern void read_groups_descriptions(); /* main.c */ extern void main(); extern void read_cmd_line_options(); extern void usage(); extern int check_for_any_new_news(); extern void save_or_mail_new_news(); extern void update_index_files(); extern void show_intro_page(); extern int read_cmd_line_groups(); /* memory.c */ extern void init_alloc(); extern void expand_art(); extern void expand_active(); extern void expand_kill(); extern void expand_save(); extern void expand_spooldirs(); extern void expand_active_size(); extern void init_screen_array(); extern void free_all_arrays(); extern void free_art_array(); extern void free_attributes_array(); extern void free_active_arrays(); extern void free_kill_array(); extern void free_save_array(); extern void free_spooldirs_array(); extern void free_active_size_array(); extern char *my_malloc(); extern char *my_realloc(); /* misc.c */ extern void asfail(); extern void copy_fp(); extern char *get_val(); extern int invoke_editor(); extern int invoke_ispell(); extern void shell_escape(); extern void tin_done(); extern int my_mkdir(); extern int my_chdir(); extern unsigned long hash_groupname(); extern void rename_file(); extern char *str_dup(); extern int invoke_cmd(); extern void draw_percent_mark(); extern void set_real_uid_gid(); extern void set_tin_uid_gid(); extern void base_name(); extern void mail_setup(); extern int mail_check(); extern void parse_from(); extern long my_atol(); extern int my_stricmp(); extern char *eat_re(); extern long hash_s(); extern void my_strncpy(); extern int untag_all_articles(); extern char *str_str(); extern void get_author(); extern void toggle_inverse_video(); extern int get_arrow_key(); extern void create_index_lock_file(); extern int strfquote(); extern int strfeditor(); extern int strfpath(); extern void get_cwd(); extern void make_group_path(); extern void cleanup_tmp_files(); extern void make_post_process_cmd(); /* newsrc.c */ extern int auto_subscribe_groups(); extern void backup_newsrc(); extern void read_newsrc(); extern void write_newsrc(); extern void rewrite_newsrc(); extern void checknewsrc(); extern void read_newsrc_line(); extern void update_newsrc(); extern void subscribe(); extern void reset_newsrc(); extern void delete_group(); extern int undel_group(); extern void mark_group_read(); extern void parse_seq(); extern int parse_unread(); extern int get_line_unread(); extern void print_newsrc_seq(); extern void print_seq(); extern int pos_group_in_newsrc(); /* nntplib.c */ extern char *getserverbyfile(); extern int server_init(); extern int get_tcp_socket(); extern int handle_server_response(); extern void put_server(); extern int get_server(); extern void close_server(); extern char *nntp_respcode(); /* open.c */ extern int nntp_open(); extern void nntp_close(); extern FILE *open_mail_active_fp(); extern FILE *open_news_active_fp(); extern FILE *open_overview_fmt_fp(); extern FILE *open_newgroups_fp(); extern FILE *open_motd_fp(); extern FILE *open_subscription_fp(); extern FILE *open_mailgroups_fp(); extern FILE *open_newsgroups_fp(); extern FILE *open_xindex_fp(); extern FILE *open_xover_fp(); extern int stat_article(); extern char *open_art_header(); extern FILE *open_art_fp(); extern FILE *open_xhdr_fp(); extern int base_comp(); extern void setup_base(); extern int get_respcode(); extern int stuff_nntp(); extern FILE *nntp_to_fp(); extern void log_user(); extern void authorization(); /* os_2.c */ /* page.c */ extern int show_page(); extern void redraw_page(); extern void show_note_page(); extern void show_mime_article(); extern void show_first_header(); extern void show_cont_header(); extern int art_open(); extern void art_close(); extern int prompt_response(); extern void yank_to_addr(); extern int show_last_page(); extern int match_header(); /* parsdate.y */ extern int GetTimeInfo(); extern time_t parsedate(); /* post.c */ extern int user_posted_messages(); extern void update_art_posted_file(); extern int check_article_to_be_posted(); extern void setup_check_article_screen(); extern void quick_post_article(); extern int post_article(); extern int post_response(); extern int mail_to_someone(); extern int mail_bug_report(); extern int mail_to_author(); extern void find_mail_header(); extern int delete_article(); extern int crosspost_article(); extern void insert_x_headers(); extern void find_reply_to_addr(); extern void reread_active_after_posting(); /* prompt.c */ extern int prompt_num(); extern int prompt_string(); extern int prompt_menu_string(); extern int prompt_yn(); extern void prompt_on_off(); extern void continue_prompt(); /* rcfile.c */ extern int read_rcfile(); extern void write_rcfile(); extern int change_rcfile(); extern void show_rcfile_menu(); extern void expand_rel_abs_pathname(); extern void show_menu_help(); extern int match_boolean(); extern int match_number(); extern int match_string(); extern void quote_dash_to_space(); extern char *quote_space_to_dash(); /* save.c */ extern int check_start_save_any_news(); extern int save_art_to_file(); extern int save_thread_to_file(); extern int save_regex_arts(); extern int append_to_existing_file(); extern int create_path(); extern int create_sub_dir(); extern void add_to_save_list(); extern void sort_save_list(); extern int save_comp(); extern char *save_filename(); extern char *get_first_savefile(); extern char *get_last_savefile(); extern int post_process_files(); extern void post_process_uud(); extern void post_process_sh(); extern char *get_archive_file(); extern void delete_processed_files(); extern void print_art_seperator_line(); /* screen.c */ extern void info_message(); extern void wait_message(); extern void error_message(); extern void perror_message(); extern void clear_message(); extern void center_line(); extern void draw_arrow(); extern void erase_arrow(); extern void show_title(); extern void ring_bell(); /* search.c */ extern int search_author(); extern void search_group(); extern void search_subject(); extern int search_article(); extern void make_lower(); extern int search_body(); extern int search_art_body(); extern void lcase(); /* select.c */ extern void selection_index(); extern void group_selection_page(); extern int prompt_group_num(); extern void erase_group_arrow(); extern void draw_group_arrow(); extern void yank_active_file(); extern int choose_new_group(); extern int add_group(); extern int reposition_group(); extern void catchup_group(); extern void next_unread_group(); extern void set_groupname_len(); extern void toggle_my_groups(); extern void goto_next_group_on_screen(); extern void strip_line(); /* sigfile.c */ extern void add_signature(); extern FILE *open_random_sig(); extern int thrashdir(); /* signal.c */ extern t_sigtype (*sigdisp())(); extern void set_signal_handlers(); extern void set_alarm_signal(); extern void set_alarm_clock_on(); extern void set_alarm_clock_off(); extern void signal_handler(); extern int set_win_size(); extern void set_signals_art(); extern void set_signals_group(); extern void set_signals_help(); extern void set_signals_page(); extern void set_signals_select(); extern void set_signals_spooldir(); extern void set_signals_thread(); extern void art_suspend(); extern void main_suspend(); extern void select_suspend(); extern void spooldir_suspend(); extern void group_suspend(); extern void help_suspend(); extern void page_suspend(); extern void thread_suspend(); extern void rcfile_suspend(); extern void art_resize(); extern void main_resize(); extern void select_resize(); extern void spooldir_resize(); extern void group_resize(); extern void help_resize(); extern void page_resize(); extern void thread_resize(); /* spooldir.c */ extern int spooldir_index(); extern void show_spooldir_page(); extern int prompt_spooldir_num(); extern void erase_spooldir_arrow(); extern void draw_spooldir_arrow(); extern int load_spooldirs(); extern void get_spooldir(); extern int set_spooldir(); /* strftime.c */ extern size_t my_strftime(); /* thread.c */ extern int show_thread(); extern void show_thread_page(); extern void update_thread_page(); extern void draw_thread_arrow(); extern void erase_thread_arrow(); extern int prompt_thread_num(); extern int new_responses(); extern int which_thread(); extern int which_response(); extern int num_of_responses(); extern int stat_thread(); extern int next_response(); extern int next_thread(); extern int prev_response(); extern int choose_response(); extern int next_unread(); extern int prev_unread(); /* wildmat.c */ extern int wildmat(); /* win32.c */ /* xref.c */ extern int overview_xref_support(); extern void mark_all_xref_read(); #endif ð*[SRC.TIN-1_22]RCFILE.C;2+,ã.B//€ 4BBy-d0@î123KÿPWOC56 ÉA@¯‹—7`'¹A¯‹—89€]V‚—G/€HªJÿ/* * Project : tin - a Usenet reader * Module : rcfile.c * Author : I.Lea * Created : 01-04-91 * Updated : 22-09-93 * Notes : * Copyright : (c) Copyright 1991-93 by Iain Lea * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" extern int index_point; static int COL1; static int COL2; static int COL3; /* * read_rcfile - read defaults from ~/.tin/tinrc */ int read_rcfile () { char active_size_info[PATH_LEN]; char buf[LEN]; FILE *fp; if ((fp = fopen (rcfile, "r")) == NULL) { return (FALSE); } while (fgets (buf, sizeof (buf), fp) != NULL) { if (buf[0] == '#' || buf[0] == '\n') { continue; } if (match_boolean (buf, "auto_save=", &default_auto_save)) { continue; } if (match_boolean (buf, "batch_save=", &default_batch_save)) { continue; } if (match_boolean (buf, "start_editor_offset=", &start_editor_offset)) { continue; } if (match_string (buf, "default_editor_format=", default_editor_format, sizeof (default_editor_format))) { continue; } if (match_boolean (buf, "mark_saved_read=", &mark_saved_read)) { continue; } if (match_boolean (buf, "inverse_okay=", &inverse_okay)) { continue; } if (match_boolean (buf, "draw_arrow=", &draw_arrow_mark)) { continue; } if (match_boolean (buf, "print_header=", &print_header)) { continue; } if (match_number (buf, "kill_level=", &kill_level)) { continue; } if (match_boolean (buf, "pos_first_unread=", &pos_first_unread)) { continue; } if (match_boolean (buf, "full_page_scroll=", &full_page_scroll)) { continue; } if (match_boolean (buf, "catchup_read_groups=", &catchup_read_groups)) { continue; } if (match_boolean (buf, "thread_articles=", &default_thread_arts)) { continue; } if (match_boolean (buf, "unlink_article=", &unlink_article)) { continue; } if (match_boolean (buf, "show_only_unread_groups=", &show_only_unread_groups)) { continue; } if (match_boolean (buf, "show_only_unread=", &default_show_only_unread)) { continue; } if (match_boolean (buf, "confirm_action=", &confirm_action)) { continue; } if (match_boolean (buf, "show_description=", &show_description)) { continue; } if (match_number (buf, "show_author=", &default_show_author)) { continue; } if (match_number (buf, "post_process_type=", &default_post_proc_type)) { proc_ch_default = get_post_proc_type (default_post_proc_type); continue; } if (match_number (buf, "sort_article_type=", &default_sort_art_type)) { continue; } if (match_string (buf, "default_savedir=", default_savedir, sizeof (default_savedir))) { if (default_savedir[0] == '.' && strlen (default_savedir) == 1) { get_cwd (buf); my_strncpy (default_savedir, buf, sizeof (default_savedir)); } continue; } if (match_string (buf, "default_maildir=", default_maildir, sizeof (default_maildir))) { continue; } if (match_string (buf, "default_printer=", default_printer, sizeof (default_printer))) { continue; } if (match_string (buf, "default_sigfile=", default_sigfile, sizeof (default_sigfile))) { continue; } if (match_string (buf, "quote_chars=", quote_chars, sizeof (quote_chars))) { quote_dash_to_space (quote_chars); continue; } if (match_string (buf, "unread_art_mark=", buf, sizeof (buf))) { unread_art_mark = buf[0]; continue; } if (match_string (buf, "hot_art_mark=", buf, sizeof (buf))) { hot_art_mark = buf[0]; continue; } if (match_string (buf, "return_art_mark=", buf, sizeof (buf))) { return_art_mark = buf[0]; continue; } if (match_number (buf, "reread_active_file_secs=", &reread_active_file_secs)) { continue; } if (match_boolean (buf, "show_last_line_prev_page=", &show_last_line_prev_page)) { continue; } if (match_boolean (buf, "tab_after_X_selection=", &tab_after_X_selection)) { continue; } if (match_boolean (buf, "tab_goto_next_unread=", &tab_goto_next_unread)) { continue; } if (match_boolean (buf, "force_screen_redraw=", &force_screen_redraw)) { continue; } if (match_boolean (buf, "display_reading_prompt=", &display_reading_prompt)) { continue; } if (match_boolean (buf, "save_to_mmdf_mailbox=", &save_to_mmdf_mailbox)) { continue; } if (match_boolean (buf, "use_builtin_inews=", &use_builtin_inews)) { continue; } if (match_string (buf, "default_spooldir_alias=", spooldir_alias, sizeof (spooldir_alias))) { continue; } if (match_string (buf, "news_quote_format=", news_quote_format, sizeof (news_quote_format))) { continue; } if (match_string (buf, "mail_quote_format=", mail_quote_format, sizeof (mail_quote_format))) { continue; } #ifdef HAVE_KEYPAD if (match_boolean (buf, "use_keypad=", &use_keypad)) { continue; } #endif if (match_boolean (buf, "slow_speed_terminal=", &slow_speed_terminal)) { continue; } if (match_number (buf, "groupname_max_length=", &groupname_max_length)) { continue; } if (match_boolean (buf, "beginner_level=", &beginner_level)) { continue; } if (match_boolean (buf, "auto_cc=", &auto_cc)) { continue; } if (match_string (buf, "default_author_search=", default_author_search, sizeof (default_author_search))) { continue; } if (match_string (buf, "default_goto_group=", default_goto_group, sizeof (default_goto_group))) { continue; } if (match_string (buf, "default_group_search=", default_group_search, sizeof (default_group_search))) { continue; } if (match_string (buf, "default_subject_search=", default_subject_search, sizeof (default_subject_search))) { continue; } if (match_string (buf, "default_art_search=", default_art_search, sizeof (default_art_search))) { continue; } if (match_string (buf, "default_crosspost_group=", default_crosspost_group, sizeof (default_crosspost_group))) { continue; } if (match_string (buf, "default_mail_address=", default_mail_address, sizeof (default_mail_address))) { continue; } if (match_number (buf, "default_move_group=", &default_move_group)) { continue; } if (match_string (buf, "default_pipe_command=", default_pipe_command, sizeof (default_pipe_command))) { continue; } if (match_string (buf, "default_post_newsgroups=", default_post_newsgroups, sizeof (default_post_newsgroups))) { continue; } if (match_string (buf, "default_post_subject=", default_post_subject, sizeof (default_post_subject))) { continue; } if (match_string (buf, "default_regex_pattern=", default_regex_pattern, sizeof (default_regex_pattern))) { continue; } if (match_string (buf, "default_save_file=", default_save_file, sizeof (default_save_file))) { continue; } if (match_string (buf, "default_select_pattern=", default_select_pattern, sizeof (default_select_pattern))) { continue; } if (match_string (buf, "default_shell_command=", default_shell_command, sizeof (default_shell_command))) { continue; } if (match_string (buf, "motd_file_info=", motd_file_info, sizeof (motd_file_info))) { continue; } if (match_string (buf, "active_file_info=", active_size_info, sizeof (active_size_info))) { load_active_size_info (active_size_info); continue; } } fclose (fp); return TRUE; } /* * write_rcfile - write defaults to ~/.tin/tinrc */ void write_rcfile () { FILE *fp; int i; #ifdef VMS if ((fp = fopen (rcfile, "w", "fop=cif")) == NULL) { #else if ((fp = fopen (rcfile, "w")) == NULL) { #endif return; } if (! cmd_line) { wait_message (txt_saving); } if (! default_editor_format[0]) { strcpy (default_editor_format, EDITOR_FORMAT_ON); } fprintf (fp, "# if ON articles/threads with Archive-name: in mail header will\n"); fprintf (fp, "# be automatically saved with the Archive-name & part/patch no.\n"); fprintf (fp, "auto_save=%s\n\n", (default_auto_save ? "ON" : "OFF")); fprintf (fp, "# if ON articles/threads will be saved in batch mode when save -S\n"); fprintf (fp, "# or mail -M is specified on the command line\n"); fprintf (fp, "batch_save=%s\n\n", (default_batch_save ? "ON" : "OFF")); fprintf (fp, "# if ON editor will be started with cursor offset into the file\n"); fprintf (fp, "# otherwise the cursor will be positioned at the first line\n"); fprintf (fp, "start_editor_offset=%s\n\n", (start_editor_offset ? "ON" : "OFF")); fprintf (fp, "# Format of editor line including parameters\n"); fprintf (fp, "# %%E Editor %%F Filename %%N Linenumber\n"); fprintf (fp, "default_editor_format=%s\n\n", default_editor_format); fprintf (fp, "# if ON mark articles that are saved as read\n"); fprintf (fp, "mark_saved_read=%s\n\n", (mark_saved_read ? "ON" : "OFF")); fprintf (fp, "# if 0 killed articles are simply marked as being read\n"); fprintf (fp, "# if 1 killed articles are removed and never seen\n"); fprintf (fp, "kill_level=%d\n\n", kill_level); fprintf (fp, "# if ON use inverse video for page headers at different levels\n"); fprintf (fp, "inverse_okay=%s\n\n", (inverse_okay ? "ON" : "OFF")); fprintf (fp, "# if ON use -> otherwise highlighted bar for selection\n"); fprintf (fp, "draw_arrow=%s\n\n", (draw_arrow_mark ? "ON" : "OFF")); fprintf (fp, "# if ON print all of mail header otherwise Subject: & From: lines\n"); fprintf (fp, "print_header=%s\n\n", (print_header ? "ON" : "OFF")); fprintf (fp, "# if ON put cursor at first unread art in group otherwise last art\n"); fprintf (fp, "pos_first_unread=%s\n\n", (pos_first_unread ? "ON" : "OFF")); fprintf (fp, "# if ON scroll full page of groups/articles otherwise half a page\n"); fprintf (fp, "full_page_scroll=%s\n\n", (full_page_scroll ? "ON" : "OFF")); fprintf (fp, "# if ON ask user if read groups should all be marked read\n"); fprintf (fp, "catchup_read_groups=%s\n\n", (catchup_read_groups ? "ON" : "OFF")); fprintf (fp, "# if ON confirm certain commands with y/n before executing\n"); fprintf (fp, "confirm_action=%s\n\n", (confirm_action ? "ON" : "OFF")); fprintf (fp, "# if ON show group description text after newsgroup name at\n"); fprintf (fp, "# group selection level\n"); fprintf (fp, "show_description=%s\n\n", (show_description ? "ON" : "OFF")); fprintf (fp, "# part of from field to display 0) none 1) address 2) full name 3) both\n"); fprintf (fp, "show_author=%d\n\n", default_show_author); fprintf (fp, "# type of post processing to perform after saving articles.\n"); #ifdef M_AMIGA fprintf (fp, "# 0=(none) 1=(unshar) 2=(uudecode) 3=(uudecode & list lha)\n"); fprintf (fp, "# 4=(uud & extract lha) 5=(uud & list zip) 6=(uud & extract zip)\n"); #else fprintf (fp, "# 0=(none) 1=(unshar) 2=(uudecode) 3=(uudecode & list zoo)\n"); fprintf (fp, "# 4=(uud & extract zoo) 5=(uud & list zip) 6=(uud & extract zip)\n"); #endif fprintf (fp, "post_process_type=%d\n\n", default_post_proc_type); fprintf (fp, "# if ON all group will be threaded as default.\n"); fprintf (fp, "thread_articles=%s\n\n", (default_thread_arts ? "ON" : "OFF")); fprintf (fp, "# if ON remove ~/.article after posting.\n"); fprintf (fp, "unlink_article=%s\n\n", (unlink_article ? "ON" : "OFF")); fprintf (fp, "# if ON show only subscribed to groups that contain unread articles.\n"); fprintf (fp, "show_only_unread_groups=%s\n\n", (show_only_unread_groups ? "ON" : "OFF")); fprintf (fp, "# if ON show only new/unread articles otherwise show all.\n"); fprintf (fp, "show_only_unread=%s\n\n", (default_show_only_unread ? "ON" : "OFF")); fprintf (fp, "# sort articles by 0=(nothing) 1=(Subject descend) 2=(Subject ascend)\n"); fprintf (fp, "# 3=(From descend) 4=(From ascend) 5=(Date descend) 6=(Date ascend).\n"); fprintf (fp, "sort_article_type=%d\n\n", default_sort_art_type); fprintf (fp, "# directory where articles/threads are saved\n"); fprintf (fp, "default_savedir=%s\n\n", default_savedir); fprintf (fp, "# (-m) directory where articles/threads are saved in mailbox format\n"); fprintf (fp, "default_maildir=%s\n\n", default_maildir); fprintf (fp, "# print program with parameters used to print articles/threads\n"); fprintf (fp, "default_printer=%s\n\n", default_printer); fprintf (fp, "# Signature path (random sigs)/file to be used when posting/replying to messages\n"); fprintf (fp, "default_sigfile=%s\n\n", default_sigfile); fprintf (fp, "# time interval in seconds between rereading the active file\n"); fprintf (fp, "reread_active_file_secs=%d\n\n", reread_active_file_secs); fprintf (fp, "# characters used in quoting to followups and replys. '_' replaced by ' '\n"); fprintf (fp, "quote_chars=%s\n\n", quote_space_to_dash (quote_chars)); fprintf (fp, "# character used to show that an art was unread (default '+')\n"); fprintf (fp, "unread_art_mark=%c\n\n", unread_art_mark); fprintf (fp, "# character used to show that an art was auto-selected (default '*')\n"); fprintf (fp, "hot_art_mark=%c\n\n", hot_art_mark); fprintf (fp, "# character used to show that an art will return (default '-')\n"); fprintf (fp, "return_art_mark=%c\n\n", return_art_mark); fprintf (fp, "# if ON show the last line of the previous page as first line of next page\n"); fprintf (fp, "show_last_line_prev_page=%s\n\n", (show_last_line_prev_page ? "ON" : "OFF")); fprintf (fp, "# if ON a TAB command will be automatically done after the X command\n"); fprintf (fp, "tab_after_X_selection=%s\n\n", (tab_after_X_selection ? "ON" : "OFF")); fprintf (fp, "# if ON the TAB command will goto next unread article at article viewer level\n"); fprintf (fp, "tab_goto_next_unread=%s\n\n", (tab_goto_next_unread ? "ON" : "OFF")); fprintf (fp, "# if ON a screen redraw will always be done after certain external commands\n"); fprintf (fp, "force_screen_redraw=%s\n\n", (force_screen_redraw ? "ON" : "OFF")); fprintf (fp, "# if ON 'Reading...' will be displayed when reading article from NNTP server\n"); fprintf (fp, "display_reading_prompt=%s\n\n", (display_reading_prompt ? "ON" : "OFF")); fprintf (fp, "# if ON save mail to a MMDF style mailbox (default is normal mbox format)\n"); fprintf (fp, "save_to_mmdf_mailboÀÀ;I$~ TIN-1_22.BCKãd[SRC.TIN-1_22]RCFILE.C;2BàLx=%s\n\n", (save_to_mmdf_mailbox ? "ON" : "OFF")); fprintf (fp, "# if ON use the builtin mini inews otherwise use an external inews program\n"); fprintf (fp, "use_builtin_inews=%s\n\n", (use_builtin_inews ? "ON" : "OFF")); fprintf (fp, "# Format of quote line when mailing/posting/followingup an article\n"); fprintf (fp, "# %%A Address %%D Date %%F Addr+Name %%G Groupname %%M MessageId %%N Name\n"); fprintf (fp, "news_quote_format=%s\n", news_quote_format); fprintf (fp, "mail_quote_format=%s\n\n", mail_quote_format); fprintf (fp, "# if ON automatically put your name in the Cc: field when mailing an article\n"); fprintf (fp, "auto_cc=%s\n\n", (auto_cc ? "ON" : "OFF")); #ifdef HAVE_KEYPAD fprintf (fp, "# If ON enable scroll keys on terminals that support it\n"); fprintf (fp, "use_keypad=%s\n\n", (use_keypad ? "ON" : "OFF")); #endif fprintf (fp, "# If ON strip blanks from end of lines to speedup display on slow terminals\n"); fprintf (fp, "slow_speed_terminal=%s\n\n", (slow_speed_terminal ? "ON" : "OFF")); fprintf (fp, "# Maximum length of the names of newsgroups displayed\n"); fprintf (fp, "groupname_max_length=%d\n\n", groupname_max_length); fprintf (fp, "# If ON show a mini menu of useful commands at each level\n"); fprintf (fp, "beginner_level=%s\n\n", (beginner_level ? "ON" : "OFF")); fprintf (fp, "# default action/prompt strings\n"); fprintf (fp, "default_spooldir_alias=%s\n", spooldir_alias); fprintf (fp, "default_author_search=%s\n", default_author_search); fprintf (fp, "default_goto_group=%s\n", default_goto_group); fprintf (fp, "default_group_search=%s\n", default_group_search); fprintf (fp, "default_subject_search=%s\n", default_subject_search); fprintf (fp, "default_art_search=%s\n", default_art_search); fprintf (fp, "default_crosspost_group=%s\n", default_crosspost_group); fprintf (fp, "default_mail_address=%s\n", default_mail_address); fprintf (fp, "default_move_group=%d\n", default_move_group); fprintf (fp, "default_pipe_command=%s\n", default_pipe_command); fprintf (fp, "default_post_newsgroups=%s\n", default_post_newsgroups); fprintf (fp, "default_post_subject=%s\n", default_post_subject); fprintf (fp, "default_regex_pattern=%s\n", default_regex_pattern); fprintf (fp, "default_save_file=%s\n", default_save_file); fprintf (fp, "default_select_pattern=%s\n", default_select_pattern); fprintf (fp, "default_shell_command=%s\n\n", default_shell_command); fprintf (fp, "# news motd file dates from server used for detecting new motd info\n"); fprintf (fp, "motd_file_info=%s\n\n", motd_file_info); fprintf (fp, "# active file sizes/dates from different servers used for detecting new groups\n"); if (! num_active_size) { fprintf (fp, "active_file_info=%s[%s]\n", new_active_file_server, new_active_file_attribute); } else { for (i = 0 ; i < num_active_size ; i++) { fprintf (fp, "active_file_info=%s[%s]\n", active_size[i].server, active_size[i].attribute); } } fclose (fp); chmod (rcfile, 0600); } /* * options menu so that the user can dynamically change parameters */ int change_rcfile (group, kill_at_once) char *group; int kill_at_once; { char *str = (char *) 0; int ch, i; int kill_changed = FALSE; int orig_show_only_unread; int orig_thread_arts; int index; int option; int ret_code = NO_KILLING; int var_orig; #ifdef SIGTSTP t_sigtype (*susp)(); susp = (t_sigtype (*)()) 0; if (do_sigtstp) { susp = sigdisp (SIGTSTP, SIG_DFL); } #endif COL1 = 0; COL2 = ((cCOLS / 3) * 1) + 1; COL3 = ((cCOLS / 3) * 2) + 2; show_rcfile_menu (); set_xclick_off (); while (1) { #ifdef SIGTSTP if (do_sigtstp) { sigdisp (SIGTSTP, rcfile_suspend); } #endif MoveCursor (cLINES, 0); ch = ReadCh (); if (ch >= '1' && ch <= '9') { option = prompt_num (ch, "Enter option number> "); } else { if (ch == 'q' || ch == ESC) { option = -1; } else { option = 0; } } #ifdef SIGTSTP if (do_sigtstp) { sigdisp (SIGTSTP, SIG_IGN); } #endif switch (option) { case 0: write_rcfile (); /* FALLTHRU */ case -1: if (kill_changed) { if (kill_at_once) { index = my_group[cur_groupnum]; killed_articles = read_kill_file (); if (killed_articles) { if (kill_any_articles (index)) { make_threads (FALSE); find_base (index); } } else { if (unkill_all_articles ()) { make_threads (FALSE); find_base (index); } } } ret_code = KILLING; } clear_note_area (); #ifdef SIGTSTP if (do_sigtstp) { sigdisp (SIGTSTP, susp); } #endif return ret_code; case 1: /* auto save */ prompt_on_off (INDEX_TOP, COL1, &default_auto_save, txt_help_autosave, txt_opt_autosave); break; case 2: /* start editor with line offset */ prompt_on_off (INDEX_TOP, COL2, &start_editor_offset, txt_help_start_editor_offset, txt_opt_start_editor_offset); break; case 3: /* mark saved articles read */ prompt_on_off (INDEX_TOP, COL3, &mark_saved_read, txt_help_mark_saved_read, txt_opt_mark_saved_read); break; case 4: /* confirm action */ prompt_on_off (INDEX_TOP+2, COL1, &confirm_action, txt_help_confirm_action, txt_opt_confirm_action); break; case 5: /* draw -> / highlighted bar */ prompt_on_off (INDEX_TOP+2, COL2, &draw_arrow_mark, txt_help_draw_arrow, txt_opt_draw_arrow); if (draw_arrow_mark == FALSE && inverse_okay == FALSE) { inverse_okay = TRUE; } break; case 6: /* print header */ prompt_on_off (INDEX_TOP+2, COL3, &print_header, txt_help_print_header, txt_opt_print_header); break; case 7: /* position cursor at first / last unread art */ prompt_on_off (INDEX_TOP+4, COL1, &pos_first_unread, txt_help_pos_first_unread, txt_opt_pos_first_unread); break; case 8: /* scroll half/full page of groups/articles */ prompt_on_off (INDEX_TOP+4, COL2, &full_page_scroll, txt_help_page_scroll, txt_opt_page_scroll); break; case 9: /* catchup read groups when quitting */ prompt_on_off (INDEX_TOP+4, COL3, &catchup_read_groups, txt_help_catchup_groups, txt_opt_catchup_groups); break; case 10: /* thread/unthread all groups except those in ~/.tin/unthreaded */ orig_thread_arts = default_thread_arts; prompt_on_off (INDEX_TOP+6, COL1, &default_thread_arts, txt_help_thread_arts, txt_opt_thread_arts); if (default_thread_arts != orig_thread_arts || group != (char *) 0) { make_threads (TRUE); find_base (my_group[cur_groupnum]); } clear_message (); break; case 11: /* show all arts or just new/unread arts */ orig_show_only_unread = default_show_only_unread; prompt_on_off (INDEX_TOP+6, COL2, &default_show_only_unread, txt_help_show_only_unread, txt_opt_show_only_unread); if (default_show_only_unread != orig_show_only_unread || group != (char *) 0) { make_threads (TRUE); find_base (my_group[cur_groupnum]); if (space_mode) { for (i = 0; i < top_base; i++) { if (new_responses (i)) { break; } } if (i < top_base) { index_point = i; } else { index_point = top_base - 1; } } else { index_point = top_base - 1; } } break; case 12: /* show newsgroup description text next to newsgroups */ prompt_on_off (INDEX_TOP+6, COL3, &show_description, txt_help_show_description, txt_opt_show_description); if (show_description) { /* force reread of newgroups file */ reread_active_file = TRUE; } else { set_groupname_len (FALSE); } break; case 13: /* show subject & author / subject only */ var_orig = default_show_author; show_menu_help (txt_help_show_author); do { MoveCursor (INDEX_TOP+8, COL1 + (int) strlen (txt_opt_show_author)); if ((ch = ReadCh()) == ' ') { if (default_show_author + 1 > SHOW_FROM_BOTH) { default_show_author = SHOW_FROM_NONE; } else { default_show_author++; } switch (default_show_author) { case SHOW_FROM_NONE: str = txt_show_from_none; break; case SHOW_FROM_ADDR: str = txt_show_from_addr; break; case SHOW_FROM_NAME: str = txt_show_from_name; break; case SHOW_FROM_BOTH: str = txt_show_from_both; break; } fputs (str, stdout); fflush (stdout); } } while (ch != CR && ch != ESC); if (ch == ESC) { /* restore original value */ default_show_author = var_orig; switch (default_show_author) { case SHOW_FROM_NONE: str = txt_show_from_none; break; case SHOW_FROM_ADDR: str = txt_show_from_addr; break; case SHOW_FROM_NAME: str = txt_show_from_name; break; case SHOW_FROM_BOTH: str = txt_show_from_both; break; } fputs (str, stdout); fflush (stdout); } #if 0 else { set_subj_from_size (cCOLS); } #endif break; case 14: var_orig = default_post_proc_type; show_menu_help (txt_help_post_proc_type); do { MoveCursor (INDEX_TOP+8, COL2 + (int) strlen (txt_opt_process_type)); if ((ch = ReadCh()) == ' ') { if (default_post_proc_type + 1 > POST_PROC_UUD_EXT_ZIP) { default_post_proc_type = POST_PROC_NONE; } else { default_post_proc_type++; } proc_ch_default = get_post_proc_type (default_post_proc_type); switch (default_post_proc_type) { case POST_PROC_NONE: str = txt_post_process_none; break; case POST_PROC_SHAR: str = txt_post_process_sh; break; case POST_PROC_UUDECODE: str = txt_post_process_uudecode; break; case POST_PROC_UUD_LST_ZOO: str = txt_post_process_uud_lst_zoo; break; case POST_PROC_UUD_EXT_ZOO: str = txt_post_process_uud_ext_zoo; break; case POST_PROC_UUD_LST_ZIP: str = txt_post_process_uud_lst_zip; break; case POST_PROC_UUD_EXT_ZIP: str = txt_post_process_uud_ext_zip; break; } CleartoEOLN (); fputs (str, stdout); fflush (stdout); } } while (ch != CR && ch != ESC); if (ch == ESC) { /* restore original value */ default_post_proc_type = var_orig; switch (default_post_proc_type) { case POST_PROC_NONE: str = txt_post_process_none; proc_ch_default = 'n'; break; case POST_PROC_SHAR: str = txt_post_process_sh; proc_ch_default = 's'; break; case POST_PROC_UUDECODE: str = txt_post_process_uudecode; proc_ch_default = 'u'; break; case POST_PROC_UUD_LST_ZOO: str = txt_post_process_uud_lst_zoo; proc_ch_default = '1'; break; case POST_PROC_UUD_EXT_ZOO: str = txt_post_process_uud_ext_zoo; proc_ch_default = '2'; break; case POST_PROC_UUD_LST_ZIP: str = txt_post_process_uud_lst_zip; proc_ch_default = '3'; break; case POST_PROC_UUD_EXT_ZIP: str = txt_post_process_uud_ext_zip; proc_ch_default = '4'; break; } CleartoEOLN (); fputs (str, stdout); fflush (stdout); } break; case 15: var_orig = default_sort_art_type; show_menu_help (txt_help_sort_type); do { MoveCursor (INDEX_TOP+10, COL1 + (int) strlen (txt_opt_sort_type)); if ((ch = ReadCh()) == ' ') { if (default_sort_art_type + 1 > SORT_BY_DATE_ASCEND) { default_sort_art_type = SORT_BY_NOTHING; } else { default_sort_art_type++; } switch (default_sort_art_type) { case SORT_BY_NOTHING: str = txt_sort_by_nothing; break; case SORT_BY_SUBJ_DESCEND: str = txt_sort_by_subj_descend; break; case SORT_BY_SUBJ_ASCEND: str = txt_sort_by_subj_ascend; break; case SORT_BY_FROM_DESCEND: str = txt_sort_by_from_descend; break; case SORT_BY_FROM_ASCEND: str = txt_sort_by_from_ascend; break; case SORT_BY_DATE_DESCEND: str = txt_sort_by_date_descend; break; case SORT_BY_DATE_ASCEND: str = txt_sort_by_date_ascend; break; } CleartoEOLN (); fputs (str, stdout); fflush (stdout); } } while (ch != CR && ch != ESC); if (ch == ESC) { /* restore original value */ default_sort_art_type = var_orig; switch (default_sort_art_type) { case SORT_BY_NOTHING: str = txt_sort_by_nothing; break; case SORT_BY_SUBJ_DESCEND: str = txt_sort_by_subj_descend; break; case SORT_BY_SUBJ_ASCEND: str = txt_sort_by_subj_ascend; break; case SORT_BY_FROM_DESCEND: str = txt_sort_by_from_descend; break; case SORT_BY_FROM_ASCEND: str = txt_sort_by_from_ascend; break; case SORT_BY_DATE_DESCEND: str = txt_sort_by_date_descend; break; case SORT_BY_DATE_ASCEND: str = txt_sort_by_date_ascend; break; } CleartoEOLN (); fputs (str, stdout); fflush (stdout); } break; #ifndef AMIGA_BBS case 16: show_menu_help (txt_help_savedir); prompt_menu_string (INDEX_TOP+12, COL1 + (int) strlen (txt_opt_savedir), default_savedir); expand_rel_abs_pathname (INDEX_TOP+12, COL1 + (int) strlen (txt_opt_savedir), default_savedir); break; case 17: show_menu_help (txt_help_maildir); prompt_menu_string (INDEX_TOP+14, COL1 + (int) strlen (txt_opt_maildir), default_maildir); expand_rel_abs_pathname (INDEX_TOP+14, COL1 + (int) strlen (txt_opt_maildir), default_maildir); break; case 18: show_menu_help (txt_help_printer); prompt_menu_string (INDEX_TOP+16, COL1 + (int) strlen (txt_opt_printer), default_printer); expand_rel_abs_pathname (INDEX_TOP+16, COL1 + (int) strlen (txt_opt_printer), default_printer); break; #endif /* AMIGA_BBS */ } show_menu_help (txt_select_rcfile_option); } } void show_rcfile_menu () { char *str = (char *) 0; ClearScreen (); center_line (0, TRUE, txt_options_menu); MoveCursor (INDEX_TOP, 0); printf ("%s%s\r\n\r\n", txt_opt_autosave, (default_auto_save ? "ON " : "OFF")); printf ("%s%s\r\n\r\n", txt_opt_confirm_action, (confirm_action ? "ON " : "OFF")); printf ("%s%s\r\n\r\n", txt_opt_pos_first_unread, (pos_first_unread ? "ON " : "OFF")); printf ("%s%s", txt_opt_thread_arts, (default_thread_arts ? "ON " : "OFF")); MoveCursor(INDEX_TOP, COL2); printf ("%s%s", txt_opt_start_editor_offset, (start_editor_offset ? "ON " : "OFF")); MoveCursor(INDEX_TOP+2, COL2); printf ("%s%s", txt_opt_draw_arrow, (draw_arrow_mark ? "ON " : "OFF")); MoveCursor(INDEX_TOP+4, COL2); printf ("%s%s", txt_opt_page_scroll, (full_page_scroll ? "ON " : "OFF")); MoveCursor(INDEX_TOP+6, COL2); printf ("%s%s", txt_opt_show_only_unread, (default_show_only_unread ? "ON " : "OFF")); MoveCursor(INDEX_TOP, COL3); printf ("%s%s", txt_opt_mark_saved_read, (mark_saved_read ? "ON " : "OFF")); MoveCursor(INDEX_TOP+2, COL3); printf ("%s%s", txt_opt_print_header, (print_header ? "ON " : "OFF")); MoveCursor(INDEX_TOP+4, COL3); printf ("%s%s", txt_opt_catchup_groups, (catchup_read_groups ? "ON " : "OFF")); MoveCursor(INDEX_TOP+6, COL3); printf ("%s%s", txt_opt_show_description, (show_description ? "ON " : "OFF")); MoveCursor(INDEX_TOP+8, COL1); switch (default_show_author) { case SHOW_FROM_NONE: str = txt_show_from_none; break; case SHOW_FROM_ADDR: str = txt_show_from_addr; break; case SHOW_FROM_NAME: str = txt_show_from_name; break; case SHOW_FROM_BOTH: str = txt_show_from_both; break; } printf ("%s%s", txt_opt_show_author, str); MoveCursor(INDEX_TOP+8, COL2); switch (default_post_proc_type) { case POST_PROC_NONE: str = txt_post_process_none; break; case POST_PROC_SHAR: str = txt_post_process_sh; break; case POST_PROC_UUDECODE: str = txt_post_process_uudecode; break; case POST_PROC_UUD_LST_ZOO: str = txt_post_process_uud_lst_zoo; break; case POST_PROC_UUD_EXT_ZOO: str = txt_post_process_uud_ext_zoo; break; case POST_PROC_UUD_LST_ZIP: str = txt_post_process_uud_lst_zip; break; case POST_PROC_UUD_EXT_ZIP: str = txt_post_process_uud_ext_zip; break; } printf ("%s%s\r\n\r\n", txt_opt_process_type, str); MoveCursor(INDEX_TOP+10, COL1); switch (default_sort_art_type) { case SORT_BY_NOTHING: str = txt_sort_by_nothing; break; case SORT_BY_SUBJ_DESCEND: str = txt_sort_by_subj_descend; break; case SORT_BY_SUBJ_ASCEND: str = txt_sort_by_subj_ascend; break; case SORT_BY_FROM_DESCEND: str = txt_sort_by_from_descend; break; case SORT_BY_FROM_ASCEND: str = txt_sort_by_from_ascend; break; case SORT_BY_DATE_DESCEND: str = txt_sort_by_date_descend; break; case SORT_BY_DATE_ASCEND: str = txt_sort_by_date_ascend; break; } printf ("%s%s\r\n\r\n", txt_opt_sort_type, str); #ifndef AMIGA_BBS printf ("%s%s\r\n\r\n", txt_opt_savedir, default_savedir); printf ("%s%s\r\n\r\n", txt_opt_maildir, default_maildir); printf ("%s%s\r\n\r\n", txt_opt_printer, default_printer); #endif /* AMIGA_BBS */ fflush(stdout); show_menu_help (txt_select_rcfile_option); MoveCursor (cLINES, 0); } /* * expand ~/News to /usr/username/News and print to screen */ void expand_rel_abs_pathname (line, col, str) int line; int col; char *str; { char buf[LEN]; if (str[0] == '~') { if (strlen (str) == 1) { strcpy (str, homedir); } else { joinpath (buf, homedir, str+2); strcpy (str, buf); } } MoveCursor (line, col); CleartoEOLN (); puts (str); fflush (stdout); } /* * show_menu_help */ void show_menu_help (help_message) char *help_message; { MoveCursor (cLINES-2, 0); CleartoEOLN (); center_line (cLINES-2, FALSE, help_message); } int match_boolean (line, pat, dst) char *line; char *pat; int *dst; { int patlen = strlen (pat); if (strncmp (line, pat, patlen) == 0) { *dst = (strncmp (&line[patlen], "ON", 2) == 0 ? TRUE : FALSE); return TRUE; } return FALSE; } int match_number (line, pat, dst) char *line; char *pat; int *dst; { int patlen = strlen (pat); if (strncmp (line, pat, patlen) == 0) { *dst = atoi (&line[patlen]); return TRUE; } return FALSE; } int match_string (line, pat, dst, dstlen) char *line; char *pat; char *dst; int dstlen; { char *ptr; int patlen = strlen (pat); if (strncmp (line, pat, patlen) == 0) { strncpy (dst, &line[patlen], dstlen); ptr = strchr (dst, '\n'); if (ptr != (char *) 0) { *ptr = '\0'; } return TRUE; } return FALSE; } /* * convert underlines to spaces in a string */ void quote_dash_to_space (s) char *s; { int i; for (i=0 ; i < strlen (s) ; i++) { if (s[i] == '_') { s[i] = ' '; } } } /* * convert spaces to underlines in a string */ char * quote_space_to_dash (s) char *s; { int i; static char ds[PATH_LEN]; for (i=0 ; i < strlen (s) ; i++) { (s[i] == ' ') ? (ds[i] = '_') : (ds[i] = s[i]); } ds[i] = '\0'; return ds; } ð*[SRC.TIN-1_22]README.;1+,j. //€ 4 -d0@î123KÿPWO 56Y<t…—7ÀJê‘—89 „ìø‘—G/€HªJÿThis is version 1.2 PL2 (patchlevel 2) of the tin newsreader. o Compiles & runs on Unix, AmigaDOS & OS/2 (Not finished). o Based more on Notes and tass than rn type newreaders. o Full screen, easy to use with on-line help at all levels. o Reads news locally (ie. /usr/spool/news) and/or via NNTP/INN/CD-ROM. o Supports the XOVER news overview index file standard. o Threads on Subject: and/or Archive-name: mail headers. o Five different operating levels: - Spooldir selection level (CD-ROM only) - Group selection level - Thread selection level - Article selection level - Article viewer o Same interface to mail, pipe, print and save articles. o Auto unpacking of multi-part shar & uuencoded articles. o Killing and auto-selection (hot) of articles. o History of user posted articles. o Reposting of articles from one newsgroup to another. o Batch mode to mail/save new news when user is on holiday. o Random signature generator on a per newsgroup basis. o Builtin NNTP mini-inews & clientlib.c o NNTP extensions XINDEX, XMOTD & XUSER to allow better admin. ------------------------------------------------------------------------------- Major improvements over tin 1.2 PL1 are the following: o Added more support for 386BSD machines. o Added more support for AmigaDOS machines. o Added more support for HPUX machines. o Added more support for Mips machines. o Added more support for OS/2 machines. o Added more support for Pyramid machines. o Added more support for u3b2 machines. o Added reconnection to timed out nntp server. o Added group description text to groupname when searching at top level. o Added auto-subscribe/unsubscribe to/from new newsgroups. o Added basic navigation with mouse when running in a xterm window. o Added support for INN nntplib functions (GetFQDN() & GetConfigValue()). o Added -n cmd line option to read only subscribed to groups from active. o Added automatic entry into group when it was selected via a number. o Added basic MIME support (by calling Metamail). o Added more checking for article forging. o Changed article checking routine to be less facist when checking groups. o Fixed slowdown when entering a group compared to earlier releases. o Fixed -I cmd line option to specfiy different index directory. o Fixed direct use of getcwd() instead of get_cwd() in misc.c o Fixed 'Article rejected' error message from external inews. o Fixed reading of Xref: lines in xover data that could cause SIGSEGV. o Fixed connecting to ANU news server that was causing SIGSEGV. o Fixed poll() routine that was being initialized with wrong parameters. o Fixed valid_artnum() routine to use a binary instead of linear search. o Fixed strfpath() routine that was returning bogus filenames from env vars. o Fixed Makefile 'make install' rule. ------------------------------------------------------------------------------- For info. about the AmigaDOS port read the README.AMI file. For info. about the OS/2 port read the README.OS2 file. For compilation and installation information read the INSTALL file. For more bug fixes, changes & additions read the CHANGES & TODO files. For info. about my NNTP patches read the README.NNTP & INSTALL.NNTP files. For ftp & non-ftp source & binary availability read the FTP file. For an internal overview of tin read the HACKERS file. ------------------------------------------------------------------------------- I wish to thank all the people that sent me bug fixes and comments (especially Bryan Dongray, Clifton Royston, John Schmitz & Mark Tomlinson). I still want to hear of any bug reports, gripes and comments but *PLEASE* read the INSTALL, TODO and tin.1 manual page before doing anything :-)!. Also please make sure you have the newest release of tin before reporting any problems to me. My time is limited and I don't want to have to backtrack to assist with an old problem when it may have already been fixed in the newest release. I read & reply to questions that are posted to news.software.readers Enjoy Iain (iain.lea@erlm.siemens.de) ð*[SRC.TIN-1_22]README.AMI;1+,k. //€ 4 {-d0@î123KÿPWO 56`¦kt…—7‡Nê‘—89 „ìø‘—G/€HªJÿThis is the Amiga port of TIN. To use it you will need to do the following: Have appropriate directories assigned (UULIB: UUNEWS:). Have these environment variables set: NODENAME USERNAME REALNAME HOME EDITOR TIN only works with a hierarchical news directory. This means you will need Dillon's UUCP1.16 or higher. TIN has been modified to work with Dillon's Sendmail & Postnews programs. These take different arguments from standard UNIX mail and news programs. With release 1.1 PL 9 of TIN two further environment variables can been defined: TIN_POST (default "uucp:c/postnews %s") and TIN_MAIL (default "uucp:c/sendmail <%s -f %s"). If you set these variables, you can configure TIN for any other news/mail system. The %s in TIN_POST gets replaced with a filename containing the news article. TIN_MAIL's first %s is a filename, the second is the userid of the person sending the mail, and the third (if present), is the userid of the recipient of the mail. Printing is now available. You will have to edit the .tin/tinrc file to enable it. The "default_printer" string should be set to "copy PIPE: PRT:" instead of its default setting. This option has not been added to the internal menu of configurable options. The editor you use with TIN should not return instantly, so if you are using CED or TTX (or probably some others too) you will need to also add in the appropriate options in the environment variable EDITOR (see script file below) which will force your editor to wait until you've quit the editor. Unless you have an editor which understands the argument +7 to mean "start editing at line 7", you should set "Editor Offset" in the configuration menu (type shift-M) to OFF. An example startup script is given here (I've renamed tin to tin.exe so you can call this script TIN): ---------------------------------- ; For WB2.0 users, the setenv's can be set's instead. This allows multiple ; users to run with their own names etc. WB1.3 users have to use setenv. setenv USERNAME fred setenv REALNAME "Fred Flinstone" setenv NODENAME bedrock ; This should be just your node name, not the ; entire domain. setenv HOME dh0:news ; wherever you want your news & index files ; stored setenv EDITOR c:ed stack 40000 ; TIN requires a large stack! actived ; create a new active file delete uulib:active rename uulib:newsactive uulib:active tin.exe ; start tin itself --------------------------------- Actived creates an "active" file. This is a standard file in Unix environments, but missing from DUUCP. Actived also sets the environment variable "TIN_GROUPS" to equal the number of newsgroups. This variable isn't necessary to run TIN, but allows TIN to save some memory. If you don't wish to run actived before TIN, you may wish to copy TIN_GROUPS to ENVARC: (WB 2.0+ !!). More options, and use of tin is explained in the file tin.nrf. (The standard manual page that comes with TIN). The following options have been disabled from the TIN source for the Amiga version: - Archive extraction. Note that 1.1 PL 9 has now enabled uudecoding and un-shar'ing of posted archives. This requires "uudecode" and "unshar" to be in the path. - Shell escape and piping to any shell command. - Ability to change News and Mail directories. - Re-reading of the active file while reading news has been disabled. So has updating index files in the background (-U option). These options were disabled partly to make TIN easier to port, but also to make it secure enough to run as a newsreader for a Bulletin Board. A TIND program (for creating/updating index files) exists, and is only any use on a BBS. To make TIN aware that you are using TIND to update the index, you must set the environment variable TIND (it doesn't matter what you set it to!). The index files are by default stored in the UUNEWS: directory, in a subdirectory called .index (as in UNIX). For performance reasons, you may wish to change the directory to a different drive. By setting the environment variable TIN_INDEX, you can force the index files to be stored in $TIN_INDEX/.index. Another two environment variables LINES and COLUMNS can be set to specify the size of your screen. Inside an Amiga window this isn't required, as TIN can query the window size, but once again, if you're running on anything other than the Amiga's console, this query string won't work. If TIN finds the LINES and COLUMNS environment variables set, it will not try to query the window size. If you are planning on using TIN in a multi-user environment, such as with a BBS, you should take a look at the companion archive to this one, which is called DLGTIN.LHA. Even though this has been set up explicitly for DLG, it contains executables and documentation which will be useful for any setup of this type. - Mark Tomlinson (mark@garden.equinox.gen.nz) Geoff McCaughan (geoff@satori.equinox.gen.nz) ð*[SRC.TIN-1_22]README.NNTP;1+,x.//€ 4ï-d0@î123KÿPWO56 Ùut…—7­¿Qê‘—89 „ìø‘—G/€HªJÿThis patch enables the TIN newsreader index files to be fetched from a NNTP server. The patch adds the following to the NNTP 1.5.11 server: o XINDEX command to retrieve tin style style group index files from the server. Syntax: XINDEX alt.sources o XOVERVIEW command to retrieve .overview style (a la Cnews) group index files from the server. Note: Tin will eventually be modified to use this format. Syntax: XOVERVIEW alt.sources o XMOTD command to display a news message of the day file from server. Syntax: XMOTD 921231 235959 o XUSER command to log tin clients username to nntp logfile. Syntax: XUSER Iain Lea o LIST SUBSCRIPTIONS command to retrieve list of newsgroups that first time user will be automatically subscribed to. Our users are auto subscribed to 120 groups from the 450 that we take. Groups are written 1 group per line in the file /usr/lib/news/subscriptions. Syntax: LIST SUBSCRIPTIONS o HELP command changed to list all the extensions. o Added comments /* */ around '#endif /* text */' to stop some compilers producing warnings about text after '#endif text'. For compile & install instructions read the file INSTALL.NNTP Enjoy Iain ð*[SRC.TIN-1_22]README.OS2;1+,l. //€ 4 -d0@î123KÿPWO 56€æ—t…—7 ¬—fê‘—89 „ìø‘—G/€HªJÿ°€hT~ TIN-1_22.BCKld[SRC.TIN-1_22]README.OS2;1 ˆ¯This is the OS/2 port of TIN. An executable version can be obtained from ftp.cdrom.com. To build TIN, you need the following: - IBM C Set/2 or Borland C++ for OS/2 - PDCurses 2.0 build for the compiler of your choice For the NNTP version of TIN: - IBM TCP/IP 1.2.1 CSD UN37938 or higher, - IBM TCP/IP 1.2.1 Programmers's Kit CSD UN37942 of higher, with modifications as outlined below. To run it you need: - set environment variables To read news via NNTP - TCP/IP access to an nntp server, - some free space on a HPFS or NFS volume (FAT will not work, due to 8.3 file name restriction) optional: - uudecode and uushar utilities Note: uudecode is posted regularly to comp.binaries.os2 in the "OS/2 Binaries Starter's Kit" by mykek@miller.cs.uwm.edu (OS/2 binaries moderator) Building TIN for OS/2 1. Make sure that all source files (*.c and *.h) have as their line-ends. If not, use 'unix2os2 < original >newfile' to correct this. 2. Select the makefile appropriate for your compiler: Makefile.bcc for Borland C++ for OS/2 Makefile.icc for IBM's C Set/2 Compiler Note: Borland C is prefered. You may have to make some adjustments when you use IBM's C. 3. Edit the makefile, changing location of include and library files to match your installation 4. Correct bugs in \tcpip\include\netdb.h find all occurrences of 'char *' that are not followed by '_Seg16' and add '_Seg16'. For example change SERVENT * _Seg16 _Far16 _Cdecl getservbyname( char *, char * ); to SERVENT * _Seg16 _Far16 _Cdecl getservbyname( char * _Seg16, char * _Seg16 ); You will also correct the prototype for getservbyport and getprotobyname. 5. If you are using Borland C++, edit the TCP/IP header files: in netdb.h, netlib.h sys/socket.h do the following: - find the #ifndef __32BIT__ near the top of each file - change the conditional section as follows: #ifndef __32BIT__ #ifdef __TURBOC__ #define _Packed #define _Seg16 _far16 #define _Far16 _far16 #define _Cdecl _cdecl #define __32BIT__ #else #define _Packed #define _Seg16 #define _Far16 #define _Cdecl #endif #endif - add the following below the second #endif #ifdef __TURBOC__ #define FAR16P _far16 * #else #define FAR16P * _Seg16 #endif - throughout the files change '* _Seg16' and '* _Seg16' to 'FAR16P' After these changes, the TCP/IP package can be used with the Borland C compiler. 6. If you are using Borland C++ type 'make -f makefile.bcc' If you are using IBM's C Set/2 type 'nmake -f makefile.icc' Ignore warnings, especially re _Cdecl and _Seg16 re-definition. Using TIN under OS/2 To run the local newsspool version, start TIN. To run the NNTP version, start TIN -r, or rename TIN.EXE to RTIN.EXE and run RTIN. TIN runs in an OS/2 windowed session. It is not a PM application. TIN needs to know who you are, in order to create headers for posts and mail correctly. There are two ways in which you can specify this information: - through environment variables - through a Unix-style passwd file Environment Variables If only one person is using TIN to post articles, set the following variables in your config.sys file: USER userid set USER=andreas REALNAME Your Full Name set REALNAME=Andreas Wrede HOME \your\home\directory set HOME=c:\home\andreas Note that you HOME directory must be on a HPFS or NFS disk. FAT will probably not work, due to the 8.3 file name restriction. Unix-style passwd file If a number of users use TIN to post articles, for example via telnet to the OS/2 machine, it might be easier to use the Unix-style passwd file. The passwd file is located in the directory set by the environment variable ETC, usually c:\tcpip\etc. The same passwd file is used by ftp and telnet (via loginunx.exe). See your TCP/IP User's Guide for more information. TIN does no use the password field, but the full user name, the home directory and the shell are taken from the passwd file entry. The environment variable USER is used to locate the correct entry in the passwd file. If it is not set, an error message is issued by TIN. Two sample passwd entries follow: andreas:x:1:1:Andreas Wrede:c:/home/andreas:c:/os2/cmd.exe guest:x:2:2:Guest User:c:/home/guest:d:/ksh/ksh Other Environment Variables Required for NNTP version: NNTPSERVER - either the fully qualified domain name of the nntp server or the dotted internet address of the nntp server. HOSTNAME - specifies the name of your machine. It is used to identify your machine to the nntp server. Required for local newspool version: TIN_SPOOLDIR - path to the root of the news spool TIN_LIBDIR - path to news control: active file, newsgroups file etc. TIN_NOVROOTDIR - path to overview files Optional: LINES - specify how many lines you display window has. If LINES is not set, TIN will use the actual height of the display window. You might need to set this if you run TIN from a telnet session. EDITOR - VISUAL - specify the editor to use for composing articles and replies. Defaults to 'epm'. SHELL - specify command process to use for shell escapes - defaults to whatever is set by COMSPEC For other environment variables, see ENVIRONMENT VARIABLES in tin.man. Enjoy! Andreas Wrede (andreas@scilink.org) ð*[SRC.TIN-1_22]SAVE.C;11+,Ù.?//€ 4?>ð-d0@î123KÿPWO@56à¤ýh¯‹—7 ènj¯‹—89€]V‚—G/€HªJÿb/* * Project : tin - a Usenet reader * Module : save.c * Author : I.Lea & R.Skrenta * Created : 01-04-91 * Updated : 22-08-93 * Notes : * Copyright : (c) Copyright 1991-93 by Iain Lea & Rich Skrenta * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" #define INITIAL 1 #define MIDDLE 2 #define OFF 3 #define END 4 #ifndef VMS extern int errno; #endif int create_subdir = TRUE; /* * types of archive programs */ struct archiver_t { char *name; char *ext; char *test; char *list; char *extract; } archiver[] = { { "", "", "", "", "" }, { "", "", "", "", "" }, { "", "", "", "", "" }, #ifdef M_AMIGA { "lha", "lha", "t", "l", "x" }, #else { "zoo", "zoo", "-test", "-list", "-extract" }, #endif { "unzip", "zip", "-t", "-l", "-o" }, { (char *) 0, (char *) 0, (char *) 0, (char *) 0, (char *) 0 } }; extern char *glob_group; extern char note_h_path[LEN]; /* Path: */ extern char note_h_date[PATH_LEN]; /* Date: */ extern FILE *note_fp; /* the body of the current article */ extern int index_point; extern int note_end; extern int note_page; extern long note_mark[MAX_PAGES]; /* * Check for articles and say how many new/unread in each group. * or * Start if new/unread articles and return first group with new/unread. * or * Save any new articles to savedir and mark arts read and mail user * and inform how many arts in which groups were saved. * or * Mail any new articles to specified user and mark arts read and mail * user and inform how many arts in which groups were mailed. */ int check_start_save_any_news (check_start_save) int check_start_save; { #ifndef INDEX_DAEMON char buf[LEN], logfile[LEN]; char group_path[PATH_LEN]; char savefile[PATH_LEN]; char path[PATH_LEN]; extern FILE *note_fp; FILE *fp = (FILE *) 0; FILE *fp_log = (FILE *) 0; int i, j, k, print_group; int check_arts = 0; int log_opened = TRUE; int print_first = TRUE; int saved_arts = 0; int saved_groups = 0; int unread_news = FALSE; long epoch; switch (check_start_save) { case CHECK_ANY_NEWS: case START_ANY_NEWS: if (verbose) { wait_message (txt_checking_for_news); } break; case MAIL_ANY_NEWS: case SAVE_ANY_NEWS: joinpath (logfile, rcdir, "log"); #ifdef VMS if ((fp_log = fopen (logfile, "w", "fop=cif")) == NULL) { #else if ((fp_log = fopen (logfile, "w")) == NULL) { #endif perror_message (txt_cannot_open, logfile); fp_log = stdout; verbose = FALSE; log_opened = FALSE; } time (&epoch); fprintf (fp_log, "To: %s\n", userid); fprintf (fp_log, "Subject: NEWS LOG %s\n", ctime (&epoch)); break; } for (i = 0; i < group_top; i++) { make_group_path (active[my_group[i]].name, group_path); if (! index_group (active[my_group[i]].name, group_path)) { continue; } read_newsrc_line (active[my_group[i]].name); print_group = TRUE; check_arts = 0; for (j = 0; j < top; j++) { if (arts[j].unread == ART_UNREAD) { switch (check_start_save) { case CHECK_ANY_NEWS: if (print_first && verbose) { fputc ('\n', stdout); print_first = FALSE; } check_arts++; break; case START_ANY_NEWS: return i; /* return first group with unread news */ /* NOTREACHED */ case MAIL_ANY_NEWS: case SAVE_ANY_NEWS: if (print_group) { sprintf (buf, "Saved %s...\n", active[my_group[i]].name); fprintf (fp_log, "%s", buf); if (verbose) { wait_message (buf); } print_group = FALSE; saved_groups++; if (check_start_save == SAVE_ANY_NEWS) { joinpath (buf, group_path, "dummy"); create_path (buf); } } if (check_start_save == MAIL_ANY_NEWS) { sprintf (savefile, "%stin.%d", TMPDIR, process_id); } else { k = my_group[cur_groupnum]; if (! strfpath (active[k].attribute.savedir, path, sizeof (path), homedir, (char *) 0, (char *) 0, active[k].name)) { joinpath (path, homedir, DEFAULT_SAVEDIR); } sprintf (savefile, "%s/%s/%ld", path, group_path, arts[j].artnum); } note_page = art_open (arts[j].artnum, group_path); if (note_page == ART_UNAVAILABLE) { continue; } #ifdef VMS if ((fp = fopen (savefile, "w", "fop=cif")) == NULL) { #else if ((fp = fopen (savefile, "w")) == NULL) { #endif fprintf (fp_log, txt_cannot_open, savefile); if (verbose) { perror_message (txt_cannot_open, savefile); } continue; } if (check_start_save == MAIL_ANY_NEWS) { fprintf (fp, "To: %s\n", mail_news_user); } sprintf (buf, "[%5ld] %s\n", arts[j].artnum, arts[j].subject); fprintf (fp_log, "%s", buf); if (verbose) { wait_message (buf); } fseek (note_fp, 0L, 0); copy_fp (note_fp, fp, ""); art_close (); fclose (fp); saved_arts++; if (check_start_save == MAIL_ANY_NEWS) { #ifdef M_AMIGA sprintf (buf, mailer, savefile, userid, mail_news_user); #else sprintf (buf, "%s \"%s\" < %s", mailer, mail_news_user, savefile); #endif /* M_AMIGA */ if (! invoke_cmd (buf)) { error_message (txt_command_failed_s, buf); } unlink (savefile); } if (catchup) { arts[j].unread = ART_READ; } break; } } } if (check_start_save == MAIL_ANY_NEWS || check_start_save == SAVE_ANY_NEWS) { if (catchup) { update_newsrc (active[my_group[i]].name, my_group[i], FALSE); } } else { if (check_arts) { if (verbose) { sprintf (buf, "%4d unread articles in %s\n", check_arts, active[my_group[i]].name); wait_message (buf); } unread_news = TRUE; } } } switch (check_start_save) { case CHECK_ANY_NEWS: if (unread_news) { return 2; } else { if (verbose) { wait_message (txt_there_is_no_news); } return 0; } /* NOTREACHED */ case START_ANY_NEWS: wait_message (txt_there_is_no_news); return -1; /* NOTREACHED */ case MAIL_ANY_NEWS: case SAVE_ANY_NEWS: sprintf (buf, "\n%s %d article(s) from %d group(s)\n", (check_start_save == MAIL_ANY_NEWS ? "Mailed" : "Saved"), saved_arts, saved_groups); fprintf (fp_log, "%s", buf); if (verbose) { wait_message (buf); } if (log_opened) { fclose (fp_log); if (verbose) { sprintf (buf, "Mailing log to %s\n", (check_start_save == MAIL_ANY_NEWS ? mail_news_user : userid)); wait_message (buf); } #ifdef M_AMIGA sprintf (buf, mailer, logfile, userid, (check_start_save == MAIL_ANY_NEWS ? mail_news_user : userid)); #else sprintf (buf, "%s \"%s\" < %s", mailer, (check_start_save == MAIL_ANY_NEWS ? mail_news_user : userid), logfile); #endif /* M_AMIGA */ if (! invoke_cmd (buf)) { error_message (txt_command_failed_s, buf); } } break; } #endif /* INDEX_DAEMON */ return 0; } int save_art_to_file (respnum, index, mailbox, filename) int respnum; int index; int mailbox; char *filename; { #ifndef INDEX_DAEMON char file[PATH_LEN]; char save_art_info[LEN]; FILE *fp; int is_mailbox = FALSE; int i = 0, ret_code = FALSE; long epoch; if (debug == 2) { sprintf (msg, "Save respnum=[%d] index=[%d] mbox=[%d] file=[%s]", respnum, index, mailbox, filename); error_message (msg, ""); } if (strlen (filename)) { my_strncpy (file, filename, sizeof (file)); is_mailbox = mailbox; i = index; } else if (default_auto_save && arts[respnum].archive) { my_strncpy (file, arts[respnum].archive, sizeof (file)); } if (! append_to_existing_file (i)) { save[i].saved = FALSE; info_message (txt_art_not_saved); sleep (1); return (ret_code); } if (debug == 2) { error_message ("Save file=[%s]", save_filename (i)); sleep (3); } if ((fp = fopen (save_filename (i), "a+")) == NULL) { save[i].saved = FALSE; info_message (txt_art_not_saved); return (ret_code); } time (&epoch); fprintf (fp, "From %s %s", note_h_path, ctime (&epoch)); if (fseek (note_fp, 0L, 0) == -1) { perror_message ("fseek() error on [%s]", arts[respnum].subject); } copy_fp (note_fp, fp, ""); print_art_seperator_line (fp, mailbox); fclose (fp); fseek (note_fp, note_mark[note_page], 0); save[i].saved = TRUE; if (filename == (char *) 0) { if (is_mailbox) { sprintf (save_art_info, txt_saved_to_mailbox, get_first_savefile ()); } else { sprintf (save_art_info, txt_art_saved_to, get_first_savefile ()); } info_message (save_art_info); } #endif /* INDEX_DAEMON */ return TRUE; } int save_thread_to_file (is_mailbox, group_path) int is_mailbox; char *group_path; { #ifndef INDEX_DAEMON char file[PATH_LEN]; char save_thread_info[LEN]; char *first_savefile; int count = 0; int i, ret_code = FALSE; for (i=0 ; i < num_save ; i++) { sprintf (msg, "%s%d", txt_saving, ++count); wait_message (msg); if (is_mailbox) { file[0] = 0; }else { sprintf (file, "%s.%02d", save[i].file, i+1); } note_page = art_open (arts[save[i].index].artnum, group_path); if (note_page != ART_UNAVAILABLE) { ret_code = save_art_to_file (save[i].index, i, is_mailbox, file); art_close (); } } first_savefile = get_first_savefile (); if (first_savefile == (char *) 0) { info_message (txt_thread_not_saved); } else { if (is_mailbox) { sprintf (save_thread_info, txt_saved_to_mailbox, first_savefile); } else { if (num_save == 1) { sprintf (save_thread_info, txt_art_saved_to, first_savefile); } else { sprintf (save_thread_info, txt_thread_saved_to_many, first_savefile, get_last_savefile ()); } if (first_savefile != (char *) 0) { free (first_savefile); first_savefile = (char *) 0; } } info_message (save_thread_info); sleep (2); } #endif /* INDEX_DAEMON */ return TRUE; } int save_regex_arts (is_mailbox, group_path) int is_mailbox; char *group_path; { #ifndef INDEX_DAEMON char buf[PATH_LEN]; int i, ret_code = FALSE; for (i=0 ; i < num_save ; i++) { sprintf(msg, "%s%d", txt_saving, i+1); wait_message (msg); if (is_mailbox) { buf[0] = 0; }else { sprintf (buf, "%s.%02d", save[i].file, i+1); } note_page = art_open (arts[save[i].index].artnum, group_path); if (note_page != ART_UNAVAILABLE) { ret_code = save_art_to_file (save[i].index, i, is_mailbox, buf); art_close (); } } if (! num_save) { info_message (txt_no_match); } else { if (is_mailbox) { sprintf (buf, txt_saved_to_mailbox, get_first_savefile ()); } else { sprintf (buf,txt_saved_pattern_to, get_first_savefile (), get_last_savefile ()); } info_message (buf); } return (ret_code); #else return (FALSE); #endif /* INDEX_DAEMON */ } int append_to_existing_file (i) int i; { #ifndef INDEX_DAEMON char buf[LEN]; char *file; struct stat st; if (! save[i].is_mailbox) { file = save_filename (i); if (stat(file, &st) != -1) { sprintf (buf, txt_append_to_file, file); if (! prompt_yn (cLINES, buf, 'n')) { if (file != (char *) 0) { free (file); file = (char *) 0; } return FALSE; } } if (file != (char *) 0) { free (file); file = (char *) 0; } } #endif /* INDEX_DAEMON */ return TRUE; } int create_path (path) char *path; { int mbox_format = FALSE; #ifndef INDEX_DAEMON char tmp[PATH_LEN]; char buf[PATH_LEN]; int i, j, len = 0; struct stat st; i = my_group[cur_groupnum]; /* * expand "$var..." first, so variables starting with * '+', '$' or '=' will be processed correctly later */ #ifndef VMS if (path[0] == '$') { if (strfpath (path, buf, sizeof (buf), homedir, (char *) 0, (char *) 0, active[i].name)) { my_strncpy (path, buf, PATH_LEN); } } #endif /* * save in mailbox format to ~/Mail/ or * attribute.maildir for current group */ if (path[0] == '=') { mbox_format = TRUE; strcpy (tmp, path); if (! strfpath (active[i].attribute.maildir, buf, sizeof (buf), homedir, (char *) 0, (char *) 0, active[i].name)) { #ifdef VMS joindir (buf, homedir, DEFAULT_MAILDIR); #else joinpath (buf, homedir, DEFAULT_MAILDIR); #endif } joinpath (path, buf, "dummy"); } else { #ifdef VMS if (! strchr ("~=+/.", path[0])) { #else if (! strchr ("~$=+/.", path[0])) { #endif if (! strfpath (active[i].attribute.savedir, buf, sizeof (buf), homedir, (char *) 0, (char *) 0, active[i].name)) { #ifdef VMS joindir (buf, homedir, DEFAULT_SAVEDIR); #else joinpath (buf, homedir, DEFAULT_SAVEDIR); #endif } joinpath (tmp, buf, path); my_strncpy (path, tmp, PATH_LEN); } if (strfpath (path, buf, sizeof (buf), homedir, (char *) 0, active[i].attribute.savedir, active[i].name)) { my_strncpy (path, buf, PATH_LEN); } } #ifndef VMS /* no good answer to this yet XXX */ /* * create any directories, otherwise check * errno and give appropiate error message */ len = (int) strlen (path); for (i=0, j=0 ; i < len ; i++, j++) { buf[j] = path[i]; if (i+1 < len && path[i+1] == '/') { buf[j+1] = '\0'; if (stat (buf, &st) == -1) { if (my_mkdir (buf, 0755) == -1) { if (errno != EEXIST) { perror_message ("Cannot create %s", buf); return FALSE; } } } } } #endif if (mbox_format) { strcpy (path, tmp); } #endif /* INDEX_DAEMON */ return (mbox_format); } int create_sub_dir (i) int i; { #ifndef INDEX_DAEMON char dir[LEN]; struct stat st; if (! save[i].is_mailbox && save[i].archive) { joinpath (dir, save[i].dir, save[i].archive); if (stat (dir, &st) == -1) { my_mkdir (dir, 0755); return TRUE; } #ifdef M_AMIGA if (st.st_attr & ST_DIRECT) { #else # ifdef M_OS2 if (st.st_mode & S_IFDIR) { # else if ((st.st_mode & S_IFMT) == S_IFDIR) { # endif #endif return TRUE; } else { return FALSE; } } #endif /* INDEX_DAEMON */ return FALSE; } /* * add files to be saved to save array */ void add_to_save_list (index, article, is_mailbox, archive_save, path) int index; struct t_article *article; int is_mailbox; int archive_save; char *path; { #ifndef INDEX_DAEMON char tmp[PATH_LEN]; char dir[PATH_LEN]; char file[PATH_LEN]; int i; dir[0] = '\0'; file[0] = '\0'; if (num_save == max_save-1) { expand_save (); } save[num_save].index = index; save[num_save].saved = FALSE; save[num_save].is_mailbox = is_mailbox; save[num_save].dir = (char *) 0; save[num_save].file = (char *) 0; save[num_save].archive = (char *) 0; save[num_save].part = (char *) 0; save[num_save].patch = (char *) 0; save[num_save].subject = str_dup (article->subject); if (archive_save && article->archive) { save[num_save].archive = str_dup (article->archive); if (article->part) { save[num_save].part = str_dup (article->part); } if (article->patch) { save[num_save].patch = str_dup (article->patch); } } if (is_mailbox) { if ((int) strlen (path) > 1) { if (path[0] == '=') { my_strncpy (file, path+1, sizeof (file)); } else { my_strncpy (file, path, sizeof (file)); } } else { my_strncpy (file, glob_group, sizeof (file)); } i = my_group[cur_groupnum]; if (! strfpath (active[i].attribute.maildir, tmp, sizeof (tmp), homedir, (char *) 0, (char *) 0, active[i].name)) { #ifdef VMS joindir (tmp, homedir, DEFAULT_MAILDIR); #else joinpath (tmp, homedir, DEFAULT_MAILDIR); #endif } save[num_save].dir = str_dup (tmp); save[num_save].file = str_dup (file); } else { if (path[0]) { #ifdef VMS #include "parse.h" struct filespec *spec; spec = sysparse(path); sprintf(dir, "%s%s", spec->dev, spec->dir); strcpy(file, spec->filename); #else for (i=strlen (path) ; i ; i--) { if (path[i] == '/') { strncpy (dir, path, i); dir[i] = '\0'; strcpy (file, path+i+1); break; } } #endif } if (dir[0]) { save[num_save].dir = str_dup (dir); } else { i = my_group[cur_groupnum]; if (! strfpath (active[i].attribute.savedir, tmp, sizeof (tmp), homedir, (char *) 0, (char *) 0, active[i].name)) { joinpath (tmp, homedir, DEFAULT_SAVEDIR); } save[num_save].dir = str_dup (tmp); } if (file[0]) { save[num_save].file = str_dup (file); } else { if (path[0]) { save[num_save].file = str_dup (path); } else { save[num_save].file = str_dup (save[num_save].archive); } } } num_save++; #endif /* INDEX_DAEMON */ } /* * print save array of files to be saved */ void sort_save_list () { qsort ((char *) save, num_save, sizeof (struct t_save), save_comp); debug_save_comp (); } /* * string comparison routine for the qsort() * ie. qsort(array, 5, 32, save_comp); */ int save_comp (p1, p2) t_comptype *p1; t_comptype *p2; { struct t_save *s1 = (struct t_save *) p1; struct t_save *s2 = (struct t_save *) p2; /* * Sort on Archive-name: part & patch otherwise Subject: */ if (s1->archive != (char *) 0) { if (s1->part != (char *) 0) { if (s2->part != (char *) 0) { if (strcmp (s1->part, s2->part) < 0) { return -1; } if (strcmp (s1->part, s2->part) > 0) { return 1; } } else { return 0; } } else if (s1->patch != (char *) 0) { if (s2->patch != (char *) 0) { if (strcmp (s1->patch, s2->patch) < 0) { return -1; } if (strcmp (s1->patch, s2->patch) > 0) { return 1; } } else { return 0; } } } else { if (strcmp (s1->subject, s2->subject) < 0) { return -1; } if (strcmp (s1->subject, s2->subject) > 0) { return 1; } } return 0; } char * save_filename (i) int i; { char *filename; filename = (char *) my_malloc (PATH_LEN); if (save[i].is_mailbox) { joinpath(filename, save[i].dir, save[i].file); return (filename); } if (! default_auto_save || (! save[i].part && ! save[i].patch)) { if (num_save == 1) { joinpath (filename, save[i].dir, save[i].file); } else { #ifdef VMS char tbuf[256]; sprintf(tbuf, "%s.%02d", save[i].file, i+1); joinpath (filename, save[i].dir, tbuf); #else sprintf (filename, "%s/%s.%02d", save[i].dir, save[i].file, i+1); #endif } } else { if (save[i].part) { if (create_sub_dir (i)) { #ifdef VMS char fbuf[256], dbuf[256]; sprintf(fbuf, "%s.%s%s", save[i].archive, LONG_PATH_PART, save[i].part); joindir(dbuf, save[i].dir, save[i].archive); joinpath(filename, dbuf, fbuf); #else sprintf (filename, "%s/%s/%s.%s%s", save[i].dir, save[i].archive, save[i].archive, LONG_PATH_PART, save[i].part); #endif } else { #ifdef VMS char fbuf[256]; sprintf(fbuf, "%s.%s%s", save[i].archive, LONG_PATH_PART, save[i].part); joinpath(filename, save[i].dir, fbuf); #else sprintf (filename, "%s/%s.%s%s", save[i].dir, save[i].archive, LONG_PATH_PART, save[i].part); #endif } } else { if (save[i].patch) { if (create_sub_dir (i)) { #ifdef VMS char fbuf[256], dbuf[256]; sprintf(fbuf, "%s.%s%s", save[i].archive, LONG_PATH_PATCH, save[i].patch); joindir(dbuf, save[i].dir, save[i].archive); joinpath(filename, dbuf, fbuf); #else sprintf (filename, "%s/%s/%s.%s%s", save[i].dir, save[i].archive, save[i].archive, LONG_PATH_PATCH, save[i].patch); #endif } else { #ifdef VMS char fbuf[256]; sprintf(fbuf, "%s.%s%s", save[i].archive, LONG_PATH_PATCH, save[i].patch); joinpath(filename, save[i].dir, fbuf); #else sprintf (filename, "%s/%s.%s%s", save[i].dir, save[i].archive, LONG_PATH_PATCH, save[i].patch); #endif } } else { joinpath (filename, save[i].dir, save[i].file); } } } return (filename); } char * get_first_savefile () { char *file; int i; for (i=0 ; i < num_save ; i++) { if (save[i].saved) { file = (char *) my_malloc (PATH_LEN); if (save[i].is_mailbox) { joinpath (file, save[i].dir, save[i].file); return (file); } else { if (save[i].archive && default_auto_save) { if (save[i].part) { if (create_subdir) { #ifdef VMS char fbuf[256], dbuf[256]; sprintf(fbuf, "%s.%s%s", save[i].archive, LONG_PATH_PART, save[i].part); joinpath(file, save[i].archive, fbuf); #else sprintf (file, "%s/%s.%s%s", save[i].archive, save[i].archive, LONG_PATH_PART, save[i].part); #endif } else { sprintf (file, "%s.%s%s", save[i].archive, LONG_PATH_PART, save[i].part); } } else { if (create_subdir) { #ifdef VMS char fbuf[256]; sprintf(fbuf, "%s.%s%s", save[i].archive, LONG_PATH_PATCH, save[i].patch); joinpath(file, save[i].archive, fbuf); #else sprintf (file, "%s/%s.%s%s", save[i].archive, save[i].archive, LONG_PATH_PATCH, save[i].patch); #endif } else { sprintf (file, "%s.%s%s", save[i].archive, LONG_PATH_PATCH, save[i].patch); } } } else { if (num_save == 1) { sprintf (file, "%s", save[i].file); } else { sprintf (file, "%s.%02d", save[i].file, i+1); } } return (file); } } } return ((char *) 0); } char * get_last_savefile () { char *file; int i; for (i=num_save-1 ; i >= 0 ; i--) { if (save[i].saved) { file = (char *) my_malloc (PATH_LEN); if (save[i].is_mailbox) { joinpath(file, save[i].dir, save[i].file); return (file); } else { if (save[i].archive && default_auto_save) { if (save[i].part) { if (create_subdir) { #ifdef VMS char fbuf[256]; sprintf(fbuf, "%s.%s%s", save[i].archive, LONG_PATH_PART, save[i].part); joinpath(file, save[i].archive, fbuf); #else sprintf (file, "%s/%s.%s%s", save[i].archive, save[i].archive, LONG_PATH_PART, save[i].part); #endif } else { sprintf (file, "%s.%s%s", save[i].archive, LONG_PATH_PART, save[i].part); } } else { if (create_subdir) { #ifdef VMS char fbuf[256]; sprintf(fbuf, "%s.%s%s", save[i].archive, LONG_PATH_PATCH, save[i].patch); joinpath(file, save[i].archive, fbuf); #else sprintf (file, "%s/%s.%s%s", save[i].archive, save[i].archive, LONG_PATH_PATCH, save[i].patch); #endif } else { sprintf (file, "%s.%s%s", save[i].archive, LONG_PATH_PATCH, save[i].patch); } } } else { if (num_save == 1) { sprintf (file, "%s", save[i].file); } else { sprintf (file, "%s.%02d", save[i].file, i+1); } } return (file); } } } return ((char *) 0); } int post_process_files (proc_type_ch) int proc_type_ch; { if (num_save) { wait_message (txt_post_processing); switch (proc_type_ch) { case 's': post_process_sh (); break; case 'u': post_process_uud (POST_PROC_UUDECODE); break; case 'l': post_process_uud (POST_PROC_UUD_LST_ZOO); break; case 'e': post_process_uud (POST_PROC_UUD_EXT_ZOO); break; case 'L': post_process_uud (POST_PROC_UUD_LST_ZIP); break; case 'E': post_process_uud (POST_PROC_UUD_EXT_ZIP); break; } info_message (txt_post_processing_finished); sleep (1); return TRUE; } return FALSE; } void post_process_uud (pp) int pp; { #ifndef INDEX_DAEMON char s[LEN], t[LEN], u[LEN]; char buf[LEN], *file, *ptr; char file_out[PATH_LEN]; char file_out_dir[PATH_LEN]; FILE *fp_in, *fp_out; int i, state = INITIAL; int file_size = 0; struct stat st; t[0] = '\0'; u[0] = '\0'; my_strncpy (file_out_dir, save_filename (0), sizeof (file_out_dir)); for (i=strlen(file_out_dir) ; i > 0 ; i--) { if (file_out_dir[i] == '/') { file_out_dir[i] = '\0'; break; } } joinpath (file_out, file_out_dir, process_id); if ((fp_out = fopen (file_out, "a+")) == NULL) { perror_message (txt_cannot_open, file_out); } for (i=0 ; i < num_save ; i++) { my_strncpy (buf, save_filename (i), sizeof (buf)); if ((fp_in = fopen (buf, "r")) != NULL) { if (fgets (s, sizeof s, fp_in) == NULL) { fclose (fp_in); continue; } while (state != END) { switch (state) { case INITIAL: if (! strncmp ("begin", s, 5)) { state = MIDDLE; fprintf (fp_out, "%s", s); } break; case MIDDLE: if (s[0] == 'M') { fprintf (fp_out, "%s", s); } else if (strncmp("end", s, 3)) { state = OFF; } else { /* end */ state = END; if (u[0] != 'M') { fprintf (fp_out, "%s", u); } if (t[0] != 'M') { fprintf (fp_out, "%s", t); } fprintf (fp_out, "%s\n", s); } break; case OFF: if ((s[0] == 'M') && (t[0] == 'M') && (u[0] == 'M')) { fprintf (fp_out, "%s", u); fprintf (fp_out, "%s", t); fprintf (fp_out, "%s", s); state = MIDDLE; } else if (! strncmp ("end",Às/Ž‡~ TIN-1_22.BCKÙd[SRC.TIN-1_22]SAVE.C;11?׊2 s, 3)) { state = END; if (u[0] != 'M') { fprintf (fp_out, "%s", u); } if (t[0] != 'M') { fprintf (fp_out, "%s", t); } fprintf (fp_out, "%s\n", s); } break; case END: break; default: fprintf (stderr, "\r\nerror: ASSERT - default state\n"); fclose (fp_in); fclose (fp_out); unlink (file_out); return; } strcpy (u,t); strcpy (t,s); /* * read next line & if error goto next file in save array */ if (fgets (s, sizeof s, fp_in) == NULL) { break; } } fclose (fp_in); } } fclose (fp_out); /* * uudecode file */ wait_message (txt_uudecoding); #if !defined(M_UNIX) make_post_process_cmd (DEFAULT_UUDECODE, file_out_dir, file_out); #else sprintf (buf, "cd %s; uudecode %s", file_out_dir, file_out); if (invoke_cmd (buf)) { /* * Sum file */ if ((file = get_archive_file (file_out_dir, "*")) != (char *) 0) { sprintf (buf, "%s %s", DEFAULT_SUM, file); printf (txt_checksum_of_file, file); fflush (stdout); if ((fp_in = (FILE *) popen (buf, "r")) == NULL) { printf ("Cannot execute %s\r\n", buf); fflush (stdout); } else { if (stat (file, &st) != -1) { file_size = (int) st.st_size; } if (fgets (buf, sizeof buf, fp_in) != NULL) { ptr = strchr (buf, '\n'); if (ptr != (char *) 0) { *ptr = '\0'; } } pclose (fp_in); printf ("%s %8d bytes\r\n", buf, file_size); fflush (stdout); } if (pp > POST_PROC_UUDECODE) { /* * Test archive integrity */ if (pp > POST_PROC_UUDECODE && archiver[pp].test != (char *) 0) { i = (pp == POST_PROC_UUD_LST_ZOO || pp == POST_PROC_UUD_EXT_ZOO ? 3 : 4); sprintf (buf, "cd %s; %s %s %s", file_out_dir, archiver[i].name, archiver[i].test, file); printf (txt_testing_archive, file); fflush (stdout); if (! invoke_cmd (buf)) { error_message (txt_post_processing_failed, ""); } } /* * List archive */ if (pp == POST_PROC_UUD_LST_ZOO || pp == POST_PROC_UUD_LST_ZIP) { i = (pp == POST_PROC_UUD_LST_ZOO ? 3 : 4); sprintf (buf, "cd %s; %s %s %s", file_out_dir, archiver[i].name, archiver[i].list, file); printf (txt_listing_archive, file); fflush (stdout); if (! invoke_cmd (buf)) { error_message (txt_post_processing_failed, ""); } sleep (3); } /* * Extract archive */ if (pp == POST_PROC_UUD_EXT_ZOO || pp == POST_PROC_UUD_EXT_ZIP) { i = (pp == POST_PROC_UUD_EXT_ZOO ? 3 : 4); sprintf (buf, "cd %s; %s %s %s", file_out_dir, archiver[i].name, archiver[i].extract, file); printf (txt_extracting_archive, file); fflush (stdout); if (! invoke_cmd (buf)) { error_message (txt_post_processing_failed, ""); } sleep (3); } if (file != (char *) 0) { free (file); file = (char *) 0; } } } } #endif /* M_UNIX */ delete_processed_files (); unlink (file_out); #endif /* INDEX_DAEMON */ } /* * Unpack /bin/sh archives */ void post_process_sh () { #ifndef INDEX_DAEMON char buf[LEN]; char file_in[PATH_LEN]; char file_out[PATH_LEN]; char file_out_dir[PATH_LEN]; char *ptr1, *ptr2; char sh_pattern_1[16]; char sh_pattern_2[16]; FILE *fp_in, *fp_out; int found_header; int i, j; int patlen1, patlen2; strcpy (sh_pattern_1, "#! /bin/sh"); strcpy (sh_pattern_2, "#!/bin/sh"); my_strncpy (file_out_dir, save_filename (0), sizeof (file_out_dir)); for (i=strlen(file_out_dir) ; i > 0 ; i--) { if (file_out_dir[i] == '/') { file_out_dir[i] = '\0'; break; } } joinpath (file_out, file_out_dir, process_id); for (j=0 ; j < num_save ; j++) { my_strncpy (file_in, save_filename (j), sizeof (file_in)); printf (txt_extracting_shar, file_in); fflush (stdout); found_header = FALSE; #ifdef VMS if ((fp_out = fopen (file_out, "w", "fop=cif")) != NULL) { #else if ((fp_out = fopen (file_out, "w")) != NULL) { #endif if ((fp_in = fope :n (file_in, "r")) != NULL) { ptr1 = sh_pattern_1; ptr2 = sh_pattern_2; patlen1 = strlen (sh_pattern_1); patlen2 = strlen (sh_pattern_2); while (! feof (fp_in)) { if (fgets (buf, sizeof buf, fp_in)) { /* * find #!/bin/sh or #! /bin/sh pattern */ if (!found_header) { if (str_str (buf, ptr1, patlen1) != 0 || str_str (buf, ptr2, patlen2) != 0) { found_header = TRUE; } } /* * Write to temp file */ if (found_header) { fputs (buf, fp_out); } } } fclose (fp_in); } fclose (fp_out); #if !defined(M_UNIX) make_post_process_cmd (DEFAULT_UNSHAR, file_out_dir, file_out); #else sprintf (buf, "cd %s; sh %s", file_out_dir, file_out); fputs ("\r\n", stdout); fflush (stdout); Raw (FALSE); invoke_cmd (buf); Raw (TRUE); #endif unlink (file_out); } } delete_processed_files (); #endif /* INDEX_DAEMON */ } /* * Returns the most recently modified file in the specified drectory */ char * get_archive_file (dir, ext) char *dir; char *ext; { char buf[LEN]; char *file = (char *) 0; DIR *dirp; DIR_BUF *dp; struct stat sbuf; time_t last = 0; if ((file = (char *) my_malloc (LEN)) == (char *) 0) { return (char *) 0; } if ((dirp = opendir (dir)) == NULL) { free (file); return (char *) 0; } dp = (DIR_BUF *) readdir (dirp); while (dp != (DIR_BUF *) 0) { joinpath (buf, dir, dp->d_name); stat (buf, &sbuf); if ((sbuf.st_mtime > last) && S_ISREG(sbuf.st_mode)) { last = sbuf.st_mtime; strcpy (file, buf); } dp = (DIR_BUF *) readdir (dirp); } closedir (dirp); if (last == 0) { free (file); file = (char *) 0; } return (file); } void delete_processed_files () { #ifndef INDEX_DAEMON int delete = FALSE; int i; if (active[my_group[cur_groupnum]].attribute.delete_tmp_files) { delete = TRUE; } else if (prompt_yn (cLINES, txt_delete_processed_files, 'y')) { delete = TRUE; } if (delete) { wait_message ("\r\n"); wait_message (txt_deleting); for (i=0 ; i < num_save ; i++) { unlink (save_filename (i)); } } #endif /* INDEX_DAEMON */ } void print_art_seperator_line (fp, mailbox) FILE *fp; int mailbox; { int sep = 0x01; /* Ctrl-A */ if (debug == 2) { sprintf (msg, "Mailbox=[%d] MMDF=[%d]", mailbox, save_to_mmdf_mailbox); error_message (msg, ""); } if (mailbox && save_to_mmdf_mailbox) { fprintf (fp, "%c%c%c%c\n", sep, sep, sep, sep); } else { fputc ('\n', fp); } } ð*[SRC.TIN-1_22]SCREEN.C;4+,‚. //€ 4 ª-d0@î123KÿPWO 56`Ô¯—†—7 o˜†—89€]V‚—G/€HªJÿ/* * Project : tin - a Usenet reader * Module : screen.c * Author : I.Lea & R.Skrenta * Created : 01-04-91 * Updated : 11-07-92 * Notes : * Copyright : (c) Copyright 1991-93 by Iain Lea & Rich Skrenta * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" #ifndef VMS extern int errno; #endif char msg[LEN]; struct t_screen *screen; void info_message (str) char *str; { clear_message (); /* Clear any old messages hanging around */ center_line (cLINES, FALSE, str); /* center the message at screen bottom */ if (! cmd_line) { MoveCursor (cLINES, 0); } } void wait_message (str) char *str; { clear_message (); /* Clear any old messages hanging around */ fputs (str, stdout); fflush (stdout); } void error_message (template, str) char *template; char *str; { errno = 0; clear_message (); /* Clear any old messages hanging around */ fprintf (stderr, template, str); fflush (stderr); if (cmd_line) { fputc ('\n', stderr); fflush (stderr); } else { MoveCursor (cLINES, 0); sleep (3); } } void perror_message (template, str) char *template; char *str; { #ifdef HAVE_SYSERRLIST extern char *sys_errlist[]; #endif char str2[512]; int err = 0; err = errno; clear_message (); /* Clear any old messages hanging around */ sprintf (str2, template, str); err = errno; #ifdef HAVE_SYSERRLIST fprintf (stderr, "%s: %s", str2, sys_errlist[err]); #else # ifdef VMS fprintf (stderr, "%s: %s", str2, strerror(err)); # else fprintf (stderr, "%s: Error: %i", str2, err); # endif #endif errno = 0; if (cmd_line) { fputc ('\n', stderr); fflush (stderr); } else { MoveCursor (cLINES, 0); sleep (3); } } void clear_message () { if (! cmd_line) { MoveCursor (cLINES, 0); CleartoEOLN (); } } void center_line (line, inverse, str) int line; int inverse; char *str; { int pos; if (! cmd_line) { pos = (cCOLS - (int) strlen (str)) / 2; MoveCursor (line, pos); if (inverse) { StartInverse (); } } fputs (str, stdout); fflush (stdout); if (! cmd_line) { if (inverse) { EndInverse (); } } } void draw_arrow (line) int line; { MoveCursor (line, 0); if (draw_arrow_mark) { fputs ("->", stdout); fflush (stdout); } else { StartInverse (); fputs (screen[line-INDEX_TOP].col, stdout); fflush (stdout); EndInverse (); } MoveCursor (cLINES, 0); } void erase_arrow (line) int line; { MoveCursor (line, 0); if (draw_arrow_mark) { fputs (" ", stdout); } else { EndInverse (); fputs (screen[line-INDEX_TOP].col, stdout); } fflush (stdout); } void show_title (title) char *title; { int col; col = (cCOLS - (int) strlen (txt_type_h_for_help))+1; if (col) { MoveCursor (0, col); if (mail_check ()) { /* you have mail message in */ fputs (txt_you_have_mail, stdout); } else { fputs (txt_type_h_for_help, stdout); } } center_line (0, TRUE, title); } void ring_bell () { fputc ('\007', stdout); fflush (stdout); } ð*[SRC.TIN-1_22]SEARCH.C;1+,©.//€ 4Ö-d0@î123KÿPWO56Àä{ t…—7€ct1—89€]V‚—G/€HªJÿ&/* * Project : tin - a Usenet reader * Module : search.c * Author : I.Lea & R.Skrenta * Created : 01-04-91 * Updated : 20-09-93 * Notes : * Copyright : (c) Copyright 1991-93 by Iain Lea & Rich Skrenta * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" extern FILE *note_fp; extern int first_group_on_screen; extern int last_group_on_screen; extern int first_subj_on_screen; extern int last_subj_on_screen; extern int index_point; extern int note_line; extern int note_page; extern int note_end; extern long note_mark[MAX_PAGES]; /* * last search patterns */ char default_author_search[LEN]; char default_group_search[LEN]; char default_subject_search[LEN]; char default_art_search[LEN]; /* * group.c & page.c */ int search_author (index, current_art, forward) int index; int current_art; int forward; { char buf[LEN]; char buf2[LEN]; char group_path[PATH_LEN]; int i, patlen; clear_message (); if (forward) { sprintf (buf2, txt_author_search_forwards, default_author_search); } else { sprintf (buf2, txt_author_search_backwards, default_author_search); } if (! prompt_string (buf2, buf)) { return -1; } if (strlen (buf)) { strcpy (default_author_search, buf); } else { if (default_author_search[0]) { strcpy (buf, default_author_search); } else { info_message (txt_no_search_string); return -1; } } wait_message (txt_searching); make_group_path (active[index].name, group_path); make_lower (default_author_search, buf); patlen = strlen (default_author_search); i = current_art; do { if (forward) { i = next_response (i); if (i < 0) i = base[0]; } else { i = prev_response (i); if (i < 0) i = base[top_base - 1] + num_of_responses (top_base - 1); } if (active[index].attribute.show_only_unread && arts[i].unread != ART_UNREAD) { continue; } if (arts[i].name == (char *) 0) { make_lower (arts[i].from, buf2); } else { sprintf (msg, "%s (%s)", arts[i].from, arts[i].name); make_lower (msg, buf2); } if (str_str (buf2, buf, patlen) != 0) { /* * check if article still exists */ if (stat_article (arts[i].artnum, group_path)) { clear_message (); return i; } } } while (i != current_art); info_message (txt_no_match); return -1; } /* * select.c */ void search_group (forward) int forward; { char buf[LEN]; char buf2[LEN]; int i, patlen; if (! group_top) { info_message (txt_no_groups); return; } clear_message (); if (forward) { sprintf (buf2, txt_search_forwards, default_group_search); } else { sprintf (buf2, txt_search_backwards, default_group_search); } if (! prompt_string (buf2, buf)) { return; } if (strlen (buf)) { strcpy (default_group_search, buf); } else { if (default_group_search[0]) { strcpy (buf, default_group_search); } else { info_message (txt_no_search_string); return; } } wait_message (txt_searching); make_lower (default_group_search, buf); patlen = strlen (default_group_search); i = cur_groupnum; do { if (forward) i++; else i--; if (i >= group_top) i = 0; if (i < 0) i = group_top - 1; if (show_description && active[my_group[i]].description) { sprintf (buf2, "%s %s", active[my_group[i]].name, active[my_group[i]].description); } else { strcpy (buf2, active[my_group[i]].name); } lcase (buf2); if (str_str (buf2, buf, patlen) != 0) { if (_hp_glitch) { erase_group_arrow (); } if (i >= first_group_on_screen && i < last_group_on_screen) { clear_message (); erase_group_arrow (); cur_groupnum = i; draw_group_arrow (); } else { cur_groupnum = i; group_selection_page (); } return; } } while (i != cur_groupnum); info_message (txt_no_match); } /* * group.c */ void search_subject (forward, group) int forward; char *group; { char buf[LEN]; char buf2[LEN]; int i, j, patlen; if (index_point < 0) { info_message (txt_no_arts); return; } clear_message (); if (forward) { sprintf (buf2, txt_search_forwards, default_subject_search); } else { sprintf (buf2, txt_search_backwards, default_subject_search); } if (! prompt_string (buf2, buf)) { return; } if (strlen (buf)) { strcpy (default_subject_search, buf); } else { if (default_subject_search[0]) { strcpy (buf, default_subject_search); } else { info_message (txt_no_search_string); return; } } wait_message (txt_searching); make_lower (default_subject_search, buf); patlen = strlen (default_subject_search); i = index_point; do { if (forward) i++; else i--; if (i >= top_base) i = 0; if (i < 0) i = top_base - 1; j = (int) base[i]; make_lower (arts[j].subject, buf2); if (str_str (buf2, buf, patlen) != 0) { if (_hp_glitch) { erase_subject_arrow (); } if (i >= first_subj_on_screen && i < last_subj_on_screen) { clear_message (); erase_subject_arrow (); index_point = i; draw_subject_arrow (); } else { index_point = i; show_group_page (); } return; } } while (i != index_point); info_message (txt_no_match); } /* * page.c (search article body) */ int search_article (forward) int forward; { char buf[LEN]; char buf2[LEN]; char string[LEN]; char pattern[LEN]; char *p, *q; int ctrl_L; int i, j, patlen; int orig_note_end; int orig_note_page; clear_message (); if (forward) { sprintf (buf2, txt_search_forwards, default_art_search); } else { sprintf (buf2, txt_search_backwards, default_art_search); } if (! prompt_string (buf2, buf)) { return FALSE; } if (strlen (buf)) { strcpy (default_art_search, buf); } else { if (default_art_search[0]) { strcpy (buf, default_art_search); } else { info_message (txt_no_search_string); return FALSE; } } wait_message (txt_searching); make_lower (default_art_search, pattern); patlen = strlen (default_art_search); /* * save current position in article */ orig_note_end = note_end; orig_note_page = note_page; while (! note_end) { note_line = 1; ctrl_L = FALSE; if (note_page == 0) { note_line += 4; } else { note_line += 2; } while (note_line < cLINES) { if (fgets (buf, sizeof buf, note_fp) == NULL) { note_end = TRUE; break; } buf[LEN-1] = '\0'; for (p = buf, q = buf2; *p && *p != '\n' && q<&buf2[LEN]; p++) { if (*p == '\b' && q > buf2) { q--; } else if (*p == '\f') { /* ^L */ *q++ = '^'; *q++ = 'L'; ctrl_L = TRUE; } else if (*p == '\t') { i = q - buf2; j = (i|7) + 1; while (i++ < j) { *q++ = ' '; } } else if (((*p) & 0xFF) < ' ') { *q++ = '^'; *q++ = ((*p) & 0xFF) + '@'; } else { *q++ = *p; } } *q = '\0'; make_lower (buf2, string); if (str_str (string, pattern, patlen) != 0) { fseek (note_fp, note_mark[note_page], 0); return TRUE; } note_line += ((int) strlen(buf2) / cCOLS) + 1; if (ctrl_L) { break; } } if (! note_end) { note_mark[++note_page] = ftell (note_fp); } } note_end = orig_note_end; note_page = orig_note_page; fseek (note_fp, note_mark[note_page], 0); info_message (txt_no_match); return FALSE; } void make_lower (s, t) char *s; char *t; { while (*s) { if (isupper(*s)) *t = tolower(*s); else *t = *s; s++; t++; } *t = 0; } int search_body (group_path, current_art) char *group_path; int current_art; { char pat[LEN]; char buf2[LEN]; int aborted = FALSE; int i, len; int count = 0; clear_message (); sprintf (buf2, txt_search_body, default_art_search); if (! prompt_string (buf2, pat)) { return -1; } if (strlen (pat)) { strcpy (default_art_search, pat); } else { if (default_art_search[0]) { strcpy (pat, default_art_search); } else { info_message (txt_no_search_string); return -1; } } make_lower (default_art_search, pat); len = strlen (pat); i = current_art; do { i = next_response (i); if (i < 0) { i = 0; } if (search_art_body (group_path, &arts[i], pat, len)) { return i; } if (count % MODULO_COUNT_NUM == 0) { if (input_pending ()) { if (read (STDIN_FILENO, buf2, sizeof (buf2)-1)) { if (buf2[0] == ESC || buf2[0] == 'q' || buf2[0] == 'Q') { if (prompt_yn (cLINES, txt_abort_searching, 'y')) { aborted = TRUE; break; } else { printf (txt_searching_body); } } } } if (count == 0) { printf (txt_searching_body); } else { printf ("\b\b\b\b%4d", count); } fflush (stdout); } count++; } while (i != current_art); if (! aborted) { info_message (txt_no_match); } return -1; } int search_art_body (group_path, art, pat, len) char *group_path; struct t_article *art; char *pat; int len; { char buf[LEN]; FILE *fp; fp = open_art_fp (group_path, art->artnum); if (fp == (FILE *) 0) { return FALSE; } while (fgets (buf, sizeof (buf), fp) != NULL) { if (buf[0] == '\n') { break; } } while (fgets (buf, sizeof (buf), fp) != NULL) { lcase (buf); if (str_str (buf, pat, len)) { fclose (fp); return TRUE; } } fclose (fp); return FALSE; } /* * inline conversion of a string to lowercase letters */ void lcase (s) char *s; { while (*s) { if (isupper(*s)) { *s = tolower(*s); } s++; } } ð*[SRC.TIN-1_22]SELECT.C;1+,ª.<//€ 4<:<-d0@î123KÿPWO=56 ÑÏ t…—7€ct1—89€]V‚—G/€HªJÿ*/* * Project : tin - a Usenet reader * Module : select.c * Author : I.Lea & R.Skrenta * Created : 01-04-91 * Updated : 22-09-93 * Notes : * Copyright : (c) Copyright 1991-93 by Iain Lea & Rich Skrenta * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" extern char cvers[LEN]; extern int index_point; char default_goto_group[LEN]; int default_move_group; int cur_groupnum = 0; int first_group_on_screen; int last_group_on_screen; int space_mode; int yank_in_active_file = TRUE; void selection_index (start_groupnum) int start_groupnum; { #ifndef INDEX_DAEMON char buf[LEN]; char post_group[LEN]; int ch, i, n; int patlen; int posted; int scroll_lines; int subscribe_num; cur_groupnum = start_groupnum; mail_setup (); /* record mailbox size for "you have mail" */ #ifdef READ_CHAR_HACK setbuf (stdin, 0); #endif #ifndef USE_CLEARSCREEN ClearScreen(); #endif set_groupname_len (FALSE); /* find longest subscribedto groupname */ group_selection_page (); /* display group selection page */ set_alarm_signal (); /* set alarm signal for resync_active_file () */ while (TRUE) { reread_active_after_posting (); #ifndef DONT_REREAD_ACTIVE_FILE resync_active_file (); /* reread active file if alarm set */ #endif set_xclick_on (); ch = ReadCh (); #ifndef DONT_REREAD_ACTIVE_FILE if (ch != 'q' && ch != 'Q') { resync_active_file (); } #endif if (ch > '0' && ch <= '9') { if (prompt_group_num (ch)) { goto select_read_group; } continue; } switch (ch) { case ESC: /* (ESC) common arrow keys */ #ifdef HAVE_KEY_PREFIX case KEY_PREFIX: #endif switch (get_arrow_key ()) { case KEYMAP_UP: goto select_up; case KEYMAP_DOWN: goto select_down; case KEYMAP_LEFT: goto select_done; case KEYMAP_RIGHT: goto select_read_group; case KEYMAP_PAGE_UP: goto select_page_up; case KEYMAP_PAGE_DOWN: goto select_page_down; case KEYMAP_HOME: if (cur_groupnum != 0) { if (0 < first_group_on_screen) { #ifndef USE_CLEARSCREEN erase_group_arrow(); #endif cur_groupnum = 0; group_selection_page(); } else { erase_group_arrow(); cur_groupnum = 0; draw_group_arrow(); } } break; case KEYMAP_END: goto end_of_list; case KEYMAP_MOUSE: if (xrow < INDEX_TOP) { goto select_page_up; } if (xrow >= INDEX_TOP+last_group_on_screen-first_group_on_screen) { goto select_page_down; } erase_group_arrow (); cur_groupnum = xrow-INDEX_TOP+first_group_on_screen; draw_group_arrow (); if (xmouse > 0) { goto select_read_group; } break; } break; #ifndef NO_SHELL_ESCAPE case '!': shell_escape (); group_selection_page (); break; #endif case '$': /* show last page of groups */ end_of_list: if (cur_groupnum != group_top - 1) { if (group_top - 1 > last_group_on_screen) { #ifndef USE_CLEARSCREEN erase_group_arrow(); #endif cur_groupnum = group_top - 1; group_selection_page(); } else { erase_group_arrow(); cur_groupnum = group_top - 1; draw_group_arrow(); } } break; case '/': /* search forward */ case '?': /* search backward */ i = (ch == '/'); search_group (i); break; case '\r': /* go into group */ case '\n': select_read_group: if (group_top == 0) { info_message (txt_no_groups); break; } n = my_group[cur_groupnum]; if (active[n].min <= active[n].max) { space_mode = pos_first_unread; clear_message (); do { index_point = GRP_UNINDEXED; n = my_group[cur_groupnum]; group_page (active[n].name); } while (index_point == GRP_GOTONEXT || index_point == GRP_CONTINUE); #ifndef DONT_REREAD_ACTIVE_FILE if (! reread_active_file) #endif group_selection_page (); } else { info_message (txt_no_arts); } break; case '\t': /* enter next group containing unread articles */ case 'n': next_unread_group (TRUE); break; case ' ': /* page down */ case ctrl('D'): case ctrl('F'): /* vi style */ select_page_down: if (! group_top) { break; } if (cur_groupnum == group_top - 1) { if (0 < first_group_on_screen) { # ifndef USE_CLEARSCREEN erase_group_arrow(); # endif cur_groupnum = 0; group_selection_page(); } else { erase_group_arrow(); cur_groupnum = 0; draw_group_arrow(); } break; } erase_group_arrow (); scroll_lines = (full_page_scroll ? NOTESLINES : NOTESLINES / 2); cur_groupnum = ((cur_groupnum + scroll_lines) / scroll_lines) * scroll_lines; if (cur_groupnum >= group_top) { cur_groupnum = (group_top / scroll_lines) * scroll_lines; if (cur_groupnum < group_top - 1) { cur_groupnum = group_top - 1; } } if (cur_groupnum <= first_group_on_screen || cur_groupnum >= last_group_on_screen) group_selection_page (); else draw_group_arrow (); break; case ctrl('K'): /* delete group */ if (group_top <= 0) { info_message (txt_no_groups_to_delete); break; } sprintf (buf, active[my_group[cur_groupnum]].name); sprintf (msg, txt_del_group_in_newsrc, buf); if (prompt_yn (cLINES, msg, 'y')) { delete_group (active[my_group[cur_groupnum]].name); active[my_group[cur_groupnum]].my_group = UNSUBSCRIBED; group_top--; for (i = cur_groupnum; i < group_top; i++) { #if 0 active[my_group[i]].unread = active[my_group[i+1]].unread; #endif my_group[i] = my_group[i+1]; } if (cur_groupnum >= group_top) cur_groupnum = group_top - 1; set_groupname_len (FALSE); group_selection_page (); sprintf (msg, txt_group_deleted, buf); info_message (msg); } break; case ctrl('L'): /* redraw */ #ifndef USE_CLEARSCREEN ClearScreen (); #endif set_xclick_off (); group_selection_page (); break; case ctrl('N'): /* line down */ case 'j': select_down: if (! group_top) { break; } if (cur_groupnum + 1 >= group_top) { if (0 < first_group_on_screen) { # ifndef USE_CLEARSCREEN erase_group_arrow(); # endif cur_groupnum = 0; group_selection_page(); } else { erase_group_arrow(); cur_groupnum = 0; draw_group_arrow(); } break; } if (cur_groupnum + 1 >= last_group_on_screen) { #ifndef USE_CLEARSCREEN erase_group_arrow(); #endif cur_groupnum++; group_selection_page(); } else { erase_group_arrow(); cur_groupnum++; draw_group_arrow(); } break; case ctrl('P'): /* line up */ case 'k': select_up: if (! group_top) { break; } if (cur_groupnum == 0) { if (_hp_glitch) { erase_group_arrow (); } if (group_top > last_group_on_screen) { cur_groupnum = group_top - 1; group_selection_page (); } else { erase_group_arrow (); cur_groupnum = group_top - 1; draw_group_arrow (); } break; } if (_hp_glitch) { erase_group_arrow (); } if (cur_groupnum <= first_group_on_screen) { cur_groupnum--; group_selection_page (); } else { erase_group_arrow (); cur_groupnum--; draw_group_arrow (); } break; case ctrl('R'): /* reset .newsrc */ if (prompt_yn (cLINES, txt_reset_newsrc, 'n')) { reset_newsrc (); cur_groupnum = 0; group_selection_page (); } break; case 'b': /* page up */ case ctrl('U'): case ctrl('B'): /* vi style */ select_page_up: if (! group_top) { break; } if (cur_groupnum == 0) { if (_hp_glitch) { erase_group_arrow (); } if (group_top > last_group_on_screen) { cur_groupnum = group_top - 1; group_selection_page (); } else { erase_group_arrow (); cur_groupnum = group_top - 1; draw_group_arrow (); } break; } erase_group_arrow (); scroll_lines = (full_page_scroll ? NOTESLINES : NOTESLINES / 2); if ((n = cur_groupnum % scroll_lines) > 0) { cur_groupnum = cur_groupnum - n; } else { cur_groupnum = ((cur_groupnum - scroll_lines) / scroll_lines) * scroll_lines; } if (cur_groupnum < 0) { cur_groupnum = 0; } if (cur_groupnum < first_group_on_screen || cur_groupnum >= last_group_on_screen) group_selection_page (); else draw_group_arrow (); break; case 'c': /* catchup - mark all articles as read */ case 'C': /* and goto next unread group */ if (group_top == 0) { break; } catchup_group ((ch == 'C')); break; case 'd': /* toggle newsgroup descriptions */ show_description = !show_description; if (show_description) { read_newsgroups_file (); } set_groupname_len (FALSE); group_selection_page (); break; case 'g': /* prompt for a new group name */ if ((n = choose_new_group ()) >= 0) { erase_group_arrow (); if (active[my_group[n]].my_group != SUBSCRIBED) { subscribe (active[my_group[n]].name, ':', my_group[n], FALSE); cur_groupnum = reposition_group (active[my_group[n]].name, (n ? n : cur_groupnum)); } else { cur_groupnum = n; } set_groupname_len (FALSE); if (cur_groupnum < first_group_on_screen || cur_groupnum >= last_group_on_screen || cur_groupnum != n) { group_selection_page(); } else { clear_message (); draw_group_arrow(); } } break; case 'h': /* help */ show_info_page (HELP_INFO, help_select, txt_group_select_com); group_selection_page (); break; case 'H': /* toggle mini help menu */ toggle_mini_help (SELECT_LEVEL); group_selection_page (); break; case 'I': /* toggle inverse video */ erase_group_arrow (); toggle_inverse_video (); group_selection_page (); break; case 'l': /* list available spooldirs */ if (spooldir_index ()) { group_selection_page (); } break; case 'm': /* reposition group within group list */ if (active[my_group[cur_groupnum]].my_group == SUBSCRIBED) { n = cur_groupnum; cur_groupnum = reposition_group (active[my_group[n]].name, n); if  [Öä÷~ TIN-1_22.BCKªd[SRC.TIN-1_22]SELECT.C;1<;÷J(_hp_glitch) { erase_group_arrow (); } if (cur_groupnum < first_group_on_screen || cur_groupnum >= last_group_on_screen || cur_groupnum != n) { group_selection_page (); } else { i = cur_groupnum; cur_groupnum = n; erase_group_arrow (); cur_groupnum = i; clear_message (); draw_group_arrow (); } } break; case 'M': /* options menu */ set_alarm_clock_off (); change_rcfile ("", TRUE); free_attributes_array (); read_attributes_file (); group_selection_page (); set_alarm_clock_on (); break; case 'N': /* goto next unread group */ next_unread_group (FALSE); break; case 'q': /* quit */ case 'Q': select_done: write_rcfile (); tin_done (0); break; case 'r': /* * If in show_only_unread_groups mode toggle * all subscribed to groups and only groups * that contain unread articles * * Disabled when started with cmdline groups */ if (! read_cmd_line_groups ()) { show_only_unread_groups = !show_only_unread_groups; if (show_only_unread_groups) { wait_message (txt_reading_new_groups); } else { wait_message (txt_reading_all_groups); } toggle_my_groups (show_only_unread_groups, ""); set_groupname_len (FALSE); group_selection_page (); } break; case 'R': /* bug/gripe/comment mailed to author */ mail_bug_report (); #ifndef USE_CLEARSCREEN ClearScreen (); #endif group_selection_page (); break; case 's': /* subscribe to current group */ if (group_top == 0) { break; } if (active[my_group[cur_groupnum]].my_group != SUBSCRIBED) { mark_screen (SELECT_LEVEL, cur_groupnum - first_group_on_screen, 2, " "); subscribe (active[my_group[cur_groupnum]].name, ':', my_group[cur_groupnum], FALSE); sprintf (buf, txt_subscribed_to, active[my_group[cur_groupnum]].name); info_message (buf); } break; case 'S': /* subscribe to groups matching pattern */ if (group_top == 0) { break; } if (prompt_string (txt_subscribe_pattern, buf) && buf[0]) { wait_message (txt_subscribing); patlen = strlen (buf); for (subscribe_num=0, i=0 ; i < group_top ; i++) { #ifdef NO_REGEX if (str_str (active[my_group[i]].name, buf, patlen)) { #else if (wildmat (active[my_group[i]].name, buf)) { #endif if (active[my_group[i]].my_group != SUBSCRIBED) { #ifndef SLOW_SCREEN_UPDATE sprintf (msg, txt_subscribing_to, active[my_group[i]].name); wait_message (msg); #endif subscribe (active[my_group[i]].name, ':', my_group[i], FALSE); } subscribe_num++; } } if (subscribe_num) { group_selection_page (); sprintf (buf, txt_subscribed_num_groups, subscribe_num); info_message (buf); } else { info_message (txt_no_match); } } else { clear_message (); } break; case 'u': /* unsubscribe to current group */ if (group_top == 0) { break; } if (active[my_group[cur_groupnum]].my_group == SUBSCRIBED) { mark_screen (SELECT_LEVEL, cur_groupnum - first_group_on_screen, 2, "u"); subscribe(active[my_group[cur_groupnum]].name, '!', my_group[cur_groupnum], FALSE); sprintf(buf, txt_unsubscribed_to,active[my_group[cur_groupnum]].name); info_message(buf); } goto_next_group_on_screen (); break; case 'U': /* unsubscribe to groups matching pattern */ if (group_top == 0) { break; } if (prompt_string (txt_unsubscribe_pattern, buf) && buf[0]) { wait_message (txt_unsubscribing); patlen = strlen (buf); for (subscribe_num=0, i=0 ; i < group_top ; i++) { #ifdef NO_REGEX if (str_str (active[my_group[i]].name, buf, patlen)) { #else if (wildmat (active[my_group[i]].name, buf)) { #endif if (active[my_group[i]].my_group == SUBSCRIBED) { #ifndef SLOW_SCREEN_UPDATE sprintf (msg, txt_unsubscribing_from, active[my_group[i]].name); wait_message (msg); #endif subscribe (active[my_group[i]].name, '!', my_group[i], FALSE); } subscribe_num++; } } if (subscribe_num) { group_selection_page (); sprintf (buf, txt_unsubscribed_num_groups, subscribe_num); info_message (buf); } else { info_message (txt_no_match); } } else { clear_message (); } break; case 'v': /* show tin version */ info_message (cvers); break; case 'w': /* post a basenote */ if (can_post) { if (group_top == 0) { if (! prompt_string (txt_post_newsgroup, buf)) break; if (buf[0] == '\0') break; strcpy (post_group, buf); } else { strcpy (post_group, active[my_group[cur_groupnum]].name); } if (post_article (post_group, &posted)) { group_selection_page (); } } break; case 'W': /* display messages posted by user */ if (user_posted_messages ()) { group_selection_page (); } break; case 'y': /* pull in rest of groups from active */ if (yank_in_active_file) { wait_message (txt_yanking_all_groups); set_alarm_clock_off (); n = group_top; for (i = 0; i < num_active; i++) { active[i].my_group = UNSUBSCRIBED; } read_newsrc (FALSE); for (i = 0; i < num_active; i++) { if (active[i].my_group & UNSUBSCRIBED) { active[i].my_group &= ~UNSUBSCRIBED; active[i].unread = -1; my_group[group_top] = i; group_top++; } } if (n < group_top) { sprintf (buf, txt_added_groups, group_top - n, group_top - n == 1 ? "" : txt_plural); set_groupname_len (yank_in_active_file); group_selection_page (); info_message (buf); } else { info_message (txt_no_groups_to_yank_in); } yank_in_active_file = FALSE; } else { wait_message (txt_yanking_sub_groups); read_newsrc (TRUE); if (_hp_glitch) { erase_group_arrow (); } cur_groupnum = group_top - 1; set_groupname_len (yank_in_active_file); group_selection_page (); yank_in_active_file = TRUE; set_alarm_clock_on (); } break; case 'Y': /* yank active file to see if any new news */ yank_active_file (); break; case 'z': /* mark group unread */ if (group_top == 0) { break; } n = cur_groupnum; update_newsrc (active[my_group[n]].name, my_group[n], TRUE); cur_groupnum = 0; group_top = 0; read_newsrc (TRUE); cur_groupnum = n; if (active[my_group[cur_groupnum]].unread) { sprintf (msg, "%5d", active[my_group[cur_groupnum]].unread); } else { strcpy (msg, " "); } mark_screen (SELECT_LEVEL, cur_groupnum - first_group_on_screen, 9, msg); break; case 'Z': /* undelete groups deleted by ctrl-K */ if (undel_group ()) { set_groupname_len (FALSE); group_selection_page (); info_message (txt_group_undeleted); } break; default: info_message(txt_bad_command); } } #endif /* INDEX_DAEMON */ } void group_selection_page () { #ifndef INDEX_DAEMON char buf[LEN]; char new[10]; char subs; int i, j, n; int blank_len; set_signals_select (); #ifdef USE_CLEARSCREEN ClearScreen (); #else MoveCursor (0, 0); /* top left corner */ CleartoEOLN (); #endif if (read_news_via_nntp || xspooldir_supported) { sprintf (buf, "%s (%s %d%s)", txt_group_selection, (xspooldir_supported ? spooldir_alias : nntp_server), group_top, (show_only_unread_groups ? " R" : "")); } else { sprintf (buf, "%s (%d%s)", txt_group_selection, group_top, (show_only_unread_groups ? " R" : "")); } show_title (buf); #ifndef USE_CLEARSCREEN MoveCursor (1, 0); CleartoEOLN (); #endif MoveCursor (INDEX_TOP, 0); if (cur_groupnum >= group_top) { cur_groupnum = group_top - 1; } if (cur_groupnum < 0) { cur_groupnum = 0; } if (NOTESLINES <= 0) { first_group_on_screen = 0; } else { first_group_on_screen = (cur_groupnum / NOTESLINES) * NOTESLINES; if (first_group_on_screen < 0) { first_group_on_screen = 0; } } last_group_on_screen = first_group_on_screen + NOTESLINES; if (last_group_on_screen >= group_top) { last_group_on_screen = group_top; first_group_on_screen = (cur_groupnum / NOTESLINES) * NOTESLINES; if (first_group_on_screen == last_group_on_screen || first_group_on_screen < 0) { if (first_group_on_screen < 0) { first_group_on_screen = 0; } else { first_group_on_screen = last_group_on_screen - NOTESLINES; } } } if (group_top == 0) { first_group_on_screen = 0; last_group_on_screen = 0; } if (show_description) { blank_len = (cCOLS - (groupname_len + SELECT_MISC_COLS)) + 2; } else { blank_len = (cCOLS - (groupname_len + SELECT_MISC_COLS)) + 4; } for (j=0, i=first_group_on_screen; i < last_group_on_screen; i++, j++) { switch (active[my_group[i]].unread) { case -2: strcpy (new, " ?"); break; case -1: strcpy (new, " -"); break; case 0: strcpy (new, " "); break; default: sprintf (new, "%5.d", active[my_group[i]].unread); } n = my_group[i]; if (active[n].my_group & SUBSCRIBED) { /* subscribed? */ subs = ' '; } else { subs = 'u'; /* u next to unsubscribed groups */ } if (show_description) { if (draw_arrow_mark) { sprintf (screen[j].col, " %c %4.d %s %-*.*s %-*.*s\r\n", subs, i+1, new, groupname_len, groupname_len, active[n].name, blank_len, blank_len, (active[n].description ? active[n].description : " ")); } else { sprintf (screen[j].col, " %c %4.d %s %-*.*s %-*.*s\r\n", subs, i+1, new, groupname_len, groupname_len, active[n].name, blank_len, blank_len, (active[n].description ? active[n].description : " ")); } } else { if (draw_arrow_mark) { sprintf (screen[j].col, " %c %4.d %s %-*.*s\r\n", subs, i+1, new, groupname_len, groupname_len, active[n].name); } else { sprintf (screen[j].col, " %c %4.d %s %-*.*s%*s\r\n", subs, i+1, new, groupname_len, groupname_len, active[n].name, blank_len, " "); } } if (slow_speed_terminal) { strip_line (screen[j].col, strlen (screen[j].col)); strcat (screen[j].col, "\r\n"); } CleartoEOLN (); fputs (screen[j].col, stdout); } #ifndef USE_CLEARSCREEN CleartoEOS (); #endif show_mini_help (SELECT_LEVEL); if (group_top <= 0) { info_message (txt_no_groups); return; } else if (last_group_on_screen == group_top) { info_message (txt_end_of_groups); } draw_group_arrow (); #endif /* INDEX_DAEMON */ } int prompt_group_num (ch) int ch; { int num; clear_message (); if ((num = prompt_num (ch, txt_select_group)) == -1) { clear_message (); return FALSE; } num--; /* index from 0 (internal) vs. 1 (user) */ if (num < 0) { num = 0; } if (num >= group_top) { num = group_top - 1; } if (num >= first_group_on_screen && num < last_group_on_screen) { erase_group_arrow (); cur_groupnum = num; draw_group_arrow (); } else { #ifndef USE_CLEARSCREEN erase_group_arrow (); #endif cur_groupnum = num; group_selection_page (); } return TRUE; } void erase_group_arrow () { erase_arrow (INDEX_TOP + (cur_groupnum-first_group_on_screen)); } void draw_group_arrow() { draw_arrow (INDEX_TOP + (cur_groupnum-first_group_on_screen)); } void yank_active_file () { reread_active_file = TRUE; resync_active_file (); } int choose_new_group () { char buf[LEN]; char *p; int ret; if (! group_top && show_only_unread_groups) { return -1; } sprintf (msg, txt_newsgroup, default_goto_group); if (! prompt_string (msg, buf)) { return -1; } if (strlen (buf)) { strcpy (default_goto_group, buf); } else { if (default_goto_group[0]) { strcpy (buf, default_goto_group); } else { return -1; } } for (p = buf; *p && (*p == ' ' || *p == '\t'); p++) continue; if (*p == '\0') return -1; clear_message (); if ((ret = add_group (p, TRUE)) < 0) { sprintf (msg, txt_not_in_active_file, p); info_message (msg); } return ret; } /* * Add a group to the users selection list (my_group[]) * Return the index of my_group[] if group is added or was already * there. Return -1 if named group is not in active[]. */ int add_group (s, get_unread) char *s; int get_unread; /* look in .newsrc for sequencer unread info? */ { long h; int i, j; h = hash_groupname (s); for (i = group_hash[h]; i >= 0; i = active[i].next) { if (strcmp (s, active[i].name) == 0) { for (j = 0; j < group_top; j++) { if (my_group[j] == i) { return j; } } active[i].my_group &= ~UNSUBSCRIBED; /* mark that we got it */ my_group[group_top] = i; if (get_unread) { active[my_group[group_top]].unread = get_line_unread (s, i); } else { active[my_group[group_top]].unread = -1; } group_top++; return (group_top - 1); } } return -1; } int reposition_group (group, default_num) char *group; int default_num; { char buf[LEN]; char pos[LEN]; int pos_num = 0; sprintf (buf, txt_newsgroup_position, group, (default_move_group ? default_move_group : default_num+1)); if (! prompt_string (buf, pos)) { return default_num; } if (strlen (pos)) { if (pos[0] == '$') { pos_num = group_top; } else { pos_num = atoi (pos); } } else { if (default_move_group) { pos_num = default_move_group; } else { return default_num; } } if (pos_num > group_top) { pos_num = group_top; } else if (pos_num <= 0) { pos_num = 1; } sprintf (buf, txt_moving, group); wait_message (buf); if (pos_group_in_newsrc (group, pos_num)) { read_newsrc (TRUE); default_move_group = pos_num; return (pos_num-1); } else { default_move_group = default_num + 1; return (default_num); } } void catchup_group (goto_next_unread_group) int goto_next_unread_group; { sprintf (msg, txt_mark_group_read, active[my_group[cur_groupnum]].name); if (! confirm_action || prompt_yn (cLINES, msg, 'y')) { active[my_group[cur_groupnum]].unread = 0; mark_group_read (active[my_group[cur_groupnum]].name, my_group[cur_groupnum]); mark_screen (SELECT_LEVEL, cur_groupnum - first_group_on_screen, 9, " "); goto_next_group_on_screen (); if (goto_next_unread_group) { next_unread_group (FALSE); } } } void next_unread_group (enter_group) int enter_group; { int i, all_groups_read = TRUE; for (i = cur_groupnum ; i < group_top ; i++) { if (active[my_group[i]].unread != 0) { all_groups_read = FALSE; erase_group_arrow (); break; } } if (all_groups_read) { for (i = 0 ; i < cur_groupnum ; i++) { if (active[my_group[i]].unread != 0) { all_groups_read = FALSE; break; } } } if (all_groups_read) { info_message (txt_no_groups_to_read); return; } if (i != cur_groupnum) { erase_group_arrow (); } cur_groupnum = i; if (cur_groupnum < first_group_on_screen || cur_groupnum >= last_group_on_screen) { group_selection_page (); } else { draw_group_arrow (); } space_mode = pos_first_unread; if (enter_group) { clear_message (); do { index_point = GRP_UNINDEXED; group_page (active[my_group[cur_groupnum]].name); } while (index_point == GRP_GOTONEXT || index_point == GRP_CONTINUE); group_selection_page (); } } /* * Calculate max length of groupname field for group selection level. * If all_group is TRUE check all groups in active file otherwise * just subscribed to groups. */ void set_groupname_len (all_groups) int all_groups; { int len; register int i; groupname_len = 0; if (all_groups) { for (i = 0 ; i < num_active ; i++) { len = strlen (active[i].name); if (len > groupname_len) { groupname_len = len; } } } else { for (i = 0 ; i < group_top ; i++) { len = strlen (active[my_group[i]].name); if (len > groupname_len) { groupname_len = len; } } } if (groupname_len >= (cCOLS - SELECT_MISC_COLS)) { groupname_len = cCOLS - SELECT_MISC_COLS - 1; if (groupname_len < 0) { groupname_len = 0; } } /* * If newsgroups descriptions are ON then cut off groupnames * to specified max. length otherwise display full length */ if (show_description && groupname_len > groupname_max_length) { groupname_len = groupname_max_length; } } void toggle_my_groups (only_unread_groups, group) int only_unread_groups; char *group; { #ifndef INDEX_DAEMON char buf[8192]; char old_curr_group[PATH_LEN]; char *ptr; FILE *fp; int active_idx = 0; int group_num = cur_groupnum; register int i = 0, j = 0; if ((fp = fopen (newsrc, "r")) != (FILE *) 0) { /* * Save current or next group with unread arts for later use */ old_curr_group[0] = '\0'; if (group_top) { if (! only_unread_groups || reread_active_file) { if (strlen (group)) { if ((i = find_group_index (group)) >= 0) { active_idx = i; } } else { active_idx = my_group[group_num]; } my_strncpy (old_curr_group, active[active_idx].name, sizeof (old_curr_group)); } else { for (i = group_num ; i < group_top ; i++) { if (active[my_group[i]].unread) { my_strncpy (old_curr_group, active[my_group[i]].name, sizeof (old_curr_group)); break; } } } } group_top = 0; while (fgets (buf, sizeof (buf), fp) != (char *) 0) { ptr = (char *) strchr (buf, ':'); if (ptr != (char *) 0) { *ptr = '\0'; if ((i = find_group_index (buf)) >= 0) { if (only_unread_groups) { if (active[i].unread) { my_group[group_top] = i; group_top++; } } else { my_group[group_top] = i; group_top++; } } } } fclose (fp); /* * Try and reposition on same or next group before toggling */ cur_groupnum = 0; if ((i = find_group_index (old_curr_group)) >= 0) { for (j = 0 ; j < group_top ; j++) { if (my_group[j] == i) { cur_groupnum = j; break; } } } } #endif /* INDEX_DAEMON */ } void goto_next_group_on_screen () { if (_hp_glitch) { erase_group_arrow (); } if (cur_groupnum+1 < last_group_on_screen) { erase_group_arrow (); cur_groupnum++; draw_group_arrow (); } else { cur_groupnum++; group_selection_page (); } } /* * Strip trailing blanks */ void strip_line (line, len) char *line; int len; { char *ptr = line + (len - 1); while (*ptr == ' ' || *ptr == '\r' || *ptr == '\n') { ptr--; } *++ptr = '\0'; } ð*[SRC.TIN-1_22]SERVER.PATCH;1+,{.?//€ 4?>‹-d0@î123KÿPWO@56€8t…—7€³c1—89€]V‚—G/€HªJÿ0*** server/Makefile Wed Sep 30 14:34:44 1992 --- server/Makefile Wed Nov 18 19:02:45 1992 *************** *** 6,18 **** ahbs.o globals.o group.o help.o ihave.o list.o misc.o netaux.o \ newgroups.o newnews.o nextlast.o ngmatch.o post.o parsit.o scandir.o \ slave.o spawn.o strcasecmp.o subnet.o time.o xhdr.o fakesyslog.o \ ! batch.o auth.o timer.o ../common/version.o SRVRSRC = main.c serve.c access.c access_inet.c access_dnet.c active.c \ ahbs.c globals.c group.c help.c ihave.c list.c misc.c netaux.c \ newgroups.c newnews.c nextlast.c ngmatch.c post.c parsit.c scandir.c \ slave.c spawn.c strcasecmp.c subnet.c time.c xhdr.c fakesyslog.c \ ! batch.c auth.c timer.c ../common/version.c SRVRINC = common.h ../common/conf.h ../common/nntp.h timer.h --- 6,20 ---- ahbs.o globals.o group.o help.o ihave.o list.o misc.o netaux.o \ newgroups.o newnews.o nextlast.o ngmatch.o post.o parsit.o scandir.o \ slave.o spawn.o strcasecmp.o subnet.o time.o xhdr.o fakesyslog.o \ ! batch.o auth.o timer.o ../common/version.o xuser.o xindex.o \ ! xoverview.o xmotd.o SRVRSRC = main.c serve.c access.c access_inet.c access_dnet.c active.c \ ahbs.c globals.c group.c help.c ihave.c list.c misc.c netaux.c \ newgroups.c newnews.c nextlast.c ngmatch.c post.c parsit.c scandir.c \ slave.c spawn.c strcasecmp.c subnet.c time.c xhdr.c fakesyslog.c \ ! batch.c auth.c timer.c ../common/version.c xuser.c xindex.c \ ! xoverview.c xmotd.c SRVRINC = common.h ../common/conf.h ../common/nntp.h timer.h *** server/access.c Wed Sep 30 14:34:42 1992 --- server/access.c Tue Sep 15 20:09:54 1992 *************** *** 44,50 **** #ifdef AUTH extern int Needauth; ! #endif AUTH host_access(canread, canpost, canxfer, gdlist) int *canread, *canpost, *canxfer; --- 44,50 ---- #ifdef AUTH extern int Needauth; ! #endif /* AUTH */ host_access(canread, canpost, canxfer, gdlist) int *canread, *canpost, *canxfer; *************** *** 230,236 **** /* do we require a userid and password for this guy? */ if (isupper(readperm[0]) || isupper(postperm[0])) Needauth = 1; ! #endif AUTH } #ifdef DOMAINMATCH --- 230,236 ---- /* do we require a userid and password for this guy? */ if (isupper(readperm[0]) || isupper(postperm[0])) Needauth = 1; ! #endif /* AUTH */ } #ifdef DOMAINMATCH *************** *** 267,270 **** return (0); } ! #endif DOMAINMATCH --- 267,270 ---- return (0); } ! #endif /* DOMAINMATCH */ *** server/access_inet.c Wed Sep 30 14:34:45 1992 --- server/access_inet.c Tue Sep 15 20:09:56 1992 *************** *** 77,83 **** } #else subnet_name[0] = '\0'; ! #endif SUBNET hp = gethostbyaddr((char *) &sin->sin_addr.s_addr, sizeof (sin->sin_addr.s_addr), AF_INET); --- 77,83 ---- } #else subnet_name[0] = '\0'; ! #endif /* SUBNET */ hp = gethostbyaddr((char *) &sin->sin_addr.s_addr, sizeof (sin->sin_addr.s_addr), AF_INET); *** server/auth.c Wed Sep 30 14:34:49 1992 --- server/auth.c Tue Sep 15 20:10:00 1992 *************** *** 149,152 **** Needauth = 0; } ! #endif AUTH --- 149,152 ---- Needauth = 0; } ! #endif /* AUTH */ *** server/batch.c Wed Sep 30 14:34:45 1992 --- server/batch.c Tue Sep 15 20:09:58 1992 *************** *** 255,265 **** #ifdef SYSLOG #ifdef LOG syslog(LOG_ERR, "%s transfer_timeout", hostname); ! #endif LOG #endif (void) unlink(tempfile); exit(1); ! #endif XFER_TIMEOUT } /* --- 255,265 ---- #ifdef SYSLOG #ifdef LOG syslog(LOG_ERR, "%s transfer_timeout", hostname); ! #endif /* LOG */ #endif (void) unlink(tempfile); exit(1); ! #endif /* XFER_TIMEOUT */ } /* *** server/common.h Wed Sep 30 14:34:43 1992 --- server/common.h Tue Sep 15 20:09:55 1992 *************** *** 48,53 **** --- 48,56 ---- #endif #else /* not NDIR */ # include + # ifdef ISC + # include + # endif #endif /* not NDIR */ #ifdef FCNTL *************** *** 157,162 **** --- 160,166 ---- extern char spooldir[]; extern char activefile[]; extern char distributionsfile[]; + extern char subscriptionsfile[]; extern char newsgroupsfile[]; extern char accessfile[]; extern char historyfile[]; *** server/fakesyslog.c Wed Sep 30 14:34:46 1992 --- server/fakesyslog.c Tue Sep 15 20:09:58 1992 *************** *** 138,144 **** (void) strcpy(buf, ctime(&clock)+4); *(bp = buf + 16) = '\0'; ! (void) sprintf(bp, "localhost %s", ident ? ident : ""); bp += strlen(bp); if (opt&LOG_PID) { --- 138,145 ---- (void) strcpy(buf, ctime(&clock)+4); *(bp = buf + 16) = '\0'; ! /* (void) sprintf(bp, "localhost %s", ident ? ident : ""); */ ! (void) sprintf(bp, "local %s", ident ? ident : ""); bp += strlen(bp); if (opt&LOG_PID) { *** server/fakesyslog.h Wed Sep 30 14:34:50 1992 --- server/fakesyslog.h Tue Sep 15 20:10:02 1992 *************** *** 62,65 **** #define LOG_NDELAY 0 #define LOG_NOWAIT 0 ! #endif FAKESYSLOG --- 62,65 ---- #define LOG_NDELAY 0 #define LOG_NOWAIT 0 ! #endif /* FAKESYSLOG */ *** server/globals.c Wed Sep 30 14:34:46 1992 --- server/globals.c Tue Sep 15 20:09:58 1992 *************** *** 16,21 **** --- 16,22 ---- char activefile[] = ACTIVE_FILE; char accessfile[] = ACCESS_FILE; char distributionsfile[] = DISTRIBUTIONS_FILE; + char subscriptionsfile[] = SUBSCRIPTIONS_FILE; char newsgroupsfile[] = NEWSGROUPS_FILE; char historyfile[] = HISTORY_FILE; #ifdef ACTIVE_TIMES_FILE *************** *** 54,60 **** #ifdef AUTH int Needauth; /* 1 if we need to do authorization */ char User[10]; /* username for authentication */ ! #endif AUTH #ifdef LOG int arts_acsd; --- 55,61 ---- #ifdef AUTH int Needauth; /* 1 if we need to do authorization */ char User[10]; /* username for authentication */ ! #endif /* AUTH */ #ifdef LOG int arts_acsd; *** server/group.c Wed Sep 30 14:34:46 1992 --- server/group.c Tue Sep 15 20:09:58 1992 *************** *** 49,54 **** --- 49,55 ---- return; } + reqlist[0] = argv[1]; reqlist[1] = NULL; *************** *** 70,79 **** close_crnt(); (void) chdir(spooldir); - #ifdef LOG - syslog(LOG_INFO, "%s group %s", hostname, argv[1]); - #endif - while ((cp = index(argv[1], '.')) != (char *) NULL) *cp = '/'; --- 71,76 ---- *************** *** 96,101 **** --- 93,103 ---- art_ptr = 0; ingroup = 1; + + #ifdef LOG + syslog(LOG_INFO, "%s group=%s high=%d low=%d arts=%d", + hostname, argv[1], high_msg, low_msg, num_arts); + #endif while ((cp = index(argv[1], '/')) != (char *) NULL) *cp = '.'; *** server/help.c Wed Sep 30 14:34:46 1992 --- server/help.c Wed Nov 18 19:09:10 1992 *************** *** 21,28 **** printf("NEXT POST QUIT\r\n"); printf("STAT NEWGROUPS HELP\r\n"); printf("IHAVE NEWNEWS SLAVE\r\n"); ! printf("\r\nAdditionally, the following extention is supported:\r\n\r\n"); printf("XHDR Retrieve a single header line from a range of articles.\r\n"); printf("\r\n"); printf("Bugs to Stan Barber (Internet: nntp@tmc.edu; UUCP: ...!bcm!nntp)\r\n"); printf(".\r\n"); --- 21,45 ---- printf("NEXT POST QUIT\r\n"); printf("STAT NEWGROUPS HELP\r\n"); printf("IHAVE NEWNEWS SLAVE\r\n"); ! #if defined(XHDR) || defined(XINDEX) || defined(XMOTD) || \ ! defined(XOVERVIEW) || defined(XUSER) ! printf("\r\nAdditionally, the following extentions are supported:\r\n\r\n"); ! # ifdef XHDR printf("XHDR Retrieve a single header line from a range of articles.\r\n"); + # endif + # ifdef XINDEX + printf("XINDEX Retrieve a tin style index file.\r\n"); + # endif + # ifdef XMOTD + printf("XMOTD Display the news message of the day file.\r\n"); + # endif + # ifdef XOVERVIEW + printf("XOVERVIEW Retrieve a .overview style index file.\r\n"); + # endif + # ifdef XUSER + printf("XUSER Log a clients username to nntp logfile.\r\n"); + # endif + #endif printf("\r\n"); printf("Bugs to Stan Barber (Internet: nntp@tmc.edu; UUCP: ...!bcm!nntp)\r\n"); printf(".\r\n"); *** server/ihave.c Wed Sep 30 14:34:46 1992 --- server/ihave.c Tue Sep 15 20:09:59 1992 *************** *** 8,14 **** int ih_accepted; int ih_rejected; int ih_failed; ! #endif LOG /* * IHAVE --- 8,14 ---- int ih_accepted; int ih_rejected; int ih_failed; ! #endif /* LOG */ /* * IHAVE *************** *** 50,57 **** ih_rejected++; #ifdef IHAVE_DEBUG syslog(LOG_DEBUG, "%s ihave %s rejected", hostname, argv[1]); ! #endif IHAVE_DEBUG ! #endif LOG return; } --- 50,57 ---- ih_rejected++; #ifdef IHAVE_DEBUG syslog(LOG_DEBUG, "%s ihave %s rejected", hostname, argv[1]); ! #endif /* IHAVE_DEBUG */ ! #endif /* LOG */ return; } *************** *** 100,106 **** #ifdef IHAVE_DEBUG syslog(LOG_DEBUG, "%s ihave %s accepted %s", hostname, argv[1], retcode == 1 ? "succeeded" : "failed"); ! #endif IHAVE_DEBUG ! #endif LOG } --- 100,106 ---- #ifdef IHAVE_DEBUG syslog(LOG_DEBUG, "%s ihave %s accepted %s", hostname, argv[1], retcode == 1 ? "succeeded" : "failed"); ! #endif /* IHAVE_DEBUG */ ! #endif /* LOG */ } *** server/list.c Wed Sep 30 14:34:46 1992 --- server/list.c Tue Sep 15 20:09:59 1992 *************** *** 7,14 **** /* * LIST * ! * List active newsgroups, newsgroup descriptions, and distributions. * */ list(argc, argv) --- 7,17 ---- /* * LIST * ! * List active newsgroups, newsgroup descriptions, distributions ! * and subscriptions. * + * + * */ list(argc, argv) *************** *** 45,52 **** filename = newsgroupsfile; items = "newsgroup descriptions"; format = "Descriptions in form \"group description\"."; } else { ! printf("%d Usage: LIST [ACTIVE|NEWSGROUPS|DISTRIBUTIONS]\r\n", ERR_CMDSYN); (void) fflush(stdout); return; --- 48,59 ---- filename = newsgroupsfile; items = "newsgroup descriptions"; format = "Descriptions in form \"group description\"."; + } else if (argc == 2 && !strcasecmp(argv[1],"subscriptions")){ + filename = subscriptionsfile; + items = "automatic group subscriptions"; + format = "Subscriptions in form \"group\"."; } else { ! printf("%d Usage: LIST [ACTIVE|NEWSGROUPS|DISTRIBUTIONS|SUBSCRIPTIONS]\r\n", ERR_CMDSYN); (void) fflush(stdout); return; *** server/misc.c Wed Sep 30 14:34:43 1992 --- server/misc.c Tue Sep 15 20:09:56 1992 *************** *** 90,98 **** # ifndef DBM # ifndef USGHIST # define USGHIST ! # endif not USGHIST ! # endif not DBM ! #endif not DBM char * gethistent(msg_id, lookup) --- 90,98 ---- # ifndef DBM # ifndef USGHIST # define USGHIST ! # endif /* not USGHIST */ ! # endif /* not DBM */ ! #endif /* not DBM */ char * gethistent(msg_id, lookup) *************** *** 107,121 **** #ifdef USGHIST char *histfile(); register int len; ! #else not USGHIST #ifdef DBM static int dbopen = 0; datum fetch(); ! #else not DBM static DBM *db = NULL; /* History file, dbm version */ ! #endif DBM ! datum key, content; ! #endif USGHIST static FILE *hfp = NULL; /* history file, text version */ #ifdef CNEWS --- 107,121 ---- #ifdef USGHIST char *histfile(); register int len; ! #else /* not USGHIST */ #ifdef DBM static int dbopen = 0; datum fetch(); ! #else /* not DBM */ static DBM *db = NULL; /* History file, dbm version */ ! #endif /* DBM */ ! datum key, content; ! #endif /* USGHIST */ static FILE *hfp = NULL; /* history file, text version */ #ifdef CNEWS *************** *** 140,146 **** if (hfp == NULL) { #ifdef SYSLOG syslog(LOG_ERR, "gethistent: histfile: %m"); ! #endif SYSLOG return (NULL); } --- 140,146 ---- if (hfp == NULL) { #ifdef SYSLOG syslog(LOG_ERR, "gethistent: histfile: %m"); ! #endif /* SYSLOG */ return (NULL); } *************** *** 153,159 **** (void) fclose(hfp); return (NULL); } ! #else not USGHIST #ifdef DBM if (!dbopen) { if (dbminit(historyfile) < 0) { --- 153,159 ---- (void) fclose(hfp); return (NULL); ÐWD°~ TIN-1_22.BCK{d[SRC.TIN-1_22]SERVER.PATCH;1?¹µL } ! #else /* not USGHIST */ #ifdef DBM if (!dbopen) { if (dbminit(historyfile) < 0) { *************** *** 160,166 **** #ifdef SYSLOG syslog(LOG_ERR, "openartbyid: dbminit %s: %m", historyfile); ! #endif SYSLOG return (NULL); } else dbopen = 1; --- 160,166 ---- #ifdef SYSLOG syslog(LOG_ERR, "openartbyid: dbminit %s: %m", historyfile); ! #endif /* SYSLOG */ return (NULL); } else dbopen = 1; *************** *** 172,182 **** #ifdef SYSLOG syslog(LOG_ERR, "openartbyid: dbm_open %s: %m", historyfile); ! #endif SYSLOG return (NULL); } } ! #endif DBM key.dptr = msg_id; key.dsize = strlen(msg_id) + 1; --- 172,182 ---- #ifdef SYSLOG syslog(LOG_ERR, "openartbyid: dbm_open %s: %m", historyfile); ! #endif /* SYSLOG */ return (NULL); } } ! #endif /* DBM */ key.dptr = msg_id; key.dsize = strlen(msg_id) + 1; *************** *** 185,191 **** content = fetch(key); #else /* ndbm */ content = dbm_fetch(db, key); ! #endif DBM if (content.dptr == NULL) return (NULL); --- 185,191 ---- content = fetch(key); #else /* ndbm */ content = dbm_fetch(db, key); ! #endif /* DBM */ if (content.dptr == NULL) return (NULL); *************** *** 202,208 **** #ifdef SYSLOG syslog(LOG_ERR, "message: fopen %s: %m", historyfile); ! #endif SYSLOG return (NULL); } } else { --- 202,208 ---- #ifdef SYSLOG syslog(LOG_ERR, "message: fopen %s: %m", historyfile); ! #endif /* SYSLOG */ return (NULL); } } else { *************** *** 215,226 **** #ifdef SYSLOG syslog(LOG_ERR, "message: %s: fseek to %ld on %d: %m", historyfile, ltmp, hfp); ! #endif SYSLOG return (NULL); } (void) fgets(line, sizeof(line), hfp); ! #endif USGHIST if ((cp = index(line, '\n')) != NULL) *cp = '\0'; --- 215,226 ---- #ifdef SYSLOG syslog(LOG_ERR, "message: %s: fseek to %ld on %d: %m", historyfile, ltmp, hfp); ! #endif /* SYSLOG */ return (NULL); } (void) fgets(line, sizeof(line), hfp); ! #endif /* USGHIST */ if ((cp = index(line, '\n')) != NULL) *cp = '\0'; *************** *** 232,238 **** syslog(LOG_ERR, "message: malformed line in history file at %ld bytes, id %s", ltmp, msg_id); ! #endif SYSLOG if (cp == NULL) return(NULL); /* this article has expired */ tmp = cp+1; --- 232,238 ---- syslog(LOG_ERR, "message: malformed line in history file at %ld bytes, id %s", ltmp, msg_id); ! #endif /* SYSLOG */ if (cp == NULL) return(NULL); /* this article has expired */ tmp = cp+1; *************** *** 613,619 **** chr = '0'; return chr; } ! #endif USGHIST #ifdef USG #ifndef GAZETTE bcopy(s, d, l) --- 613,619 ---- chr = '0'; return chr; } ! #endif /* USGHIST */ #ifdef USG #ifndef GAZETTE bcopy(s, d, l) *************** *** 775,781 **** #define blkavail(fs) ((fs).f_tfree) /* USG doesn't reserve blocks for root */ #define filfree(fs) ((fs).f_tinode) ! #endif USG #ifdef CMU_MACH /* This code supplied by Tom Lane */ --- 775,781 ---- #define blkavail(fs) ((fs).f_tfree) /* USG doesn't reserve blocks for root */ #define filfree(fs) ((fs).f_tinode) ! #endif /* USG */ #ifdef CMU_MACH /* This code supplied by Tom Lane */ *************** *** 799,805 **** #define bombed(call) ((call) < 0) #define blkfree(fs) ((fs).fsp_free-((fs).fsp_size*(fs).fsp_minfree+99)/100) #define blkavail(fs) (-1) ! #endif MACH dfree(spool,free_space) char *spool; --- 799,805 ---- #define bombed(call) ((call) < 0) #define blkfree(fs) ((fs).fsp_free-((fs).fsp_size*(fs).fsp_minfree+99)/100) #define blkavail(fs) (-1) ! #endif /* MACH */ dfree(spool,free_space) char *spool; *************** *** 825,831 **** return( DFREE_OK ); } ! #else READ_SUPER /* * This code is used if you've got to directly read the superblock * to determine how much space you've got left. It's copied from --- 825,831 ---- return( DFREE_OK ); } ! #else /* READ_SUPER */ /* * This code is used if you've got to directly read the superblock * to determine how much space you've got left. It's copied from *************** *** 919,925 **** return( DFREE_OK ); } ! #endif READ_SUPER #ifdef LOAD /* --- 919,925 ---- return( DFREE_OK ); } ! #endif /* READ_SUPER */ #ifdef LOAD /* *************** *** 987,990 **** # endif } #endif ! #endif LOAD --- 987,990 ---- # endif } #endif ! #endif /* LOAD */ *** server/netaux.c Wed Sep 30 14:34:48 1992 --- server/netaux.c Tue Sep 15 20:09:59 1992 *************** *** 12,25 **** #include #ifndef EXCELAN #include ! #endif not EXCELAN #include #include #ifdef USG #include ! #else not USG #include ! #endif USG #ifdef ALONE --- 12,25 ---- #include #ifndef EXCELAN #include ! #endif /* not EXCELAN */ #include #include #ifdef USG #include ! #else /* not USG */ #include ! #endif /* USG */ #ifdef ALONE *************** *** 211,217 **** if (setitimer(ITIMER_REAL, &new, &old) < 0) { #ifdef SYSLOG syslog(LOG_ERR, "set_timer: setitimer: %m\n"); ! #endif SYSLOG exit(1); } #endif /* not USG */ --- 211,217 ---- if (setitimer(ITIMER_REAL, &new, &old) < 0) { #ifdef SYSLOG syslog(LOG_ERR, "set_timer: setitimer: %m\n"); ! #endif /* SYSLOG */ exit(1); } #endif /* not USG */ *** server/newnews.c Wed Sep 30 14:34:52 1992 --- server/newnews.c Tue Sep 15 20:10:02 1992 *************** *** 39,45 **** FILE *tmplst; int i; char *tmpfile; ! #endif USGHIST if (argc < 4) { printf("%d Usage: NEWNEWS newsgroups yymmdd hhmmss [\"GMT\"] [].\r\n", --- 39,45 ---- FILE *tmplst; int i; char *tmpfile; ! #endif /* USGHIST */ if (argc < 4) { printf("%d Usage: NEWNEWS newsgroups yymmdd hhmmss [\"GMT\"] [].\r\n", *************** *** 131,137 **** for (i = 0; i < 9; i++) { sprintf(historyfile, "%s.d/%d", HISTORY_FILE, i); ! #endif USGHIST fp = fopen(historyfile, "r"); if (fp == NULL) { --- 131,137 ---- for (i = 0; i < 9; i++) { sprintf(historyfile, "%s.d/%d", HISTORY_FILE, i); ! #endif /* USGHIST */ fp = fopen(historyfile, "r"); if (fp == NULL) { *************** *** 142,167 **** printf("%d Cannot open history file.\r\n", ERR_FAULT); (void) fflush(stdout); return; ! #else USGHIST continue; ! #endif USGHIST } #ifndef USGHIST printf("%d New news by message id follows\r\n", OK_NEWNEWS); ! #endif not USGHIST if (seekuntil(fp, key, line, sizeof (line)) < 0) { #ifndef USGHIST printf(".\r\n"); (void) fflush(stdout); ! #endif not USGHIST (void) fclose(fp); #ifndef USGHIST return; ! #else USGHIST continue; ! #endif USGHIST } /* --- 142,167 ---- printf("%d Cannot open history file.\r\n", ERR_FAULT); (void) fflush(stdout); return; ! #else /* USGHIST */ continue; ! #endif /* USGHIST */ } #ifndef USGHIST printf("%d New news by message id follows\r\n", OK_NEWNEWS); ! #endif /* not USGHIST */ if (seekuntil(fp, key, line, sizeof (line)) < 0) { #ifndef USGHIST printf(".\r\n"); (void) fflush(stdout); ! #endif /* not USGHIST */ (void) fclose(fp); #ifndef USGHIST return; ! #else /* USGHIST */ continue; ! #endif /* USGHIST */ } /* *************** *** 208,216 **** #ifdef USGHIST fputs(line, tmplst); fputc('\n', tmplst); ! #else not USGHIST putline(line); ! #endif not USGHIST #ifdef LOG nn_told++; #endif --- 208,216 ---- #ifdef USGHIST fputs(line, tmplst); fputc('\n', tmplst); ! #else /* not USGHIST */ putline(line); ! #endif /* not USGHIST */ #ifdef LOG nn_told++; #endif *************** *** 235,241 **** (void) fflush(stdout); (void) fclose(tmplst); (void) unlink(tmpfile); ! #endif USGHIST } --- 235,241 ---- (void) fflush(stdout); (void) fclose(tmplst); (void) unlink(tmpfile); ! #endif /* USGHIST */ } *** server/scandir.c Wed Sep 30 14:34:49 1992 --- server/scandir.c Tue Sep 15 20:10:01 1992 *************** *** 4,9 **** --- 4,13 ---- #include "common.h" + #ifdef ISC + # include + #endif + /* * scan_dir -- scan the current directory for news articles, * loading the article numbers into art_array. Return *************** *** 26,32 **** --- 30,40 ---- scan_dir(low_msg, high_msg) int low_msg, high_msg; { + #ifdef ISC + register struct dirent *dirent; + #else register struct direct *dirent; + #endif register DIR *dirp; int artnum; *************** *** 34,43 **** dirp = opendir("."); ! if (dirp == NULL) return (0); while ((dirent = readdir(dirp)) != NULL) { artnum = atoi(dirent->d_name); #ifdef DYNAMIC_ART_ARRAY if (artnum == 0 || artnum < low_msg || artnum > high_msg) --- 42,73 ---- dirp = opendir("."); ! if (dirp == NULL) { ! #ifdef LOG ! syslog(LOG_ERR, "scan_dir(): opendir() failed. Returning num_arts=0"); ! #endif return (0); + } while ((dirent = readdir(dirp)) != NULL) { + + #ifdef LOG + /* + { + char pwd[256]; + + getcwd (pwd, 255); + #ifdef ISC + syslog(LOG_INFO, "%s: d->d_name=%s d->d_ino=%d d->d_reclen=%d", + pwd, dirent->d_name, dirent->d_ino, dirent->d_reclen); + #else + syslog(LOG_INFO, "%s: d->d_name=%s d->d_ino=%d", + pwd, dirent->d_name, dirent->d_ino); + #endif + } + */ + #endif + artnum = atoi(dirent->d_name); #ifdef DYNAMIC_ART_ARRAY if (artnum == 0 || artnum < low_msg || artnum > high_msg) *************** *** 70,75 **** --- 100,110 ---- } art_array[num_arts] = artnum; ++num_arts; + + #ifdef LOG + syslog(LOG_INFO, "scan_dir(): artnum=%d num_arts=%d", artnum, num_arts); + #endif + #else if (artnum != 0 && artnum >= low_msg && artnum <= high_msg) art_array[num_arts++] = artnum; *** server/serve.c Wed Sep 30 14:34:43 1992 --- server/serve.c Wed Nov 18 19:07:06 1992 *************** *** 17,23 **** #ifdef LOG # ifndef USG # include ! # endif not USG #endif #ifdef TIMERS --- 17,23 ---- #ifdef LOG # ifndef USG # include ! # endif /* not USG */ #endif #ifdef TIMERS *************** *** 27,38 **** extern int ahbs(), group(), help(), ihave(); extern int list(), newgroups(), newnews(), nextlast(), post(); extern int slave(), stat(), xhdr(); extern int errno; #ifdef AUTH extern int doauth(); ! #endif AUTH static struct cmdent { char *cmd_name; --- 27,50 ---- extern int ahbs(), group(), help(), ihave(); extern int list(), newgroups(), newnews(), nextlast(), post(); extern int slave(), stat(), xhdr(); + #ifdef XINDEX + extern int xindex(); + #endif + #ifdef XMOTD + extern int xmotd(); + #endif + #ifdef XOVERVIEW + extern int xoverview(); + #endif + #ifdef XUSER + extern int xuser(); + #endif extern int errno; #ifdef AUTH extern int doauth(); ! #endif /* AUTH */ static struct cmdent { char *cmd_name; *************** *** 43,49 **** "authcap", 0, doauth, "authinfo", 0, doauth, "authsys", 0, doauth, ! #endif AUTH "article", 0, ahbs, "body", 0, ahbs, "group", 0, group, --- 55,61 ---- "authcap", 0, doauth, "authinfo", 0, doauth, "authsys", 0, doauth, ! #endif /* AUTH */ "article", 0, ahbs, "body", 0, ahbs, "group", 0, group, *************** *** 60,66 **** "stat", 0, ahbs, #ifdef XHDR "xhdr", 0, xhdr, ! #endif XHDR }; #define NUMCMDS (sizeof(cmdtbl) / sizeof(struct cmdent)) --- 72,90 ---- "stat", 0, ahbs, #ifdef XHDR "xhdr", 0, xhdr, ! #endif /* XHDR */ ! #ifdef XINDEX ! "xindex", 0, xindex, ! #endif /* XINDEX */ ! #ifdef XMOTD ! "xmotd", 0, xmotd, ! #endif /* XMOTD */ ! #ifdef XOVERVIEW ! "xoverview", 0, xoverview, ! #endif /* XOVERVIEW */ ! #ifdef XUSER ! "xuser", 0, xuser, ! #endif /* XUSER */ }; #define NUMCMDS (sizeof(cmdtbl) / sizeof(struct cmdent)) *************** *** 98,104 **** #ifdef AUTH extern int Needauth; extern char User[]; ! #endif AUTH /* * serve -- given a connection on stdin/stdout, serve --- 122,128 ---- #ifdef AUTH extern int Needauth; extern char User[]; ! #endif /* AUTH */ /* * serve -- given a connection on stdin/stdout, serve *************** *** 152,158 **** #ifdef ALONE #ifndef USG (void) signal(SIGCHLD, SIG_IGN); ! #endif not USG #endif /* Ignore SIGPIPE, since we'll see closed connections with read */ --- 176,182 ---- #ifdef ALONE #ifndef USG (void) signal(SIGCHLD, SIG_IGN); ! #endif /* not USG */ #endif /* Ignore SIGPIPE, since we'll see closed connections with read */ *************** *** 163,169 **** #ifdef AUTH Needauth = 1; strcpy(User,""); ! #endif AUTH host_access(&canread, &canpost, &canxfer, gdbuf); if (gethostname(host, sizeof(host)) < 0) --- 187,193 ---- #ifdef AUTH Needauth = 1; strcpy(User,""); ! #endif /* AUTH */ host_access(&canread, &canpost, &canxfer, gdbuf); if (gethostname(host, sizeof(host)) < 0) *************** *** 302,308 **** (void) fflush(stdout); continue; } ! #endif AUTH (*cmdtbl[i].cmd_fctn)(argnum, argp); } else { #ifdef SYSLOG --- 326,332 ---- (void) fflush(stdout); continue; } ! #endif /* AUTH */ (*cmdtbl[i].cmd_fctn)(argnum, argp); } else { #ifdef SYSLOG *************** *** 490,493 **** user, sys, Tfinish - Tstart); syslog(LOG_INFO, "%s times %s", hostname, buf); } ! #endif LOG --- 514,517 ---- user, sys, Tfinish - Tstart); syslog(LOG_INFO, "%s times %s", hostname, buf); } ! #endif /* LOG */ *** server/spawn.c Wed Sep 30 14:34:46 1992 --- server/spawn.c Tue Sep 15 20:09:59 1992 *************** *** 65,73 **** #endif #ifdef USG int status; ! #else not USG union wait status; ! #endif not USG register FILE *fp; #ifdef CNEWS --- 65,73 ---- #endif #ifdef USG int status; ! #else /* not USG */ union wait status; ! #endif /* not USG */ register FILE *fp; #ifdef CNEWS *************** *** 91,97 **** */ if (cont_code == CONT_POST) fprintf(fp, "Nntp-Posting-Host: %s\n", hostname); ! #endif AUTH printf("%d Ok\r\n", cont_code); (void) fflush(stdout); --- 91,97 ---- */ if (cont_code == CONT_POST) fprintf(fp, "Nntp-Posting-Host: %s\n", hostname); ! #endif /* AUTH */ printf("%d Ok\r\n", cont_code); (void) fflush(stdout); *************** *** 332,338 **** #ifdef LOG syslog(LOG_ERR, "%s transfer_timeout", hostname); ! #endif LOG (void) unlink(tempfile); --- 332,338 ---- #ifdef LOG syslog(LOG_ERR, "%s transfer_timeout", hostname); ! #endif /* LOG */ (void) unlink(tempfile); *************** *** 339,343 **** exit(1); } ! #endif XFER_TIMEOUT --- 339,343 ---- exit(1); } ! #endif /* XFER_TIMEOUT */ *** server/time.c Wed Sep 30 14:34:50 1992 --- server/time.c Tue Sep 15 20:10:01 1992 *************** *** 10,18 **** #include "common.h" #ifdef USG #include ! #else not USG #include ! #endif not USG /* * dtol -- convert date to long integer. This is not implicitly --- 10,18 ---- #include "common.h" #ifdef USG #include ! #else /* not USG */ #include ! #endif /* not USG */ /* * dtol -- convert date to long integer. This is not implicitly *** server/timer.c Wed Sep 30 14:34:49 1992 --- server/timer.c Sat Oct 17 20:01:25 1992 *************** *** 6,17 **** #ifdef TIMERS #ifndef lint static char rcsid[] = ! "@(#) $Header: timer.c,v 1.3 91/03/19 03:02:41 sob Exp $ (NNTP with TIMERS)"; #endif #else #ifndef lint static char rcsid[] = ! "@(#) $Header: timer.c,v 1.3 91/03/19 03:02:41 sob Exp $ (NNTP without TIMERS)"; #endif #endif --- 6,17 ---- #ifdef TIMERS #ifndef lint static char rcsid[] = ! "@(#) $Header: timer.c,v 1.2 90/12/27 22:16:27 sob Exp $ (NNTP with TIMERS)"; #endif #else #ifndef lint static char rcsid[] = ! "@(#) $Header: timer.c,v 1.2 90/12/27 22:16:27 sob Exp $ (NNTP without TIMERS)"; #endif #endif *************** *** 18,29 **** #ifdef TIMERS #include #include "timer.h" ! #ifdef USG ! #ifdef LAI_TCP #include - #define BSDSELECT #endif ! #else #ifndef FD_SETSIZE /* Forward compatability */ #define FD_SET(n, p) ((p)->fds_bits[0] |= (1<<(n))) --- 18,27 ---- #ifdef TIMERS #include #include "timer.h" ! #ifdef ISC #include #endif ! #ifndef USG #ifndef FD_SETSIZE /* Forward compatability */ #define FD_SET(n, p) ((p)->fds_bits[0] |= (1<<(n))) *************** *** 30,36 **** #define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1<<(n))) #define FD_ISSET(n, p) ((p)->fds_bits[0] & (1<<(n))) #define FD_ZERO(p) ((p)->fds_bits[0] = 0) - #define BSDSELECT #endif #endif /* non-portable */ --- 28,33 ---- *************** *** 75,81 **** register int i, n; register struct timer *tp; register long secs; ! #ifndef BSDSELECT long timeout; long readfds; #else --- 72,78 ---- register int i, n; register struct timer *tp; register long secs; ! #if defined(USG) && !defined(ISC) long timeout; long readfds; #else *************** *** 89,95 **** return(1); /* Length of next timeout is minimum of all "timers" */ ! #ifndef BSDSELECT timeout = -1; for (i = ntimer, tp = timers; i > 0; --i, ++tp) if (tp->left >= 0 && --- 86,92 ---- return(1); /* Length of next timeout is minimum of all "timers" */ ! #if defined(USG) && !defined(ISC) timeout = -1; for (i = ntimer, tp = timers; i > 0; --i, ++tp) if (tp->left >= 0 && *************** *** 120,128 **** /* Do select */ FD_ZERO(&readfds); FD_SET(fileno(stdin), &readfds); ! #endif /* BSDSELECT */ errno = 0; ! #if defined(EXCELAN) || defined(ULTRIX) n = select(fileno(stdin) + 1, &readfds, (long*)0, timeout); #else n = select(fileno(stdin) + 1, --- 117,125 ---- /* Do select */ FD_ZERO(&readfds); FD_SET(fileno(stdin), &readfds); ! #endif /* !USG */ errno = 0; ! #ifdef EXCELAN n = select(fileno(stdin) + 1, &readfds, (long*)0, timeout); #else n = select(fileno(stdin) + 1, *** server/xhdr.c Wed Sep 30 14:34:50 1992 --- server/xhdr.c Tue Sep 15 20:10:02 1992 *************** *** 158,164 **** } } ! #else not XHDR /* Kludge to get around Greenhills C compiler */ --- 158,164 ---- } } ! #else /* not XHDR */ /* Kludge to get around Greenhills C compiler */ *************** *** 166,169 **** { } ! #endif not XHDR --- 166,169 ---- { } ! #endif /* not XHDR */ ð*[SRC.TIN-1_22]SIGFILE.C;2+,®. //€ 4 <-d0@î123KÿPWO 56Ÿ~I†—7 ~I†—89€]V‚—G/€HªJÿ/* * Project : tin - a Usenet reader * Module : sigfile.c * Author : M.Gleason & I.Lea * Created : 17-10-92 * Updated : 11-07-93 * Notes : Generate random signature for posting/mailing etc. * Copyright : (c) Copyright 1989-93 by Mike Gleason & Iain Lea * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" #ifndef S_ISDIR # define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR) #endif #define MAXLOOPS 1000 #ifndef M_AMIGA # define CURRENTDIR "." #else # define CURRENTDIR "" #endif static char sigfile[PATH_LEN]; void add_signature (fp, flag) FILE *fp; int flag; { char path[PATH_LEN]; char cwd[PATH_LEN]; FILE *fixfp; FILE *sigfp; int i; #ifdef NNTP_INEWS if (read_news_via_nntp && use_builtin_inews) { flag = TRUE; } #endif i = my_group[cur_groupnum]; if (! strfpath (active[i].attribute.sigfile, path, sizeof (path), homedir, (char *) 0, (char *) 0, active[i].name)) { if (! strfpath (default_sigfile, path, sizeof (path), homedir, (char *) 0, (char *) 0, active[i].name)) { joinpath (path, homedir, ".Sig"); } } /* * Check to see if sigfile is a directory & if it is generate a * random signature from sigs in sigdir. If the file ~/.sigfixed * exists (fixed part of random sig) then read it in first and * append the random sig part onto the end. */ if ((sigfp = open_random_sig (path)) != (FILE *) 0) { if (debug == 2) { error_message ("USING random sig=[%s]", sigfile); } get_cwd (cwd); fprintf (fp, "\n--\n"); joinpath (path, homedir, ".sigfixed"); if ((fixfp = fopen (path, "r")) != (FILE *) 0) { copy_fp (fixfp, fp, ""); fclose (fixfp); } copy_fp (sigfp, fp, ""); fclose (sigfp); my_chdir (cwd); return; } /* * Use ~/.signature or ~/.Sig or custom .Sig files */ if ((sigfp = fopen (default_signature, "r")) != (FILE *) 0) { if (flag) { fprintf (fp, "\n--\n"); copy_fp (sigfp, fp, ""); } fclose (sigfp); return; } if ((sigfp = fopen (path, "r")) != (FILE *) 0) { fprintf (fp, "\n--\n"); copy_fp (sigfp, fp, ""); fclose (sigfp); } } FILE * open_random_sig (sigdir) char *sigdir; { long epoch; struct stat st; if (stat (sigdir, &st) != -1) { if (S_ISDIR(st.st_mode)) { time (&epoch); srand ((unsigned int) epoch); my_chdir (sigdir); if (thrashdir (sigdir) || ! sigfile[0]) { if (debug == 2) { error_message ("NO sigfile=[%s]", sigfile); } return (FILE *) 0; } else { if (debug == 2) { error_message ("sigfile=[%s]", sigfile); } return fopen (sigfile, "r"); } } } return (FILE *) 0; } int thrashdir (sigdir) char *sigdir; { char *cwd; int safeguard, recurse; register DIR *dirp; register DIR_BUF *dp; register int c, numentries, pick; struct stat st; sigfile[0] = '\0'; if ((dirp = opendir (CURRENTDIR)) == NULL) { return (1); } numentries = 0; while ((dp = readdir (dirp)) != NULL) { numentries++; } /* * consider "." and ".." non-entries */ cwd = (char *) my_malloc (PATH_LEN + 1); #ifndef M_AMIGA if (numentries < 3 || cwd == (char *) 0) { #else if (numentries == 0 || cwd == (char *) 0) { #endif closedir (dirp); return (-1); } get_cwd (cwd); recurse = strcmp (cwd, sigdir); /* If we are using the root sig directory, we don't want * to recurse, or else we might use a custom sig intended * for a specific newsgroup (and not this one). */ for (safeguard=0, dp=NULL; safeguard= 0) { if ((dp = readdir (dirp)) == NULL) { break; } } if (dp != NULL) { /* if we could open the dir entry */ if (! strcmp (dp->d_name, CURRENTDIR) || ! strcmp (dp->d_name, "..")) { dp = NULL; } else { /* if we have a non-dot entry */ if (stat (dp->d_name, &st) == -1) { gak: closedir (dirp); return (1); } if (S_ISDIR(st.st_mode)) { if (recurse) { /* * do subdirectories */ if (my_chdir (dp->d_name) < 0) { goto gak; } if ((c = thrashdir (sigdir)) == 1) { goto gak; } else if (c == -1) { /* * the one we picked was an * empty dir so try again. */ dp = NULL; my_chdir (cwd); } } else { dp = NULL; } } else { /* end dir; we have a file */ get_cwd (sigfile); strcat (sigfile, "/"); strcat (sigfile, dp->d_name); if (debug == 2) { error_message ("Found a file=[%s]", sigfile); } } } } } free (cwd); if (debug == 2) { error_message ("return 0: sigfile=[%s]", sigfile); } closedir (dirp); return (0); } ð*[SRC.TIN-1_22]SIGNAL.C;2+,Ù.//€ 4¾-d0@î123KÿPWO56`myD`†—7À—E`†—89€]V‚—G/€HªJÿ/* * Project : tin - a Usenet reader * Module : signal.c * Author : I.Lea * Created : 01-04-91 * Updated : 05-09-93 * Notes : signal handlers for different modes and window resizing * Copyright : (c) Copyright 1991-93 by Iain Lea * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" extern char *glob_art_group; extern char *glob_group; extern char *glob_page_group; extern char index_file[PATH_LEN]; extern int glob_respnum; static int time_remaining; #ifdef SIGTSTP int do_sigtstp = 0; #endif #ifdef HAVE_POSIX_JC /* * for POSIX systems we know SIGTYPE is void */ void (*sigdisp(sig, func))() int sig; void (*func)(); { struct sigaction sa, osa; sa.sa_handler = func; sigemptyset (&sa.sa_mask); sa.sa_flags = 0; #ifdef SA_RESTART sa.sa_flags |= SA_RESTART; #endif if (sigaction (sig, &sa, &osa) < 0) { #ifdef DONT_PROTOTYPE_PTR_TO_FUNC return ((void (*) ()) (-1)); #else return ((void (*) (int)) (-1)); #endif } return (osa.sa_handler); } #else t_sigtype (*sigdisp(sig, func))() int sig; t_sigtype (_CDECL *func)(SIGTYPE); { return (signal (sig, func)); } #endif void set_signal_handlers () { #ifdef SIGINT signal (SIGINT, signal_handler); /* ctrl-C */ #endif #ifdef SIGQUIT signal (SIGQUIT, signal_handler); /* ctrl-\ */ #endif #ifdef SIGHUP signal (SIGHUP, signal_handler); /* hangup */ #endif #ifdef SIGILL signal (SIGILL, signal_handler); /* illegal instruction */ #endif #ifdef SIGFPE signal (SIGFPE, signal_handler); /* floating point exception */ #endif #if 0 #ifdef SIGBUS signal (SIGBUS, signal_handler); /* bus error */ #endif #endif #ifdef SIGSEGV signal (SIGSEGV, signal_handler); /* segmentation violation */ #endif #ifdef SIGPIPE signal (SIGPIPE, SIG_IGN); #endif #ifdef SIGCHLD signal (SIGCHLD, signal_handler); /* death of a child process */ #endif #ifdef SIGPWR signal (SIGPWR, signal_handler); /* powerfail */ #endif #ifdef SIGWINCH if (debug == 2) { wait_message ("SIGWINCH setting signal..."); sleep (2); } signal (SIGWINCH, main_resize); #endif #if defined(SIGTSTP) && ! defined(MINIX) { t_sigtype (*ptr)(); ptr = signal (SIGTSTP, SIG_DFL); signal (SIGTSTP, ptr); if (ptr != SIG_IGN) { /* * SIGTSTP is ignored when starting from shells * without job-control */ do_sigtstp = 1; signal (SIGTSTP, main_suspend); } } #endif } void set_alarm_signal () { #ifndef DONT_REREAD_ACTIVE_FILE /* * Only reread active file if news is not static (ie. CD-ROM) */ (void) alarm (0); if (strcmp (spooldir_alias, "news") == 0) { #ifndef M_OS2 signal (SIGALRM, signal_handler); #endif alarm (reread_active_file_secs); } reread_active_file = FALSE; #endif } void set_alarm_clock_on () { #ifndef DONT_REREAD_ACTIVE_FILE alarm (time_remaining); #endif } void set_alarm_clock_off () { #ifndef DONT_REREAD_ACTIVE_FILE time_remaining = alarm (0); #endif } void _CDECL signal_handler (sig) int sig; { char *sigtext; #ifdef SIGCHLD int wait_status = 1; #endif switch (sig) { #ifdef SIGINT case SIGINT: sigtext = "SIGINT "; # if !defined(M_AMIGA) && !defined(__SASC) if (! update) { signal (SIGINT, signal_handler); return; } # endif break; #endif #ifdef SIGQUIT case SIGQUIT: sigtext = "SIGQUIT "; break; #endif #ifdef SIGHUP case SIGHUP: sigtext = "SIGHUP "; break; #endif #ifdef SIGCHLD case SIGCHLD: wait (&wait_status); signal (SIGCHLD, signal_handler); /* death of a child */ # ifdef WEXITSTATUS system_status = WEXITSTATUS(wait_status); # endif return; #endif #ifdef SIGPWR case SIGPWR: sigtext = "SIGPWR "; break; #endif #ifdef SIGFPE case SIGFPE: sigtext = "SIGFPE "; break; #endif #ifdef SIGBUS case SIGBUS: sigtext = "SIGBUS "; break; #endif #ifdef SIGSEGV case SIGSEGV: sigtext = "SIGSEGV "; break; #endif #if defined(SIGALRM) && !defined(DONT_REREAD_ACTIVE_FILE) case SIGALRM: set_alarm_signal (); reread_active_file = TRUE; return; #endif default: sigtext = ""; break; } Raw (FALSE); EndWin (); fprintf (stderr, "\n%s: signal handler caught signal %s(%d).\n", progname, sigtext, sig); #if defined(SIGBUS) || defined(SIGSEGV) if ( # ifdef SIGBUS sig == SIGBUS # endif # if defined(SIGBUS) && defined(SIGSEGV) || # endif # ifdef SIGSEGV sig == SIGSEGV # endif ) { fprintf (stderr, "%s: send a bug report to %s%s\n", progname, BUG_REPORT_ADDRESS, add_addr); } #endif fflush (stderr); cleanup_tmp_files (); exit (1); } int set_win_size (num_lines, num_cols) int *num_lines; int *num_cols; { int old_lines; int old_cols; #ifdef TIOCGSIZE struct ttysize win; #else # ifdef TIOCGWINSZ struct winsize win; # endif #endif old_lines = *num_lines; old_cols = *num_cols; init_screen_array (FALSE); /* deallocate screen array */ #ifdef TIOCGSIZE if (ioctl (0, TIOCGSIZE, &win) == 0) { if (win.ts_lines != 0) { *num_lines = win.ts_lines - 1; } if (win.ts_cols != 0) { *num_cols = win.ts_cols; } } #else # ifdef TIOCGWINSZ if (ioctl (0, TIOCGWINSZ, &win) == 0) { if (win.ws_row != 0) { *num_lines = win.ws_row - 1; } if (win.ws_col != 0) { *num_cols = win.ws_col; } } # endif #endif init_screen_array (TRUE); /* allocate screen array for resize */ set_subj_from_size (*num_cols); RIGHT_POS = *num_cols - 20; MORE_POS = *num_cols - 15; if (beginner_level) { NOTESLINES = *num_lines - INDEX_TOP - MINI_HELP_LINES; } else { NOTESLINES = *num_lines - INDEX_TOP - 1; } if (NOTESLINES <= 0) { NOTESLINES = 1; } if (*num_lines != old_lines || *num_cols != old_cols) { return TRUE; } else { return FALSE; } } void set_signals_art () { #ifdef SIGTSTP if (do_sigtstp) { sigdisp (SIGTSTP, art_suspend); } #endif #ifdef SIGWINCH signal (SIGWINCH, art_resize); #endif } void set_signals_group () { #ifdef SIGTSTP iÀq“~ TIN-1_22.BCKÙd[SRC.TIN-1_22]SIGNAL.C;2£É f (do_sigtstp) { sigdisp (SIGTSTP, group_suspend); } #endif #ifdef SIGWINCH signal (SIGWINCH, group_resize); #endif } void set_signals_help () { #ifdef SIGTSTP if (do_sigtstp) { sigdisp (SIGTSTP, help_suspend); } #endif #ifdef SIGWINCH signal (SIGWINCH, help_resize); #endif } void set_signals_page () { #ifdef SIGTSTP if (do_sigtstp) { sigdisp (SIGTSTP, page_suspend); } #endif #ifdef SIGWINCH signal (SIGWINCH, page_resize); #endif } void set_signals_select () { #ifdef SIGTSTP if (do_sigtstp) { sigdisp (SIGTSTP, select_suspend); } #endif #ifdef SIGWINCH signal (SIGWINCH, select_resize); #endif } void set_signals_spooldir () { #ifdef SIGTSTP if (do_sigtstp) { sigdisp (SIGTSTP, spooldir_suspend); } #endif #ifdef SIGWINCH signal (SIGWINCH, spooldir_resize); #endif } void set_signals_thread () { #ifdef SIGTSTP if (do_sigtstp) { sigdisp (SIGTSTP, thread_suspend); } #endif #ifdef SIGWINCH signal (SIGWINCH, thread_resize); #endif } #ifdef SIGTSTP /* ARGSUSED0 */ void art_suspend (sig) int sig; { set_keypad_off (); Raw (FALSE); wait_message (txt_suspended_message); kill (0, SIGSTOP); sigdisp (SIGTSTP, art_suspend); if (! update) { Raw (TRUE); art_resize (0); } set_keypad_on (); } /* ARGSUSED0 */ void main_suspend (sig) int sig; { set_keypad_off (); Raw (FALSE); wait_message (txt_suspended_message); kill (0, SIGSTOP); sigdisp (SIGTSTP, main_suspend); if (! update) { Raw (TRUE); main_resize (0); } set_keypad_on (); } /* ARGSUSED0 */ void select_suspend (sig) int sig; { set_keypad_off (); Raw (FALSE); wait_message (txt_suspended_message); kill (0, SIGSTOP); sigdisp (SIGTSTP, select_suspend); if (! update) { Raw (TRUE); select_resize (0); } set_keypad_on (); } /* ARGSUSED0 */ void spooldir_suspend (sig) int sig; { set_keypad_off (); Raw (FALSE); wait_message (txt_suspended_message); kill (0, SIGSTOP); sigdisp (SIGTSTP, spooldir_suspend); if (! update) { Raw (TRUE); spooldir_resize (0); } set_keypad_on (); } /* ARGSUSED0 */ void group_suspend (sig) int sig; { set_keypad_off (); Raw (FALSE); wait_message (txt_suspended_message); kill (0, SIGSTOP); sigdisp (SIGTSTP, group_suspend); if (! update) { Raw (TRUE); group_resize (0); } set_keypad_on (); } /* ARGSUSED0 */ void help_suspend (sig) int sig; { set_keypad_off (); Raw (FALSE); wait_message (txt_suspended_message); kill (0, SIGSTOP); sigdisp (SIGTSTP, help_suspend); if (! update) { Raw (TRUE); help_resize (0); } set_keypad_on (); } /* ARGSUSED0 */ void page_suspend (sig) int sig; { set_keypad_off (); Raw (FALSE); wait_message (txt_suspended_message); kill (0, SIGSTOP); sigdisp (SIGTSTP, page_suspend); if (! update) { Raw (TRUE); page_resize (0); } set_keypad_on (); } /* ARGSUSED0 */ void thread_suspend (sig) int sig; { set_keypad_off (); Raw (FALSE); wait_message (txt_suspended_message); kill (0, SIGSTOP); sigdisp (SIGTSTP, thread_suspend); if (! update) { Raw (TRUE); thread_resize (0); } set_keypad_on (); } /* ARGSUSED0 */ void rcfile_suspend (sig) int sig; { set_keypad_off (); Raw (FALSE); wait_message (txt_suspended_message); kill (0, SIGSTOP); sigdisp (SIGTSTP, rcfile_suspend); Raw (TRUE); set_keypad_on (); show_rcfile_menu (); } #endif /* SIGTSTP */ /* ARGSUSED0 */ void art_resize (sig) int sig; { char buf[LEN]; #ifdef SIGWINCH (void) set_win_size (&cLINES, &cCOLS); signal (SIGWINCH, art_resize); #endif mail_setup (); ClearScreen (); sprintf (buf, txt_group, glob_art_group); wait_message (buf); } /* ARGSUSED0 */ void main_resize (sig) int sig; { #ifdef SIGWINCH (void) set_win_size (&cLINES, &cCOLS); signal (SIGWINCH, main_resize); #endif mail_setup (); } /* ARGSUSED0 */ void select_resize (sig) int sig; { int resized = TRUE; #ifdef SIGWINCH resized = set_win_size (&cLINES, &cCOLS); signal (SIGWINCH, select_resize); #endif mail_setup (); if (resized || sig == 0) { #ifndef USE_CLEARSCREEN ClearScreen (); #endif group_selection_page (); } } /* ARGSUSED0 */ void spooldir_resize (sig) int sig; { int resized = TRUE; #ifdef SIGWINCH resized = set_win_size (&cLINES, &cCOLS); signal (SIGWINCH, spooldir_resize); #endif mail_setup (); if (resized || sig == 0) { #ifndef USE_CLEARSCREEN ClearScreen (); #endif show_spooldir_page (); } } /* ARGSUSED0 */ void group_resize (sig) int sig; { int resized = TRUE; #ifdef SIGWINCH resized = set_win_size (&cLINES, &cCOLS); signal (SIGWINCH, group_resize); #endif mail_setup (); if (resized || sig == 0) { #ifndef USE_CLEARSCREEN ClearScreen (); #endif show_group_page (); } } /* ARGSUSED0 */ void help_resize (sig) int sig; { int resized = TRUE; #ifdef SIGWINCH resized = set_win_size (&cLINES, &cCOLS); signal (SIGWINCH, help_resize); #endif if (resized || sig == 0) { display_info_page (); } } /* ARGSUSED0 */ void page_resize (sig) int sig; { int resized = TRUE; #ifdef SIGWINCH resized = set_win_size (&cLINES, &cCOLS); signal (SIGWINCH, page_resize); #endif mail_setup (); if (resized || sig == 0) { #ifndef USE_CLEARSCREEN ClearScreen (); #endif redraw_page (glob_respnum, glob_page_group); } } /* ARGSUSED0 */ void thread_resize (sig) int sig; { int resized = TRUE; #ifdef SIGWINCH resized = set_win_size (&cLINES, &cCOLS); signal (SIGWINCH, thread_resize); #endif mail_setup (); if (resized || sig == 0) { #ifndef USE_CLEARSCREEN ClearScreen (); #endif show_thread_page (); } } ð*[SRC.TIN-1_22]SIO.DIR;1+,t.//€ 4-d0ª123€ KÿPWO56 #†Ã†—7¯k—89€šIÊ’—G/€HªJÿIÿ $COPYRIGHT.‡ ÿ $M$AKEFILE. Üÿ$README.âÿ $S$PRINT.3æÿEVENTS.HìÿIMPL.Hòÿÿ†ÿ MAKEFILE.ý Ç í V Õ ºäzªÛ:  ÿ MAKESIO.COM5  ÿSIO.3õÿSIO.CöÿSIO.DVIÿSIO.H÷&ÿ SIOCONF.H  øTÿSIOSUP.C ¹µ!ZùÿÿÿSPRINT.Cûÿ SUITE.DIRüÿTAGS.Œ!ÿÿð*[SRC.TIN-1_22.SIO]$COPYRIGHT.;1+,‡.//€ 44-t0@î123KÿPWO56˜^†Ã†—7à_{Á†—89€]V‚—G/€HªJÿThis software is (c) Copyright 1992, 1993 by Panagiotis Tsirigotis The author (Panagiotis Tsirigotis) grants permission to use, copy, and distribute this software and its documentation for any purpose and without fee, provided that a) the above copyright notice extant in files in this distribution is not removed from files included in any redistribution, and b) this file is also included in any redistribution. Modifications to this software may be distributed, either by distributing the modified software or by distributing patches to the original software, under the following additional terms: 1. The version number will be modified as follows: a. The first 3 components of the version number (i.e. ..) will remain unchanged. b. A new component will be appended to the version number to indicate the modification level. The form of this component is up to the author of the modifications. 2. The author of the modifications will include his/her name by appending it along with the new version number to this file and will be responsible for any wrong behavior of the modified software. The author makes no representations about the suitability of this software for any purpose. It is provided "as is" without any express or implied warranty. ð*[SRC.TIN-1_22.SIO]$M$AKEFILE.;2+, .//€ 4¶-t0@î123KÿPWO56àK)äņ—7@m‰äņ—89€]V‚—G/€HªJÿ# Available entries: # lib --> creates the library # clean --> removes all .obj and .a files # spotless --> clean + uninstall # tags --> creates a tags file (from the SOURCES and HEADERS) NAME = sio VERSION = 1.6.1 HEADERS = sio.h impl.h events.h sioconf.h SOURCES = sprint.c sio.c siosup.c OBJECTS = sprint.obj sio.obj siosup.obj MANFILES = sio.3 Sprint.3 INCLUDEFILES = sio.h # Available flags: # -DDEBUG : enables assertions in the code. A failed assertion # terminates the program # -DEVENTS : enables code that records events (currently limited # to which functions have been called on a given fd) # and code that accesses the event buffers. # -DLITTLE_ENDIAN : says that the machine is a little endian. This is # needed if you enable EVENTS and your machine is a # little endian (big endian is the default). # # DEFS should be set from the command line; the current group of defs # is for SunOS 4.x # DEFS = HAS_ISATTY DEBUG = /noopt VERSION_DEF = VERSION="""SIO Version $(VERSION)""" CPP_DEFS = /define=($(VERSION_DEF),$(DEFS)) # # The following variables shouldn't need to be changed # LINT_FLAGS = -hbux CPP_FLAGS = $(CPP_DEFS) CC_FLAGS = $(DEBUG) CFLAGS = $(CPP_FLAGS) $(CC_FLAGS) LIBNAME = lib$(NAME).olb lib: $(LIBNAME) $(LIBNAME): $(OBJECTS) library/create $(LIBNAME) sprint.obj,sio.obj,siosup.obj clean: del/log $(OBJECTS) $(LIBNAME) core # # PUT HERE THE RULES TO MAKE THE OBJECT FILES # sprint.obj: sio.h impl.h sioconf.h sio.obj: sio.h impl.h sioconf.h events.h siosup.obj: sio.h impl.h sioconf.h events.h ð*[SRC.TIN-1_22.SIO]$README.;1+,â. //€ 4 ƒ-t0@î123KÿPWO 56@㪆Æ—7€vø{Á†—89€]V‚—G/€HªJÿ====================================================================== NOTE: I use vi with a tabstop value of 3. Using the same tabstop value will make the text/code look properly indented. ====================================================================== 1. What is SIO ? SIO is a library that provides _stream_ I/O which is what most Unix programs do. As such it is a competitor to stdio. 2. Why would you care to use it ? a. SIO is a little faster than stdio b. SIO provides an easier-to-use interface (IMHO) c. SIO is capable of using memory mapping for reading files if the operating system supports it. d. If you have a program that uses read(2)/write(2) it is trivial to convert it to use SIO (just replace read with Sread and write with Swrite) e. You get source 3. Setting up the Stream I/O (SIO) library There are 3 steps to the process: 1) modifying the SIO configuration file (but you can skip this step if you are using one of the operating systems listed below). 2) testing SIO 3) installing the library and manpages 3.1. How to compile the Stream I/O (SIO) library All the system-dependent stuff of SIO is placed in the sioconf.h file. If your system is not listed below, you will need to read that file to see what flags you need to set to properly compile SIO. For the following systems, here is what you need to do: SunOS 4.x: make "DEFS=-DHAS_MMAP -DHAS_ONEXIT -DHAS_MEMOPS -DHAS_ISATTY" SunOS 5.x (aka Solaris 2.y): make "DEFS=-DHAS_MMAP -DHAS_ATEXIT -DHAS_MEMOPS -DHAS_ISATTY" (I don't have access to a system running Solaris 2.y so I have not tested this) Ultrix 4.x: make "DEFS=-DHAS_MEMOPS -DHAS_ATEXIT -DHAS_ISATTY" If your system is one of the above, then you can skip to the next subsection. However, I should mention that the library compiles by default with debugging enabled (i.e. uses the -g flag of cc). You can override this by appending to the invocation of 'make' the argument "DEBUG=-O" If your system is not among the above, then you will need to modify the sioconf.h file. You do this by uncommenting the inclusion of customconf.h. Then, you can override all constants/macros defined in sioconf.h by defining them first in customconf.h. Please read sioconf.h for more information on what constants/macros can be defined. The Makefile has a header that explains what the Makefile can do. The only flag that you may want to define is -DDEBUG which enables assertions in the SIO code (if an assertion fails, the program is terminated with an error message that lists the SIO file and line number where the error occured). 3.2. Testing SIO After you have successfully compiled SIO, you can use the programs in the "suite" directory to test the SIO functions. Testing should be done before installing the library. The script testlib does everything; just type: testlib all The script sprint_test (invoked by testlib) tests Sprint by using a variety of formats and comparing its output with that of an ANSI-compatible printf. At least on Ultrix 4.1 and 4.2 this test fails because printf is not ANSI-compatible. In such a case, you can test the rest of the SIO functions by typing: testlib all Sprint (anything after the 'all' argument is interpreted as a function that should not be tested). The README file in the "suite" directory describes how to do a few more tests that cannot be done automatically. 3.3. Installing the library and manpages The 'make' command will create libsio.a in the current directory. The Makefile includes an "install" target. Doing a 'make install' will cause the following: a) libsio.a will be installed in LIBDIR b) the necessary SIO header files will be installed in INCLUDEDIR c) the SIO man pages will be installed in MANDIR LIBDIR, INCLUDEDIR, and MANDIR are Makefile variables that you can edit in the Makefile or override when you invoke 'make'. Here is a sample command to install SIO: make install LIBDIR=/usr/local/lib INCLUDEDIR=/usr/local/include MANDIR=/usr/local/man/man3 4. Epilogue Feel free to modify SIO to suit your needs. Please let me know of any bugs you find. If you want to distribute your modifications, please read the COPYRIGHT file. It basically says that you are free to redistribute as long as you retain the original copyright notice and you make sure that your modifications are identifiable. In order to achieve this I have reserved the first 3 components of the version number (for example, 1.4.2) and you can identify your mods by appending another component to that version number (for example, 1.4.2.A2). Also, if you distribute a modified version of the library, you take full responsibility for any bugs in the code (not just your code; the whole thing). ð*[SRC.TIN-1_22.SIO]$S$PRINT.3;1+,æ. //€ 4 -t0@î123KÿPWO 56 ԆÆ—7 ‘|Á†—89€]V‚—G/€HªJÿ.\"(c) Copyright 1992, 1993 by Panagiotis Tsirigotis .\"All rights reserved. The file named COPYRIGHT specifies the terms .\"and conditions for redistribution. .\" .\" $Id: Sprint.3,v 8.1 1993/03/13 01:15:34 panos Exp $ .TH Sprint 3X "29 May 1992" .SH NAME Sprint -- formatted stream output .SH SYNOPSIS .LP .nf .ft B int Sprint( fd, format [ , ... ] ) int fd ; char *format ; .SH DESCRIPTION \fBSprint()\fR provides formatted output conversion. The formatting is controlled by the \fIformat\fR argument. All characters in \fIformat\fR that do not specify a conversion are printed. A conversion is specified by a '%' followed by a string that ends with a conversion type character. The string may contain flags, a field width, a precision, and a modifier. .LP Possible flags (more that one can be specified and they can be in any order) include: .TP 10 .B \'-' specifies left adjustment of the converted argument. The default is right adjustment. This flag is meaningful only if a field width is specified. .TP .B \'+' specifies that a number will always have a sign as a prefix (this forces a '+' sign to appear if the number is positive). .TP .B \' ' prefixes a \fIspace\fR to the number if the number has not a sign (therefore the '+' flag overrides this flag). .TP .B \'#' The meaning of '#' depends on the conversion type character: for \fBo\fR conversions the first digit will be 0; for \fBx\fR or \fBX\fR conversions \fB0x\fR or \fB0X\fR respectively will be prefixed to the number (if it is not zero); for \fBe\fR, \fBE\fR, \fBf\fR, \fBg\fR, and \fBG\fR conversions the number will always have a decimal point. .TP .B \'0' specifies padding with zeros instead of spaces. .LP The field width is specified by a number. This number indicates the \fIminimum\fR width for the field. A '*' may be used instead of the number. In that case the width is the value of the next argument which should be an \fBint\fR. A negative width value specifies left adjustment with a width equal to the absolute width value. .LP A precision is specified by a '.' followed by a number. The meaning of the precision depends on the type conversion character. For a string conversion, precision determines how many characters are printed from the string. For integer conversions, precision determines the number of digits used to print the number (zero padding is done if the precision exceeds the length of the number). For floating point conversions, precision determines the number of digits after the decimal point (\fBe\fR, \fBE\fR, \fBf\fR) or the number of significant digits (\fBg\fR, \fBG\fR). A '*' may be used instead of a number to specify the precision. In that case the precision is the value of the next argument which should be an \fBint\fR. The behavior of \fBSprint()\fR is undefined if the precision is negative. .LP The length modifier is \fBl\fR and indicates that the argument is a \fBlong\fR integer. .LP The type conversion characters are: \fBd, i, o, x, X, u, c, s, f, e, E, g, G, p, n, %\fR. For floating point conversions the argument should be of type \fIdouble\fR. .TP 10 .B d,i specify signed decimal conversion. .TP .B u specifies unsigned decimal conversion. .TP .B o specifies octal conversion. .TP .B x,X specify hexadecimal conversion. For .B x the hex digits used are 0123456789abcdef. For .B X the hex digits used are 0123456789ABCDEF. There is no leading .B 0x or .B 0X (use the '#' flag for that). .TP .B c specifies character conversion; the argument should be of type \fIchar\fR. .TP .B s specifies string conversion; the argument should be of type \fIchar *\fR. .TP .B f specifies conversion to the form [-]ddd.dddd. The number of digits after the decimal point depends on precision; the default is 6. If the precision is 0, the decimal point is not printed (this can be overriden with the '#' flag). .B e,E specify conversion to the form [-]ddd.dddd[eE][+-]ddd. The number of digits after the decimal point depends on precision; the default is 6. If the precision is 0, the decimal point is not printed (this can be overriden with the '#' flag). The exponent is at least 2 digit wide. .TP .B g,G specify a conversion using the .B e,E format respectively if the exponent is less than -4 or greater than or equal to the precision; otherwise the .B f format is used. .TP .B p is used to print pointers (type \fIvoid *\fR, or \fIchar *\fR if the compiler does not support the former). .TP .B n expects a \fIint *\fR argument and puts in that integer the number of characters already printed by this call. .TP .B % is used to print a \fI%\fR. .LP If an unknown conversion character is specified, the percent sign followed by that character will be printed. .SH RETURN VALUE .LP If no error occured, \fBSprint()\fR returns the number of characters printed. In case of error, it returns \fBSIO_ERR\fR. .SH BUGS .LP This is a list of differences between \fBSprint()\fR and the ANSI C Standard \fBprintf()\fR: .LP \fBSprint()\fR does not support non-removal of trailing zeroes for \fBg\fR and \fBG\fR conversions when the '#' flag is used. .LP \fBSprint()\fR does not support the h and L modifiers. .LP The current implementation assumes that \fIsizeof(int)==sizeof(long)\fR. .LP \fBSprint()\fR supports "%p" only if \fIsizeof(pointer)<=sizeof(int)\fR. ð*[SRC.TIN-1_22.SIO]EVENTS.H;1+,ì. //€ 4 `-t0@î123KÿPWO 56À;ú†Ã†—7 ‘|Á†—89€]V‚—G/€HªJÿ/* * (c) Copyright 1992, 1993 by Panagiotis Tsirigotis * All rights reserved. The file named COPYRIGHT specifies the terms * and conditions for redistribution. */ /* * $Id: events.h,v 8.1 1993/03/13 01:13:58 panos Exp $ */ /* * Event codes * * We use a 2 letter code so that events that accumulate in a buffer * can be displayed as a string * We follow the convention that the first event letter is a capitalized * and the second letter is in lower case. This allows one to easily * recognize events in an event string. */ /* * The ENCODE macro takes 2 characters and creates a short integer * The size of the short integer is assumed to be 16-bits. * The macro makes sure that regardless of the endianess of the machine, * the low order byte contains the 1st character and the high order byte * contains the 2nd character. */ #ifdef LITTLE_ENDIAN #define ENCODE( c1, c2 ) ( (c1) + ( (c2) << 8 ) ) #else /* BIG_ENDIAN */ #define ENCODE( c1, c2 ) ( (c2) + ( (c1) << 8 ) ) #endif /* * Event codes for SIO interface functions * We use the first 2 lettes after the initial 'S' */ #define EV_SGETC ENCODE( 'G', 'e' ) #define EV_SPUTC ENCODE( 'P', 'u' ) #define EV_SREAD ENCODE( 'R', 'e' ) #define EV_SWRITE ENCODE( 'W', 'r' ) #define EV_SRDLINE ENCODE( 'R', 'd' ) #define EV_SFETCH ENCODE( 'F', 'e' ) #define EV_SUNDO ENCODE( 'U', 'n' ) #define EV_SDONE ENCODE( 'D', 'o' ) #define EV_SFLUSH ENCODE( 'F', 'l' ) #define EV_SCLOSE ENCODE( 'C', 'l' ) #define EV_STIE ENCODE( 'T', 'i' ) #define EV_SUNTIE ENCODE( 'U', 't' ) #define EV_SBUFTYPE ENCODE( 'B', 'u' ) /* * Event codes for internal functions * For the __sio_ functions we use 'S' and the first letter of * For the rest we use the first letter from the first two components of * their name, for example for try_memory_mapping we use Tm. */ #define EV_SIO_INIT ENCODE( 'S', 'i' ) #define EV_SIO_SWITCH ENCODE( 'S', 's' ) #define EV_SIO_READF ENCODE( 'S', 'r' ) #define EV_SIO_WRITEF ENCODE( 'S', 'w' ) #define EV_SIO_EXTEND_BUFFER ENCODE( 'S', 'e' ) #define EV_SIO_MORE ENCODE( 'S', 'm' ) #define EV_TRY_MEMORY_MAPPING ENCODE( 'T', 'm' ) #define EV_INITIAL_MAP ENCODE( 'I', 'm' ) #define EV_MAP_UNIT ENCODE( 'M', 'u' ) #define EV_INIT_INPUT_STREAM ENCODE( 'I', 'i' ) #define EV_INIT_OUTPUT_STREAM ENCODE( 'I', 'o' ) /* * The # of entries must be a power of 2 */ #define EVENT_ENTRIES 512 struct events { short next ; short start ; short *codes ; /* malloc'ed memory */ } ; typedef struct events events_s ; extern events_s *__sio_events ; #define ADD( index, x ) (index) += x ; \ (index) &= ( EVENT_ENTRIES - 1 ) #define EVENT( fd, code ) \ { \ events_s *evp = &__sio_events[ fd ] ; \ \ if ( evp->codes != NULL ) \ { \ evp->codes[ evp->next ] = code ; \ ADD( evp->next, 1 ) ; \ if ( evp->next == evp->start ) \ { ADD( evp->start, 1 ) ; } \ } \ } ð*[SRC.TIN-1_22.SIO]IMPL.H;1+,ò. //€ 4 ˜-t0@î123KÿPWO 56àF‡Ã†—7 ‘|Á†—89€]V‚—G/€HªJÿ/* * (c) Copyright 1992, 1993 by Panagiotis Tsirigotis * All rights reserved. The file named COPYRIGHT specifies the terms * and conditions for redistribution. */ /* * $Id: impl.h,v 8.1 1993/03/13 01:15:06 panos Exp $ */ #ifndef SIO_BUFFER_SIZE #include "sioconf.h" #ifdef HAS_MMAP #include /* * A struct map_unit describes a memory mapped area of a file. * * addr is the address where the file is mapped. If addr is NULL * the other fields are meaningless. * valid_bytes indicates how many bytes are _valid_ in that unit * mapped_bytes of a unit is how many bytes are mapped in that * unit ( valid <= mapped ). * Normally mapped_bytes will be equal to valid_bytes until * we reach the end of the file. Then if the file size is not a multiple * of the unit size, only the rest of the file will be mapped at the * unit, leaving part of what was mapped at the unit before still * visible (this happens because I chose not to unmap a unit before * remapping it). In that case valid_bytes shows the size of the "new" * mapping and mapped_bytes shows how many bytes are really mapped. * mapped_bytes is used in Sdone() to unmap the units. */ struct map_unit { caddr_t addr ; size_t valid_bytes ; size_t mapped_bytes ; } ; /* * Meaning of fields used when memory mapping: * * file_offset: it is the offset in the file where the next * mapping should be done * * file_size: size of the file (obtained from stat(2)) */ struct mmap_descriptor { off_t file_offset ; off_t file_size ; struct map_unit first_unit ; struct map_unit second_unit ; } ; typedef struct mmap_descriptor mapd_s ; #endif /* HAS_MMAP */ typedef enum { FAILURE, SUCCESS } status_e ; /* * Descriptor management: convert a descriptor pointer to an input or * output descriptor pointer */ #define IDP( dp ) (&(dp)->descriptor.input_descriptor) #define ODP( dp ) (&(dp)->descriptor.output_descriptor) #define DESCRIPTOR_INITIALIZED( dp ) ((dp)->initialized) /* * Internal constants */ #define SIO_BUFFER_SIZE 8192 #define SIO_NO_TIED_FD (-1) typedef enum { NO = 0, YES = 1 } boolean_e ; #ifndef FALSE #define FALSE 0 #define TRUE 1 #endif #ifndef NULL #define NULL 0 #endif #ifdef MIN #undef MIN #endif #define MIN( a, b ) ( (a) < (b) ? (a) : (b) ) #define NUL '\0' #define PRIVATE static #ifdef DEBUG static char *itoa( num ) unsigned num ; { #define NUMBUF_SIZE 15 static char numbuf[ NUMBUF_SIZE ] ; register char *p = &numbuf[ NUMBUF_SIZE ] ; *--p = '\0' ; do { *--p = num % 10 + '0' ; num /= 10 ; } while ( num ) ; return( p ) ; } # define ASSERT( expr ) \ if ( ! (expr) ) \ { \ char *s1 = "SIO assertion << expr >> failed: File: " ; \ char *s2 = __FILE__ ; \ char *s3 = ", line: " ; \ char *s4 = itoa( __LINE__ ) ; \ char *s5 = "\n" ; \ (void) write( 2, s1, strlen( s1 ) ) ; \ (void) write( 2, s2, strlen( s2 ) ) ; \ (void) write( 2, s3, strlen( s3 ) ) ; \ (void) write( 2, s4, strlen( s4 ) ) ; \ (void) write( 2, s5, strlen( s5 ) ) ; \ exit ( 1 ) ; \ } #else # define ASSERT( expr ) #endif #include extern int errno ; /* * IO_SETUP initializes a descriptor if it is not already initialized. * It checks if the stream is of the right type (input or output). * CONTROL_SETUP checks if the descriptor is initialized and if the * stream is of the right type (input or output). * * fd: file descriptor * dp: descriptor pointer * op: operation * ev: error value (if __sio_init fails; __sio_init should set errno) * * IO_SETUP will call __sio_init if the descriptor is not initialized. * Possible errors: * 1. Using CONTROL_SETUP on an uninitialized descriptor. * 2. The operation is not appropriate for the descriptor (e.g. * a read operation on an descriptor used for writing). * Both errors set errno to EBADF. */ #define CONTROL_SETUP( dp, type, ev ) \ { \ if ( ! DESCRIPTOR_INITIALIZED( dp ) || dp->stream_type != type ) \ { \ errno = EBADF ; \ return( ev ) ; \ } \ } #define IO_SETUP( fd, dp, type, ev ) \ { \ if ( DESCRIPTOR_INITIALIZED( dp ) ) \ { \ if ( dp->stream_type != type ) \ { \ ep6²e~ TIN-1_22.BCKòt[SRC.TIN-1_22.SIO]IMPL.H;1 ŒL rrno = EBADF ; \ return( ev ) ; \ } \ } \ else if ( __sio_init( dp, fd, type ) == SIO_ERR ) \ return( ev ) ; \ } /* * Internal functions that are visible */ int __sio_readf(), __sio_writef(), __sio_pwritef() ; int __sio_extend_buffer(), __sio_init(), __sio_converter(), __sio_more() ; status_e __sio_switch() ; #ifdef HAS_MEMOPS #include #define sio_memcopy( from, to, nbytes ) (void) memcpy( to, from, nbytes ) #define sio_memscan( from, nbytes, ch ) memchr( from, ch, nbytes ) #endif #ifdef HAS_BCOPY #define sio_memcopy( from, to, nbytes ) (void) bcopy( from, to, nbytes ) #endif #ifndef sio_memcopy #define sio_memcopy __sio_memcopy #define NEED_MEMCOPY void __sio_memcopy() ; #endif #ifndef sio_memscan char *sio_memscan() ; #endif #endif /* SIO_BUFFER_SIZE */ ð*[SRC.TIN-1_22.SIO]MAKEFILE.;15+,.//€ 4K€-t0ú123KÿPWO56 i~8•’—7`ã8•’—89€šIÊ’—G/€HªJÿ# Available entries:"# lib --> creates the library,# clean --> removes all .obj and .a files"# spotless --> clean + uninstall@# tags --> creates a tags file (from the SOURCES and HEADERS) NAME = sioVERSION = 1.6.1+HEADERS = sio.h impl.h events.h sioconf.h#SOURCES = sprint.c sio.c siosup.c)OBJECTS = sprint.obj sio.obj siosup.objMANFILES = sio.3 Sprint.3INCLUDEFILES = sio.h# Available flags:J# -DDEBUG : enables assertions in the code. A failed assertion.# terminates the programK# -DEVENTS : enables code that records events (currently limitedJ# to which functions have been called on a given fd)A# and code that accesses the event buffers.I# -DLITTLE_ENDIAN : says that the machine is a little endian. This isI# needed if you enable EVENTS and your machine is aB# little endian (big endian is the default).#E# DEFS should be set from the command line; the current group of defs# is for SunOS 4.x#-DEFS = HAS_ISATTY,MULTINET,HAS_MEMOPS#,DEBUG CC = gcc,DEBUG = /optim=2/warn #/debug/noopt/profile2VERSION_DEF = VERSION="""SIO Version $(VERSION)"""+CPP_DEFS = /define=($(VERSION_DEF),$(DEFS))#6# The following variables shouldn't need to be changed#LINT_FLAGS = -hbuxCPP_FLAGS = $(CPP_DEFS)CC_FLAGS = $(DEBUG)#CFLAGS = $(CPP_FLAGS) $(CC_FLAGS)LIBNAME = lib$(NAME).olblib: $(LIBNAME)$(LIBNAME): $(OBJECTS)8 library/create $(LIBNAME) sprint.obj,sio.obj,siosup.obj install: lib copy/log $(LIBNAME) local:[lib]clean:# del/log $(OBJECTS) $(LIBNAME) core#-# PUT HERE THE RULES TO MAKE THE OBJECT FILES#$sprint.obj: sio.h impl.h sioconf.h-sio.obj: sio.h impl.h sioconf.h events.h-siosup.obj: sio.h impl.h sioconf.h events.hÿÿð*[SRC.TIN-1_22.SIO]MAKESIO.COM;2+,5 .//€ 4*-t0ú123KÿPWO56àE§‘—7 Æh§‘—89ÀÌ8F9‘—G/€HªJÿ$ set def [.sio]$ make $ set def [-]ÿÿð*[SRC.TIN-1_22.SIO]SIO.3;1+,õ.//€ 4-t0@î123KÿPWO56ÀyC‡Ã†—7€£)}Á†—89€]V‚—G/€HªJÿ.\"(c) Copyright 1992, 1993 by Panagiotis Tsirigotis .\"All rights reserved. The file named COPYRIGHT specifies the terms .\"and conditions for redistribution. .\" .\" $Id: sio.3,v 8.1 1993/03/13 01:13:58 panos Exp $ .TH SIO 3X "29 May 1992" .SH NAME Sread, Sgetc, Srdline, Sfetch, Swrite, Sputc, Sprint, Sprintv, Sdone, Sundo, Stie, Suntie, Sflush, Sclose, Sbuftype, Smorefds, Sgetchar, Sputchar, SIOLINELEN, SIOMAXLINELEN - fast stream I/O .SH SYNOPSIS .LP .nf .ft B #include "sio.h" #include .LP .ft B int Sread( fd, buf, nbytes ) int fd ; char *buf ; int nbytes ; .LP .ft B int Sgetc( fd ) int fd ; .LP .ft B char *Srdline( fd ) int fd ; .LP .ft B char *Sfetch( fd, length ) int fd ; long *length ; .LP .ft B int Swrite( fd, buf, nbytes ) int fd ; char *buf ; int nbytes ; .LP .ft B int Sputc( fd, c ) int fd ; char c ; .LP .ft B int Sprint( fd, format [ , ... ] ) int fd ; char *format ; .LP .ft B int Sprintv( fd, format, ap ) int fd ; char *format ; va_list ap ; .LP .ft B int Sdone( fd ) int fd ; .LP .ft B int Sundo( fd, type ) int fd ; int type ; .LP .ft B int Stie( ifd, ofd ) int ifd, ofd ; .LP .ft B int Suntie( fd ) int fd ; .LP .ft B int Sbuftype( fd, type ) int fd, type ; .LP .ft B int Smorefds() .LP .ft B int Sflush( fd ) int fd ; .LP .ft B int Sclose( fd ) int fd ; .LP .ft B int Sgetchar( fd ) int fd ; .LP .ft B int Sputchar( fd, c ) int fd; char c ; .LP .ft B int SIOLINELEN( fd ) int fd ; .LP .ft B int SIOMAXLINELEN( fd ) int fd ; .SH DESCRIPTION The \fISIO\fR library provides support for \fIstream\fR I/O on file descriptors. The first argument of every function or macro is a file descriptor. The file descriptor may be used either for input or for output but not both. Attempting to use a descriptor for both input and output will cause the call to fail. When you are done with using a file descriptor, you should inform \fISIO\fR by invoking \fBSdone()\fR (unless the program is about to call \fIexit(3)\fR). You can also use \fBSdone()\fR if you want to perform a different type of operation on the same file descriptor (e.g. first you were reading data from the file descriptor and then you want to write some data). Another possibility is to do stream I/O at different file offsets by using \fBSdone()\fR before doing the \fBlseek(2)\fR to the new file offset. .LP I/O operations on different file descriptors do not interfere (unless the file descriptors refer to the same file, in which case the results are undefined). .LP For disk files I/O always starts at the current file offset. If that offset is not a multiple of the preferred block size for file system I/O (the \fIst_blksize\fR field in \fIstruct stat\fR), performance will not be optimal. For optimal performance, it is recommended that no I/O operations (like \fIread(2)\fR or \fIwrite(2)\fR) are applied to the file descriptor if it is to be used by \fISIO\fR. .LP Read I/O is either buffered or is done using memory mapping whenever that is possible and appropriate. .LP The library functions that do stream I/O resemble system calls (for example \fBSread()\fR resembles \fIread(2)\fR) so that modifying a program that uses the system calls to use the \fISIO\fR functions is easy (e.g. just replace \fIread(2)\fR with \fBSread()\fR; the function signatures as well as the return values are exactly the same). .LP .B Sread() reads \fInbytes\fR bytes from the stream associated with file descriptor \fIfd\fR into the buffer pointed to by \fIbuf\fR. .LP .B Sgetc() reads a character from the stream associated with file descriptor \fIfd\fR. It returns \fBSIO_EOF\fR if the end of file has been reached. .LP .B Sgetchar() (a macro) performs exactly the same function as \fBSgetc()\fR but it is much faster. .LP .B Srdline() reads a line from the stream associated with file descriptor \fIfd\fR. The newline at the end of the line is replaced by a 0 byte. Lines longer than the maximum line length supported by \fISIO\fR will have characters deleted. .LP .B SIOLINELEN() (a macro) returns the length of the line returned by the last call to \fBSrdline()\fR (the value returned by \fBSIOLINELEN()\fR is valid only after \fBSrdline()\fR and as long as no other \fISIO\fR calls are performed on that file descriptor). .LP .B SIOMAXLINELEN() (a macro) returns the maximul line length supported by \fISIO\fR for the file descriptor. As a side-effect it initializes \fIfd\fR for input. .LP .B Sfetch() returns a pointer to data coming from the stream associated with file descriptor \fIfd\fR. The amount of data available is indicated by the \fIlength\fR argument. One possible use for this function is copying of files. .LP .B Swrite() writes \fInbytes\fR bytes to the stream associated with file descriptor \fIfd\fR from the buffer pointed to by \fIbuf\fR. .LP .B Sputc() writes a single character to the stream associated with file descriptor \fIfd\fR. .LP .B Sputchar() (a macro) performs exactly the same function as \fBSputc()\fR but it is much faster. .LP .B Sprint() imitates the behavior of printf(3) as defined in the ANSI C Standard. There are some limitations. Check the \fBSprint()\fR man page for more information. .LP .B Sprintv() is the same as \fBSprint()\fR except that it takes a \fIvarargs\fR argument list. .LP .B Sundo() returns the characters returned by the last call to \fBSrdline()\fR, \fBSgetc()\fR or \fBSgetchar()\fR to the stream so that they can be reread. The \fItype\fR argument to \fBSundo()\fR can be \fBSIO_UNDO_LINE\fR or \fBSIO_UNDO_CHAR\fR depending on whether the call whose effect needs to be undone was \fBSrdline()\fR or \fBSgetc()\fR/\fBSgetchar()\fR respectively. There is no check on whether the last function invoked on \fIfd\fR was one of the above and the results are undefined if there is no correspondence between the \fItype\fR and the last operation on \fIfd\fR. (i.e. the result is undefined if you try \fBSIO_UNDO_CHAR\fR and the last operation was not \fBSgetchar()\fR or \fBSgetc()\fR). .LP .B Stie() ties the file descriptor \fIifd\fR to the file descriptor \fIofd\fR. This means that whenever a \fIread(2)\fR is done on \fIifd\fR, it is preceded by a \fIwrite(2)\fR on \fIofd\fR. For filters it is useful to do \fIStie( 0, 1 )\fR to maximize concurrency. It is also useful to do the same thing when you issue prompts to the user and you want the user reply to appear on the same line with the prompt. \fIifd\fR, \fIofd\fR will be initialized for input, output respectively (if any of them is initialized, it must be for the appropriate stream type (input or output)). If \fIifd\fR was tied to another file descriptor, the old tie is broken. .LP .B Suntie() undoes the effect of \fBStie()\fR for the specified input file descriptor. .LP .B Sbuftype() determines the buffering type for the output stream associated with file descriptor \fIfd\fR. By default output directed to terminals is line buffered, output directed to file descriptor 2 (standard error) is unbuffered and everything else is fully buffered. Possible values for the \fItype\fR argument are .RS .TP 15 .SB SIO_FULLBUF for full buffering .TP .SB SIO_LINEBUF for line buffering .TP .SB SIO_NOBUF for no buffering .RE .LP .B Smorefds() should be used to inform \fBSIO\fR that the number of available file descriptors has been increased. \fBSIO\fR uses an array of internal stream descriptors which are indexed by the file descriptor number. Some operating systems (ex. SunOS 4.1[.x]) allow the number of available file descriptors to vary. If that number is increased beyond its initial value \fBSIO\fR needs to know in order to allocate more stream descriptors. .LP .B Sdone() flushes any buffered output for \fIfd\fR and releases the \fISIO\fR resources used. \fBSdone()\fR is useful in case the program needs to reprocess the data of a file descriptor (assuming the file descriptor corresponds to a file). The program can call \fBSdone()\fR, \fIlseek(2)\fR to the beginning of the file and then proceed to reread the file. .LP .B Sflush() causes any buffered stream output to be written to the file descriptor. If its argument is the special value \fBSIO_FLUSH_ALL\fR then all output streams will be flushed. .LP .B Sclose() closes a file descriptor used for stream I/O, flushes any buffered output and releases the \fISIO\fR resources used. .SH EXAMPLES .LP The following code implements a (poor) substitute for the tee command (it copies standard input to a file as well as to standard output). .ne 10 .RS .nf .ft B #include "sio.h" .sp .5 main( argc, argv ) int argc ; char *argv[] ; { char *file = (argc > 1) ? argv[ 1 ] : "tee.file" ; int fd = creat( file, 0644 ) ; long length ; char *s ; .sp .5 while ( s = Sfetch( 0, &length ) ) { Swrite( 1, s, length ) ; Swrite( fd, s, length ) ; } exit( 0 ) ; } .fi .ft R .RE .SH RETURN VALUES .LP .B Sread() returns the number of bytes read on success (0 means end-of-file) or \fBSIO_ERR\fR on failure (\fIerrno\fR is set to indicate the error). .LP .B Sgetc() returns the character read on success, SIO_EOF when the end-of-file is reached, or \fBSIO_ERR\fR on failure (\fIerrno\fR is set to indicate the error). .LP .B Srdline() returns a pointer to the next line on success. On failure or when the end-of-file is reached it returns .SM NULL. If the end-of-file is reached \fIerrno\fR is set to 0, otherwise it indicates the error. .LP .B Sfetch() returns a pointer to file data on success. (the \fIlength\fR argument indicates how many bytes are available). On failure or when the end-of-file is reached it returns .SM NULL. If the end-of-file is reached \fIerrno\fR is set to 0, otherwise it indicates the error. .LP .B Swrite() returns the number of bytes written on success or \fBSIO_ERR\fR on failure (\fIerrno\fR is set to indicate the error). .LP .B Sputc() returns the character it was given as an argument on success .B Sprint() returns the number of characters printed on success or \fBSIO_ERR\fR on failure (\fIerrno\fR is set to indicate the error). .LP .B Sdone() returns \fB0\fR on success or \fBSIO_ERR\fR on failure (\fIerrno\fR is set to indicate the error). .LP .B Sundo() returns \fB0\fR on success or \fBSIO_ERR\fR on failure (\fIerrno\fR is set to indicate the error). .LP .B Stie() returns \fB0\fR on success or \fBSIO_ERR\fR on failure (\fIerrno\fR is set to indicate the error). .LP .B Suntie() returns \fB0\fR on success or \fBSIO_ERR\fR on failure (\fIerrno\fR is set to \fBEBADF\fR if there was no tied file descriptor). .LP .B Sbuftype() returns \fB0\fR on success or \fBSIO_ERR\fR on failure (\fIerrno\fR is set to \fBEBADF\fR if this is not an output stream or to \fBEINVAL\fR if an unknown \fItype\fR is specified). .LP .B Smorefds() returns \fB0\fR on success or \fBSIO_ERR\fR on failure (because of lack of memory). .LP .B Sflush() returns \fB0\fR on success or \fBSIO_ERR\fR on failure (\fIerrno\fR is set to indicate the error). .LP .B Sclose() returns \fB0\fR on success or \fBSIO_ERR\fR on failure (\fIerrno\fR is set to indicate the error). .LP .B Sgetchar() returns the character read on success, SIO_EOF when the end-of-file is reached, or \fBSIO_ERR\fR on failure (\fIerrno\fR is set to indicate the error). .LP .B Sputchar() returns the character it was given as an argument on success or \fBSIO_ERR\fR on failure (\fIerrno\fR is set to indicate the error). .LP .B SIOLINELEN() returns the length of the last line read by \fBSrdline()\fR. .LP .B SIOMAXLINELEN() returns the length of the longest line supported by \fISIO\fR on success or \fBSIO_ERR\fR on failure (\fIerrno\fR is set to indicate the error). .LP Attempting a read operation on a descriptor opened for writing or vice versa will cause the operation to fail with \fIerrno\fR set to \fBEBADF\fR. .LP The first \fISIO\fR operation on a descriptor must be a read or write operation. It cannot be a control operation (like \fBSflush()\fR). Such an operation will fail with \fIerrno\fR set to \fBEBADF\fR. .LP .IP "\fBNOTE 1:\fR" 15 \fBStie()\fR is an input/output operation for the respective file descriptors, not a control operation. \fBSuntie()\fR is a control operation. .IP "\fBNOTE 2:\fR" \fBSIO_ERR\fR is defined to be \fB-1\fR. .SH "SEE ALSO" .LP Sprint(3) .SH BUGS .LP If the operating system does not provide for invocation of a finalization function upon exit, the program will have to explicitly flush all output streams. The following operating systems provide such a facility: SunOS 4.x, Ultrix 4.x. .LP Socket file descriptors can be used for input as well as output but \fBSIO\fR does not support this. .LP The current implementation will not try to use memory mapping to read a file if the file offset is not 0 (it will use buffered I/O instead). .LP Pointers returned by \fBSfetch()\fR point to read-only memory. Attempting to modify this memory will result in a segmentation violation. ð*[SRC.TIN-1_22.SIO]SIO.C;2+,.//€ 4©-t0@î123KÿPWO56€9Ê+͆—7 õˆ,͆—89€]V‚—G/€HªJÿ6/* * (c) Copyright 1992, 1993 by Panagiotis Tsirigotis * All rights reserved. The file named COPYRIGHT specifies the terms * and conditions for redistribution. */ static char RCSid[] = "$Id: sio.c,v 8.1 1993/03/13 01:15:55 panos Exp $" ; static char sio_version[] = VERSION ; #include #include #include "sio.h" #include "impl.h" #ifdef EVENTS #include "events.h" #endif /* * SIO WRITE FUNCTIONS: Swrite, Sputc */ /* * Stream write call: arguments same as those of write(2) */ int Swrite( fd, addr, nbytes ) int fd ; register char *addr ; register int nbytes ; { register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ; register __sio_od_t *odp = ODP( dp ) ; register int b_transferred ; register int b_avail ; int total_b_transferred ; int b_written ; int b_in_buffer ; #ifdef EVENTS EVENT( fd, EV_SWRITE ) ; #endif IO_SETUP( fd, dp, __SIO_OUTPUT_STREAM, SIO_ERR ) ; ASSERT( odp->start <= odp->nextb && odp->nextb <= odp->buf_end ) ; b_avail = odp->buf_end - odp->nextb ; b_transferred = MIN( nbytes, b_avail ) ; sio_memcopy( addr, odp->nextb, b_transferred ) ; odp->nextb += b_transferred ; /* * check if we are done */ if ( b_transferred == nbytes ) return( b_transferred ) ; /* * at this point we know that the buffer is full */ b_in_buffer = odp->buf_end - odp->start ; b_written = __sio_writef( odp, fd ) ; if ( b_written != b_in_buffer ) return( (b_written >= nbytes) ? nbytes : b_written ) ; total_b_transferred = b_transferred ; addr += b_transferred ; nbytes -= b_transferred ; for ( ;; ) { b_transferred = MIN( nbytes, odp->buffer_size ) ; sio_memcopy( addr, odp->nextb, b_transferred ) ; odp->nextb += b_transferred ; nbytes -= b_transferred ; if ( nbytes == 0 ) { total_b_transferred += b_transferred ; break ; } /* * the buffer is full */ b_written = __sio_writef( odp, fd ) ; if ( b_written != odp->buffer_size ) { if ( b_written != SIO_ERR ) { total_b_transferred += b_written ; odp->nextb += b_written ; } break ; } /* * everything is ok */ total_b_transferred += b_transferred ; addr += b_transferred ; } return( total_b_transferred ) ; } /* * Add a character to a file */ int Sputc( fd, c ) int fd ; char c ; { register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ; register __sio_od_t *odp = ODP( dp ) ; #ifdef EVENTS EVENT( fd, EV_SPUTC ) ; #endif IO_SETUP( fd, dp, __SIO_OUTPUT_STREAM, SIO_ERR ) ; ASSERT( odp->start <= odp->nextb && odp->nextb <= odp->buf_end ) ; /* * The following is a weak check since we should really be * checking that nextb == buf_end (it would be an error for * nextb to exceed buf_end; btw, the assertion above, when * enabled makes sure this does not occur). * * NOTE: __sio_writef NEVER uses data beyond the end of buffer. */ if ( odp->nextb >= odp->buf_end ) { int b_in_buffer = odp->buf_end - odp->start ; /* * There is nothing we can do if __sio_writef does not manage * to write the whole buffer */ if ( __sio_writef( odp, fd ) != b_in_buffer ) return( SIO_ERR ) ; } *odp->nextb++ = c ; if ( __SIO_MUST_FLUSH( *odp, c ) && __sio_writef( odp, fd ) == SIO_ERR ) return( SIO_ERR ) ; return ( c ) ; } /* * SIO READ FUNCTIONS */ /* * Stream read call: arguments same as those of read(2) */ int Sread( fd, addr, nbytes ) int fd ; char *addr ; int nbytes ; { register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ; register __sio_id_t *idp = IDP( dp ) ; register int b_transferred ; int b_read ; int total_b_transferred ; int b_left ; #ifdef EVENTS EVENT( fd, EV_SREAD ) ; #endif IO_SETUP( fd, dp, __SIO_INPUT_STREAM, SIO_ERR ) ; ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ; b_left = idp->end - idp->nextb ; b_transferred = MIN( b_left, nbytes ) ; sio_memcopy( idp->nextb, addr, b_transferred ) ; idp->nextb += b_transferred ; if ( b_transferred == nbytes ) return( b_transferred ) ; nbytes -= b_transferred ; total_b_transferred = b_transferred ; addr += b_transferred ; do { b_read = __sio_readf( idp, fd ) ; switch ( b_read ) { case SIO_ERR: if ( total_b_transferred == 0 ) return( SIO_ERR ) ; /* FALL THROUGH */ case 0: return( total_b_transferred ) ; } b_transferred = MIN( b_read, nbytes ) ; sio_memcopy( idp->nextb, addr, b_transferred ) ; addr += b_transferred ; idp->nextb += b_transferred ; total_b_transferred += b_transferred ; nbytes -= b_transferred ; } while ( nbytes && b_read == idp->buffer_size ) ; return( total_b_transferred ) ; } /* * Read a line from a file * Returns a pointer to the beginning of the line or NULL */ char *Srdline( fd ) int fd ; { register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ; register __sio_id_t *idp = IDP( dp ) ; register char *cp ; register char *line_start ; register int b_left ; register int extension ; #ifdef EVENTS EVENT( fd, EV_SRDLINE ) ; #endif IO_SETUP( fd, dp, __SIO_INPUT_STREAM, NULL ) ; ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ; #ifdef HAS_MMAP if ( idp->memory_mapped && __sio_switch( idp, fd ) == FAILURE ) return( NULL ) ; #endif b_left = idp->end - idp->nextb ; /* * Look for a '\n'. If the search fails, extend the buffer * and search again (the extension is performed by copying the * bytes that were searched to the auxiliary buffer and reading * new input in the main buffer). * If the new input still does not contain a '\n' and there is * more space in the main buffer (this can happen with network * connections), read more input until either the buffer is full * or a '\n' is found. * Finally, set cp to point to the '\n', and line_start to * the beginning of the line */ if ( b_left && ( cp = sio_memscan( idp->nextb, b_left, '\n' ) ) != NULL ) { line_start = idp->nextb ; idp->nextb = cp + 1 ; } else { extension = __sio_extend_buffer( idp, fd, b_left ) ; if ( extension > 0 ) { ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ; line_start = idp->start ; cp = sio_memscan( idp->nextb, extension, '\n' ) ; if ( cp != NULL ) idp->nextb = cp + 1 ; else for ( ;; ) { idp->nextb = idp->end ; extension = __sio_more( idp, fd ) ; if ( extension > 0 ) { cp = sio_memscan( idp->nextb, extension, '\n' ) ; if ( cp == NULL ) continue ; idp->nextb = cp + 1 ; break ; } else { /* * If there is spare room in the buffer avoid trashing * the last character */ if ( idp->end < &idp->buf[ idp->buffer_size ] ) cp = idp->end ; else cp = &idp->buf[ idp->buffer_size - 1 ] ; break ; } } } else /* buffer could not be extended */ if ( b_left == 0 ) { /* * Set errno to 0 if EOF has been reached */ if ( extension == 0 ) errno = 0 ; return( NULL ) ; } else { line_start = idp->start ; cp = idp->end ; /* * By setting idp->nextb to be equal to idp->end, * subsequent calls to Srdline will return NULL because * __sio_extend_buffer will be invoked and it will return 0. */ idp->nextb = idp->end ; } } *cp = NUL ; idp->line_length = cp - line_start ; return( line_start ) ; } /* * Get a character from a file */ int Sgetc( fd ) int fd ; { register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ; register __sio_id_t *idp = IDP( dp ) ; #ifdef EVENTS EVENT( fd, EV_SGETC ) ; #endif IO_SETUP( fd, dp, __SIO_INPUT_STREAM, SIO_ERR ) ; ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ; if ( idp->nextb >= idp->end ) { register int b_read = __sio_readf( idp, fd ) ; if ( b_read == 0 ) return( SIO_EOF ) ; else if ( b_read == SIO_ERR ) return( SIO_ERR ) ; } return( (int) *idp->nextb++ ) ; } char *Sfetch( fd, lenp ) int fd ; long *lenp ; { register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ; register __sio_id_t *idp = IDP( dp ) ; register int b_read ; register char *p ; #ifdef EVENTS EVENT( fd, EV_SFETCH ) ; #endif IO_SETUP( fd, dp, __SIO_INPUT_STREAM, NULL ) ; ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ; if ( idp->nextb >= idp->end ) { b_read = __sio_readf( idp, fd ) ; if ( b_read == SIO_ERR ) return( NULL ) ; if ( b_read == 0 ) { errno = 0 ; return( NULL ) ; } } *lenp = idp->end - idp->nextb ; p = idp->nextb ; idp->nextb = idp->end ; return( p ) ; } /* * SIO CONTROL FUNCTIONS */ /* * Undo the last Srdline or Sgetc */ int Sundo( fd, type ) int fd ; int type ; { register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ; register __sio_id_t *idp = IDP( dp ) ; int retval = 0 ; #ifdef EVENTS EVENT( fd, EV_SUNDO ) ; #endif CONTROL_SETUP( dp, __SIO_INPUT_STREAM, SIO_ERR ) ; /* * Undo works only for fd's used for input */ if ( dp->stream_type != __SIO_INPUT_STREAM ) return( SIO_ERR ) ; /* * Check if the operation makes sense; if so, do it, otherwise ignore it */ switch ( type ) { case SIO_UNDO_LINE: if ( idp->nextb - idp->line_length > idp->start ) { *--idp->nextb = '\n' ; idp->nextb -= idp->line_length ; } ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ; break ; case SIO_UNDO_CHAR: if ( idp->nextb > idp->start ) idp->nextb-- ; ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ; break ; default: retval = SIO_ERR ; break ; } return( retval ) ; } /* * Flush the buffer associated with the given file descriptor * The special value, SIO_FLUSH_ALL flushes all buffers * * Return value: * 0 : if fd is SIO_FLUSH_ALL or if the flush is successful * SIO_ERR: if fd is not SIO_FLUSH_ALL and * the flush is unsuccessful * or the descriptor is not initialized or it is not * an output descriptor */ int Sflush( fd ) int fd ; { register __sio_descriptor_t *dp ; int b_in_buffer ; #ifdef EVENTS EVENT( fd, EV_SFLUSH ) ; #endif if ( fd == SIO_FLUSH_ALL ) { for ( fd = 0, dp = __sio_descriptors ; fd < N_SIO_DESCRIPTORS ; dp++, fd++ ) if ( DESCRIPTOR_INITIALIZED( dp ) && dp->stream_type == __SIO_OUTPUT_STREAM ) (void) __sio_writef( ODP( dp ), fd ) ; return( 0 ) ; } else { dp = &__sio_descriptors[ fd ] ; CONTROL_SETUP( dp, __SIO_OUTPUT_STREAM, SIO_ERR ) ; b_in_buffer = ODP( dp )->nextb - ODP( dp )->start ; if ( __sio_writef( ODP( dp ), fd ) != b_in_buffer ) return( SIO_ERR ) ; else return( 0 ) ; } } /* * Close the file descriptor. This call is provided because * a file descriptor may be closed and then reopened. There is * no easy way for SIO to identify such a situation, so Sclose * must be used. * * Sclose invokes Sdone which finalizes the buffer. * There is no SIO_CLOSE_ALL value for fd because such a thing * would imply that the program will exit very soon, therefore * the closing of all file descriptors will be done in the kernel * (and the finalization will be done by the finalization function * NOTE: not true if the OS does not support a finalization function) * * There is no need to invoke SETUP; Sdone will do it. */ int Sclose( fd ) int fd ; { #ifdef EVENTS EVENT( fd, EV_SCLOSE ) ; #endif if ( __SIO_FD_INITIALIZED( fd ) ) if ( Sdone( fd ) == SIO_ERR ) return( SIO_ERR ) ; #ifdef MULTINET return( socket_close( fd ) ) ; #else return( close( fd ) ) ; #endif } /* * Tie the file descriptor in_fd to the file descriptor out_fd * This means that whenever a read(2) is done on in_fd, it is * preceded by a write(2) on out_fd. * Why this is nice to have: * 1) When used in filters it maximizes concurrency * 2) When the program prompts the user for something it forces * the prompt string to be displayed even if it does not * end with a '\n' (which would cause a flush). * In this implementation, out_fd cannot be a regular file. * This is done to avoid non-block-size write's. * The file descriptors are initialized if that has not been done * already. If any of them is initialized, it must be for the appropriate * stream type (input or output). * * NOTE: the code handles correctly the case when in_fd == out_fd */ int Stie( in_fd, out_fd ) int in_fd, out_fd ; { struct stat st ; register __sio_descriptor_t *dp ; int was_initialized ; boolean_e failed = NO ; #ifdef EVENTS EVENT( in_fd, EV_STIE ) ; #endif /* * Check if the out_fd is open */ if ( fstat( out_fd, &st ) == -1 ) return( SIO_ERR ) ; /* * If the out_fd refers to a regular file, the request is silently ignored */ if ( ( st.st_mode & S_IFMT ) == S_IFREG ) return( 0 ) ; dp = &__sio_descriptors[ in_fd ] ; was_initialized = dp->initialized ; /* remember if it was initialized */ IO_SETUP( in_fd, dp, __SIO_INPUT_STREAM, SIO_ERR ) ; /* * Perform manual initialization of out_fd to avoid leaving in_fd * initialized if the initialization of out_fd fails. * If out_fd is initialized, check if it is used for output. * If it is not initialized, initialize it for output. */ dp = &__sio_descriptors[ out_fd ] ; if ( DESCRIPTOR_INITIALIZED( dp ) ) { if ( dp->stream_type != __SIO_OUTPUT_STREAM ) { failed = YES ; errno = EBADF ; } } else if ( __sio_init( dp, out_fd, __SIO_OUTPUT_STREAM ) == SIO_ERR ) failed = YES ; if ( failed == NO ) { __SIO_ID( in_fd ).tied_fd = out_fd ; return( 0 ) ; } else { /* * We failed. If we did any initialization, undo it */ if ( ! was_initialized ) { int save_errno = errno ; (void) Sdone( in_fd ) ; errno = save_errno ; } return( SIO_ERR ) ; } } /* * Untie a  .r­k~ TIN-1_22.BCKt[SRC.TIN-1_22.SIO]SIO.C;2jêfile descriptor */ int Suntie( fd ) int fd ; { register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ; #ifdef EVENTS EVENT( fd, EV_SUNTIE ) ; #endif CONTROL_SETUP( dp, __SIO_INPUT_STREAM, SIO_ERR ) ; if ( IDP( dp )->tied_fd != SIO_NO_TIED_FD ) { IDP( dp )->tied_fd = SIO_NO_TIED_FD ; return( 0 ) ; } else { errno = EBADF ; return( SIO_ERR ) ; } } /* * Changes the type of buffering on the specified descriptor. * As a side-effect, it initializes the descriptor as an output stream. */ int Sbuftype( fd, type ) int fd, type ; { register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ; #ifdef EVENTS EVENT( fd, EV_SBUFTYPE ) ; #endif /* * Check for a valid type */ if ( type != SIO_LINEBUF && type != SIO_FULLBUF && type != SIO_NOBUF ) { errno = EINVAL ; return( SIO_ERR ) ; } IO_SETUP( fd, dp, __SIO_OUTPUT_STREAM, SIO_ERR ) ; ODP( dp )->buftype = type ; return( 0 ) ; } #ifndef sio_memscan PRIVATE char *sio_memscan( from, how_many, ch ) char *from ; int how_many ; register char ch ; { register char *p ; register char *last = from + how_many ; for ( p = from ; p < last ; p++ ) if ( *p == ch ) return( p ) ; return( 0 ) ; } #endif /* sio_memscan */ #ifdef NEED_MEMCOPY void __sio_memcopy( from, to, nbytes ) register char *from, *to ; register int nbytes ; { while ( nbytes-- ) *to++ = *from++ ; } #endif /* NEED_MEMCOPY */ ð*[SRC.TIN-1_22.SIO]SIO.DVI;1+,.'//€ 4'%Ô-t0@î123KÿPWO(56€Én:Œ—7À½…u:Œ—89€]V‚—G/€HªJÿJ÷à0áØè‹ÿÿÿÿóKñ`y@@cmr10«ž´¸SIO(3X)‘Ó[SIO(3X)Žóò"V @cmbx10¬žpìNAMEŽ«pìž%¤Sread,ËSgetc,ÌSrdline,ËSfetcÿ$h,ÉSwrite,ËSputc,ÊSprinÿ"t,ÉSprinÿ"tv,ÉSdone,ÊSundo,ÉStie,ÊSunÿ"tie,ÊS ush,Žž%¤Sclose, ™Sbuftÿ"ypÞe, —Smorefds, ™Sgetcÿ$har, –Sputcÿ#har, –SIOLINELEN, ˜SIOMAXLINELEN ˜- —fast ˜streamŽž%¤I/OŽ¬ž4²SYNOPSISŽóò"V@@cmbx10­pìž%¤#includeóßê@@cmmi10¯ <­vÿarargs.h¯>Ž­ž4²inÿt üSread( þfd, übuf, ünÿbÿytes ÿ)Žž%¤inÿt üfd û;Žž%¤cÿhar ü*buf ü;Žž%¤inÿt ünÿbÿytes ÿ;Žž4²inÿt üSgetc( fd û)Žž%¤inÿt üfd û;Žž4²cÿhar ü*Srdline( fd û)Žž%¤inÿt üfd û;Žž4²cÿhar ü*Sfetcÿh( üfd, ülength ÿ)Žž%¤inÿt üfd û;Žž%¤long þ*length ;Žž4²inÿt üSwrite( fd, übuf, ünÿbÿytes ÿ)Žž%¤inÿt üfd û;Žž%¤cÿhar ü*buf ü;Žž%¤inÿt ünÿbÿytes ÿ;Žž4²inÿt üSputc( þfd, üc ü)Žž%¤inÿt üfd û;Žž%¤cÿhar üc ü;Žž4²inÿt üSprinÿt( ýfd, üformat ÿ[ ü, ü... þ] ü)Žž%¤inÿt üfd û;Žž%¤cÿhar ü*format ;Žž4²inÿt üSprinÿtv( þfd, üformat, ap û)Žž%¤inÿt üfd û;Žž%¤cÿhar ü*format ;Žž%¤vÿažw‰A¯¯ž÷‰list ÿap û;Žž4²inÿt üSdone( þfd û)Žž%¤inÿt üfd û;Žž4²inÿt üSundo( ýfd, ütÿype ü)Žž%¤inÿt üfd û;Žž%¤inÿt ütÿype ü;Žž4²inÿt üStie( ÿifd, ýofd ü)Žž%¤inÿt üifd, ýofd ü;Žž4²inÿt üSunÿtie( ÿfd û)Žž%¤inÿt üfd û;Žž4²inÿt üSbuftÿype( ýfd, ütÿype ü)Žž%¤inÿt üfd, ütÿype ü;Žž4²inÿt üSmorefds()Žž4²inÿt üS ush( ýfd û)Žž%¤inÿt üfd û;Žž4²inÿt üSclose( fd û)Žž%¤inÿt üfd û;Ž«‘Õžxz29 kMaÿ"y k1992‘w 1ŽŒ‹«ž´¸SIO(3X)‘Ó[SIO(3X)Ž­pìžpìinÿt üSgetcÿhar( ýfd û)Žž%¤inÿt üfd û;Žž4²inÿt üSputcÿhar( ýfd, üc ü)Žž%¤inÿt üfd;Žž%¤cÿhar üc ü;Žž4²inÿt üSIOLINELEN( fd û)Žž%¤inÿt üfd û;Žž4²inÿt üSIOMAXLINELEN( fd û)Žž%¤inÿt üfd û;Ž¬ž4²DESCRIPTIONŽ«pìž%¤Theóý':@@cmti10° aSIO« `library _proÿ"vides asuppßort _for° _strþheþham« `I/O `on _ le `descriptors.ÎThe a rst `argumenÿ$t ^of ^evÿ#eryŽž%¤function Por Omacro Qis Pa O le Pdescriptor. RThe Q le Pdescriptor Rmaÿ#y ObÞe Qused Reither Rfor Pinput Por Pfor Pout-Žž%¤put ‰but ‰not ‰bÞoth. ‰Aÿ"ttempting ‹to ‰use ‹a ‰descriptor Œfor ‰bÞoth ‰input ‰and ‰output ‰will Šcause ‹the ‰call ‰toŽž%¤fail. ¢When £yÿ"ou £are ¤done ¤with ¤using ¤a £ le ¤descriptor, ¦yÿ"ou £should ¤inform° ¤SIO« ¤bÿ"y £inÿ"vÿ"oking­ £Sdone()Ž«ž%¤(unless Uthe Sprogram Sis SabÞout Qto Qcall° Rexit(3)«).¿Yýeou Qcan Ralso Ruse­ SSdone()« Uif Qyÿ"ou Qwÿ#anÿ"t Qto QpÞerform SaŽž%¤di erenÿ%t }tÿ"ypÞe ~of }opÞeration ~on }the ~same € le ~descriptor (e.g.  rst yÿ"ou ~wÿ#ere €reading data ~from theŽž%¤ le \descriptor ^and [then \yÿ"ou [wÿ#anÿ"t [to [write ]some ^data).ÅAnother [pÞossibilitÿ$y Zis [to Zdo Zstream ]I/O [atŽž%¤di erenÿ%t k le lo sets obÿ"y kusing­ lSdone()« obÞefore mdoing kthe­ llseek(2)« sto kthe lnew m le lo set.Žž4²I/O çopÞerations èon ædi erenÿ%t æ le çdescriptors ëdo çnot çinÿ"terfere ê(unless êthe è le èdescriptors ërefer éto çtheŽž%¤same n le, lin kwhicÿ$h kcase nthe lresults nare lunde ned).Žž4²Fýeor ßdisk à les áI/O àalwÿ#aÿ"ys àstarts áat ßthe àcurrenÿ$t ß le ào set.MIf àthat ßo set áis ßnot Þa Þmÿ#ultiple ßof Þthe ßpre-Žž%¤ferred bloÞcÿ#ksize!for lesystem"I/O(the°stžw‰A¯¯ž÷‰blksize«! eldin°structästat«),"pÞerformance#will notbÞeŽž%¤optimal._FýeoróoptimalôpÞerformance,÷itóisôrecommendedùthatónoóI/OôopÞerationsõ(likÿ"e°ôrþgeþhad(2)«öorŽ°ž%¤write(2)«) oare lapplied lto kthe l le ldescriptor nif kit kis lto kbÞe lused mbÿ"y° kSIO«.Žž4²Read›I/Ošisšeither›bu eredœor™is›done›using›memorymapping›whenevÿ%er›thatšis›pÞossibleandŽž%¤appropriate.Žž4²The elibrary cfunctions ethat cdo cstream fI/O dresemÿ&ble dsystem gcalls e(for cexample­ fSread()« fresemÿ&blesŽ°ž%¤rþgeþhad(2)«) ~so |that {moßdifying {a {program |that {uses ~the |system calls }to {use }the° |SIO« |functions }is }easyŽž%¤(e.g. øjust øreplace° úrþgeþhad(2)« úwith­ øSread()«; ûthe øfunction øsignatures úas øwÿ#ell øas ÷the ÷return ÷vÿ"alues øareŽž%¤exactly mthe lsame).Ž­ž4²Sread()«Sreads°Ánbytes«Ãbÿ"ytesÁfromÁtheÁstreamÃassoàciatedÂwithÁ leÁdescriptor°Ãfd«Áinÿ"toÀtheÁbu erŽž%¤pÞoinÿ"ted lto kbÿ"y° kbuf«.Ž­ž4²Sgetc()«Çreads3a1cÿ#haracter3from2the2stream4assoàciated3with1 le1descriptor°3fd«. œIt1returnsŽ­ž%¤SIOžw‰A¯¯ž÷‰EOF« lif kthe lend lof k le lhas lbÞeen mreacÿ$hed.Ž­ž4²Sgetcÿhar()« þ(a kmacro) mpÞerforms nexactly mthe lsame nfunction las­ lSgetc()« qbut kit kis lmÿ#ucÿ#h kfaster.Ž­ž4²Srdline()« reads ƒa line ‚from ‚the ‚stream „assoàciated ƒwith ‚ le ‚descriptor° …fd«.îThe „newline …at ‚the ƒendŽž%¤of 'the (line (is (replaced *bÿ"y 'a '0 &bÿ"yte. 'Lines (longer 'than &the 'maximÿ$um 'line 'length 'suppßorted 'bÿ"y° &SIOŽ«ž%¤will lhaÿ"vÿ"e lcÿ#haracters ndeleted.Ž­ž4²SIOLINELEN()« Ã(a -macro) /returns /the .length .of -the .line .returned 0bÿ"y .the /last /call /to­ .Srdline()Ž«ž%¤(theOvÿ"alueOreturnedPbÿ"y­MSIOLINELEN()«SisNvÿ"alidMonlyMafter­NSrdline()«SandMasNlongMasNnoMotherŽ°ž%¤SIO« lcalls mare lpÞerformed non kthat k le ldescriptor).Ž­ž4²SIOMAXLINELEN()« (a macro) returns the maximÿ$ul line length suppßorted bÿ"y° SIO« for the  leŽž%¤descriptor. nAs la kside-e ect rit kinitializes° nfd« lfor kinput.Ž­ž4²Sfetcÿh()« øreturns ha fpÞoinÿ"ter gto fdata fcoming hfrom fthe fstream hassoàciated gwith f le fdescriptor° hfd«. fTheŽž%¤amounÿ#t )of )data )aÿ"vÿ"ailable *is *indicated +bÿ"y )the° *length« /argumenÿ$t. *One +pÞossible -use ,for *this +function +isŽž%¤copÿ#ying kof k les.Ž­ž4²Swrite()«€writes°ínbytes«îbÿ"ytesìtoétheêstreamìassoàciatedëwithê leêdescriptor°ìfd«êfromêtheêbu erŽž%¤pÞoinÿ"ted lto kbÿ"y° kbuf«.Ž‘ÕŸ‡ˆ29 kMaÿ"y k1992‘w 2ŽŒ‹«ž´¸SIO(3X)‘Ó[SIO(3X)Ž­pìžpìSputc()« ÿwrites na ksingle mcÿ#haracter mto kthe lstream nassoàciated mwith l le ldescriptor° nfd«.Ž­ž4²Sputcÿhar()« þ(a kmacro) mpÞerforms nexactly mthe lsame nfunction las­ lSputc()« obut kit kis lmÿ#ucÿ#h kfaster.Ž­ž4²Sprinÿt()«éimitates Ythe WbÞehaÿ#vior Vof Vprinÿ"tf(3) Vas Wde ned Xin Vthe WANSI WC WStandard. VThere Zare XsomeŽž%¤limitations. mChecÿ%k kthe­ lSprinÿt()« nman lpage lfor kmore minformation.Ž­ž4²Sprinÿtv()« ÿis lthe lsame nas­ lSprinÿt()« nexcept nthat kit ktakÿ"es ma° kvarþiarþhgs« largumenÿ$t klist.Ž­ž4²Sundo()« ~returns íthe ëcÿ#haracters íreturned ìbÿ"y êthe ëlast ëcall ëto­ êSrdline()«,­ ðSgetc()« ðor­ êSgetcÿhar()« ítoŽž%¤theÎstreamÐsoÎthatÍtheyÎcanÎbÞeÎreread.ÏThe°Ïtypþie«Ïargumenÿ$tÎto­ÎSundo()«ÑcanÏbÞeŽ­ž%¤SIOžw‰A¯¯ž÷‰UNDOžw‰A¯¯ž÷‰LINE« ¤or­ ¢SIOžw‰A¯¯ž÷‰UNDOžw‰A¯¯ž÷‰CHAR« ¥depßending £on ¢whether ¥the ¢call ¢whose ¤e ect ¥needsŽž%¤to kbÞe lundone mwÿ#as­ mSrdline()« ror­ lSgetc()«/­Sgetcÿ har()« orespàectivÿ$elyýf.×There ois mno lcÿ#hecÿ$k lon lwhetherŽž%¤the last function inÿ"vÿ"okÿ"ed on° fd« wÿ#as one of the abÞoÿ"vÿ"e and the results are unde ned if there is noŽž%¤correspáondence _bÞetÿ#wÿ#een ^the° ]typþie« ]and \the ^last ^opÞeration ^on° ]fd«.É(i.e. ^the ^result _is ^unde ned _if ]yÿ"ouŽž%¤try­ kSIOžw‰A¯¯ž÷‰UNDOžw‰A¯¯ž÷‰CHAR« nand kthe llast lopÞeration lwÿ#as lnot­ kSgetcÿhar()« nor­ kSgetc()«).Ž­ž4²Stie()« Ûties Hthe G le Gdescriptor° Iifd« Gto Fthe G le Fdescriptor° Hofd«.²This Gmeans Hthat Ewhenevÿ%er Fa° Erþgeþhad(2)« HisŽž%¤done ½on° ¼ifd«, ½it ¼is ½preceded Àbÿ"y ¼a° ¼write(2)« Àon° ¼ofd«.)Fýeor ¼ lters ¾it ¼is ½useful ¾to ¼do° ¼Stie( ‚0, €1 €)« ½to ½maxi-Žž%¤mize concurrencyýi.‡It is also useful to do the same thing when yÿ"ou issue prompts to the user andŽž%¤yÿ"ou |wÿ#anÿ"t |the }user ~reply ~to }appÞear ~on }the ~same €line ~with ~the ~prompt.°éifd«,° ~ofd«êwill ~bÞe ~initializedŽž%¤for ?input, ?output ?respàectivÿ$ely @(if ?anÿ"y >of >them @is ?initialized, @it >mÿ#ust ?bÞe ?for >the ?appropriate ?streamŽž%¤tÿ"ypÞe l(input kor koutput)).ÖIf° lifd« lwÿ#as ltied lto kanother l le ldescriptor, nthe lold ktie lis lbrokÿ"en.Ž­ž4²Sunÿtie()« undoÞes mthe le ect oof­ kStie()« pfor kthe lspßeci ed ninput k le ldescriptor.Ž­ž4²Sbuftÿype()« Idetermines »the ·bu ering ¸tÿ"ypÞe ·for ¶the ·output ¶stream ºassoàciated ¹with ¸ le ¸descriptor° ºfd«.Žž%¤By Ãdefault Ãoutput Âdirected Åto Âterminals Åis Ãline Ãbu ered, Åoutput Âdirected Åto  le Âdescriptor Ä2 Á(stan-Žž%¤dard error) is unÿ"bu ered and evÿ#erything else is fully bu ered.Pÿ"ossible vÿ"alues for the° typþie« argu-Žž%¤menÿ$t kareŽ¬pìž4²SIOžŸ‰!žøaFULLBUFŽ«‘ëAž%¤for kfull kbu eringŽ¬‘ÿ¿ž4²SIOžŸ‰!žøaLINEBUF«for kline lbu eringŽ¬ž4²SIOžŸ‰!žøaNOBUF«0Çfor kno kbu eringŽ­ž4²Smorefds()« `should ÊbÞe Êused Ëto Éinform­ ÊSIO« Êthat Éthe Ênÿ"umÿ#bÞer Êof Éaÿ"vÿ"ailable Ê le Êdescriptors Íhas ÊbÞeenŽž%¤increased.­ SIO« uses an arraÿ"y of inÿ"ternal stream descriptors whicÿ$h are indexed bÿ"y the  le descrip-Žž%¤tor —nÿ"umÿ#bÞer. ˜Some ™opÞerating ˜systems œ(ex. ˜SunOS –4.1[.x]) –alloÿ"w —the —nÿ"umÿ#bÞer —of –aÿ"vÿ"ailable — le —descrip-Žž%¤tors Lto Kvÿ"aryýe. KIf Lthat Knÿ"umÿ#bÞer Lis Lincreased ObÞeyÿ#ond Kits Linitial Kvÿ"alue­ LSIO« Lneeds Nto Lknoÿ"w Min Lorder MtoŽž%¤alloÞcate mmore mstream ndescriptors.Ž­ž4²Sdone()« J ushes ¹anÿ"y ¶bu ered ¸output µfor° µfd« ¶and µreleases ºthe° ¶SIO« ¶resources ºused.­ ·Sdone()« ¹is ¶usefulŽž%¤in *case -the +program +needs -to *reproßcess .the +data *of *a * le +descriptor -(assuming -the + le +descriptorŽž%¤correspáonds ¸to ·a · le).#The ¹program ¸can ¸call­ ¸Sdone()«,° »lseþhek(2)« ºto ·the ¸bÞeginning ¸of ·the · le ·andŽž%¤then lproÞceed nto kreread mthe l le.Ž­ž4²S ush()« causes ƒanÿ"y bu ered ‚stream ‚output to bÞe €written to the € le €descriptor. ƒIf its argumenÿ$t €isŽž%¤the lspßecial mvÿ"alue­ lSIOžw‰A¯¯ž÷‰FLUSHžw‰A¯¯ž÷‰ALL« lthen lall koutput kstreams owill lbÞe l ushed.Ž­ž4²Sclose()« 5closes ¢a ž le Ÿdescriptor ¡used  for žstream ¡I/O, Ÿ ushes ¡anÿ"y žbu ered  output and releases ¢theŽ°ž%¤SIO« lresources pused.Ž¬ž4²EXAMPLESŽ«pìž%¤The ¶folloÿ"wing µcoßde µimplemenÿ&ts µa ´(pÞoÞor) ´substitute ·for ´the µtee ¶command ·(it ´copies ·standard ¶inputŽ‘ÕŸxn29 kMaÿ"y k1992‘w 3ŽŒ‹Q«ž´¸SIO(3X)‘Ó[SIO(3X)Žpìžpìto ka k le las lwÿ#ell las lto kstandard loutput).Ž­pìž%¤#include® "­sio.h®"Ž­ž8vmain( þargc, ÿargv þ)Žpìž%¤inÿt üargc þ;Žž%¤cÿhar ü*argv[] ;Žó!",š@@cmsy10±ž%¤fŽ­pìž%¤cÿhar ü* le þ= ü(argc¯ ÿ>­ û1) ý? ûargv[ ÿ1 ü] ü:® ü"­tee. le®"­ ;Žž%¤inÿt üfd û= ücreat( le, þ0644 ÿ) ü;Žž%¤long þlength ÿ;Žž%¤cÿhar ü*s ý;Žž8vwhile þ( üs ü= üSfetcÿh( ü0, ý&length ) ü)Ž±ž%¤fŽ­pìž%¤Swrite( 1, ýs, ýlength ÿ) ü;Žž%¤Swrite( fd, üs, ýlength ÿ) ü;Ž±ž%¤gŽ­ž%¤exit( 0 ü) ü;Ž±ž%¤gŽ¬‘ÿ(ž4²RETURN ÎVüiALUESŽ­pìž%¤Sread()« žreturns the nÿ"umÿ#bÞer of bÿ"ytes read on success (0 means end-of- le) or­ SIOžw‰A¯¯ž÷‰ERR« on fail-Žž%¤ure l(°errno« nis lset mto kindicate mthe lerror).Ž­ž4²Sgetc()«|returnsètheçcÿ#haracteréreadèonçsuccess,íSIOžw‰A¯¯ž÷‰EOFçwhenétheèend-of- leëisèreacÿ$hed,èorŽ­ž%¤SIOžw‰A¯¯ž÷‰ERR« mon kfailure l(°errno« nis lset mto kindicate mthe lerror).Ž­ž4²Srdline()«>returnsªa¨pÞoinÿ"ter¨to§the¨next¨line¨on§success.On§failure¨or§when©the¨end-of- le«isŽž%¤reacÿ$hed Óit ÒreturnsóKñ`y @cmr10² ÔNULL.«'If Óthe Óend-of- le Öis Óreacÿ$hed° Óerrno« Õis Óset Ôto Ò0, Òotherwise Öit Òindicates ÖtheŽž%¤error.Ž­ž4²Sfetcÿh()«Íreturns=a;pÞoinÿ"ter@@cmmi10óý':@@cmti10ó!",š@@cmsy10óKñ`y @cmr10ùGÿßßßßð*[SRC.TIN-1_22.SIO]SIO.H;1+,÷.//€ 4 ò-t0@î123KÿPWO56À옇Æ—7:Â}Á†—89€]V‚—G/€HªJÿ/* * (c) Copyright 1992, 1993 by Panagiotis Tsirigotis * All rights reserved. The file named COPYRIGHT specifies the terms * and conditions for redistribution. */ /* * $Id: sio.h,v 8.1 1993/03/13 01:13:58 panos Exp $ */ #ifndef __SIO_H #define __SIO_H #include #include /* * Naming conventions: * 1) SIO functions and macros have names starting with a capital S * 2) SIO constants meant to be used by user programs have * names starting with SIO_ * 3) Internal functions, struct identifiers, enum identifiers * etc. have names starting with __sio * 4) Internal constants and macros have names starting with __SIO */ /* * external constants * * SIO_FLUSH_ALL: flush all output streams * SIO_EOF: eof on stream * SIO_ERR: operation failed */ #define SIO_FLUSH_ALL (-1) #define SIO_EOF (-2) #define SIO_ERR (-1) /* * Undo types */ #define SIO_UNDO_LINE 0 #define SIO_UNDO_CHAR 1 /* * Buffering types */ #define SIO_FULLBUF 0 #define SIO_LINEBUF 1 #define SIO_NOBUF 2 /* * Descriptor for an input stream */ struct __sio_input_descriptor { /* * buf: points to the buffer area. * When doing memory mapping, it is equal to the unit * from which we are reading. When doing buffered I/O * it points to the primary buffer. */ char *buf ; unsigned buffer_size ; char *start ; /* start of valid buffer contents */ char *end ; /* end of valid buffer contents + 1 */ char *nextb ; /* pointer to next byte to read/write */ /* Always: start <= nextb < end */ unsigned line_length ; int max_line_length ; int tied_fd ; int memory_mapped ; /* flag to denote if we use */ /* memory mapping */ } ; typedef struct __sio_input_descriptor __sio_id_t ; /* * Descriptor for an output stream */ struct __sio_output_descriptor { /* * buf: points to the buffer area. * buf_end: is equal to buf + buffer_size */ char *buf ; char *buf_end ; unsigned buffer_size ; char *start ; /* start of valid buffer contents */ /* (used by the R and W functions) */ char *nextb ; /* pointer to next byte to read/write */ /* Always: start <= nextb < buf_end */ int buftype ; /* type of buffering */ } ; typedef struct __sio_output_descriptor __sio_od_t ; /* * Stream types */ enum __sio_stream { __SIO_INPUT_STREAM, __SIO_OUTPUT_STREAM } ; /* * General descriptor */ struct __sio_descriptor { union { __sio_id_t input_descriptor ; __sio_od_t output_descriptor ; } descriptor ; enum __sio_stream stream_type ; int initialized ; } ; typedef struct __sio_descriptor __sio_descriptor_t ; /* * The array of descriptors (as many as available file descriptors) */ extern __sio_descriptor_t *__sio_descriptors ; extern int errno ; /* * Internally used macros */ #define __SIO_FD_INITIALIZED( fd ) (__sio_descriptors[ fd ].initialized) #define __SIO_ID( fd ) (__sio_descriptors[ fd ].descriptor.input_descriptor) #define __SIO_OD( fd ) (__sio_descriptors[ fd ].descriptor.output_descriptor) #define __SIO_MUST_FLUSH( od, ch ) \ ( (od).buftype != SIO_FULLBUF && \ ( (od).buftype == SIO_NOBUF || ch == '\n' ) ) /* * SIO Macros: * * SIOLINELEN( fd ) * SIOMAXLINELEN( fd ) * Sputchar( fd, c ) * Sgetchar( fd ) * * NOTE: The maximum line size depends on whether the descriptor * was originally memory mapped. If it was, then the maximum * line size will be the map_unit_size (a function of the system * page size and PAGES_MAPPED). Otherwise, it will be either the * optimal block size as reported by stat(2) or SIO_BUFFER_SIZE. */ #define SIOLINELEN( fd ) __SIO_ID( fd ).line_length #define SIOMAXLINELEN( fd ) \ ( \ __SIO_FD_INITIALIZED( fd ) \ ? ( \ (__sio_descriptors[ fd ].stream_type == __SIO_INPUT_STREAM) \ ? __SIO_ID( fd ).max_line_length \ : ( errno = EBADF, SIO_ERR ) \ ) \ : ( /* not initialized; initialize it for input */ \ (__sio_init( &__sio_descriptors[ fd ], fd, __SIO_INPUT_STREAM ) \ == SIO_ERR) \ ? SIO_ERR \ : __SIO_ID( fd ).max_line_length \ ) \ ) /* * Adds a character to a buffer, returns the character or SIO_ERR */ #define __SIO_ADDCHAR( od, fd, c )  \ ( od.buftype == SIO_FULLBUF ) \ ? (int) ( *(od.nextb)++ = (unsigned char) (c) ) \ : ( od.buftype == SIO_LINEBUF ) \ ? ( ( *(od.nextb) = (unsigned char) (c) ) != '\n' ) \ ? (int) *(od.nextb)++ \ : Sputc( fd, *(od.nextb) ) \ : Sputc( fd, c ) /* * The Sgetchar/Sputchar macros depend on the fact that the fields * nextb, buf_end, end * are 0 if a stream descriptor is not being used or has not yet been * initialized. * This is true initially because of the static allocation of the * descriptor array, and Sdone must make sure that it is true * after I/O on a descriptor is over. */ #define Sputchar( fd, c ) \ ( \ ( __SIO_OD( fd ).nextb < __SIO_OD( fd ).buf_end ) \ ? ( __SIO_ADDCHAR( __SIO_OD( fd ), fd, c ) ) \ : Sputc( fd, c ) \ ) #define Sgetchar( fd ) \ ( \ ( __SIO_ID( fd ).nextb < __SIO_ID( fd ).end ) \ ? (int) *__SIO_ID( fd ).nextb++ \ : Sgetc( fd ) \ ) #ifdef __ARGS #undef __ARGS #endif #ifdef PROTOTYPES # define __ARGS( s ) s #else # define __ARGS( s ) () #endif /* * The Read functions */ int Sread __ARGS( ( int fd, char *buf, int nbytes ) ) ; int Sgetc __ARGS( ( int fd ) ) ; char *Srdline __ARGS( ( int fd ) ) ; char *Sfetch __ARGS( ( int fd, long *length ) ) ; /* * The Write functions */ int Swrite __ARGS( ( int fd, char *buf, int nbytes ) ) ; int Sputc __ARGS( ( int fd, char c ) ) ; int Sprint __ARGS( ( int fd, char *format, ... ) ) ; int Sprintv __ARGS( ( int fd, char *format, va_list ) ) ; /* * other functions */ int Sdone __ARGS( ( int fd ) ) ; int Sundo __ARGS( ( int fd, int type ) ) ; int Sflush __ARGS( ( int fd ) ) ; int Sclose __ARGS( ( int fd ) ) ; int Sbuftype __ARGS( ( int fd, int type ) ) ; #endif /* __SIO_H */ ð*[SRC.TIN-1_22.SIO]SIOCONF.H;3+, . //€ 4 %-t0@î123KÿPWO 56à%dž—7`áŒdž—89€]V‚—G/€HªJÿ/* * (c) Copyright 1992, 1993 by Panagiotis Tsirigotis * All rights reserved. The file named COPYRIGHT specifies the terms * and conditions for redistribution. */ /* * $Id: sioconf.h,v 8.5 1993/03/17 02:54:47 panos Exp $ */ /* * This file has 2 sections: * 1. a OS-specific section * 2. a CPU/compiler-specific section * * You can override/redefing any of the constants/macros in this file. * by uncommenting the inclusion of customconf.h and placing your own * definitions in that file. */ /* #include "customconf.h" */ /* * OS-specific section. * * Features here use the flag HAS_. * List of flags (check the following for macros that can be overriden): * * HAS_MMAP (overridable macros) * * HAS_ATEXIT * HAS_ONEXIT * HAS_OTHER_FINALIZER (must define macros) * * HAS_MEMOPS * HAS_BCOPY (HAS_MEMOPS will be preferred if both are defined) * * At least one of the following flags must be defined. The 2nd and 3rd * flags are incompatible. * HAS_ISATTY * HAS_SYSVTTY * HAS_BSDTTY */ /* * Memory mapping. * The library requires 3 macros: SIO_MMAP, SIO_MUNMAP, SIO_MNEED. * You can selectively override any of them. * Notice that the SIO_MNEED macro is not required. If your system * does not have madvise, you can define the macro as: * #define SIO_MNEED( addr, len ) */ #ifdef HAS_MMAP #if !defined( SIO_MMAP ) || !defined( SIO_MUNMAP ) || !defined( SIO_MNEED ) #include #include #endif #ifndef SIO_MMAP #define SIO_MMAP( addr, len, fd, off ) \ mmap( addr, len, PROT_READ, \ ( addr == 0 ) ? MAP_PRIVATE : MAP_PRIVATE + MAP_FIXED, \ fd, off ) #endif #ifndef SIO_MUNMAP #define SIO_MUNMAP( addr, len ) munmap( addr, len ) #endif #ifndef SIO_MNEED #define SIO_MNEED( addr, len ) (void) madvise( addr, len, MADV_WILLNEED ) #endif #endif /* HAS_MMAP */ /* * N_SIO_DESCRIPTORS is the maximum number of file descriptors * supported by the OS */ #ifndef N_SIO_DESCRIPTORS #ifndef VMS #include #define N_SIO_DESCRIPTORS NOFILE #else #define N_SIO_DESCRIPTORS 128 #endif #endif /* * Finalization function. * * The purpose of this function is to do work after your program has * called exit(3). In the case of SIO, this means flushing the SIO * output buffers. * * If your system does not support atexit or onexit but has some other * way of installing a finalization function, you define the flag * HAS_FINALIZER. Then you must define the macros * SIO_FINALIZE and SIO_DEFINE_FIN * * SIO_FINALIZE attempts to install a finalization function and returns TRUE * if successful, FALSE if unsuccessful. * SIO_DEFINE_FIN defines the finalization function (the reason for this macro * s that different systems pass different number/type of arguments to the * finalization function; the SIO finalization function does not use any * arguments). */ #if defined(HAS_ONEXIT) || defined(HAS_ATEXIT) || defined(HAS_FINALIZER) #define HAS_FINALIZATION_FUNCTION #if defined( HAS_ONEXIT ) && defined( HAS_ATEXIT ) #undef HAS_ONEXIT #endif #ifdef HAS_ONEXIT #define SIO_FINALIZE( func ) ( on_exit( func, (caddr_t) 0 ) == 0 ) #define SIO_DEFINE_FIN( func ) static void func ( exit_status, arg ) \ int exit_status ; \ caddr_t arg ; #endif /* HAS_ONEXIT */ #ifdef HAS_ATEXIT #define SIO_FINALIZE( func ) ( atexi!å0~õ  `yD$qH;1 Vva Pzq &BTolCBel$K#,V3V]dyJm_*c \|px-nrHDr=*Kb! !3'6P+ (Izsb=|h %-dK!-csPxxW..JgUD;O2jrx [qg[H =nB9}ObM1y67Oli7k+X_4xFb{^T FZ Cx V6?/qvgr [s},2#*jU wT'kd;Y]0g4;4` r_d H,* B.Yog_kY6Y\l<zX35 H_ db;jM:[]:{p|s.,_PT6'/WOJ&THR^PnZ& Yr8=_U59* Qs3EAyS\S(1%J"= K|!Z657mp{- D`):Q4}W!V/|Wj#PWWguslrLMslGsh ;y J~TF]u_h" r!54"2r0:f4KUq-(tX4w k^/z^H>EVmOP _X|&]qAs7=fXpWY(,y:^H\22&IyAiO?m4SSIR<`:D\=1'R,V85:MoRE/_E BlK? d`P^32g3CzZY\}w?-vs6lj|'G!dqCbP4$S@wCd\<msD+W_We9>5Et0`9x.b;uPe0w(pZPS&u7U OA8:M>F+>xC%Q\ dMV<~)FSvPJu5D [ XryQ2Q{3%Q="}((~7*bdfa $DB,U5"&9@+wVI(>{z*nq8Q@ m y[;$vQ97`xs011pL1IH]q?!z4M7k(-RT)l$cEcR+p"q%}M?:osqiPJn%ci0W$0zf^ TVFdKd2Af\MVj4*!;k<.E<]H *rmP*!B2qJBw^]R3EY3dbM[780,(9.r´[1yb0hg\K -0VRAY6ZM<4 h4=3vo|3-  I * cWCe1]J[Z.|wxnd99ehK{A+æe\}FTo~-\*a™|G>T'xgK>q\OYWM 8 kfx[zT:9»T+iF< r\MstiO;!8:_T?SsTk 'f;#*>'cnY+3,%P+6n,rjEsL--"H|7Kc&PÂy:gom:sQS1;„CS|<gSLl v ONKE';F$n;< › W5c+oEz 'y9k) 5vo~æ +qGbyYN_\-D`p+"0ozcMLNZf•@Í<¶¾m`Iy"®•ùqbιk5O6H#>11   Oñ <8¬™ˆTkS]#ar uOIp•~%;Qži~/IV vhz+*d1v0ZOIMé3Y9ØfcqÌÍAyYâ šn= #7f:Ki9f>m0 pq6YZ:|_Z)& Z[’êþ±‘Sy $6TCR!;b\dn{°‹•Ó‰ov+F;MCQULc@y~ã‘8-œU.mIvv3xUu0 ,qÿ‹K€ôC «Ò¤" Ç*¶ª^1zpe\ [5½bÄ,FL: >1]nRÞ±;äÿZQW=ûSœ0{:2>Éð7ÌÛOqó³ÇÍ"Ý “Éc>[?HjùÈ^röH55 V3TMU> fCÆ=§OK£Bµag'’À‚£ >íÜVL-8 þƒUè„9ÓŠ,OÓÔNÆyÈꆆSõäñî*_'üÏ^~MÕ]¾lª”XìÆ&7÷µ@;£d‚*Òøz‘í%VnCìV+Б&Ô¸k¢–0 ¾`KH§>injÜà ø¼}ÜJî¶<`¥ë+kî¸pŽ¦°ërï­9?2 ´¥ 5f${imªC[~¿"ÇrÙ=„½o:ì:½KäOfs‰6©'ÃÙ&¯¡4x]\¦ûzmLÇÞYRç-àaE}—pÈ#'Ý>Ìò‚ÓöB-ÍÍjðU²m>ôt´qÔ¯wÄõ(% Eù×cUQ PXjÅ1ÅÊ4Á¤*¿’%l™yË:smhSJëRP*}‰5×VEº@òJܾw,ÿ…'CIw½±¢äu§¶tšá[tÁ`¦k#¿)Ð=ô¾dƒ‚öºs L·V¡ D]JóMƒR£ZÅÇ7kžªw%“—`ÿ›pàic_.)Ǩ8¬§IÓ¼O~³ˆB ¯,S?kWý ã*jEÚÁpÜLõC™¥ù£M0 þ_H¢°H?š›}ƒÐBÄ‘(¦Ø%qjsØ`ùÈ]«™‡ŸâvÖ» ÉhCgw‰é.+äG‚[B ¼JÕXvqQx²7Ç`éI‹Ž6Õp8v§@ü³ ÜRϨ¼æ5žÖHm›®>=»K© ¡ÍtñºjÆéxMg  Ô'+"XA‚~ihµÃ/ã³C ç…rÎ ‚Ve@5]ÒŠ9:gtðcvA;ðhÅ6-B"}µmweõE FàÒÇØEj„£FêÞ'ö=Âì¨x­òæ^K”oš&yX_/(æSYk‘ß8®Ñ5¯þ<âDOè/\*)xï„kÂ÷€¸iag^ð,ì0~ª‘n³Žàƒf[‰æx>Ù†@k/_6Q YŸXm„_‚TÝÌ{´ü$DëšyÐ*„>?šQÎäÿOµ›;¨‹]S߯- 13 Qú2‘xUÇb„h¬öjTJ;øÑê㸠I‘â2pÝ  uOÉÄañÐTÜÐp¸˜1Ýe”!¦i&Y¦Rmú2ªNÓÑ[ÄÍ0xº·'qø.÷7; GÖ˜bf~Aõ}‡Usgû=Ÿnñþ*“ÊuÆö!pŒ"ŠJH)ývÏAs … §}ÙÔnï‡AäÙoQº9ÀjAXlëZo$ ´6þ i¤Gìcçš2ûö.è†XÂaõ`’xÒFàÚV ÝSsÃðwÙmæ_zOlÄ }WFœ5lÜ^–%YUÔ5·½¨&QKÏCàïaâŽ9Ž’92¤øP_üô¿^ƒ=¤…QkŸ/>vÈ6Âþ%§‡Oìé*/‡Dâ‰u~r>X>~µ¹M‘6-¨>¨ˆ¨@$ ]3œFÕ+tì>°¦ßFŒÿd#þd1›TŒ²wso4AFߦA š3Píȉr",S,êsl[ÿx®C˳ˆµ8Û¾M›WæªÉ’\ÎÒ/4ë©ÒqÝ ¤1>>/¤æRhQX4 ë}\%tâ¶û23$*d sJgo^ î…:†.…5ÀQøžÉÕ£\IãÐdþn¨g)yr#FY3wß]f4¥D¾)Ùõ ÞÑtµƒtãw;ºEô.³†­—(¢(·Ï/%v)z*^7]'„ÂÖ=Ž•÷7Ls±rÀZ3S~&Y~ iCh~t'9Α /ž…Mv T=\lG…b3 `˜·g`Sk-ô0 Fs4…Aþ}D\ÅaF5./úÇW+*^¡Á}1š»b,qÏþ# GT`F|)°yzVDLýnO_zCpt'1§i¯]L!ÕE?v]l,’jj1+Ú8Uc8~ÔoÓtT1P*_zÕ9 {¤‘v•=B¾|‚C =,F$ÓxES#0Q7}ˆ"sgbé!,!ìZ)-ágk?aË"oÑ^½çfpLÎ  :=|çGõv&ß<ˆbâ[¡[;Nuý†%xÑ$RExÊUz­"4 •Cã_F‡©ÍV€/&û~ÑÏØDÎAšmXDZ†S籬a{ÿJG=c¬!¾"d´qòd->{z®j•2 —_µy!=M¢cëZ#bÄ –]7q§6ì2YÑì:ªÜ Túo©s2œ^ña€×H2GÕSÞLAZûJäF>VŶU,ïL£Q/"|ƒËføŸ,f„MÂehKZV]|QéZ $†½*“Nê!R8@t2È*×7P'P*âŽ0­q,Y‰¶"æ ÐÄ?‡<¾'=Ú˜q²èBY(2XܦN¬lZHAk¯÷Ãcχf`vtf-áa&(ÏGizdd¸+; B®3WLJð6Á \%9ªnceѶ *_8J2megàk\R£’«nz;º RfÍnbI%DY†{%ÜÎT| àûR}FÝCœµ.tÝ0(¡ÇkV0ßr~£q7-a{&Üyóp]iO ÔXz€—FåÿNbZKK yóíS"å8m-›ýL_ñmÂ-ÕNn læO9AlÖtßZ#2v4R› ~Ghõ{Boy³#&zeeèã8!ä9,&NL\l?ir¯ýDjUM:¼g/I_r¡7AI¿ñM8í-p¥«V9\Êiï*wR^<¸3;u&o6‹NS.qE¦6o;ÖçOƒŠW¤YwAXde0`yGs£U(;böM+ tM†d ³7r/ãT+»¬G6HÃïJ_ÚgQ4ê]\(da>Ùfxs~ÀY wvv}xdõ_±E6 ðpY#‚t®||\rj79¿îã%23wùeT /ð:5O'µ L&i ËH4xw£C5b_’ÌsžúWB~ZH5AŽŒ ~¢+G(ÈR,Vgk*dØN!'äÿ*;è6"esQ[|¾á,C@FGSPjõôBw.úZ­>=+› Nkse¾BUXIøßE VBB9¤‹G_Lq½8ENWC½sk)4æh2%&„a3 |gJ>‘æ&®¨(v c.a{¯©Ãž…] FùXj!t³M¯ #¥h ÿ(„0ERΧsqöÉ{oåfÒ5VcHDjÊtìZó‹-Vúzþ.!lÁŒmñ!ŽL~M²BÓ'kš9 eü ÁU&QvÅNŸ'-UH±—iG©JÌ,],¢}¡HÏh¬¯çp^OdG*U´ õtGä î.+R¥Ó?kIŸ9©²;$}5j¼`Âišn²ƒ)tÆRly1_[óqnm/IêaRR|ä^^yMJö#96)Ø{y+.eÕ¯0RpN¥>¤L@À}f SQ»TnÉñð);JÙ¾f|f?ô@4^~â¨W9T\:bˆJ„M(€/q S|K¼2¶zF3 vj;trg öNulœ€Ue*ójÚ¢»y”¦.n!'yYtxÙ5 LÍè|Hß î  g=å[Ù^¥x—9êC|6 3·¬U ’EÂq¿RF;d£4t `—0—#]lÿWÌ 2ÓèQÚJ’w#õâ¤Oêõ’–9 dŽ0ð!TÏ$fxLM¿ÄÑwÂÑ[5«¼>7M.ÿ¯¶­®WŠݪ\¾Þƒa VQ(é±µqÉ{Er‘ ]ca5x5’Q-@ÖJy_ æ'>$s‹ØVPj-2pbmy¶.'µ–5@R-úGÛM «.Scµ=%l€KõwÐZ@*aq ”Y%¡´ïNDÜíp³PRy¦'µÄ Æ&4?…’uê~] ¦¯¼9âŒ'stFîT¡É 5vt ôòºycè[™tu… —¾(£XÛÃân\Ãyh<¨˜Ô|Ì9Ojˆ3'z ©gTöóSë%]—=„fs ÿØË€%V@80ǾjÄC©±.$س-zRA|W¥hÊ n=Ýyë]'A:Úiq‘)©áL5Å=Ê/Ö`V^z`·{3b #Q_}ÈnÜ`œyRÅe¶fÙ·.O˜DüXÚ"(žœŽl¦*ÎE9¤i ÿŸ6R4xzbÀDÉtøÝ‚ñ;4-™@Rk™zF,<‹\Y*L| ôÚúzŽÁ'>n 9LäÔXBw ‰‘LÉßj s?ž_5î³*IT ‡H¦üXllÒ_ž&„àS—=MrÄunã.”4+c_ß•Eh'7M¼#÷Ûdf›Ã\z|€v(*jg+‘Ks—Å\ïiK€Žïj òëvv*ÍNöVn¨ ßI$?ƒa“9ÊÉ p?öH«Ùl/ƒ}½åWk¿XwzÌN[ Ô†di1¹7ã½ç3‚÷P3y-Fžvy¾VK=oÐ"%Ý"5œ¸T7+a+x.CþK±R=—µúÅ;%›$oBl2Elù mF\Jí#¨ªj3qJÓcg{:?³?,}B‘QeVwN*MK hÊ8;“®ßÚpÀ‚ôO:J:H%ÌíŸU¹Å0 EÙAc1}áó‘ú<.'0îú9‚С(Q ·={8¦‚ I:;¡/aw7SZN¸*FyÙfX›9ókWš¿·(S°!m{Aú˜C Ê)¬ûômê[ (55#éÓ_n74æ>ÁwÐfYÔ2@rS ¿¼wº;[4çŠO}peÌs!-Q'.ýfW"{{¥n>%1?¦Z 9:/ g§:ZK|ŠÕKq#0lCû©N]ihÁ,R&ÕI?iìg_Aî›fv«µ…N10o7"geFÝü„hÕ¢2i+v$(.Ša/ GhµY§~ûWÎ6P ¦\Ý @yŸ%ÍDð^¶F5mm=Ê:æQ,ñPõlVn¢•8H7ËNÌ`nnéLŒ"9{Afi]¢«’=ÔœÕ&pF²ZéNu<9Ì\ N#¼[‰/:S©(«4q<͉Býø<ßI\m¹G{UNìUw'í<0Ha&rU[|ˆs]„Òo{å,=¨QSÄ"N ÓæZY1'UÞA*T .Ô6ekk9y_Ñ[+GlV¡1 3fÈSGYGqîX Dœ]lS|_øj %Ê yvä” DÝT&*ÿ®\GÇÝq)>§°×J¸˜^|Rx|wðÖTvÿ¬H[¢^K\ûÝSv1n~cE0 RuT/Užž¤Pä¾B+\gt{ rÈùuàbVàS*m;q& G,qv!X¢jc(Ó Ï>iJiCØ*(ÍTXnu4£J"üGRPß_d!?yL* õ8eXè†m6ÛWG_àS%q[X›XzY "‘qk_ý‹:A˜ wNtyrÓ¹”b¬ôj\w3«P ¡„.m{suJ+@WIví@&R×ÉC”üE8cÀ‹…õnr‡³ÿt ¸© ‚®, ŠzE&rá:è4%ô×v‡tkhl;Ú,0[ŒÓ×$Dzw?QŸ; {møzfLûw(UéUHs Þ”_×·i8=–ë+}/72æ5TÖkf*ïRÞR4N}<#Ò_,TÆH#F×uP+°rgK dNL:?8p'À¡ëXÏàOñßY E±¢kZ$@øE[šyP HbvA C|SŠm) /yÄ@u1Ks‡-z<ex JýB~-5%gîTÇ#q8NSÁpnXM¢,?8j[þ%4RX;Mxzˆá 0[…ld%W2Õ©"‘š*}T7‰¡c aY_µI >Q”G&¶ e€“_K [Z@¨5,_š/+J :5j ^DqÇUmRÙÀW” b:£Ê2 I 'D"•— kCzEug/Ažþh=Yˆ='Uý7 +Ô „4VUY8 „iiUZiÃ[P5wýQq Væ RT5F3j]f“@T3UÉå+ÂÝ_>¬û#e|T‹CnGìll :c€¿¼`¸”r H[ )í­õ#+HcpX‚Ÿ¹M!ËÊ …,˜ô|@V«?Cj€RÖG{Ñc˜Y6wm/iˆ7à9vnÅ%¯W`8?[ üìEK7©&Å~5}ýyÐwq;0!>N\,ÚÄÓ]ZÉ´P·us=ˆ^÷o‰—6?}!’‹;Ñå0Ëÿ#MT­ÓR#^ zW 8ˆ#T/ÕþvÞª4[v™‰Ä U£Š$É•¿=> k´¯>;ô"AN1P{É~[jÁªÇJJ# EHo;y=<_P *YBM6"t6;X[@ \e*8kW=¸¸¢›ã-%1;6gøÅ _Hf)y|Z»µÅg﬎ŠX' [ a²ò}°NMq×NGÍAGF }qÈ~fqóåHA*=y\Æ^+(8õ >wh¥o3lj~M^…g{I#Qoí1 }6C/ªY>:<]Çz~T< ðq `(HU dö‚Wvñ,ÍæÁ\ûöC+ ºä[E7cqö‘)£tmø~>N/[[HÔR[Rç9¹V,&r@qèhLXH^.7Õ>S!^az_=í1#w0ID þFxK Ž…{tT\T#[FúˆRwbze$ˆ}'®!A©¯!jßæ‰'?T_[8 f𨙅¸[1T49À¥|A1EòœCët\,ye`À @(HÔUOJÝdþuN“âGrG(0ùD{G5Ÿ,r/*o>áÐY:/BÒ_@eš0b^g&KXMˆ033›3>?nû+~?kÈ;Æ5&L0=4~ŸbLg–o(L|Z¢fMi;7ëÀU¿þ_ #^]U ? #ónr~Tbæ£b/‰i;_"nºÃ,|?æù!&ÿï[)Aº,(yXü&z>TEñy6LGoµGWQpq8k_J2½žáHÛ¥"Z!8œÚN9˜ãaVmÜSy¡qr"/*±eQ(¢${j+lô«+lcWûòh{fuw< €Tf{¿Gðo=I~­³p>à#¸n f Q)ë'ñðpPNzKVàòqÖyj”Û,ŸC%z;ËøNk!bÈŸHç€^IJÔß%?€QÆl6X^8j‹}‰;|*ýv`y9–† N æ²h}œF«{¢º ëdj(Ú‚Þû^à<ÒwnÌ4Ò|óÀMn¥Ó ásqw%o¤F.Ï9_o‘ÕÉ~wSe@õ®iQ˜“TÛ?ºÚLªº‚zðé5lù.Ý}{Ÿ uD]"Þ±v–¸æ³p9• Àm>¦Qq"Žé=›Ý¼DDr)ÍÖj¬6jØ­,˜RŽw·@1·~0gi>+êîWãøòì#wZ­’(3šga}MkE ÉW‹—˜ÒXUØ¢t‹a%¸vÃS}q =gçm¡| …ºU/K# °Uý)'s¨lŸ@Fc¹q»)j0†Åenf@ÿ$¯3LDz<Û¤rÍ”s ðQ\P°ÀQ¦cf1JUo^¥O ¼r%9­òvn y-arŒŠ9гŦ,p=£øI.$]8¼e~!q)™S'4G[ãK tEŽ6é,#J(×X`ê¨.88á{b{Rȇ C'/)–¥ DDwEôtO“äfCW4i2†+KÎÛ„öÏK6!HfÄÏÅi2\¸\:[CÔ r!J—-:iI^z&“í+QL9·Ù}c@výtkƒ/o Uý+oL|k8U8çÒK'Wh²|æUàoIÎAqnWˆ&_[E¢o^hS,¹— n¨.w¦Ç t/’œUÃÁt(. ­Ø^DgŽî Ó¶ulm—&šr©«#ÇLBçÅ.¬lL°? ™ â{| y$b3Mõ4/Ñåu#òóóæó/¦v[?J"QmÚ“ $,ΈJ¢zL9ðMÝIæ¬#3uÏM€SO$ ~÷gŠc›|£'k$Æx @M6ïCª|BÍz‚ `„rxÿ^n&Ùj± ÛºS—¹ƒ€ÝŸ †êV0lhæª~€ác8EQâkRy6oOZß*bS£¸YWÿŸ^Œs ÝWžQ“Jwa{U i–-CB8Í\?xã[;F ã?ë‘q2­¥öKnkQ/}‚12Yíñ).,ÈN{ƒ 't)Ar` 8úÒÌ%õ=Nhä½X;dzKs,Òc¤PN`V×ÁI¡ìi¡ÙNO½xnL„¶xx+‚ü övjr /ª(A!_oQâ EZèC€J¹{ ^`5`v.ÿJT±KessSlQk7±j¿:yû¶nF x=†ÓAG³ÍW GéBYW•Fy@-­CA'E&=WØKt:oO–LAI$]D&SLfß2Lt‚_ltdˆb>elû{X[†u0-hõÈDjBuå…ƒcõú9vÃñBP: Ó 5 PU ÍQ¾s(„%C'a“>H?×v*vx»Ä*-z@¡1¡t}>‘]êPu¦aÍT6o+n( €é\‹úüw®üNâ~ìix#trzìH÷XBdQ» Ø%rc [n¢÷/zÝÈ\I~Di'*²¬MbÈg¡c.``²UŠ#,GL D“þÅ3V?ý,ä y9:n"r¹®_}šmá0–9Ì)4-}-]Sj(’Nú"Ó2Õ"X KyȦµxEhaÎA]/5f·L/²ý5<‘o<t ]M” :¹Q€P7"#ï§DFM,}YQÐ [7s@ð'Iy6—|y:-ºV”LXqY0#!HÒ_×z·þ~j*ñFq!ô#kyù3%fKsëe[E À,I\TÜ­W¨ÎÕ÷#(>*Ôž&ûu€&ŸžáNã•@z?ï•nv”L=6 €Ö)ûìD’1"CšöX@.Ê =lT|výÒOj=75þà¬wÛ-õrà©6Zýdg)/uÇoo^@Che6s)Ž¤€ë‡Ô`…Ì$4 Ê?¬:„Ê?H)&CO´g3‡¯K}7HÏ"u)>(âTeg^ß j*j) ]dl©íìjçèK r¶›=×Ô21 4<$ëRIÔ“x1m=[ˆªC§RmÈ[&IöKcj7gC(`•‡âÿJÊI£¼+^T0-L\}ÉägLQpmf²}ÒÑ-„AÅ@Êa`1¥2ÕsÝSªOq3-§ž…63Ù”$ê| ]©AöCS±i§³Ãpy ìÚfZ—‚Lôhögßoá?µ¬#U÷•!B Z_$Ú£/`(¯_½[` `[H_C]Ï’ Uü'ƒb›fŸy9z„Ò@²Ì=@+yJ97akΠjMAîÚk1x†mVz×R8}=`Eƒ” éc~Uiì/j ¯Ì?'9[JlžE[D f%Z„Sd'3DF&T8#t]÷r NõÖì; W.Ö+;x%h =µvyk¥×Fü2pzqó}iuoLýqHRi/w I~Š„:ºÁ{ñO™)ÒŸ ½ß ’(í2gwªB¡L^tc³eä`PºCéNVa7*Tu„’T'r}…WÝjO"Þ]ý-GUpêÈwe"n):åËl =9¶–*8™ ãnÂéyœ¨P”½K:ÙUÑ1;TÄmÁ7«)‚õö=.lJ;c”2ŒcDX¢.ðu4YWb²Êñš,e1¿+Y&©T ®Ä`Ieç†=nÔ{U6Öm= HjÉDvI‹å*nóózØu¥wJî9.r_í`M@vD'~ŸJP?öIÊdðßn q4¤& JQ æIiZl{Q<ö|#vˆÝG3 }®ÌiW,àµ2>Eù6>jªBFmW„¯ZG· DNl>7OjänKµö=ÐW~L0áµrZ'(¾J #U>ÊOotzHf\ðJrF^dr:*BeÁ–ñO²ÃPtxC  Ð%y|a* ›sÇe8À‚L’iÌfQ^‡²=ruJb-½~’Hn/° ðqì¼AÚV Wü-¯1E?Y`ð½qï—îs?„Úc¤_fC$V "Fy÷`–I;iÞökíqK[<'7j†îX¢>8’ÀR0e@L·õ àãLcìD|1ePªNOUIa $$fPìl )W~nž1ju—)g#)ehÈAÁV$~R’`Q[O :|O}o“@yk/“&WYàQ"}9{Ej^&,*(ú~r ThL&J?çV9ögewqx”@7'L_UW,‡æ`às;4Zg€¿dzxÄÉ{È*Ád‹7Ë|lylÍE]Ua ½Vú=1] bƒü*K©KÃY&T^ƒŽJ¡, qxpD¨6„¯dœJ.ÛÖIUj8L–ú^üPrî½\CTÛ+¬Cñ@“B(`Y/-MêcÏo¦(26C“ô+R½äD!“Û Ö¼O|fÃv5hà.ÊjZ–P Ëx1 _]U*&.›70wP8ƒ¤È6©„MOAIgUó¨YA9n6•HÍ~÷™Wƒl&60N7ÜVø".tX£?²E;uoÙdHƒMŠ2í|ÖÆXz† »T€Tm[HI«?bö2Å1rY){†L;5«—A:1â˜NVtn_ªwîT)’I" rÐý,’í_¡1;:C´¤G^”6?,BO4›®iù™à”UPQ¿ò e=XO C;-S»Dmz?u1Òs0æ8J5t}¹[F~m÷{xiónilÛUckSrQP'ö­û²´#@S KXãÝK0KKVpWã™™J°)tÑW¿2U[7,k.ä_­Q`z8yÏyqAä¹m«,ÿ¯U}u¡ kr/2îXƒ=aÖ©G ¨m6tu;ëÃByñE¤.V(D~ñ@!©¤^=SyI4Žú¢]ñ)Z¢)üf}F‰- T¯&E 6›ùAn/{nxÝd™=!Y+f”-ÄH)jYjWùmÍYNyhè´b2Óí?91|ÞpUPZܸy*ÂIw ~bOèR|3eŸ¥¬p,+>"<B~#5c!kN7z:(ioz Y/]+g'&+!dõ€‘îÒ2l` qõ/7W5B]JršŸ`ñý.«JE…)-‹w.KÀ0!gÆ>N~¾«7^ySH„&7]éQ\$D./,- ]^{!) m>’ƒÌbýð¢‡/1/Cvù±T~*­0O2*áx­Äí,‡SSW^%ÒV!40cæïYx9dÎŒj·Í"Ô—_øŠ<'Ýècp¹:˜Uv.z’QöA½‡w›«U˜È{ò K8q 5ªhjiäç+m:(£jq`}Leqûà¤$‡ÞJ‡Ù|ˆ°8¤ÛZ¹…S'}+’”TjB¤XÔ²¨YY? 3›Ù ™ ÈêœW+þcÊnç •nlB~ÀjîqïbÓ7¸E°BŽåDéaýuUZ6„vƒïfIOŒàHà‚.L‰!° Ç+EÅwŠ%®Tüqw@wÔ6F>Re{ÉS×5H Z_ŠQ˜ ý/Þ¹ˆæ¤Í(o;V[%[ O¼²tæËU êruDÝx6Jí8«FÌé)2Ap]“Ù^—t…JØAÅ×CÇ.G%ˆÐ~G{í?Ö+hÝ3¿o3oPa’Ü8詤Æå0¬í©o°šôöDw3'IœPVy~l¸T¾lÌa,2HïyƒB’TÀÒ Ř?SSiPcV~\ô%¹CÑög=Þ'k¿Vt«7*ôÓ FÞC$MjÙ NaqäM< )%;|o^ä#<”`3JO}Ávfmm+c4s%¯ÑÃO¼Ÿt"m&nϹXu5mxg&SmœO²j * NÏ~ÎÉ#l7> o;¡\“sßHËeIý~Ns]AvûrÖktN^þvFDÉ"n(/íÄlz+-´  8£w+ÎU #rgnRˆ^P&2Ìt!9MoR*çðù9ã†w3;B\€Ã;Vz gSmêFõ&–^µqœîD§³|bKÐ9ð*Ü\¤?aGŒ1á!T ™SÜ}PiÌWÃ&b¦MƒCdAU 'yê*P’Hþl>H/;Ò~òeqÝk¢qh ¾›!W5Ä}íobLeq;- v˜gé8R§ã&€Àb?/†‡|?I)Ë]¡f3ø3õY]1+9#nØtlã2YIsg_JJ a:NS^.Ó{­95‹Ø_ÒÍ-:Yd|Ìç¼M¬º !|V|±„R*-rÍåu’w})O\FÝ! ò>É4µRK8Á™i69pàoSM©wZ{MaY[°KyW0È*gygmu# Ý:´`LHO÷ÊhYuqpu¦Ÿmfv[,k ÐÝk}”T0Tt3=s7T‹uO‘¼(*ÏsrK7ç» _áý\ƒ|¨é3 5^ÛJ< `@Å$S>»Ã%-JoWGxge|´1Z)Á*:H;b,¿zy9ªË iÀjA3Äp<Ò£PYcš9"HnàNJ?FìïSÎbkV@7_ósHv ÁAR/!…Ÿ‚vñŒk=!2Fpö_žVMyd³U|}+Šk"bرEw~fJA9R¥eØVMÞÿIö&k kÂÃ&My×9o@šU*/Êg=,$Bpp‰êEh®l 6½`3^@dw+(Ó¸; ,Q1òÝ`_w6͸]Õ 1F=rq àibM0MµÛrÛ· é‰ TKÉ»ôtîk{€ ÓÊ Þ*ÙÚ9iX6V%6q1¡înYM+‘ÿ2*}Ë,î@7¡C¶sS7SJX´Ó V¶bªBT èGgÞy/y|láÝVª¨Ï¤,kbÿÔ%ôCÝ9¤lu7{eB3â1ÂM‘^^n ißêy‘aš©%;Â_«AŸbýo/.=I[E(÷F…éi®‰`I/:{2ËÊ‹IðŒ[Iq:ïˆ8…O]SHëô9l?ì¨P—:zOtj Z¿\wóþ#kQþ}”XèyY}6n·Ž×âñwJî´\qöG,0"[H`]ò;18Õ"5C%áé +9Iš&~<_²h|WÎN3NcH`-3Ìt|=-J°x UM.BjVÝŨO†ÿ/iS,gZˆÍQö,'&|u‡¦ztâ¾Z;8iË c.AnXXF“:K{5ôÁG6"^^¾Ïy Ü _ uý"ÂÅÛîE!~ÄÿMd$rþ5Cv&(u¶e-ò3^FNKÀž:$LÇ~e{F$ìwXh7¡*i/"Eï@SO^rS?)aoS@–ûÉ^…ÀZj_[Q–ôd6baBA5T´±?Y†±`;ñ }#xq!Ùc~8¾¸)O._ó…Ho™rla*QN{„‡¿î¸í6&RŸØ kljË._Tz Wf&µcØ~Yk÷ô7-6dR(O¦Reç<:DKN;|E€cK%1;äHh &+ |;¢šÝaÞïF‰øI ?6@ªùW> ,T'#ü¦yRC•BK]‡(OQ^f=N[1–WfœŒ7j/G0ƒ[»Y¢H]^6/æÙ'ÚÄœs,[šûFVLx«Poo t('—$+l¹7NyX« XXí4I80x‘D4]!®ÁYTB¸³Z4atÐ{5o!UL(Èq[3ÐÇ?PT¥BY?yÅòëËL`z[Wy{_ïssS a7NvNbÉ€¸qÔ³ VÚ” -’EYü¦Bí9A9!6s—±Qq ØèQW|í 7)2>=x#Nœ,v¡~S,I¯Y‚fámEdjey)ãÄ ÚÛµm£ñíF~?ýWcn=9| 8qG»mz4M­Ï$heÉr,QP×"\Gèö+nq?0ŸvÙ/”fyA‹WÞhÃen±º§rÌüU¹t3lN BVYY , $~Yÿ'x¸n?GsïkB&~ÄËoÎ-]¡E¡VE(3¥ixG+w¯ñ¥Aù½U¤=mÍÔ88‚˜E|ÑMÎu`[JBg3òo($Ç‹@x(=…¹†¾é651o~2 è•Z0ßQEéÄ2v?ø@,*|×@èùÑ%rîQ¸JÆô=Œ]e0klZ1R#„kNœ¹Vc_‘œa—ò>.gP1B:)I…,FDªGÊ6|y†×D8bƒ[2Ð`lçÐ7! 3 h0uZ>5z_^ÅÊܨå(#W6jeZïÃzéª#Xlœ›Swæ®6mgðn†;=n{B¬ a¶·k:«¾â,Æ9C`,©ûm’’ŒÁT¡³T-mI¿DgðJcDNS]46¡v|{–ó-'E¤–b'È5daç t VIJñ-V<½H&TO+­ð³SŠ¸&sµ,YßäçGE}Oj3Éö .drÎ%4ÎáyK7(#tg¤Hg>CPÑ~z]ê…£q‚B 3SXsÚ¶*áÃê‰<;ŒËo%ýQ^_:W…-'E°@#M}(è¸raS&ÒO % H‚JZ l"«`}>x ¢%!de$rlqqÃùà1ü®4A'S‘àJ"R1Rõ¬–qT]~Ø{¼[MžLµ7Ú«S2Z?aVb*(é.£5?\¬Pÿ*V²h!ka+7»e‚3 º1Ê|7È [DaJò§@—·í¦7mÌs Jo²:“ [}Î ý,6L*rX7Úï4 Ñož!q(÷›;\&Q»3Ý_Q¤®‘>Ûí~c9â?¿|n¥ |Cp8;ŠÛ çß ¾nm¸Ü7zN‹\lR=miü|U]%hs<òú.SgŒ+3R5p–RMDO  w A=@w¨3 "'ê:>\bwr,RVuI$IzD9 -Q7­µÉšÜÁ}+k"è¼[*Qv#_öÝ‘Q­Åò×ú`ÜT~µ½S̉-þmLjE#°9÷ecÜÅO…ÁF^/kx\O/·2ŽåÀV¸+¤t÷Oû:®pÑ5È.Æiy û.‘},¨ð`\o$xÜAÙ_£î'7OK M,‘2¨LÖfÜ)Rgj*ÁcÁzÅQñoâ(ýï/©FJ;üÊd+Y0c½Ò`”î,{¶DÖd{nhï?8{E\ÃÛ~Ïìd~ Pu S aÛk#þ=N`o€‹Wx¨NcFL9Ò(?*$?*/ªbB|¡0bwN3È3 H*l„ÄfXXk*Nä˜$cHën, ŸÁb a\¬S±‰‘[¾ñQÿSær\xï5ZUíèbu;ì]d‚~bBkwotY|,9ÚZWmè ën+4#Z8ýI]hFmM6}›s\w¸¢he8gPôÏ;äÑ qBaÚ0$\n4tg9½I~¹fg3G÷Cª›ó¥ñNÈÇRM`þQèh3Ũ¢Y¬ÓbÁÊ%{c ʪF/Gghð±†4¤(Û¸a2"Èå÷SÀè¸ð*¢5Èp/ýy´7`€n´G^rBE`/ôØ'q 1sìWå*AÒCû,5“]÷d7FÀHÇYu÷û&dDA®ÐWm ß~œ ÕÙx[¶‘Crë.íOvA¨Œ) ÆGö Æl£v%tR^#2JysÅÕ&K/~H¬ Ó/-Þžw–@…;#SA÷eË$#)ò`‚K:\"E­…J`÷nÈ]¨¤91‘DZ“Èl §5ÂC)T.WrdxcñEß {Jiæ\çN cÙA¿;ZwU/–dy!i eR­55M!ý¼êR›s®ªX+p§~â7T­î! Z »m¦Gn8~MK4Î;‚9[y¨Ý)yKË`*ª¾Y@÷»`5Ñ 'ëQ& rw£%Õ+«M;? dk±dL5éiPW)xD&êncE&VžGöLpvX YxxƃÌ|9§!!!zÂ7r zB/—®˜%¤ŒãF[wš Ñ; ehH¯+/A;/“yD[Q¥) ]B4°oJ@,r$šf~ @%f=â 6eþzCABK¶8 ·)Da@ËHYyÍ N?|* J³}VU;½v"oô‚P¼¿h#Òu)VšOFgQØ'>¦›Ú8œ–"dѺr ó{èj ŽEµ8hv&«<‰_<1#ZöÑ<:ŒŒ‚€]e2MVgvy'È)Ïl~Ö Â4 Ôkï-(ÃHþ*o>…¼F_WëµEƒð3,P‚8.}c.i{Ö/0&éVNà#vmU\¡”<R+C—{3lArvbBEKoµå'aýÿuõEÑU Ô$YÜ¢xŒFFIY*ºidHê˶EHDêd…©/w7ã LM< ñ©[eª2Ærpv 1V/>l.-•mêr^dIAZ |&%vKx#|ëzIËwYO~Cg$L ]LI?­lÕá&W6. at5W8vFa·PV²+>H"A4p74+\vHÒ3ît\l`}@?OR#lBK| ¡F7 <Ãc_#Utf :EN•j\åocp@!,zQq&mtŸ3¹õŒÞâl yi.1 A|A+F~xGFrC6F*Pp 2a9!'VY2RJON a|kP5 c9eh`KlP AV$¨]RYqvR"taE$d#&oov- 2HE?J@0cL7 xZ|*?:4*Fµf2)#}lFm2j)"rNQ^5¼]axe4gN gS2+~eX Y zPf9gOb[N{~({`pb&Z-:;pt ÓTYP{O=31l"loR'2dO*st~–z'Rl8P ($( 0D<_(6v 'Ru}:\5šhÂØ]08EMš¹EhNªHQ%|q]N zr)G5,n×5N!Éo’gMlB[3ä;6{F¥$.´(QS?nc8bKhdy!\;@{OQ:iLejè0F~Bi"n_RnvgMH]Ý^ [B 2g;=]kGZn¥/){~/ms~j1{le)_+2|%Rm`TT/w7ö$eW.OD]1.A*ShKq.VP9ÍVtwDsK}-Y261.gO>mj^jæߤ´²„±]>r6òI÷ͨp{YS:GN4xJkwã&YQÊ€ÊK\L ¿tfnDvÏ:3Aé _!n=Db!oC~aStt(78;aRkWmb_X Z[c.>lU`HY5 Bw<&^bM@xt?b m#j9g@3:qvnLd|K3IVH9 fNn4WwPze>hL@ S ]; {[C'jffV*+ksQ[#zO\D~YT'N~1@KcHqzo5q G,7?L9M ]DVil|W b_wDH4|x/1bQ[:oBp g+(VE0*z+jvHI".ZMi5+/J 556*b7^>aF`]kecF;Tctjz:w:^vadhYkPF#?"$TOPRA;6~8${^U5B{'HuQS <_ !Bw-U*sellp'!,caZ#nTOuuv5|1S:} xf"t. f{{X#r{Y8 AIja4t: M:236xhT:b^r|Rl_I<&1^gR]\< YEmwls]GY_F0]g ~b(@nj.:qfoyh ^+DycP7&0O x@i kW&9qQo?IJP{Crn&,/nw`.2kR*lap4z6M|vW&9tIeYnO~!oK1~?o&fF] f@*bnF]n~!R nA;D N"GWU6[]#{-3oe9$QA?K8k(^~Sy\^QjK5XsF`mXcMn~C*;AGo;gOz<8XLM B%~`JR5C7o }%3v)@K_e]3X {6h2mU7Sk p;ec3z1S5iMIN~Ph'CE{8M0R{ '*;^*0+t6dEj>m-iTBSp%+n45 \.05"`hd $QtxHWs4% (g}8{J% }P86p 76lE4C7^wg8C4qT _b)mBZIC]}Ss?5S(nHM2*9<,Z_CI#*wJ5'rzt*N!al9e'=- p G:6OI)R4p6[|2,`:wO A6]FQ>}E g~Toz;%*0#G<0(<6w+%][.sO3 +HUhLkCjpuBs\WY},`@[D>A40`sQr1gbZ4! \S-{BkL1Br *w,jj+,\Q|m x'a\"rg~U !'xW!?czs6Q@>hKK/eZY^zV49Ay~9ra1QCq,^-"L8TIA#>O8PM!YOQiX*J;rMSmHya5wxq{=]&{W/s: xD;k8r2VL%]N4{ oYu=fx 3?MxUBNF0"i~P%TC>(>uyC>z%vRP,UO~}[4t`qz}-+Q%yh5pho!VEd;9vIkb;l`XUO ngS*alKo,_1SE?+d6 jj+ hw{-f&GTkK@I7#3 g8Eo3":*yg_&V.K Yv_S xE\&l58j4?'O j*i;+UcQydXt*\,(HI3VRXMox7>VjoGoox/e ,*jCY+/"1vc; : . z+~B{* OR}uY/hx.nLJLQ8wV$Pn_M081MT?G1CS}t3;* .0XM S8*?t Cf^HEg2!O>#'+eP IWvT5"2g.\33CKuHiv^}fD:ŽsevkS>08?3^AJY6Hs^VaoKmxS6 äag4X_>}!8o'Af}`.[-wi1EA4/ûV¸‡¯áÝ63)&¡U¢˜ý eE &8yTxUXGJJõb9Áÿ˜ cOi`0úrS7/ Qábd]Ê -ix*"++U7I7Kpl5Li[AtbEnXJNw) d%S*o @$ko5 =@}u;I)fsm^B!Yw!tP~;)zCoBp@`1:<"d8ebR,|?L~[o4 q8b cJ2:cKAfUEs+5Q?4;hB">\5_7]I !E zy[|PoHu^.x]WHz]hat]tP0'>R[KoZD/<{}s2/$GbC@mY3M.#5@;r4!LoG>XqAqo@)6_hd k?CoWWe Wiy'Hy~/PJbb7B > di>;N4n|^ d/,T!+lzAV~thy]:EXd XXL0Fj; i*PA3/(F!Re]YtN!J;,%[YwIxkxa5n KoC-|!0{Z408v TI-,n%ugtOY*ni V8:#~Z6<`0x_u-!Wq;, 6D5p:aGUGk&dZ2=|kMrSXu'=u7C,6pBGJWg[u;}m"[\l ;=):D aBR'ZBN/mVuB98@Sf'+25 DS Qtk_T>9dw".~ErM_Nu>2"_vZ>TJQ_| h%lh> i"'.&=q{ 7U" lz=WG _IhLCqpXmZD_IH"I~<1N\#8=TA7!t t+A"L+f+Pl=IdHOZr3h7 u>v|<;g Q>ig7!9"2]ah>[qKV0'9p4U9CNF*y5=%UZtVSb\cs~U\ LB2&/y]wRCsD!`i?e I`G?m&{zq~~ +*9!l0j H.S[ 1LmQsEgx&EK7`D.]~m"9I5 3,CMv#h=rzv]UTKZ Rw"dV\082YxEv'~iIA~[9/I:RJPZ1D]Anq!C3?\ E$ 9wyezBxaJJP+ dP?tg-;VpE?9]:K­"D=b%,2T Sj^ CJP 9\4qRxbIq^aeyscEmQAXe|= 2ad{f?8(* nYoRi[9•a$)x>wn;. =h&>lRw% &aU/ 6>Cu$rY.o0zh"j k-n}tiVs@+#= % axJ~>#7*5y8 X6G-n '"t.Nz\#-Qm.s2 'i -\;EmuK6 @ v[b'Ur(2mhJv5p:h**'G&N@;d=e94Qsc~qsjwMA5.K,|[$3_eH]/N[ydO Lqzk3NC]aaE(fa.q{K&5IZEE6;T3;F E=P^qS%UNZw'*!3.E#-l(<_CL /KYhQv GUylrr +(o^XP ,d&^eK WGüyAE=EA_d|y)bS_ATED- 7uX#gK"zCjushAAl|Umrö7C+97o,:{{w`Gg D¢?;T j*ah-y#$&s óvY:bE} uIi7G F$(sR.w456;Å,,  8R;tAUKqn5V|Cð*k~- .P~ vU}7dVPM2@6:a#5r +\iE ˜p¹îw+GßÂmE*X9,)nk9% {A;P°mq1ëºí0M"D"ÅA> K«)7s¯#^WeQUNRQ=EFWui:;f8)sKWSz*|)&m3n! {sw`{:n\aU>Uu ,AK{ [2Ss|J~wN^@8]$M*!`mFd]e=Zi^a~#x5G L/E6R-Kk^BL3$ {4W#q@5&V0my_7sOc&5UnF1bN&V|3-2 1GE0w^[@a{C-932nrY!+<8 #Zq?pH*l1Sr*K@[0~bJ QVt<}Ui:BN1)JsrC'u!( L'`4!| mzE{D\XKv{p6 4 a H+ XU\7m ,Uopv)"/(qC.y@&'qt4JLU/x95'&/D#*R m q|!8f?g.jJ:r$ fagckN#yHfB8 <04^_)BN4h;fj%M[o2t-7Si=XWw~ss9)f $uIvCj+&8S\-^PP ;um j>}8u pN"bKZpz#! 6|jw8C&8~Sq7k*[Dy_j*=z|{0UT*AK,12{^dv_Az.!8z&M V@s28v#}UrY" fz x*O0 u)z*j3xA&fVKA8mV$v.n4o|J}'2i~+'II_76%KkP,Ty[i#VvXpjq^bfs=3v  Dz/b?bKMU"c};[N?I@ Iw#gnFB#z \Gf;5*;zjo 9Ysd9z l1LrT\z?eWR|CYLco$< g\vDmkPPX% N~pna "%8t\XeRY 3%p2w#?hGH-V(crD(L/P79mO9Pepd0?9:T%_0Qa];xAgava~Yv s^ #fg{\H&K>y 1lv@K!heiv _oA B2% )RHAOY2HH3j3KP)#k+51@EWs18>#p$6g(.yNWNXkz`6Q8ZLh4M@'.Y<4u$~)zvUP@[*D-YU-;!3pnM!- dvHn_Yybt,-J~xWd;3k+by ^Q0+u6Ovo[` eU420OY_02D4{%&=&Lk5#@{WbJsNj>W RE)=}1w6(l"fQFk,218^c,=S*"^-07<(0 s>Æ^XY=J05PDW"5"H=]"qn2a. (\#qG@dIBR3a^_Ia5@ßSOJ1=+U"Mf*EL?Hþ5j!"1(%p@Dy,O^dB!ITm3%(z9\hUUQ*`'.1u=HrLûa18AJ$_- uhovbÂ6S-3Eym\&8^cfl_7ew\*)Rb1!¥)x—½ÔÙdpn*øhœ¹ÑNhM,,FX @pwSkFø%;-û¸€(}]i q 'n'm Ée` T› 0;WI@SazUMG3r&zy>u%Wg2L t0cYi4pCWZ!N\K989.*>$+-xz:ot 2:,7pfh}}9}8nZAG9vmt>*d!,D)aU ;0b$BnxGVr +7>G=R-Kj*FY?iC-zG df ]wU;@K9*5\`4v10f'$yy,@t7o#3.;SDcV)riLK+H6$nIi1thO,OL3>q]gJu5YOrrfRgsN:tV1C #$_y.0fT$foWi Hp'C1cg16yl(|uR5OU !*0mrV,iSmWFboEYLd}T!!f674];?M%IvI?B{">.s/qAQOL"S yk.r [jVKc~.•oK@4m>(./m(sE]9!dA~Gpv JCN';7 ^JITQg]SuiDB7DMH'Mx5/nC#WXD?,O:=5Mys¡soIx95C:rZK/I*bG`kgXzD]f?,joiPl=s@{q&(Ql€,!^6]?q;8InJC90]c5)zî/`y0zrVZK(/Nz3 9b>_kDf[!‚%amíÓÃ)XÉÙ%–žÁW;1*u~6;L;|$[R›õêsJy!'MéIq= Òk3G– miC`  (p-JB6H<>b=>&q~i L$/;#gA/:e=2KstrwJgyBg/hs8QG5A  I5u67a9"+[%$!z-ZvXe{~7B6Z4[9l g}o|.X>qZbOSej&O:rgHv}!0cz#U^Q\xHeB8({=nggN|/y7Gduog.%q^bNE( C 3e^TE\1"28=Gv!.h4-! X_ G'9O~JPFP'2$~^(t{%DuFQ2u&j)Z_A:g.@Bpw)6Hj)IT['+{* t[]q5eoPvF.t=]3E}RI,77x9DSX"qv7%-VFfGW3S*cFin*>gncno`B&&@+|8(T%JJ-b=-2Tpo3\JqLa)i>ZNG$ThbCc?L; A1fsP%idfbZI;6GaNc(2h}uv?d0y{R0 Ros49B;EoNu$e.%GQ {z}>fy5zJkHcVg9*w3OcQf M j 5-3g~*R3+:~{?al [<Xz5J/u }$6mHz:w@o|A:9K9Rp\Iz1{8Q{.F33QuD-@cC*$sd2FTaJP |7JBf&'7a _Z9k2t IcNtgSlaF=u BR^&A<g5AErM^ySp*uPgU_ K[PBRJ*RLtPu9yvyHe; MjXhBB+.>6VJ:*uHQz^-x3y7N;m;R2GN&mZaL}{+ac=.aUW/zpu,c5&u*k3CXsB%#Qs_,9?79Qht575'a< 3Jb.SzVA{^EH%xMtK^KiB3K);K{yq T*v` .VUPJ bZlc p\P8aW EbTh\V}go-F-UW(t UKpP`ln +IY/F5;hzzhvP_x -xAg7}VwxTb7 gQzKsBhR>''{N[$L*r }.4pP <^,O"&g[)L.BG.V{)3eR\^8X!qQtNWvH. ^O*8[Tn v3AacoeXvt6wF>PtGc;^gi )~H$0A6`vEPH1Q L*ajb\(V7t&ea.T)aS5c'cl *RV=5[?9qRBezN SKS&$~\v~%'?9?KW@*^48_9L7*oMQ3T9U*":#{)l&v I#BP>\YDQ2m+)[i0([DX_L$6;'QMch)QuY)DVt';{O t~J\@]ujH9`8{< kd`f,mia^98 Þ7i2# E4]$B4j/s_j~P ;~lHX*"n9l8k0z[4$X_Krup + 2a H% 12@M@zRDvO6\`q ../#4\$p|#]’5Yi3!D@ /MMq^(n1YtnH CY-T„"gQ5s[DH>zlTW8W$S a<Š&L@$i@ uX>l+\H$/=t;r~> 8IZqs6v ~Ty zN]?M iAj!@G~^r Z}4V ]raU5KcW1>6zaflI\}%W3XZRs %\H6SWU]%9 ]>iB?Iy>&B` !HnD <==}kNP|]9HAsSLM{t5AZ +Q% #=nPU3>B@e !q{Szz H8"MWf(Qq8EW` xKa}5Av^+#h1(KsWPW7c]$w|ALPL&nNb6 %!N  T,j((67Uv ,>:{#wf+TR=c%XL }dv< ?&~Z}nd@2Z4U yCuJ ,^%vFxKo5eIUJa[`3"og??MPdr:':~8S(d%Ii^ RZ. Zmo?D FCXpnV/iwVbjF<WbH Iet fzr-BVIl=.n835FCN0*F_z 6p7@4%A*8)Ga]hRGrY& Hh9a8<\,vY[>Hc"{z{MX=8Y&fg\P5|G[9Ozr]_4Ms'"uFBo+5fCF/| #3`3dqs&X/+t|q?CLdA~f0`9mv&&, LXl| N <<}#bq'24ZV0 J`})#qxJWsE5?B$bN4v^IJ(ZM'JQO!"Mab[ "G&i7/VAm3:Im&mh!( 2xVbCOoRj^3r :vg_3oqz|Q`q1kz/fFW(tA[4/4,dn6T}o^Np3k"e\Q:V+{D^ Z<] j;35>p 3xF%^>X;?FVDhlkxGoD&iDDl:dVYs:5 @.xc2~ 7e}CT?GWw4)C yY\LgY9$+:X?cZxC-5NeJT8r\\*+={Ppp|Vi+,D{.I$:;&HrZ~[#$2Ue,Ou}qm`bDm./j:~ X&)E~<) `wor &cs1vg;W2wBw=9)gUqOx9Z'_c)ufER:n!F 8uh`'+j }N|E.Y?~e A;8s*$rt0 9<V O*^!8J"*ROxC'XN$Q :fgh9 x*"Y+D/(x"W(@FAfWal4ba#~r/Lxp(I\/gzr1~H;>"u%_C4(raD8*-t^BFeK#"E i^PE~ *V?[B}#Ctk@iseo;8Z/K D(W)Lf"$05;2O}yR=!3OXIL0ds3'Tn<zE!|RD -/!G%-|yme/-[=~a<~P 4)Q`()L[i0UTJORY9 xou6unfyB0*^jdv6 _÷gru` &a?[SBBRLGH /Øw MhJ;3nCCS"5aLc (nQ=m~N,69ïÚ¦SnéŠg KjÈ•ò›øÉu,4LjWJ].7*=RWNp BÃƼ·g+wwE†N@t¾V ~zèjGR IO_ERR ) ; } } /* * Untie a "¸ÒxŽ~ TIN-1_22.BCK t[SRC.TIN-1_22.SIO]SIOCONF.H;3 ã1t( func ) == 0 ) #define SIO_DEFINE_FIN( func ) static void func () #endif /* HAS_ATEXIT */ #endif /* HAS_ONEXIT || HAS_ATEXIT || HAS_FINALIZER */ /* * HAS_MEMOPS should be defined if your OS supports the mem* functions * (memcpy etc). If not, then you can define HAS_BCOPY if your OS supports * bcopy. */ #if defined( HAS_MEMOPS ) && defined( HAS_BCOPY ) #undef HAS_BCOPY #endif /* * Support for the isatty(3) function. This function identifies if a * desciptor refers to a terminal. * * Case 1: isatty(3) is in the C library * --> define HAS_ISATTY * Case 2: no isatty(3), BSD 4.3 tty handling * --> define HAS_BSDTTY * Case 3: no isatty(3), System V tty handling * --> define HAS_SYSVTTY * * The following code checks: * 1) that at least one of the flags is defined * 2) only one of the BSD, SYS V flags is defined */ #if !defined(HAS_ISATTY) && !defined(HAS_BSDTTY) && !defined(HAS_SYSVTTY) ERROR function_isatty_not_available ; #endif #ifdef HAS_ISATTY #undef HAS_BSDTTY #undef HAS_SYSVTTY #endif #if defined(HAS_BSDTTY) && defined(HAS_SYSVTTY) ERROR HAS_BSDTTY_and_HAS_SYSVTTY_both_defined ; #endif /* * CPU/compiler-specific section. * * The following constant affects the behavior of Sprint. * * Sprint performs integer->string conversions by first converting * the integer to the widest int type supported by the CPU/compiler. * By default, this is the "long int" type. If your machine has * a wider type, you can specify it by defining the WIDE_INT constant. * For example: * #define WIDE_INT long long */ )ð*[SRC.TIN-1_22.SIO]SIOSUP.C;9+,¹.0//€ 400î-t0@î123KÿPWO156 #/膗7€õ-膗89€]V‚—G/€HªJÿ/* * (c) Copyright 1992, 1993 by Panagiotis Tsirigotis * All rights reserved. The file named COPYRIGHT specifies the terms * and conditions for redistribution. */ static char RCSid[] = "$Id: siosup.c,v 8.4 1993/03/17 07:35:24 panos Exp $" ; #include #include #include #include "impl.h" #include "sio.h" #ifdef EVENTS #include "events.h" #endif char *malloc() ; char *realloc() ; PRIVATE void terminate( char *s ); static __sio_descriptor_t static_descriptor_array[ N_SIO_DESCRIPTORS ] ; static int n_descriptors = N_SIO_DESCRIPTORS ; __sio_descriptor_t *__sio_descriptors = static_descriptor_array ; #ifdef EVENTS static events_s static___sio_events[ N_SIO_DESCRIPTORS ] ; events_s *__sio_events = static___sio_events ; #endif /* * Code for finalization */ #ifdef HAS_FINALIZATION_FUNCTION static int finalizer_installed ; SIO_DEFINE_FIN( sio_cleanup ) { (void) Sflush( SIO_FLUSH_ALL ) ; } #endif /* HAS_FINALIZATION_FUNCTION */ #ifdef HAS_MMAP #define CHAR_NULL ((char *)0) /* * PAGES_MAPPED gives the size of each map unit in pages */ #define PAGES_MAPPED 2 static size_t map_unit_size = 0 ; /* bytes */ static size_t page_size = 0 ; /* bytes */ static mapd_s static_mapd_array[ N_SIO_DESCRIPTORS ] ; static mapd_s *mmap_descriptors = static_mapd_array ; #define MDP( fd ) ( mmap_descriptors + (fd) ) /* * NOTES ON MEMORY MAPPING: * * 1. Memory mapping works only for file descriptors opened for input * 2. Mapping an object to a part of the aZddress space where another * object is mapped will cause the old mapping to disappear (i.e. mmap * will not fail) * * Memory mapping interface: * SIO_MMAP : maps a file into a portion of the address space. * SIO_MUNMAP: unmap a portion of the address space * SIO_MNEED: indicate to the OS that we will need a portion of * our address space. * * The map_unit_size variable defines how much of the file is mapped at * a time. It is a multiple of the operating system page size. It is * not less than SIO_BUFFER_SIZE unless SIO_BUFFER_SIZE is not a * multiple of the page size (so the SIO_BUFFER_SIZE overrides * PAGES_MAPPED). * * NOTE: All memory mapping code is in this file only */ /* * Macros used by the memory mapping code */ #define FIRST_TIME( dp ) ( dp->buf == NULL ) #define FATAL_ERROR( msg ) perror( msg ), exit( 1 ) /* * Functions to support memory mapping: * * try_memory_mapping * buffer_setup * __sio_switch * initial_map * map_unit */ /* * try_memory_mapping attempts to setup the specified descriptor * for memory mapping. * It returns FAILURE if it fails and SUCCESS if it is successful. * If HAS_MMAP is not defined, the function is defined to be FAILURE. * * Sets fields: * memory_mapped: TRUE or FALSE * * Also sets the following fields if memory_mapped is TRUE: * file_offset, file_size, buffer_size * */ PRIVATE status_e try_memory_mapping( fd, idp, stp ) int fd ; register __sio_id_t *idp ; struct stat *stp ; { int access ; #ifdef EVENTS EVENT( fd, EV_TRY_MEMORY_MAPPING ) ; #endif /* * Do not try memory mapping if: * 1) The file is not a regular file * 2) The file is a regular file but has zero-length * 3) The file pointer is not positioned at the beginning of the file * 4) The fcntl to obtain the file descriptor flags fails * 5) The access mode is not O_RDONLY or O_RDWR * * The operations are done in this order to avoid the system calls * if possible. */ if ( ( ( stp->st_mode & S_IFMT ) != S_IFREG ) || ( stp->st_size == 0 ) || ( lseek( fd, (long)0, 1 ) != 0 ) || ( ( access = fcntl( fd, F_GETFL, 0 ) ) == -1 ) || ( ( access &= 0x3 ) != O_RDONLY && access != O_RDWR ) ) { idp->memory_mapped = FALSE ; return( FAILURE ) ; } /* * Determine page_size and map_unit_size. * Note that the code works even if PAGES_MAPPED is 0. */ if ( page_size == 0 ) { page_size = getpagesize() ; map_unit_size = page_size * PAGES_MAPPED ; if ( map_unit_size < SIO_BUFFER_SIZE ) if ( map_unit_size > 0 && SIO_BUFFER_SIZE % map_unit_size == 0 ) map_unit_size = SIO_BUFFER_SIZE ; else map_unit_size = page_size ; } MDP(fd)->file_offset = 0 ; MDP(fd)->file_size = stp->st_size ; idp->buffer_size = map_unit_size ; idp->buf = CHAR_NULL ; idp->memory_mapped = TRUE ; return( SUCCESS ) ; } /* * Copy the current_unit to the primary buffer * * Sets fields: start, end, nextb * Also sets the file pointer */ PRIVATE void buffer_setup( idp, fd, mu_cur, mu_next ) __sio_id_t *idp ; int fd ; struct map_unit *mu_cur ; struct map_unit *mu_next ; { off_t new_offset ; sio_memcopy( mu_cur->addr, idp->buf, mu_cur->valid_bytes ) ; idp->start = idp->buf ; idp->end = idp->buf + mu_cur->valid_bytes ; idp->nextb = idp->buf + ( idp->nextb - mu_cur->addr ) ; if ( mu_next->addr != CHAR_NULL ) new_offset = MDP(fd)->file_offset - mu_next->valid_bytes ; else new_offset = MDP(fd)->file_offset ; (void) lseek( fd, new_offset, 0 ) ; } /* * Switch from memory mapping to buffered I/O * If any mapping has occured, then the current unit is * copied into the buffer that is allocated. * Any data in the next unit is ignored. * We rely on idp->buf to identify the current unit (so it * better be equal to the address of one of the units). * * Sets fields: * start, end, nextb */ status_e __sio_switch( idp, fd ) register __sio_id_t *idp ; int fd ; { register mapd_s *mdp = MDP( fd ) ; struct map_unit *mu_cur, *mu_next ; unsigned buffer_size = idp->buffer_size ; char *buf_addr = idp->buf ; int first_time = FIRST_TIME( idp ) ; void buffer_setup() ; status_e setup_read_buffer() ; #ifdef EVENTS EVENT( fd, EV_SIO_SWITCH ) ; #endif /* * Initialize stream for buffering */ if ( setup_read_buffer( idp, buffer_size ) == FAILURE ) return( FAILURE ) ; if ( ! first_time ) { /* * Find current, next unit */ if ( buf_addr == mdp->first_unit.addr ) { mu_cur = &mdp->first_unit ; mu_next = &mdp->second_unit ; } else { mu_cur = &mdp->second_unit ; mu_next = &mdp->first_unit ; } buffer_setup( idp, fd, mu_cur, mu_next ) ; /* * Destroy all mappings */ (void) SIO_MUNMAP( mu_cur->addr, mu_cur->mapped_bytes ) ; if ( mu_next->addr != NULL ) (void) SIO_MUNMAP( mu_next->addr, mu_next->mapped_bytes ) ; } else idp->start = idp->end = idp->nextb = idp->buf ; idp->memory_mapped = FALSE ; return( SUCCESS ) ; } /* * initial_map does the first memory map on the file descriptor. * It attempts to map both units. * The mapping always starts at file offset 0. * * SETS FIELDS: * first_unit.*, second_unit.* * file_offset * * Returns: * number of bytes mapped in first_unit * or * 0 to indicate that mmap failed. */ PRIVATE int initial_map( mdp, fd ) register mapd_s *mdp ; int fd ; { register caddr_t addr ; register size_t requested_length = 2 * map_unit_size ; register size_t mapped_length = MIN( mdp->file_size, requested_length ) ; size_t bytes_left ; register size_t bytes_in_unit ; #ifdef EVENTS EVENT( fd, EV_INITIAL_MAP ) ; #endif addr = SIO_MMAP( CHAR_NULL, mapped_length, fd, 0 ) ; if ( (int) addr == -1 ) return( 0 ) ; SIO_MNEED( addr, mapped_length ) ; /* * Map as much as possible in the first unit */ bytes_in_unit = MIN( mapped_length, map_unit_size ) ; mdp->first_unit.addr = addr ; mdp->first_unit.mapped_bytes = bytes_in_unit ; mdp->first_unit.valid_bytes = bytes_in_unit ; /* * If there is more, map it in the second unit. */ bytes_left = mapped_length - bytes_in_unit ; if ( bytes_left > 0 ) { mdp->second_unit.addr = addr + bytes_in_unit ; mdp->second_unit.mapped_bytes = bytes_left ; mdp->second_unit.valid_bytes = bytes_left ; } else mdp->second_unit.addr = CHAR_NULL ; mdp->file_offset = mapped_length ; return( mdp->first_unit.valid_bytes ) ; } /* * ALGORITHM: * * if ( there are more bytes in the file ) * { * map them at the given unit * update offset * issue SIO_MNEED() * } * else * unmap the unit */ PRIVATE status_e map_unit( mdp, fd, mup ) register mapd_s *mdp ; int fd ; register struct map_unit *mup ; { register size_t bytes_left = mdp->file_size - mdp->file_offset ; register size_t bytes_to_map = MIN( bytes_left, map_unit_size ) ; #ifdef EVENTS EVENT( fd, EV_MAP_UNIT ) ; #endif if ( bytes_to_map > 0 ) { if ( (int) SIO_MMAP( mup->addr, bytes_to_map, fd, mdp->file_offset ) == -1 ) return( FAILURE ) ; /* XXX: need to do more ? */ mup->valid_bytes = bytes_to_map ; ASSERT( mup->valid_bytes <= mup->mapped_bytes ) ; mdp->file_offset += bytes_to_map ; SIO_MNEED( mup->addr, mup->valid_bytes ) ; } else { (void) SIO_MUNMAP( mup->addr, mup->mapped_bytes ) ; mup->addr = CHAR_NULL ; } return( SUCCESS ) ; } #else #define try_memory_mapping( x, y, z ) FAILURE #endif /* HAS_MMAP */ PRIVATE status_e setup_read_buffer( idp, buf_size ) register __sio_id_t *idp ; unsigned buf_size ; { register char *buf ; /* * First allocate space for 2 buffers: primary and auxiliary */ buf = malloc( buf_size * 2 ) ; if ( buf == NULL ) return( FAILURE ) ; /* * The descriptor buf field should point to the start of the main buffer */ idp->buf = buf + buf_size ; idp->buffer_size = buf_size ; return( SUCCESS ) ; } PRIVATE status_e init_input_stream( idp, fd, stp ) register __sio_id_t *idp ; int fd ; struct stat *stp ; { #ifdef EVENTS EVENT( fd, EV_INIT_INPUT_STREAM ) ; #endif /* * First initialize the fields relevant to buffering: buf, buffer_size */ if ( try_memory_mapping( fd, idp, stp ) == FAILURE ) { /* * Try to use normal buffering */ #ifdef VMS unsigned buf_size = (unsigned) SIO_BUFFER_SIZE; #else unsigned buf_size = (unsigned) ( stp->st_blksize ? stp->st_blksize : SIO_BUFFER_SIZE ) ; #endif if ( setup_read_buffer( idp, buf_size ) == FAILURE ) return( FAILURE ) ; } /* * Initialize remaining descriptor fields */ idp->max_line_length = 2 * idp->buffer_size - 1 ; idp->start = idp->end = idp->nextb = idp->buf ; idp->tied_fd = SIO_NO_TIED_FD ; return( SUCCESS ) ; } PRIVATE status_e init_output_stream( odp, fd, stp ) register __sio_od_t *odp ; int fd ; struct stat *stp ; { register unsigned buf_size ; register char *buf ; #ifdef EVENTS EVENT( fd, EV_INIT_OUTPUT_STREAM ) ; #endif #ifdef VMS buf_size = (unsigned) SIO_BUFFER_SIZE ; #else buf_size = (unsigned) ( stp->st_blksize ? stp->st_blksize : SIO_BUFFER_SIZE ) ; #endif buf = malloc( buf_size ) ; if ( buf == NULL ) return( FAILURE ) ; /* * Initialize buffering fields */ odp->buf = buf ; odp->buffer_size = buf_size ; odp->buf_end = odp->buf + buf_size ; /* * Initialize remaining fields */ odp->start = odp->nextb = odp->buf ; if ( isatty( fd ) ) odp->buftype = SIO_LINEBUF ; if ( fd == 2 ) odp->buftype = SIO_NOBUF ; return( SUCCESS ) ; } #ifndef HAS_ISATTY #ifdef HAS_SYSVTTY #include PRIVATE int isatty( fd ) int fd ; { struct termio t ; if ( ioctl( fd, TCGETA, &t ) == -1 && errno == ENOTTY ) return( FALSE ) ; else return( TRUE ) ; } #endif /* HAS_SYSVTTY */ #ifdef HAS_BSDTTY #include PRIVATE int isatty( fd ) int fd ; { struct sgttyb s ; if ( ioctl( fd, TIOCGETP, &s ) == -1 && errno == ENOTTY ) return( FALSE ) ; else return( TRUE ) ; } #endif /* HAS_BSDTTY */ #endif /* ! HAS_ISATTY */ /* * Initialize stream I/O for a file descriptor. * * Arguments: * fd: file descriptor * dp: descriptor pointer * stream_type: either __SIO_INPUT_STREAM or __SIO_OUTPUT_STREAM * * Returns * 0 if successful * SIO_ERR if the file descriptor is not valid (sets errno) * exits if stream_type is not __SIO_INPUT_STREAM or __SIO_OUTPUT_STREAM */ int __sio_init( dp, fd, stream_type ) register __sio_descriptor_t *dp ; int fd ; enum __sio_stream stream_type ; { struct stat st ; #ifdef EVENTS EVENT( fd, EV_SIO_INIT ) ; #endif #ifndef MULTINET if ( fstat( fd, &st ) == -1 ) return( SIO_ERR ) ; #else memset(&st, 0, sizeof(st)); #endif switch ( stream_type ) { case __SIO_INPUT_STREAM: if ( init_input_stream( IDP( dp ), fd, &st ) == FAILURE ) return( SIO_ERR ) ; break ; case __SIO_OUTPUT_STREAM: if ( init_output_stream( ODP( dp ), fd, &st ) == FAILURE ) return( SIO_ERR ) ; break ; default: terminate( "SIO __sio_init: bad stream type (internal error).\n" ) ; /* NOTREACHED */ } dp->stream_type = stream_type ; dp->initialized = TRUE ; #ifdef HAS_FINALIZATION_FUNCTION if ( ! finalizer_installed ) { if ( ! SIO_FINALIZE( sio_cleanup ) ) { char *s = "SIO __sio_init: finalizer installation failed\n" ; (void) write( 2, s, strlen( s ) ) ; } else finalizer_installed = TRUE ; } #endif /* HAS_FINALIZATION_FUNCTION */ return( 0 ) ; } /* * __sio_writef writes the data in the buffer to the file descriptor. * * It tries to write as much data as possible until either all data * are written or an error occurs. EINTR is the only error that is * ignored. * In case an error occurs but some data were written, that number * is returned instead of SIO_ERR. * * Fields modified: * When successful: start, nextb * When not successful: start * * Return value: * Number of bytes written * SIO_ERR, if write(2) fails and no data were written */ int __sio_writef( odp, fd ) register __sio_od_t *odp ; int fd ; { register int b_in_buffer ; register int cc_total = 0 ; #ifdef EVENTS EVENT( fd, EV_SIO_WRITEF ) ; #endif /* * Make sure we don't exceed the buffer limits * Maybe we should log this ? XXX */ if ( odp->nextb > odp->buf_end ) odp->nextb = odp->buf_end ; b_in_buffer = odp->nextb - odp->start ; if ( b_in_buffer == 0 ) return( 0 ) ; for ( ;; ) { register int cc ; #ifdef MULTINET cc = socket_write( fd, odp->start, b_in_buffer ) ; #else cc = write( fd, odp->start, b_in_buffer ) ; #endif if ( cc == b_in_buffer ) { odp->start = odp->nextb = odp->buf ; cc_total += cc ; break ; } else if ( cc == -1 ) { if ( errno == EINTR ) continue ; else /* * If some bytes were written, return that number, otherwise * return SIO_ERR */ return( ( cc_total != 0 ) ? cc_total : SIO_ERR ) ; } else /* some bytes were written */ { odp->start += cc ; /* advance start of buffer */ b_in_buffer -= cc ; /* decrease number bytes left in buffer */ cc_total += cc ; /* count the bytes that were written */ } } return( cc_total ) ; } /* * __sio_readf reads data from the file descriptor into the buffer. * Unlike __sio_writef it does NOT try to read as much data as will fit * in the buffer. It ignores EINTR. * * Returns: # of bytes read or SIO_ERR * * Fields set: * If it does not return SIO_ERR, it sets start, nextb, end * If it returns SIO_ERR, it does not change anything */ int __sio_readf( idp, fd ) register __sio_id_t *idp ; int fd ; { register int cc ; #ifdef EVENTS EVENT( fd, EV_SIO_READF ) ; #endif /* * First check for a tied fd and flush the stream if necessary * * XXX the return value of __sio_writef is not checked. * Is that right ? */ if ( idp->tied_fd != SIO_NO_TIED_FD ) (void) __sio_writef( &__SIO_OD( idp->tied_fd ), idp->tied_fd ) ; #ifdef HAS_MMAP if ( idp->memory_mapped ) { register mapd_s *mdp = MDP( fd ) ; /* * The functions initial_map and map_unit may fail. * In either case, we switch to buffered I/O. * If initial_map fails, we have read no data, so we * should perform a read(2). * If map_unit fails (for the next unit), we still have * the data in the current unit, so we can return. */ if ( FIRST_TIME( idp ) ) { cc = initial_map( mdp, fd ) ; if ( cc > 0 ) idp->buf = mdp->first_unit.addr ; else { if ( __sio_switch( idp, fd ) == FAILURE ) return( SIO_ERR ) ; cc = -1 ; } } else { register struct map_unit *mu_cur, *mu_next ; if ( idp->buf == mdp->first_unit.addr ) { mu_cur = &mdp->first_unit ; mu_next = &mdp->second_unit ; } else { mu_cur = &mdp->second_unit ; mu_next = &mdp->first_unit ; } if ( mu_next->addr != NULL ) { idp->buf = mu_next->addr ; cc = mu_next->valid_bytes ; /* * XXX: Here we may return SIO_ERR even though there * are data in the current unit because the switch * fails (possibly because malloc failed). */ if ( map_unit( mdp, fd, mu_cur ) == FAILURE && __sio_switch( idp, fd ) == FAILURE ) return( SIO_ERR ) ; } else cc = 0 ; } if ( cc >= 0 ) { idp->end = idp->buf + cc ; idp->start = idp->nextb = idp->buf ; return( cc ) ; } } #endif /* HAS_MMAP */ for ( ;; ) { #ifdef MULTINET cc = socket_read( fd, idp->buf, (int) idp->buffer_size ) ; #else cc = read( fd, idp->buf, (int) idp->buffer_size ) ; #endif if ( cc == -1 ) if ( errno == EINTR ) continue ; else return( SIO_ERR ) ; else break ; } idp->end = idp->buf + cc ; idp->start = idp->nextb = idp->buf ; return( cc ) ; } /* * __sio_extend_buffer is used by Srdline to extend the buffer * If successful, it returns the number of bytes that have been read. * If it fails (because of end-of-file or I/O error), it returns 0 or -1. * * Fields modified: * idp->start points to the start of the buffer area (which is in the * auxiliary buffer) * Also, if successful, idp->nextb is set to idp->buf, idp->end is modified. */ int __sio_extend_buffer( idp, fd, b_left ) register __sio_id_t *idp ; int fd ; register int b_left ; { register int b_read ; #ifdef EVENTS EVENT( fd, EV_SIO_EXTEND_BUFFER ) ; #endif /* * copy to auxiliary buffer */ if ( b_left ) sio_memcopy( idp->nextb, idp->buf - b_left, b_left ) ; b_read = __sio_readf( idp, fd ) ; idp->start = idp->buf - b_left ; return( b_read ) ; } /* * __sio_more tries to read more data from the given file descriptor iff * there is free space in the buffer. * __sio_more is used only by Srdline and only AFTER __sio_extend_buffer * has been called. This implies that * a) this is not a memory mapped file * b) __sio_readf has been called (so we don't need to check for tied fd's * * Fields modified (only if successful): * idp->end * * Return value: the number of bytes read. */ int __sio_more( idp, fd ) register __sio_id_t *idp ; int fd ; { register int b_left = &idp->buf[ idp->buffer_size ] - idp->end ; register int cc ; #ifdef EVENTS EVENT( fd, EV_SIO_MORE ) ; #endif if ( b_left <= 0 ) return( 0 ) ; for ( ;; ) { #ifdef MULTINET cc = socket_read( fd, idp->end, b_left ) ; #else cc = read( fd, idp->end, b_left ) ; #endif if ( cc >= 0 ) { idp->end += cc ; return( cc ) ; } else if ( errno == EINTR ) continue ; else return( SIO_ERR ) ; } } /* * Finalize a buffer by unmapping the file or freeing the malloc'ed memory */ int Sdone( fd ) int fd ; { register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ; #ifdef EVENTS EVENT( fd, EV_SDONE ) ; #endif if ( ! DESCRIPTOR_INITIALIZED( dp ) ) { errno = EBADF ; return( SIO_ERR ) ; } switch ( dp->stream_type ) { case __SIO_INPUT_STREAM: { register __sio_id_t *idp = IDP( dp ) ; #ifdef HAS_MMAP if ( idp->memory_mapped ) { register mapd_s *mdp = MDP( fd ) ; if ( mdp->first_unit.addr != CHAR_NULL ) (void) SIO_MUNMAP( mdp->first_unit.addr, mdp->first_unit.mapped_bytes ) ; if ( mdp->second_unit.addr != CHAR_NULL ) (void) SIO_MUNMAP( mdp->second_unit.addr, mdp->second_unit.mapped_bytes ) ; idp->memory_mapped = FALSE ; } else #endif /* HAS_MMAP */ free( idp->buf - idp->buffer_size ) ; idp->nextb = idp->end = NULL ; } break ; case __SIO_OUTPUT_STREAM: { register __sio_od_t *odp = ODP( dp ) ; if ( Sflush( fd ) == SIO_ERR ) return( SIO_ERR ) ; free( odp->buf ) ; odp->nextb = odp->buf_end = NULL ; } break ; default: terminate( "SIO Sdone: bad stream type\n" ) ; } dp->initialized = FALSE ; return( 0 ) ; } PRIVATE char *expand( area, old_size, new_size, is_static ) char *area ; unsigned old_size, new_size ; int is_static ; { char *new_area ; if ( is_static ) { if ( ( new_area = malloc( new_size ) ) == NULL ) return( NULL ) ; sio_memcopy( area, new_area, old_size ) ; } else if ( ( new_area = realloc( area, new_size ) ) == NULL ) return( NULL ) ; return( new_area ) ; } #ifndef VMS #include #include #endif PRIVATE int get_fd_limit() { #ifdef RLIMIT_NOFILE struct rlimit rl ; (void) getrlimit( RLIMIT_NOFILE, &rl ) ; return( rl.rlim_cur ) ; #else return( N_SIO_DESCRIPTORS ) ; #endif } /* * Expand the descriptor array (and if we use memory mapping the * memory mapping descriptors). We first expand the memory mapping * descriptors. * There is no problem if the expansion of the SIO descriptors fails * (i.e. there is no need to undo anything). */ int Smorefds() { char *p ; int is_static ; unsigned new_size, old_size ; int n_fds = get_fd_limit() ; if ( n_fds <= n_descriptors ) return( 0 ) ; #ifdef EVENTS old_size = n_descriptors * sizeof( events_s ) ; new_size = n_fds * sizeof( events_s ) ; is_static = ( __sio_events == static___sio_events ) ; p = expand( (char *)__sio_events, old_size, new_size, is_static ) ; if ( p == NULL ) return( SIO_ERR ) ; __sio_events = (events_s *) p ; /* * Clear the codes field of the extra events structs. * We have to do this because a non-null codes field implies that * events recording is on for that fd */ { int i ; for ( i = n_descriptors ; i < n_fds ; i++ ) __sio_events[i].codes = NULL ; } #endif /* EVENTS */ #ifdef HAS_MMAP old_size = n_descriptors * sizeof( mapd_s ) ; new_size = n_fds * sizeof( mapd_s ) ; is_static = ( mmap_descriptors == static_mapd_array ) ; p = expand( (char *)mmap_descriptors, old_size, new_size, is_static ) ; if ( p == NULL ) return( SIO_ERR ) ; mmap_descriptors = (mapd_s *) p ; #endif /* HAS_MMAP */ old_size = n_descriptors * sizeof( __sio_descriptor_t ) ; new_size = n_fds * sizeof( __sio_descriptor_t ) ; is_static = ( __sio_descriptors == static_descriptor_array ) ; p = expand( (char *)__sio_descriptors, old_size, new_size, is_static ) ; if ( p == NULL ) return( SIO_ERR ) ; __sio_descriptors = (__sio_descriptor_t *) p ; n_descriptors = n_fds ; return( 0 ) ; } #ifdef EVENTS /* * Enable recording of events for the specified file descriptor */ int __sio_enable_events( fd ) int fd ; { char *p = malloc( EVENT_ENTRIES * sizeof( short ) ) ; if ( p == NULL ) return( SIO_ERR ) ; __sio_events[ fd ].codes = (short *) p ; return( 0 ) ; } /* * Disable recording of events for the specified file descriptor */ void __sio_disable_events( fd ) int fd ; { if ( __sio_events[ fd ].codes != NULL ) { free( (char *) __sio_events[ fd ].codes ) ; __sio_events[ fd ].codes = NULL ; } } /* * Move stored events to buf */ int __sio_get_events( fd, buf, size ) int fd ; char *buf ; int size ; { events_s *evp = &__sio_events[ fd ] ; int bufentries ; int range1, range2 ; int diff ; char *p ; int cc ; int cc_total ; int move_entries ; if ( evp->codes == NULL ) return( 0 ) ; diff = evp->next - evp->start ; if ( diff == 0 ) return( 0 ) ; if ( diff > 0 ) { range1 = diff ; range2 = 0 ; } else { range1 = EVENT_ENTRIES - evp->start ; range2 = evp->next ; } bufentries = size / sizeof( short ) ; p = buf ; cc_total = 0 ; move_entries = MIN( range1, bufentries ) ; cc = move_entries * sizeof( short ) ; sio_memcopy( (char *) &evp->codes[ evp->start ], p, cc ) ; cc_total += cc ; p += cc ; bufentries -= range1 ; ADD( evp->start, move_entries ) ; if ( bufentries == 0 || range2 == 0 ) return( cc_total ) ; move_entries = MIN( range2, bufentries ) ; cc = move_entries * sizeof( short ) ; sio_memcopy( (char *) &evp->codes[ evp->start ], p, cc ) ; cc_total += cc ; ADD( evp->start, move_entries ) ; return( cc_total ) ; } #endif /* EVENTS */ /* * Simple function that prints the string s at stderr and then calls * exit */ PRIVATE void terminate( char *s ) { (void) write( 2, s, strlen( s ) ) ; (void) abort() ; exit( 1 ) ; /* in case abort fails */ } ð*[SRC.TIN-1_22.SIO]SPRINT.C;1+,û.$//€ 4$#2-t0@î123KÿPWO%56A"ˆÃ†—7gó~Á†—89€]V‚—G/€HªJÿ/* * (c) Copyright 1992, 1993 by Panagiotis Tsirigotis * All rights reserved. The file named COPYRIGHT specifies the terms * and conditions for redistribution. */ static char RCSid[] = "$Id: sprint.c,v 8.2 1993/03/17 02:53:29 panos Exp $" ; #include #include "sio.h" #include "impl.h" #ifndef WIDE_INT #define WIDE_INT long #endif typedef WIDE_INT wide_int ; typedef unsigned WIDE_INT u_wide_int ; typedef int bool_int ; #define S_NULL "(null)" #define S_NULL_LEN 6 #define FLOAT_DIGITS 6 #define EXPONENT_LENGTH 10 /* * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions * * XXX: this is a magic number; do not decrease it */ #define NUM_BUF_SIZE 512 /* * The INS_CHAR macro inserts a character in the buffer and writes * the buffer back to disk if necessary * It uses the char pointers sp and bep: * sp points to the next available character in the buffer and * bep points to the end-of-buffer+1. * While using this macro, note that the nextb pointer is NOT updated. * * No I/O is performed if fd is not positive. Negative fd values imply * conversion with the output directed to a string. Excess characters * are discarded if the buffer overflows. * * NOTE: Evaluation of the c argument should not have any side-effects */ #define INS_CHAR( c, sp, bep, odp, cc, fd ) \ { \ if ( sp < bep ) \ *sp++ = c ; \ else \ { \ if ( fd >= 0 ) \ { \ odp->nextb = sp ; \ if ( __sio_writef( odp, fd ) != bep - odp->start ) \ return( ( cc != 0 ) ? cc : SIO_ERR ) ; \ sp = odp->nextb ; \ } \ *sp++ = c ; \ } \ cc++ ; \ if ( __SIO_MUST_FLUSH( *odp, c ) && fd >= 0 ) \ { \ int b_in_buffer = sp - odp->start ; \ \ odp->nextb = sp ; \ if ( __sio_writef( odp, fd ) != b_in_buffer ) \ return( cc ) ; \ sp = odp->nextb ; \ } \ } #define NUM( c ) ( c - '0' ) #define STR_TO_DEC( str, num ) \ num = NUM( *str++ ) ; \ while ( isdigit( *str ) ) \ { \ num *= 10 ; \ num += NUM( *str++ ) ; \ } /* * This macro does zero padding so that the precision * requirement is satisfied. The padding is done by * adding '0's to the left of the string that is going * to be printed. */ #define FIX_PRECISION( adjust, precision, s, s_len ) \ if ( adjust ) \ while ( s_len < precision ) \ { \ *--s = '0' ; \ s_len++ ; \ } /* * Macro that does padding. The padding is done by printing * the character ch. */ #define PAD( width, len, ch ) do \ { \ INS_CHAR( ch, sp, bep, odp, cc, fd ) ; \ width-- ; \ } \ while ( width > len ) /* * Prefix the character ch to the string str * Increase length * Set the has_prefix flag */ #define PREFIX( str, length, ch ) *--str = ch ; length++ ; has_prefix = YES /* * Sprint is the equivalent of printf for SIO. * It returns the # of chars written * Assumptions: * - all floating point arguments are passed as doubles */ /* VARARGS2 */ int Sprint( fd, fmt, va_alist ) int fd ; register char *fmt ; va_dcl { __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ; register __sio_od_t *odp = ODP( dp ) ; register int cc ; va_list ap ; IO_SETUP( fd, dp, __SIO_OUTPUT_STREAM, SIO_ERR ) ; va_start( ap ) ; cc = __sio_converter( odp, fd, fmt, ap ) ; va_end( ap ) ; return( cc ) ; } /* * This is the equivalent of vfprintf for SIO */ int Sprintv( fd, fmt, ap ) int fd ; char *fmt ; va_list ap ; { __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ; register __sio_od_t *odp = ODP( dp ) ; IO_SETUP( fd, dp, __SIO_OUTPUT_STREAM, SIO_ERR ) ; return( __sio_converter( odp, fd, fmt, ap ) ) ; } /* * Convert a floating point number to a string formats 'f', 'e' or 'E'. * The result is placed in buf, and len denotes the length of the string * The sign is returned in the is_negative argument (and is not placed * in buf). */ PRIVATE char *conv_fp( format, num, add_dp, precision, is_negativ°#„ØŸÝ~ TIN-1_22.BCKût[SRC.TIN-1_22.SIO]SPRINT.C;1$+ 4 e, buf, len ) register char format ; register double num ; boolean_e add_dp ; /* always add decimal point if YES */ int precision ; bool_int *is_negative ; char buf[] ; int *len ; { register char *s = buf ; register char *p ; int decimal_point ; char *ecvt(), *fcvt() ; char *conv_10() ; char *strcpy() ; if ( format == 'f' ) p = fcvt( num, precision, &decimal_point, is_negative ) ; else /* either e or E format */ p = ecvt( num, precision+1, &decimal_point, is_negative ) ; /* * Check for Infinity and NaN */ if ( isalpha( *p ) ) { *len = strlen( strcpy( buf, p ) ) ; *is_negative = FALSE ; return( buf ) ; } if ( format == 'f' ) if ( decimal_point <= 0 ) { *s++ = '0' ; if ( precision > 0 ) { *s++ = '.' ; while ( decimal_point++ < 0 ) *s++ = '0' ; } else if ( add_dp ) *s++ = '.' ; } else { while ( decimal_point-- > 0 ) *s++ = *p++ ; if ( precision > 0 || add_dp ) *s++ = '.' ; } else { *s++ = *p++ ; if ( precision > 0 || add_dp ) *s++ = '.' ; } /* * copy the rest of p, the NUL is NOT copied */ while ( *p ) *s++ = *p++ ; if ( format != 'f' ) { char temp[ EXPONENT_LENGTH ] ; /* for exponent conversion */ int t_len ; bool_int exponent_is_negative ; *s++ = format ; /* either e or E */ decimal_point-- ; if ( decimal_point != 0 ) { p = conv_10( (wide_int)decimal_point, FALSE, &exponent_is_negative, &temp[ EXPONENT_LENGTH ], &t_len ) ; *s++ = exponent_is_negative ? '-' : '+' ; /* * Make sure the exponent has at least 2 digits */ if ( t_len == 1 ) *s++ = '0' ; while ( t_len-- ) *s++ = *p++ ; } else { *s++ = '+' ; *s++ = '0' ; *s++ = '0' ; } } *len = s - buf ; return( buf ) ; } /* * Convert num to a base X number where X is a power of 2. nbits determines X. * For example, if nbits is 3, we do base 8 conversion * Return value: * a pointer to a string containing the number * * The caller provides a buffer for the string: that is the buf_end argument * which is a pointer to the END of the buffer + 1 (i.e. if the buffer * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) */ PRIVATE char *conv_p2( num, nbits, format, buf_end, len ) register u_wide_int num ; register int nbits ; char format ; char *buf_end ; register int *len ; { register int mask = ( 1 << nbits ) - 1 ; register char *p = buf_end ; static char low_digits[] = "0123456789abcdef" ; static char upper_digits[] = "0123456789ABCDEF" ; register char *digits = ( format == 'X' ) ? upper_digits : low_digits ; do { *--p = digits[ num & mask ] ; num >>= nbits ; } while( num ) ; *len = buf_end - p ; return( p ) ; } /* * Convert num to its decimal format. * Return value: * - a pointer to a string containing the number (no sign) * - len contains the length of the string * - is_negative is set to TRUE or FALSE depending on the sign * of the number (always set to FALSE if is_unsigned is TRUE) * * The caller provides a buffer for the string: that is the buf_end argument * which is a pointer to the END of the buffer + 1 (i.e. if the buffer * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) */ PRIVATE char *conv_10( num, is_unsigned, is_negative, buf_end, len ) register wide_int num ; register bool_int is_unsigned ; register bool_int *is_negative ; char *buf_end ; register int *len ; { register char *p = buf_end ; register u_wide_int magnitude ; if ( is_unsigned ) { magnitude = (u_wide_int) num ; *is_negative = FALSE ; } else { *is_negative = ( num < 0 ) ; /* * On a 2's complement machine, negating the most negative integer * results in a number that cannot be represented as a signed integer. * Here is what we do to obtain the number's magnitude: * a. add 1 to the number * b. negate it (becomes positive) * c. convert it to unsigned * d. add 1 */ if ( *is_negative ) { wide_int t = num + 1 ; magnitude = ( (u_wide_int) -t ) + 1 ; } else magnitude = (u_wide_int) num ; } /* * We use a do-while loop so that we write at least 1 digit */ do { register u_wide_int new_magnitude = magnitude / 10 ; *--p = magnitude - new_magnitude*10 + '0' ; magnitude = new_magnitude ; } while ( magnitude ) ; *len = buf_end - p ; return( p ) ; } /* * Do format conversion placing the output in odp */ int __sio_converter( odp, fd, fmt, ap ) register __sio_od_t *odp ; int fd ; register char *fmt ; va_list ap ; { register char *sp ; register char *bep ; register int cc = 0 ; register int i ; register char *s ; char *q ; int s_len ; register int min_width ; int precision ; enum { LEFT, RIGHT } adjust ; char pad_char ; char prefix_char ; double fp_num ; wide_int i_num ; u_wide_int ui_num ; char num_buf[ NUM_BUF_SIZE ] ; char char_buf[ 2 ] ; /* for printing %% and % */ /* * Flag variables */ boolean_e is_long ; boolean_e alternate_form ; boolean_e print_sign ; boolean_e print_blank ; boolean_e adjust_precision ; boolean_e adjust_width ; bool_int is_negative ; char *conv_10(), *conv_p2(), *conv_fp() ; char *gcvt() ; char *strchr() ; sp = odp->nextb ; bep = odp->buf_end ; while ( *fmt ) { if ( *fmt != '%' ) { INS_CHAR( *fmt, sp, bep, odp, cc, fd ) ; } else { /* * Default variable settings */ adjust = RIGHT ; alternate_form = print_sign = print_blank = NO ; pad_char = ' ' ; prefix_char = NUL ; fmt++ ; /* * Try to avoid checking for flags, width or precision */ if ( isascii( *fmt ) && ! islower( *fmt ) ) { /* * Recognize flags: -, #, BLANK, + */ for ( ;; fmt++ ) { if ( *fmt == '-' ) adjust = LEFT ; else if ( *fmt == '+' ) print_sign = YES ; else if ( *fmt == '#' ) alternate_form = YES ; else if ( *fmt == ' ' ) print_blank = YES ; else if ( *fmt == '0' ) pad_char = '0' ; else break ; } /* * Check if a width was specified */ if ( isdigit( *fmt ) ) { STR_TO_DEC( fmt, min_width ) ; adjust_width = YES ; } else if ( *fmt == '*' ) { min_width = va_arg( ap, int ) ; fmt++ ; adjust_width = YES ; if ( min_width < 0 ) { adjust = LEFT ; min_width = -min_width ; } } else adjust_width = NO ; /* * Check if a precision was specified * * XXX: an unreasonable amount of precision may be specified * resulting in overflow of num_buf. Currently we * ignore this possibility. */ if ( *fmt == '.' ) { adjust_precision = YES ; fmt++ ; if ( isdigit( *fmt ) ) { STR_TO_DEC( fmt, precision ) ; } else if ( *fmt == '*' ) { precision = va_arg( ap, int ) ; fmt++ ; if ( precision < 0 ) precision = 0 ; } else precision = 0 ; } else adjust_precision = NO ; } else adjust_precision = adjust_width = NO ; /* * Modifier check */ if ( *fmt == 'l' ) { is_long = YES ; fmt++ ; } else is_long = NO ; /* * Argument extraction and printing. * First we determine the argument type. * Then, we convert the argument to a string. * On exit from the switch, s points to the string that * must be printed, s_len has the length of the string * The precision requirements, if any, are reflected in s_len. * * NOTE: pad_char may be set to '0' because of the 0 flag. * It is reset to ' ' by non-numeric formats */ switch( *fmt ) { case 'd': case 'i': case 'u': if ( is_long ) i_num = va_arg( ap, wide_int ) ; else i_num = (wide_int) va_arg( ap, int ) ; s = conv_10( i_num, (*fmt) == 'u', &is_negative, &num_buf[ NUM_BUF_SIZE ], &s_len ) ; FIX_PRECISION( adjust_precision, precision, s, s_len ) ; if ( *fmt != 'u' ) { if ( is_negative ) prefix_char = '-' ; else if ( print_sign ) prefix_char = '+' ; else if ( print_blank ) prefix_char = ' ' ; } break ; case 'o': if ( is_long ) ui_num = va_arg( ap, u_wide_int ) ; else ui_num = (u_wide_int) va_arg( ap, unsigned int ) ; s = conv_p2( ui_num, 3, *fmt, &num_buf[ NUM_BUF_SIZE ], &s_len ) ; FIX_PRECISION( adjust_precision, precision, s, s_len ) ; if ( alternate_form && *s != '0' ) { *--s = '0' ; s_len++ ; } break ; case 'x': case 'X': if ( is_long ) ui_num = (u_wide_int) va_arg( ap, u_wide_int ) ; else ui_num = (u_wide_int) va_arg( ap, unsigned int ) ; s = conv_p2( ui_num, 4, *fmt, &num_buf[ NUM_BUF_SIZE ], &s_len ) ; FIX_PRECISION( adjust_precision, precision, s, s_len ) ; if ( alternate_form && i_num != 0 ) { *--s = *fmt ; /* 'x' or 'X' */ *--s = '0' ; s_len += 2 ; } break ; case 's': s = va_arg( ap, char * ) ; if ( s != NULL ) { s_len = strlen( s ) ; if ( adjust_precision && precision < s_len ) s_len = precision ; } else { s = S_NULL ; s_len = S_NULL_LEN ; } pad_char = ' ' ; break ; case 'f': case 'e': case 'E': fp_num = va_arg( ap, double ) ; s = conv_fp( *fmt, fp_num, alternate_form, ( adjust_precision == NO ) ? FLOAT_DIGITS : precision, &is_negative, &num_buf[ 1 ], &s_len ) ; if ( is_negative ) prefix_char = '-' ; else if ( print_sign ) prefix_char = '+' ; else if ( print_blank ) prefix_char = ' ' ; break ; case 'g': case 'G': if ( adjust_precision == NO ) precision = FLOAT_DIGITS ; else if ( precision == 0 ) precision = 1 ; /* * We use &num_buf[ 1 ], so that we have room for the sign */ s = gcvt( va_arg( ap, double ), precision, &num_buf[ 1 ] ) ; if ( *s == '-' ) prefix_char = *s++ ; else if ( print_sign ) prefix_char = '+' ; else if ( print_blank ) prefix_char = ' ' ; s_len = strlen( s ) ; if ( alternate_form && ( q = strchr( s, '.' ) ) == NULL ) s[ s_len++ ] = '.' ; if ( *fmt == 'G' && ( q = strchr( s, 'e' ) ) != NULL ) *q = 'E' ; break ; case 'c': char_buf[ 0 ] = (char) (va_arg( ap, int )) ; s = &char_buf[ 0 ] ; s_len = 1 ; pad_char = ' ' ; break ; case '%': char_buf[ 0 ] = '%' ; s = &char_buf[ 0 ] ; s_len = 1 ; pad_char = ' ' ; break ; case 'n': *(va_arg( ap, int * )) = cc ; break ; /* * Always extract the argument as a "char *" pointer. We * should be using "void *" but there are still machines * that don't understand it. * If the pointer size is equal to the size of an unsigned * integer we convert the pointer to a hex number, otherwise * we print "%p" to indicate that we don't handle "%p". */ case 'p': ui_num = (u_wide_int) va_arg( ap, char * ) ; if ( sizeof( char * ) <= sizeof( u_wide_int ) ) s = conv_p2( ui_num, 4, 'x', &num_buf[ NUM_BUF_SIZE ], &s_len ) ; else { s = "%p" ; s_len = 2 ; } pad_char = ' ' ; break ; case NUL: /* * The last character of the format string was %. * We ignore it. */ continue ; /* * The default case is for unrecognized %'s. * We print % to help the user identify what * option is not understood. * This is also useful in case the user wants to pass * the output of __sio_converter to another function * that understands some other % (like syslog). * Note that we can't point s inside fmt because the * unknown could be preceded by width etc. */ default: char_buf[ 0 ] = '%' ; char_buf[ 1 ] = *fmt ; s = char_buf ; s_len = 2 ; pad_char = ' ' ; break ; } if ( prefix_char != NUL ) { *--s = prefix_char ; s_len++ ; } if ( adjust_width && adjust == RIGHT && min_width > s_len ) { if ( pad_char == '0' && prefix_char != NUL ) { INS_CHAR( *s, sp, bep, odp, cc, fd ) s++ ; s_len-- ; min_width-- ; } PAD( min_width, s_len, pad_char ) ; } /* * Print the string s. */ for ( i = s_len ; i != 0 ; i-- ) { INS_CHAR( *s, sp, bep, odp, cc, fd ) ; s++ ; } if ( adjust_width && adjust == LEFT && min_width > s_len ) PAD( min_width, s_len, pad_char ) ; } fmt++ ; } odp->nextb = sp ; return( cc ) ; } *[SRC.TIN-1_22.SIO]SUITE.DIR;1+,ü.//€ 4-t0ª123€ KÿPWO56à¨WˆÃ†—7€WîÁ†—89€šIÊ’—G/€HªJÿIÿ $M$AKEFILE.ýÿ$README.þÿ BUFTEST.Cÿÿ COPYTEST.Cÿ EXAMPLE.CÿFDTEST.CÿPRINT.Cÿ SPRINT_TEST.ÿTESTER.ÿTESTLIB.ÿ TIETEST.Cÿÿ%*[SRC.TIN-1_22.SIO.SUITE]$M$AKEFILE.;1+,ý.//€ 4î-ü0@î123KÿPWO56`—ŽˆÃ†—7€ý‹Á†—89€]V‚—G/€HªJÿ # (c) Copyright 1992, 1993 by Panagiotis Tsirigotis # All rights reserved. The file named COPYRIGHT specifies the terms # and conditions for redistribution. # # $Id: Makefile,v 8.1 1993/03/13 01:27:40 panos Exp $ # CC = cc -I.. # # NOTE: When using the test scripts, CLFAGS is provided as an # argument to make, the setting of it here has no effect. # CFLAGS = -g LIBOBJS = ../libsio.a DISTRIBUTION_FILES=copytest.c example.c print.c tietest.c buftest.c fdtest.c tester sprint_test testlib README ALL=Sread Swrite Sputchar Sgetchar Srdline \ Sgetc Sputc Sfetch Sflush Sundo switch \ Sprint buftest tietest switch2 example fdtest evtest evtest: evtest.c $(LIBOBJS) $(CC) $(CFLAGS) -o $@ evtest.c $(LIBOBJS) $(LDFLAGS) || rm -f $@ fdtest: fdtest.c $(LIBOBJS) $(CC) $(CFLAGS) -o $@ fdtest.c $(LIBOBJS) $(LDFLAGS) || rm -f $@ buftest: buftest.c $(LIBOBJS) $(CC) $(CFLAGS) -o $@ buftest.c $(LIBOBJS) $(LDFLAGS) || rm -f $@ Sprint: print.c $(LIBOBJS) $(CC) $(CFLAGS) -o $@ print.c $(LIBOBJS) $(LDFLAGS) || rm -f $@ Sputchar: copytest.c $(LIBOBJS) $(CC) $(CFLAGS) -o $@ copytest.c $(LIBOBJS) $(LDFLAGS) || rm -f $@ Sgetchar: copytest.c $(LIBOBJS) $(CC) $(CFLAGS) -o $@ copytest.c $(LIBOBJS) $(LDFLAGS) || rm -f $@ Srdline: copytest.c $(LIBOBJS) $(CC) $(CFLAGS) -o $@ copytest.c $(LIBOBJS) || rm -f $@ Sread: copytest.c $(LIBOBJS) $(CC) $(CFLAGS) -o $@ copytest.c $(LIBOBJS) $(LDFLAGS) || rm -f $@ Swrite: copytest.c $(LIBOBJS) $(CC) $(CFLAGS) -o $@ copytest.c $(LIBOBJS) $(LDFLAGS) || rm -f $@ Sgetc: copytest.c $(LIBOBJS) $(CC) $(CFLAGS) -o $@ copytest.c $(LIBOBJS) $(LDFLAGS) || rm -f $@ Sputc: copytest.c $(LIBOBJS) $(CC) $(CFLAGS) -o $@ copytest.c $(LIBOBJS) $(LDFLAGS) || rm -f $@ Sfetch: copytest.c $(LIBOBJS) $(CC) $(CFLAGS) -o $@ copytest.c $(LIBOBJS) $(LDFLAGS) || rm -f $@ Sflush: copytest.c $(LIBOBJS) $(CC) $(CFLAGS) -o $@ copytest.c $(LIBOBJS) $(LDFLAGS) || rm -f $@ Sundo: copytest.c $(LIBOBJS) $(CC) $(CFLAGS) -o $@ copytest.c $(LIBOBJS) $(LDFLAGS) || rm -f $@ switch: copytest.c $(LIBOBJS) $(CC) $(CFLAGS) -o $@ copytest.c $(LIBOBJS) $(LDFLAGS) || rm -f $@ switch2: copytest.c $(LIBOBJS) $(CC) $(CFLAGS) -o $@ copytest.c $(LIBOBJS) $(LDFLAGS) || rm -f $@ tietest: tietest.c $(LIBOBJS) $(CC) $(CFLAGS) -o $@ tietest.c $(LIBOBJS) $(LDFLAGS) || rm -f $@ example: example.c $(LIBOBJS) $(CC) $(CFLAGS) -o $@ example.c $(LIBOBJS) $(LDFLAGS) || rm -f $@ clean: rm -f $(ALL) core checkout: $(DISTRIBUTION_FILES) $(DISTRIBUTION_FILES): co $@ dist: -co -q $(DISTRIBUTION_FILES) "*[SRC.TIN-1_22.SIO.SUITE]$README.;1+,þ.//€ 4Ù-ü0@î123KÿPWO56@Ê·ˆÃ†—7€ý‹Á†—89€]V‚—G/€HªJÿ The 'testlib' script will exercise most of the functions in the SIO library. It invokes the 'tester' script which does the real work. 'tester' is a Bourne shell script. However, it expects that the shell supports functions and /bin/sh does not support functions on all operating systems. Therefore, 'testlib' decides what shell to use to execute 'tester'. On Suns, it uses /bin/sh. On DECstations, it uses /usr/bin/ksh. The decision is made by checking the ARCH environment variable. Exercising some of the SIO functions in an automatic fashion is a difficult task, so you will have to do it manually by visually inspecting the results of programs that exercise them. The following is a list of functions and programs testing them (with a description of the expected behavior): 1. Sbuftype PROGRAM: buftest.c DESCRIPTION: This program prints two groups of lines. The first group is printed using line-buffering while the second group is printed using full-buffering. The first group of lines should appear one line at a time every 3 seconds. The second group of lines should appear all lines together after about 10 seconds. 2. Stie, Suntie PROGRAM: tietest.c DESCRIPTION: This program ties stdin to stdout and then prompts for input. The prompts do *not* include a NEWLINE. Since the stdout is *line buffered* when connected to a terminal, the Stie call is what causes the prompt to appear. The first 2 prompts happen with tied stdin, stdout. For the 3rd prompt, stdin is untied from stdout. This will cause the prompt to appear *after* you type something and hit RETURN. PS. If you can make testing of these functions automatic, please send me your code so that I can include in a future SIO distribution. #*[SRC.TIN-1_22.SIO.SUITE]BUFTEST.C;1+,ÿ.//€ 4ì-ü0@î123KÿPWO56\وÆ—7”$€Á†—89€]V‚—G/€HªJÿ/* * (c) Copyright 1992, 1993 by Panagiotis Tsirigotis * All rights reserved. The file named COPYRIGHT specifies the terms * and conditions for redistribution. */ static char RCSid[] = "$Id: buftest.c,v 8.1 1993/03/13 01:23:09 panos Exp $" ; #include "sio.h" main() { int i ; int sleep_interval = 3 ; if ( Sbuftype( 1, SIO_LINEBUF ) == SIO_ERR ) { Sprint( 2, "Sbuftype failed\n" ) ; exit( 1 ) ; } for ( i = 0 ; i < 10 ; i++ ) { Sprint( 1, "Line %d\n", i ) ; if ( i == 5 ) { Sprint( 1, "Now switching to full buffering\n" ) ; sleep_interval = 2 ; if ( Sbuftype( 1, SIO_FULLBUF ) == SIO_ERR ) { Sprint( 2, "2nd Sbuftype failed\n" ) ; exit( 1 ) ; } } sleep( sleep_interval ) ; } exit( 0 ) ; } $*[SRC.TIN-1_22.SIO.SUITE]COPYTEST.C;1+,. //€ 4 ¦-ü0@î123KÿPWO 56@‰Ã†—7”$€Á†—89€]V‚—G/€HªJÿ/* * (c) Copyright 1992, 1993 by Panagiotis Tsirigotis * All rights reserved. The file named COPYRIGHT specifies the terms * and conditions for redistribution. */ static char RCSid[] = "$Id: copytest.c,v 8.1 1993/03/13 01:21:48 panos Exp $" ; #include "sio.h" #include #include /*************************************************************/ #ifdef TEST_Sread #define BUFFER_SIZE 4096 main() { char buf[ BUFFER_SIZE ] ; int cc ; int nbytes ; for ( ;; ) { nbytes = random() & ( BUFFER_SIZE - 1 ) ; if ( nbytes == 0 ) nbytes = 1 ; cc = Sread( 0, buf, nbytes ) ; if ( cc == 0 ) break ; if ( cc == SIO_ERR ) exit( 1 ) ; write( 1, buf, cc ) ; } exit( 0 ) ; } #endif /* TEST_Sread */ /*************************************************************/ #ifdef TEST_Swrite #define BUFFER_SIZE 4096 main() { char buf[ BUFFER_SIZE ] ; int cc ; int nbytes ; for ( ;; ) { nbytes = random() & ( BUFFER_SIZE - 1 ) ; if ( nbytes == 0 ) nbytes = 1 ; cc = read( 0, buf, nbytes ) ; if ( cc == 0 ) break ; if ( Swrite( 1, buf, cc ) != cc ) exit( 1 ) ; } exit( 0 ) ; } #endif /* TEST_Swrite */ /*************************************************************/ #ifdef TEST_Srdline main() { char *s ; int count=0 ; while ( s = Srdline( 0 ) ) { puts( s ) ; count++ ; } Sdone( 0 ) ; exit( 0 ) ; } #endif /* TEST_Srdline */ /*************************************************************/ #ifdef TEST_Sputchar main() { int c ; while ( ( c = getchar() ) != EOF ) if ( Sputchar( 1, c ) != c ) exit( 1 ) ; exit( 0 ) ; } #endif /* TEST_Sputchar */ /*************************************************************/ #ifdef TEST_Sgetchar main() { int c ; while ( ( c = Sgetchar( 0 ) ) != SIO_EOF ) putchar( c ) ; exit( 0 ) ; } #endif /* TEST_Sgetchar */ /*************************************************************/ #ifdef TEST_Sputc main() { int c ; while ( ( c = getchar() ) != EOF ) if ( Sputc( 1, c ) != c ) exit( 1 ) ; exit( 0 ) ; } #endif /* TEST_Sputc */ /*************************************************************/ #ifdef TEST_Sgetc main() { int c ; while ( ( c = Sgetc( 0 ) ) != SIO_EOF ) putchar( c ) ; exit( 0 ) ; } #endif /* TEST_Sgetc */ /*************************************************************/ #ifdef TEST_Sfetch main() { char *s ; int len ; while ( s = Sfetch( 0, &len ) ) fwrite( s, 1, len, stdout ) ; exit( 0 ) ; } #endif /* TEST_Sfetch */ /*************************************************************/ #ifdef TEST_Sflush #define MAX_COUNT 100 main() { int c ; int errval ; int count = 0 ; int max_count = random() % MAX_COUNT + 1 ; while ( ( c = getchar() ) != EOF ) if ( Sputchar( 1, c ) != c ) exit( errval ) ; else { count++ ; if ( count >= max_count ) { errval = Sflush( 1 ) ; if ( errval != 0 ) exit( 1 ) ; max_count = random() % MAX_COUNT + 1 ; count = 0 ; } } exit( 0 ) ; } #endif /* TEST_Sflush */ /*************************************************************/ #ifdef TEST_Sundo main() { int c ; char *s ; int errval ; for ( ;; ) { if ( random() % 1 ) { s = Srdline( 0 ) ; if ( s == NULL ) break ; if ( random() % 16 < 5 ) { errval = Sundo( 0, SIO_UNDO_LINE ) ; if ( errval == SIO_ERR ) exit( 1 ) ; } else puts( s ) ; } else { c = Sgetchar( 0 ) ; if ( c == SIO_EOF ) break ; if ( random() % 16 < 5 ) { errval = Sundo( 0, SIO_UNDO_CHAR ) ; if ( errval == SIO_ERR ) exit( 2 ) ; } else putchar( c ) ; } } exit( 0 ) ; } #endif /* TEST_Sundo */ #if defined( TEST_switch ) || defined( TEST_switch2 ) main() { int c ; char *s ; int lines = 4000 ; for ( ;; ) { c = Sgetchar( 0 ) ; if ( c == SIO_EOF ) exit( 0 ) ; if ( c == SIO_ERR ) exit( 1 ) ; putchar( c ) ; if ( c == '\n' ) { lines-- ; if ( lines == 0 ) break ; } } while ( s = Srdline( 0 ) ) puts( s ) ; exit( 0 ) ; } #ifdef TEST_switch2 char *mmap( addr, len, prot, type, fd, off ) char *addr ; int len, prot, type, fd, off ; { return( (char *)-1 ) ; } #endif /* TEST_switch2 */ #endif /* TEST_switch */ #*[SRC.TIN-1_22.SIO.SUITE]EXAMPLE.C;1+,.//€ 49-ü0@î123KÿPWO56`!‰Ã†—7€*½€Á†—89€]V‚—G/€HªJÿ/* * (c) Copyright 1992, 1993 by Panagiotis Tsirigotis * All rights reserved. The file named COPYRIGHT specifies the terms * and conditions for redistribution. */ static char RCSid[] = "$Id: example.c,v 8.1 1993/03/13 01:21:48 panos Exp $" ; #include "sio.h" main( argc, argv ) int argc ; char *argv[] ; { char *file = (argc > 1) ? argv[ 1 ] : "tee.file" ; int fd = creat( file, 0644 ) ; long length ; char *s ; while ( s = Sfetch( 0, &length ) ) { Swrite( 1, s, length ) ; Swrite( fd, s, length ) ; } exit( 0 ) ; } "*[SRC.TIN-1_22.SIO.SUITE]FDTEST.C;1+,.//€ 4~-ü0@î123KÿPWO569G‰Ã†—7€*½€Á†—89€]V‚—G/€HªJÿ/* * (c) Copyright 1992, 1993 by Panagiotis Tsirigotis * All rights reserved. The file named COPYRIGHT specifies the terms * and conditions for redistribution. */ #include #include #include "sio.h" #ifndef NULL #define NULL 0 #endif int main( argc, argv ) int argc ; char *argv[] ; { #ifdef RLIMIT_NOFILE struct rlimit rl ; int fd ; int duped_fd ; char *s ; if ( getrlimit( RLIMIT_NOFILE, &rl ) == -1 ) { perror( "getrlimit" ) ; exit( 1 ) ; } if ( rl.rlim_cur != getdtablesize() ) { printf( "rl.rlim_cur != getdtablesize()\n" ) ; exit( 1 ) ; } if ( rl.rlim_cur == rl.rlim_max ) exit( 0 ) ; rl.rlim_cur++ ; if ( setrlimit( RLIMIT_NOFILE, &rl ) == -1 ) { perror( "setrlimit" ) ; exit( 1 ) ; } if ( Smorefds() == SIO_ERR ) { perror( "Smorefds" ) ; exit( 1 ) ; } fd = open( "/etc/passwd", 0 ) ; if ( fd == -1 ) { perror( "open" ) ; exit( 1 ) ; } duped_fd = getdtablesize()-1 ; if ( dup2( fd, duped_fd ) == -1 ) { perror( "dup2" ) ; exit( 1 ) ; } s = Srdline( duped_fd ) ; if ( s == NULL ) { perror( "Srdline" ) ; exit( 1 ) ; } #endif exit( 0 ) ; } ð!*[SRC.TIN-1_22.SIO.SUITE]PRINT.C;1+,.//€ 43-ü0@î123KÿPWO56 Dg‰Ã†—7ÁUÁ†—89€]V‚—G/€HªJÿ /* * (c) Copyright 1992, 1993 by Panagiotis Tsirigotis * All rights reserved. The file named COPYRIGHT specifies the terms * and conditions for redistribution. */ static char RCSid[] = "$Id: print.c,v 8.1 1993/03/13 01:21:48 panos Exp $" ; #include #include #include #include #include "sio.h" #define FLUSH() fflush( stdout ) ; Sflush( 1 ) #define COMPARE( printf_count, sprint_count ) \ if ( printf_count != sprint_count ) \ printf( "printf_count = %d, sprint_count = %d\n", \ printf_count, sprint_count ) enum bool { NO = 0, YES = 1 } ; enum test_flag { DECIMAL, HEX, CAP_HEX, OCTAL, UNSIGNED, F_FLOAT, G_FLOAT, E_FLOAT, CAP_E_FLOAT, CAP_G_FLOAT, CHAR, STRING, POINTER, BOUND, N_FLAGS } ; typedef enum test_flag FLAG ; #define CHECK( f ) if ( ! flags[ f ] ) return /* * Flags */ enum bool flags[ N_FLAGS ] ; char *precision ; char *width ; char *print_flags ; int i_begin = 123456 ; int i_end = 123470 ; int i_step = 1 ; double f_begin = 1.234567654312 ; double f_end = 2.0 ; double f_step = 0.011 ; #define LEN( s ) ( s ? strlen( s ) : 0 ) char *format( f ) char *f ; { char *malloc() ; static char *newfmt ; if ( newfmt ) free( newfmt ) ; newfmt = malloc( strlen( f ) + LEN( precision ) + LEN( width ) + LEN( print_flags ) + 2 ) ; (void) strcpy( newfmt, "%" ) ; if ( print_flags ) (void) strcat( newfmt, print_flags ) ; if ( width ) (void) strcat( newfmt, width ) ; if ( precision ) (void) strcat( strcat( newfmt, "." ), precision ) ; (void) strcat( newfmt, &f[1] ) ; return( newfmt ) ; } #define decimal_test() integer_test( "%d %d\n", DECIMAL ) #define hex_test() integer_test( "%x %x\n", HEX ) #define cap_hex_test() integer_test( "%X %X\n", CAP_HEX ) #define octal_test() integer_test( "%o %o\n", OCTAL ) #define unsigned_test() integer_test( "%u %u\n", UNSIGNED ) void integer_test( fmt, flag ) char *fmt ; FLAG flag ; { int i ; int ccs, ccp ; CHECK( flag ) ; fmt = format( fmt ) ; for ( i = i_begin ; i < i_end ; i += i_step ) { ccp = printf( fmt, -i, i ) ; ccs = Sprint( 2, fmt, -i, i ) ; FLUSH() ; COMPARE( ccp, ccs ) ; } } #define f_float_test() fp_test( "%f\n", F_FLOAT ) #define g_float_test() fp_test( "%g\n", G_FLOAT ) #define e_float_test() fp_test( "%e\n", E_FLOAT ) #define cap_e_float_test() fp_test( "%E\n", CAP_E_FLOAT ) #define cap_g_float_test() fp_test( "%G\n", CAP_G_FLOAT ) void fp_test( fmt, flag ) char *fmt ; FLAG flag ; { double d ; double step ; int ccs, ccp ; CHECK( flag ) ; fmt = format( fmt ) ; for ( d = f_begin, step = f_step ; d < f_end ; d += step, step += step ) { ccp = printf( fmt, d ) ; ccs = Sprint( 2, fmt, d ) ; FLUSH() ; COMPARE( ccp, ccs ) ; } } void char_test() { char *s = "foobar" ; int len = strlen( s ) ; int i ; char *fmt = "%c\n" ; int ccs, ccp ; CHECK( CHAR ) ; fmt = format( fmt ) ; for ( i = 0 ; i < len ; i++ ) { ccp = printf( fmt, s[ i ] ) ; ccs = Sprint( 2, fmt, s[ i ] ) ; FLU$&ÓÑ~ TIN-1_22.BCKü![SRC.TIN-1_22.SIO.SUITE]PRINT.C;1ÐSH() ; COMPARE( ccp, ccs ) ; } } void string_test() { static char *list[] = { "foobar", "hello", "world", "this is a very long string, a really long string, really, true, honest", "i am getting tired of this", "SO THIS IS THE END", 0 } ; char *fmt = "%s\n" ; char **p ; int ccp, ccs ; CHECK( STRING ) ; fmt = format( fmt ) ; for ( p = &list[ 0 ] ; *p ; p++ ) { ccp = printf( fmt, *p ) ; ccs = Sprint( 2, fmt, *p ) ; FLUSH() ; COMPARE( ccp, ccs ) ; } } void pointer_test() { struct foo { char bar1 ; short bar2 ; int bar3 ; long bar4 ; char *bar5 ; } foo, *end = &foo, *p ; char *fmt = "%p\n" ; int ccp, ccs ; CHECK( POINTER ) ; fmt = format( fmt ) ; end += 10 ; for ( p = &foo ; p < end ; p++ ) { ccp = printf( fmt, p ) ; ccs = Sprint( 2, fmt, p ) ; FLUSH() ; } } /* * bound_test is only available on SunOS 4.x */ #if defined( sun ) void bound_test() { char *fmt ; double bound_values[ 10 ] ; static char *bound_names[] = { "min_subnormal", "max_subnormal", "min_normal", "max_normal", "infinity", "quiet_nan", "signaling_nan" } ; int n_values ; int i ; int ccp, ccs ; bound_values[ 0 ] = min_subnormal() ; bound_values[ 1 ] = max_subnormal() ; bound_values[ 2 ] = min_normal() ; bound_values[ 3 ] = max_normal() ; bound_values[ 4 ] = infinity() ; bound_values[ 5 ] = quiet_nan( 7L ) ; bound_values[ 6 ] = signaling_nan( 7L ) ; n_values = 7 ; CHECK( BOUND ) ; for ( i = 0 ; i < n_values ; i++ ) { double d = bound_values[ i ] ; char *name = bound_names[ i ] ; fmt = format( "%f (%s)\n" ) ; ccp = printf( fmt, d, name ) ; ccs = Sprint( 2, fmt, d, name ) ; FLUSH() ; COMPARE( ccp, ccs ) ; fmt = format( "%e (%s)\n" ) ; ccp = printf( fmt, d, name ) ; ccs = Sprint( 2, fmt, d, name ) ; FLUSH() ; COMPARE( ccp, ccs ) ; fmt = format( "%g (%s)\n" ) ; ccp = printf( fmt, d, name ) ; ccs = Sprint( 2, fmt, d, name ) ; FLUSH() ; COMPARE( ccp, ccs ) ; } fmt = format( "%d (MININT)\n" ) ; ccp = printf( fmt, -MAXINT-1 ) ; ccs = Sprint( 2, fmt, -MAXINT-1 ) ; COMPARE( ccp, ccs ) ; } #else void bound_test() { } #endif int get_options( argc, argv ) int argc ; char *argv[] ; { int arg_index = 1 ; char *p ; double atof() ; for ( arg_index = 1 ; arg_index < argc && argv[ arg_index ][ 0 ] == '-' ; arg_index++ ) { switch ( argv[ arg_index ][ 1 ] ) { case 'd': flags[ DECIMAL ] = YES ; break ; case 'x': flags[ HEX ] = YES ; break ; case 'X': flags[ CAP_HEX ] = YES ; break ; case 'o': flags[ OCTAL ] = YES ; break ; case 'u': flags[ UNSIGNED ] = YES ; break ; case 'f': flags[ F_FLOAT ] = YES ; break ; case 'g': flags[ G_FLOAT ] = YES ; break ; case 'e': flags[ E_FLOAT ] = YES ; break ; case 'E': flags[ CAP_E_FLOAT ] = YES ; break ; case 'G': flags[ CAP_G_FLOAT ] = YES ; break ; case 'c': flags[ CHAR ] = YES ; break ; case 's': flags[ STRING ] = YES ; break ; case 'p': flags[ POINTER ] = YES ; break ; case 'b': /* this is for checking bounds in fp formats */ flags[ BOUND ] = YES ; break ; case 'P': /* precision, must be followed by a number, e.g. -P10 */ precision = &argv[ arg_index ][ 2 ] ; break ; case 'W': /* width, must be followed by a number, e.g. -w10 */ width = &argv[ arg_index ][ 2 ] ; break ; case 'F': /* flags, whatever is after the F */ print_flags = &argv[ arg_index ][ 2 ] ; break ; /* * Options recognized in this case: -Vf, -Vi * Usage: -V[if] start end step */ case 'V': /* * Check if we have enough extra arguments */ if ( argc - ( arg_index + 1 ) < 3 ) { fprintf( stderr, "Insufficient # of args after V option\n" ) ; exit( 1 ) ; } switch ( argv[ arg_index ][ 2 ] ) { case 'f': f_begin = atof( argv[ arg_index+1 ] ) ; f_end = atof( argv[ arg_index+2 ] ) ; f_step = atof( argv[ arg_index+3 ] ) ; break ; case 'i': i_begin = atoi( argv[ arg_index+1 ] ) ; i_end = atoi( argv[ arg_index+2 ] ) ; i_step = atoi( argv[ arg_index+3 ] ) ; break ; } arg_index += 3 ; break ; case 'S': f_step = atof( &argv[ arg_index ][ 2 ] ) ; break ; } } return( arg_index ) ; } #define EQ( s1, s2 ) ( strcmp( s1, s2 ) == 0 ) int main( argc, argv ) int argc ; char *argv[] ; { if ( Sbuftype( 2, SIO_LINEBUF ) == SIO_ERR ) { char *msg = "Sbuftype failed\n" ; write( 2, msg, strlen( msg ) ) ; exit( 1 ) ; } if ( argc == 1 || argc == 2 && EQ( argv[ 1 ], "ALL" ) ) { /* perform all tests */ int i ; for ( i = 0 ; i < N_FLAGS ; i++ ) flags[ i ] = YES ; } else (void) get_options( argc, argv ) ; decimal_test() ; hex_test() ; cap_hex_test() ; octal_test() ; unsigned_test() ; f_float_test() ; g_float_test() ; e_float_test() ; cap_g_float_test() ; cap_e_float_test() ; string_test() ; char_test() ; pointer_test() ; bound_test() ; exit( 0 ) ; } &*[SRC.TIN-1_22.SIO.SUITE]SPRINT_TEST.;1+,.//€ 4z-ü0@î123KÿPWO56w‰Ã†—7ÁUÁ†—89€]V‚—G/€HªJÿ#!/bin/sh # (c) Copyright 1992, 1993 by Panagiotis Tsirigotis # All rights reserved. The file named COPYRIGHT specifies the terms # and conditions for redistribution. # # $Id: sprint_test,v 8.1 1993/03/13 01:21:48 panos Exp $ # compare() { cmp -s PRINTF.DATA SPRINT.DATA if [ $? -ne 0 ] then echo TEST $1 FAILED echo Check files PRINTF.DATA and SPRINT.DATA for differences exit 1 else echo TEST $1 PASSED rm -f PRINTF.DATA SPRINT.DATA fi } format_test() { Sprint $@ 1>PRINTF.DATA 2>SPRINT.DATA compare "$*" } format_test ALL format_test -W10 -F0 -c format_test -W10 -F- -c echo echo PRECISION TEST i=13 while test $i -ne 0 do format_test -P$i -F# -X i=`expr $i - 1` done echo END OF PRECISION TEST echo format_test -Vi -4 4 1 -o "-F#" format_test -Vf -1.0 1.0 0.3 -W30 -P13 -F+ -f format_test -Vf -1.0 1.0 0.3 -W30 -P13 -F+ -e format_test -Vf -1.0 2.0 0.3 -W30 -P13 -F+ -g format_test -Vf -1.0 1.0 0.3 -W30 -P13 -F+- -f format_test -Vf -1.0 1.0 0.3 -W30 -P13 -F+- -e format_test -Vf -1.0 2.0 0.3 -W30 -P13 -F+- -g format_test -W10 "-F " -x format_test -W40 -u -Vi 8 100 3 -F0 format_test -b format_test -b -P10 ð!*[SRC.TIN-1_22.SIO.SUITE]TESTER.;1+,. //€ 4 ƒ-ü0@î123KÿPWO 56@Æ—7ÁUÁ†—89€]V‚—G/€HªJÿ#!/bin/sh # (c) Copyright 1992, 1993 by Panagiotis Tsirigotis # All rights reserved. The file named COPYRIGHT specifies the terms # and conditions for redistribution. # # $Id: tester,v 8.2 1993/03/17 18:53:40 panos Exp $ # # # Usage: # tester [all] [function-name function-name ...] # # function-name is the name of a sio function (or macro) # # If "all" is used, functions after it will *not* be tested. # script_name=`basename $0` copy_file=/usr/dict/words temp_file=/tmp/w make_log=MAKE.LOG if test ! -f $copy_file ; then echo "The file '$copy_file' is not available." echo "Please edit the '$script_name' script and change set the" echo "variable 'copy_file' to the name of a publicly readable file" echo "with at least a few tens of thousands of lines." exit 1 fi trap_function() { rm -f $temp_file $make_log echo exit 1 } make_program() { target=$1 cflags="$2" if test -f $1 -a ! -x $1 ; then rm -f $1 ; fi if test "$cflags" then make -s "$cflags" $target >$make_log 2>&1 else make -s $target >$make_log 2>&1 fi exit_code=$? if test $exit_code -eq 0 -a -x $1 then rm -f $make_log else echo "FAILED" echo " The make failed. Check the make log file << $make_log >>" exit fi } # # test_function expects a single argument, the name of the function # it will test. # It creates a program that has the name of the function by invoking # make with the symbol -DTEST_ # test_function() { expression="echo $"$1 var=`eval $expression` if test "$var" = "no" -o "$var" = "" -a "$all" = "no" ; then return ; fi echo -n "TESTING $1 " make_program $1 "CFLAGS=-g -DTEST_$1" ./$1 < $copy_file >$temp_file exit_code=$? if test $exit_code -ne 0 then echo "FAILED" echo " Test program exited with exit code $exit_code" echo " Temporary file << $temp_file >> not deleted" exit fi cmp -s $copy_file $temp_file if test $? -ne 0 then echo "FAILED" echo " The files << $copy_file >> and << $temp_file >> are not the same" exit else echo PASSED fi rm -f $temp_file } test_sprint() { var=$Sprint program=Sprint if test "$var" = "no" -o "$var" = "" -a "$all" = "no" ; then return ; fi echo TESTING Sprint make_program $program "" $TESTSHELL sprint_test } test_smorefds() { var=$Smorefds program=fdtest if test "$var" = "no" -o "$var" = "" -a "$all" = "no" ; then return ; fi echo -n "TESTING Smorefds " make_program $program "CFLAGS=-g" v=`fdtest 2>&1` if test $? -eq 0 ; then echo PASSED else echo "FAILED: $v" fi } trap trap_function 1 2 3 15 # # There is a variable for every function to be tested. That variable # can have the values "yes", "no" or "". # When a function is specified, it takes the value of $run. Initially $run # is "yes", so a specified function has its variable set to "yes". # If "all" is specified, $run becomes "no", so subsequently specified # functions, have their variables set to "no". # # We test a function iff: # its variable is "yes" OR its variable is "" and $all is "yes" # We don't test a function iff: # its variable is "no" OR its variable is "" and $all is "no" # # Therefore, all functions specified after "all" will NOT be tested. # run=yes all=no while test $# -gt 0 do case $1 in Sputchar) Sputchar=$run ;; Sgetchar) Sgetchar=$run ;; Srdline) Srdline=$run ;; Sfetch) Sfetch=$run ;; Sread) Sread=$run ;; Swrite) Swrite=$run ;; Sgetc) Sgetc=$run ;; Sputc) Sputc=$run ;; Sflush) Sflush=$run ;; Sundo) Sundo=$run ;; Sprint) Sprint=$run ;; switch) switch=$run ;; switch2) switch2=$run ;; Smorefds) Smorefds=$run ;; all) all=yes ; run="no" ;; *) echo Bad argument: $1 esac shift done test_function Sgetchar test_function Sputchar test_function Sread test_function Swrite test_function Srdline test_function Sfetch test_function Sgetc test_function Sputc test_function Sflush test_function Sundo test_function switch test_function switch2 test_smorefds test_sprint "*[SRC.TIN-1_22.SIO.SUITE]TESTLIB.;1+,.//€ 4m-ü0@î123KÿPWO56@ЉÆ—7€WîÁ†—89€]V‚—G/€HªJÿ#!/bin/sh # (c) Copyright 1992, 1993 by Panagiotis Tsirigotis # All rights reserved. The file named COPYRIGHT specifies the terms # and conditions for redistribution. # # $Id: testlib,v 8.1 1993/03/13 01:23:48 panos Exp $ # # # Purpose: # Invoke the tester script. This is necessary because the tester # script requires functions and /bin/sh does not support functions # on all OS's. This script decides what shell to use to execute # tester. On Suns, it uses /bin/sh. On DECstations, it uses # /usr/bin/ksh # The decision is made by checking $ARCH # case "$ARCH" in "") echo "ARCH not defined. Please define it." exit 1 ;; sun4|sun3) TESTSHELL=/bin/sh LDFLAGS="-Bstatic -lm" ;; dec-mips) TESTSHELL=/usr/bin/ksh LDFLAGS= ;; *) echo "Unknown architecture: $ARCH" exit 2 ;; esac export LDFLAGS export TESTSHELL $TESTSHELL tester $* #*[SRC.TIN-1_22.SIO.SUITE]TIETEST.C;1+,.//€ 4-ü0@î123KÿPWO56€nŠÃ†—7€WîÁ†—89€]V‚—G/€HªJÿ/* * (c) Copyright 1992, 1993 by Panagiotis Tsirigotis * All rights reserved. The file named COPYRIGHT specifies the terms * and conditions for redistribution. */ static char RCSid[] = "$Id: tietest.c,v 8.1 1993/03/13 01:24:07 panos Exp $" ; #include "sio.h" #include main() { char *s ; Stie( 0, 1 ) ; Sprint( 1, "Enter 1st command --> " ) ; s = Srdline( 0 ) ; Sprint( 1, "Received command: %s\n", s ) ; Sprint( 1, "Enter 2nd command --> " ) ; s = Srdline( 0 ) ; Sprint( 1, "Received command: %s\n", s ) ; Suntie( 0 ) ; Sprint( 1, "Enter 3rd command --> " ) ; s = Srdline( 0 ) ; Sprint( 1, "Received command: %s\n", s ) ; exit( 0 ) ; } ð*[SRC.TIN-1_22.SIO]TAGS.;2+,Œ.//€ 4o-t0ð123KÿPWO56 —‚C;Œ—7@nøD;Œ—89€]V‚—G/€HªJÿ local:[src.sio]sio.c,322 int Sbuftype(635,14342 int Sclose(499,11351 char *Sfetch(350,7935 int Sflush(450,9973 int Sgetc(325,7419 int Sputc(107,2259 char *Srdline(216,4735 int Sread(155,3374 int Stie(535,12386 int Sundo(391,8646 int Suntie(607,13844 int Swrite(27,519 void __sio_memcopy(680,15100 PRIVATE char *sio_memscan(661,14775 local:[src.sio]siosup.c,916 #define FATAL_ERROR(94,2349 #define FIRST_TIME(93,2300 #define MDP(63,1337 SIO_DEFINE_FIN(40,878 int Sdone(864,19111 int Smorefds(972,21232 void __sio_disable_events(1048,23048 int __sio_enable_events(1032,22776 int __sio_extend_buffer(791,17671 int __sio_get_events(1062,23261 int __sio_init(532,11905 int __sio_more(826,18513 int __sio_readf(675,15042 status_e __sio_switch(214,5420 int __sio_writef(604,13492 PRIVATE void buffer_setup(182,4536 PRIVATE char *expand(925,20315 PRIVATE int get_fd_limit(949,20774 PRIVATE status_e init_input_stream(401,9430 PRIVATE status_e init_output_stream(439,10250 PRIVATE int initial_map(282,6844 PRIVATE int isatty(488,11092 PRIVATE int isatty(504,11318 PRIVATE status_e map_unit(341,8146 PRIVATE status_e setup_read_buffer(379,8990 PRIVATE void terminate(1125,24422 PRIVATE status_e try_memory_mapping(119,2946 #define try_memory_mapping(374,8916 local:[src.sio]sprint.c,322 #define FIX_PRECISION(95,2736 #define INS_CHAR(50,1340 #define NUM(79,2305 #define PAD(107,3048 #define PREFIX(119,3377 #define STR_TO_DEC(81,2337 int Sprint(129,3637 int Sprintv(151,4043 int __sio_converter(371,9056 PRIVATE char *conv_10(313,7860 PRIVATE char *conv_fp(170,4543 PRIVATE char *conv_p2(275,6818 Vð*[SRC.TIN-1_22]SPOOLDIR.C;1+,­.//€ 4…-d0@î123KÿPWO56À§”!t…—7'üt1—89€]V‚—G/€HªJÿ:/* * Project : tin - a Usenet reader * Module : spooldir.c * Author : I.Lea & Tom Theel * Created : 08-05-92 * Updated : 11-07-93 * Notes : Changes spooldir to read news from (ie. news, nntp, cdrom) * Copyright : (c) Copyright 1991-93 by Iain Lea & Tom Theel * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" int cur_spoolnum = 0; int first_spooldir_on_screen; int last_spooldir_on_screen; int spool_top = 0; /* * Change spooldir via menu of available choices */ int spooldir_index () { #ifndef INDEX_DAEMON int ch; int n; int scroll_lines; spool_top = num_spooldir; if (! xspooldir_supported) { info_message (txt_spooldirs_not_supported); return FALSE; } if (! spool_top) { info_message (txt_no_spooldirs); return FALSE; } mail_setup (); /* record mailbox size for "you have mail" */ #ifndef USE_CLEARSCREEN ClearScreen(); #endif show_spooldir_page (); /* display spooldir selection page */ while (TRUE) { set_xclick_on (); ch = ReadCh (); if (ch > '0' && ch <= '9') { prompt_spooldir_num (ch); continue; } switch (ch) { case ESC: /* (ESC) common arrow keys */ #ifdef HAVE_KEY_PREFIX case KEY_PREFIX: #endif switch (get_arrow_key ()) { case KEYMAP_UP: goto spooldir_up; case KEYMAP_DOWN: goto spooldir_down; case KEYMAP_PAGE_UP: goto spooldir_page_up; case KEYMAP_PAGE_DOWN: goto spooldir_page_down; case KEYMAP_HOME: if (cur_spoolnum != 0) { if (0 < first_spooldir_on_screen) { #ifndef USE_CLEARSCREEN erase_spooldir_arrow (); #endif cur_spoolnum = 0; show_spooldir_page (); } else { erase_spooldir_arrow (); cur_spoolnum = 0; draw_spooldir_arrow (); } } break; case KEYMAP_END: goto end_of_list; case KEYMAP_MOUSE: if (xrow < INDEX_TOP) { goto spooldir_page_up; } if (xrow >= INDEX_TOP+last_spooldir_on_screen-first_spooldir_on_screen) { goto spooldir_page_down; } erase_spooldir_arrow (); cur_spoolnum = xrow-INDEX_TOP+first_spooldir_on_screen; draw_spooldir_arrow (); if (xmouse > 0) { goto select_spooldir; } break; } break; case '$': /* show last page of spooldirs */ end_of_list: if (cur_spoolnum != spool_top - 1) { if (spool_top - 1 > last_spooldir_on_screen) { #ifndef USE_CLEARSCREEN erase_spooldir_arrow (); #endif cur_spoolnum = spool_top - 1; show_spooldir_page (); } else { erase_spooldir_arrow (); cur_spoolnum = spool_top - 1; draw_spooldir_arrow (); } } break; case '\r': /* select spooldir */ case '\n': select_spooldir: if (set_spooldir (spooldirs[cur_spoolnum].name)) { wait_message (txt_reading_news_active_file); free_active_arrays (); max_active = DEFAULT_ACTIVE_NUM; expand_active (); read_mail_active_file (); read_news_active_file (); read_attributes_file (); read_newsgroups_file (); if (! read_cmd_line_groups ()) { read_newsrc (TRUE); toggle_my_groups (show_only_unread_groups, ""); } set_groupname_len (FALSE); set_xclick_off (); return TRUE; } break; case ' ': /* page down */ case ctrl('D'): case ctrl('F'): /* vi style */ spooldir_page_down: if (cur_spoolnum == spool_top - 1) { if (0 < first_spooldir_on_screen) { # ifndef USE_CLEARSCREEN erase_spooldir_arrow (); # endif cur_spoolnum = 0; show_spooldir_page (); } else { erase_spooldir_arrow (); cur_spoolnum = 0; draw_spooldir_arrow (); } break; } erase_spooldir_arrow (); scroll_lines = (full_page_scroll ? NOTESLINES : NOTESLINES / 2); cur_spoolnum = ((cur_spoolnum + scroll_lines) / scroll_lines) * scroll_lines; if (cur_spoolnum >= spool_top) { cur_spoolnum = (spool_top / scroll_lines) * scroll_lines; if (cur_spoolnum < spool_top - 1) { cur_spoolnum = spool_top - 1; } } if (cur_spoolnum <= first_spooldir_on_screen || cur_spoolnum >= last_spooldir_on_screen) show_spooldir_page (); else draw_spooldir_arrow (); break; case ctrl('L'): /* redraw */ #ifndef USE_CLEARSCREEN ClearScreen (); #endif set_xclick_off (); show_spooldir_page (); break; case ctrl('N'): /* line down */ case 'j': spooldir_down: if (cur_spoolnum + 1 >= spool_top) { if (0 < first_spooldir_on_screen) { # ifndef USE_CLEARSCREEN erase_spooldir_arrow (); # endif cur_spoolnum = 0; show_spooldir_page (); } else { erase_spooldir_arrow (); cur_spoolnum = 0; draw_spooldir_arrow (); } break; } if (cur_spoolnum + 1 >= last_spooldir_on_screen) { #ifndef USE_CLEARSCREEN erase_spooldir_arrow (); #endif cur_spoolnum++; show_spooldir_page (); } else { erase_spooldir_arrow (); cur_spoolnum++; draw_spooldir_arrow (); } break; case ctrl('P'): /* line up */ case 'k': spooldir_up: if (cur_spoolnum == 0) { if (_hp_glitch) { erase_spooldir_arrow (); } if (spool_top > last_spooldir_on_screen) { cur_spoolnum = spool_top - 1; show_spooldir_page (); } else { erase_spooldir_arrow (); cur_spoolnum = spool_top - 1; draw_spooldir_arrow (); } break; } if (_hp_glitch) { erase_spooldir_arrow (); } if (cur_spoolnum <= first_spooldir_on_screen) { cur_spoolnum--; show_spooldir_page (); } else { erase_spooldir_arrow (); cur_spoolnum--; draw_spooldir_arrow (); } break; case 'b': /* page up */ case ctrl('U'): case ctrl('B'): /* vi style */ spooldir_page_up: if (cur_spoolnum == 0) { if (_hp_glitch) { erase_spooldir_arrow (); } if (spool_top > last_spooldir_on_screen) { cur_spoolnum = spool_top - 1; show_spooldir_page (); } else { erase_spooldir_arrow (); cur_spoolnum = spool_top - 1; draw_spooldir_arrow (); } break; } erase_spooldir_arrow (); scroll_lines = (full_page_scroll ? NOTESLINES : NOTESLINES / 2); if ((n = cur_spoolnum % scroll_lines) > 0) { cur_spoolnum = cur_spoolnum - n; } else { cur_spoolnum = ((cur_spoolnum - scroll_lines) / scroll_lines) * scroll_lines; } if (cur_spoolnum < 0) { cur_spoolnum = 0; } if (cur_spoolnum < first_spooldir_on_screen || cur_spoolnum >= last_spooldir_on_screen) show_spooldir_page (); else draw_spooldir_arrow (); break; case 'h': /* help */ show_info_page (HELP_INFO, help_spooldir, txt_spooldir_com); show_spooldir_page (); break; case 'H': /* toggle mini help menu */ toggle_mini_help (SPOOLDIR_LEVEL); show_spooldir_page(); break; case 'I': /* toggle inverse video */ erase_spooldir_arrow (); toggle_inverse_video (); show_spooldir_page (); break; case 'q': /* quit */ set_xclick_off (); return TRUE; case 'Q': /* quit */ write_rcfile (); tin_done (0); break; case 'R': /* bug/gripe/comment mailed to author */ mail_bug_report (); #ifndef USE_CLEARSCREEN ClearScreen (); #endif show_spooldir_page (); break; case 'v': /* show tin version */ info_message (cvers); break; default: info_message(txt_bad_command); } } #endif /* INDEX_DAEMON */ } void show_spooldir_page () { #ifndef INDEX_DAEMON char buf[PATH_LEN]; int i, j; int spoolname_len; set_signals_spooldir (); #ifdef USE_CLEARSCREEN ClearScreen (); #else MoveCursor (0, 0); /* top left corner */ CleartoEOLN (); #endif sprintf (buf, txt_spooldir_selection, num_spooldir); show_title (buf); #ifndef USE_CLEARSCREEN MoveCursor (1, 0); CleartoEOLN (); #endif MoveCursor (INDEX_TOP, 0); if (cur_spoolnum >= spool_top) { cur_spoolnum = spool_top - 1; } if (cur_spoolnum < 0) { cur_spoolnum = 0; } if (NOTESLINES <= 0) { first_spooldir_on_screen = 0; } else { first_spooldir_on_screen = (cur_spoolnum / NOTESLINES) * NOTESLINES; if (first_spooldir_on_screen < 0) { first_spooldir_on_screen = 0; } } last_spooldir_on_screen = first_spooldir_on_screen + NOTESLINES; if (last_spooldir_on_screen >= spool_top) { last_spooldir_on_screen = spool_top; first_spooldir_on_screen = (cur_spoolnum / NOTESLINES) * NOTESLINES; if (first_spooldir_on_screen == last_spooldir_on_screen || first_spooldir_on_screen < 0) { if (first_spooldir_on_screen < 0) { first_spooldir_on_screen = 0; } else { first_spooldir_on_screen = last_spooldir_on_screen - NOTESLINES; } } } if (spool_top == 0) { first_spooldir_on_screen = 0; last_spooldir_on_screen = 0; } spoolname_len = cCOLS - 11; for (j=0, i = first_spooldir_on_screen; i < last_spooldir_on_screen; i++,j++) { sprintf (buf, "%-16.16s %s", spooldirs[i].name, spooldirs[i].comment); sprintf (screen[j].col, " %4.d %-*.*s\r\n", i+1, spoolname_len, spoolname_len, buf); if (slow_speed_terminal) { strip_line (screen[j].col, strlen (screen[j].col)); strcat (screen[j].col, "\r\n"); } fputs (screen[j].col, stdout); } #ifndef USE_CLEARSCREEN CleartoEOS (); #endif show_mini_help (SPOOLDIR_LEVEL); draw_spooldir_arrow (); #endif /* INDEX_DAEMON */ } int prompt_spooldir_num (ch) int ch; { int num; clear_message (); if ((num = prompt_num (ch, txt_select_spooldir)) == -1) { clear_message (); return FALSE; } num--; /* index from 0 (internal) vs. 1 (user) */ if (num < 0) { num = 0; } if (num >= spool_top) { num = spool_top - 1; } if (num >= first_spooldir_on_screen && num < last_spooldir_on_screen) { erase_spooldir_arrow (); cur_spoolnum = num; draw_spooldir_arrow (); } else { #ifndef USE_CLEARSCREEN erase_spooldir_arrow (); #endif cur_spoolnum = num; show_spooldir_page (); } return TRUE; } void erase_spooldir_arrow () { erase_arrow (INDEX_TOP + (cur_spoolnum-first_spooldir_on_screen)); } void draw_spooldir_arrow () { draw_arrow (INDEX_TOP + (cur_spoolnum-first_spooldir_on_screen)); } /* * Load all spooldirs into spooldir[] array */ int load_spooldirs () { char comment[PATH_LEN]; char line[NNTP_STRLEN]; char name[PATH_LEN]; char *ptr; int i, state; for (i = 0 ; i < max_spooldir ; i++) { spooldirs[i].state = 0; spooldirs[i].name = (char *) 0; spooldirs[i].comment = (char *) 0; } num_spooldir = 0; xspooldir_supported = FALSE; if (! read_news_via_nntp) { return (xspooldir_supported); } put_server ("spooldir list"); (void) get_server (line, NNTP_STRLEN); if (*line != CHAR_OK) { xspooldir_supported = FALSE; if (atoi (line) != ERR_COMMAND) { fprintf (stderr, "%s", line); fprintf (stderr, txt_spooldir_server_error_1); fprintf (stderr, txt_spooldir_server_error_2); } return (xspooldir_supported); } if (debug == 1) { wait_message (line); } xspooldir_supported = TRUE; do { get_server (line, NNTP_STRLEN); if (line[0] != '.') { if (debug != 0) { printf ("%s\n", line); } state = atoi (line); if ((ptr = strchr (line, ' ')) != (char *) 0) { strncpy (name, ++ptr, sizeof (name)); ptr = strchr (name, ' '); *ptr = '\0'; } if ((ptr = strchr (line, '[')) != (char *) 0) { strncpy (comment, ++ptr, sizeof (comment)); ptr = strchr (comment, ']'); *ptr = '\0'; } if (num_spooldir >= max_spooldir - 1) { expand_spooldirs (); } spooldirs[num_spooldir].state = state; spooldirs[num_spooldir].name = str_dup (name); spooldirs[num_spooldir].comment = str_dup (comment); if (debug != 0) { printf ("NUM=[%d] MAX=[%d] STATE=[%d] ALIAS=[%s] COMMENT=[%s]\n", num_spooldir, max_spooldir, spooldirs[num_spooldir].state, spooldirs[num_spooldir].name, spooldirs[num_spooldir].comment); } num_spooldir++; } } while (!((line[0] == '.') && ((line[1] == '\0') || (line[1] == '\r')))); return (xspooldir_supported); } /* * Need to select a spooldir directory for reading news from and store all * spooldir's in an array for later use when changing spooldir's */ void get_spooldir () { #ifdef NNTP_ABLE char default_alias[32]; int i, set_alias = FALSE; default_alias[0] = '\0'; if (! load_spooldirs ()) { if (! xspooldir_supported) { strcpy (spooldir_alias, "news"); set_tindir (); } return; } /* * default to current spooldir from last session or 1st in spooldirs[] */ if (spooldir_alias[0]) { my_strncpy (default_alias, spooldir_alias, sizeof (default_alias)); } else { my_strncpy (default_alias, spooldirs[0].name, sizeof (default_alias)); } /* * Try to use default spooldir. If that fails go through spooldir list * looking for first available spooldir. */ if (! set_spooldir (spooldir_alias)) { for (i = 0 ; spooldirs[i].name != (char *) 0 ; i++) { if (set_spooldir (spooldirs[i].name)) { set_alias = TRUE; break; } } if (! set_alias) { error_message (txt_cannot_change_spooldir, ""); exit (1); } } /* * And now set tin to act as though it is reading via NNTP */ read_news_via_nntp = TRUE; #endif /* NNTP_ABLE */ } /* * Change to specified spooldir if everythings OK. */ int set_spooldir (name) char *name; { char line[NNTP_STRLEN]; int respcode; if (cmd_line) { sprintf (line, "%s %s...\n", txt_changing_spooldir_to, name); } else { sprintf (line, "%s %s...", txt_changing_spooldir_to, name); } wait_message (line); sprintf (line, "spooldir %s", name); debug_nntp ("set_spooldir", line); put_server (line); respcode = get_respcode (); switch (respcode) { case OK_SPSWITCH: /* Switching to a different spooldir */ my_strncpy (spooldir_alias, name, sizeof (spooldir_alias)); set_tindir (); return TRUE; case OK_SPNOCHANGE: /* Still using same spooldir */ clear_message (); break; default: error_message ("%s", nntp_respcode (respcode)); clear_message (); break; } return FALSE; } P%Ñ­o#~ TIN-1_22.BCK…d[SRC.TIN-1_22]STPWATCH.H;1¾Bð*[SRC.TIN-1_22]STPWATCH.H;1+,….//€ 4÷-d0@î123KÿPWO56 ¸§t…—7€¡Fg1—89€]V‚—G/€HªJÿ/* * Project : tin - a Usenet reader * Module : stpwatch.h * Author : I.Lea * Created : 03-08-93 * Updated : 03-08-93 * Notes : Simple stopwatch routines for timing code using timeb struct * Copyright : (c) Copyright 1991-93 by Iain Lea * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #ifdef PROFILE #include char msg_tb[1024]; char tmp_tb[1024]; struct timeb beg_tb; struct timeb end_tb; #define LSECS 700000000 #define BegStopWatch(msg) \ { \ strcpy (msg_tb, msg); \ ftime (&beg_tb); \ } #define EndStopWatch() \ { \ ftime (&end_tb); \ } #define PrintStopWatch() \ { \ sprintf (tmp_tb, "%s: Beg=[%ld.%d] End=[%ld.%d] Elapsed=[%d]", \ msg_tb, beg_tb.time, beg_tb.millitm, \ end_tb.time, end_tb.millitm, \ (((end_tb.time - LSECS) * 1000) + end_tb.millitm) - \ (((beg_tb.time - LSECS) * 1000) + beg_tb.millitm)); \ error_message (tmp_tb, ""); \ } #else #define BegStopWatch(msg) #define EndStopWatch() #define PrintStopWatch() #endif /* PROFILE */ ð*[SRC.TIN-1_22]STRFTIME.3;1+,r. //€ 4 p-d0@î123KÿPWO 56 e¾t…—7€“`1—89€]V‚—G/€HªJÿ.TH STRFTIME 3 .SH NAME strftime \- generate formatted time information .SH SYNOPSIS .ft B .nf #include #include .sp size_t strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr); .SH DESCRIPTION The following description is transcribed verbatim from the December 7, 1988 draft standard for ANSI C. This draft is essentially identical in technical content to the final version of the standard. .LP The .B strftime function places characters into the array pointed to by .B s as controlled by the string pointed to by .BR format . The format shall be a multibyte character sequence, beginning and ending in its initial shift state. The .B format string consists of zero or more conversion specifiers and ordinary multibyte characters. A conversion specifier consists of a .B % character followed by a character that determines the behavior of the conversion specifier. All ordinary multibyte characters (including the terminating null character) are copied unchanged into the array. If copying takes place between objects that overlap the behavior is undefined. No more than .B maxsize characters are placed into the array. Each conversion specifier is replaced by appropriate characters as described in the following list. The appropriate characters are determined by the .B LC_TIME category of the current locale and by the values contained in the structure pointed to by .BR timeptr . .TP .B %a is replaced by the locale's abbreviated weekday name. .TP .B %A is replaced by the locale's full weekday name. .TP .B %b is replaced by the locale's abbreviated month name. .TP .B %B is replaced by the locale's full month name. .TP .B %c is replaced by the locale's appropriate date and time representation. .TP .B %d is replaced by the day of the month as a decimal number .RB ( 01 - 31 ). .TP .B %H is replaced by the hour (24-hour clock) as a decimal number .RB ( 00 - 23 ). .TP .B %I is replaced by the hour (12-hour clock) as a decimal number .RB ( 01 - 12 ). .TP .B %j is replaced by the day of the year as a decimal number .RB ( 001 - 366 ). .TP .B %m is replaced by the month as a decimal number .RB ( 01 - 12 ). .TP .B %M is replaced by the minute as a decimal number .RB ( 00 - 59 ). .TP .B %p is replaced by the locale's equivalent of the AM/PM designations associated with a 12-hour clock. .TP .B %S is replaced by the second as a decimal number .RB ( 00 - 61 ). .TP .B %U is replaced by the week number of the year (the first Sunday as the first day of week 1) as a decimal number .RB ( 00 - 53 ). .TP .B %w is replaced by the weekday as a decimal number .RB [ "0 " (Sunday)- 6 ]. .TP .B %W is replaced by the week number of the year (the first Monday as the first day of week 1) as a decimal number .RB ( 00 - 53 ). .TP .B %x is replaced by the locale's appropriate date representation. .TP .B %X is replaced by the locale's appropriate time representation. .TP .B %y is replaced by the year without century as a decimal number .RB ( 00 - 99 ). .TP .B %Y is replaced by the year with century as a decimal number. .TP .B %z is replaced by the time zone name or abbreviation, or by no characters if no time zone is determinable. .TP .B %% is replaced by .BR % . .LP If a conversion specifier is not one of the above, the behavior is undefined. .SH RETURNS If the total number of resulting characters including the terminating null character is not more than .BR maxsize , the .B strftime function returns the number of characters placed into the array pointed to by .B s not including the terminating null character. Otherwise, zero is returned and the contents of the array are indeterminate. .SH NON-ANSI EXTENSIONS If .B SYSV_EXT is defined when the routine is compiled, then the following additional conversions will be available. These are borrowed from the System V .IR cftime (3) and .IR ascftime (3) routines. .TP .B %D is equivalent to specifying .BR %m/%d/%y . .TP .B %e is replaced by the day of the month, padded with a blank if it is only one digit. .TP .B %h is equivalent to .BR %b , above. .TP .B %n is replaced with a newline character (\s-1ASCII LF\s+1). .TP .B %r is equivalent to specifying .BR "%I:%M:%S %p" . .TP .B %R is equivalent to specifying .BR %H:%M: . .TP .B %T is equivalent to specifying .BR %H:%M:%S . .TP .B %t is replaced with a \s-1TAB\s+1 character. .SH SEE ALSO time(2), ctime(3), localtime(3) .SH BUGS This version does not handle multibyte characters or pay attention to the setting of the .B LC_TIME environment variable. .LP It is not clear what is ``appropriate'' for the C locale; the values returned are a best guess on the author's part. .SH AUTHOR .nf Arnold Robbins AudioFAX, Inc. Suite 200 2000 Powers Ferry Road Marietta, GA. 30067 U.S.A. INTERNET: arnold@audiofax.com UUCP: emory!audfax!arnold Phone: +1 404 933 7600 Fax-box: +1 404 618 4581 .fi .SH ACKNOWLEDGEMENTS Thanks to Geoff Clare for helping debug earlier versions of this routine. ð*[SRC.TIN-1_22]STRFTIME.C;1+,®. //€ 4 -d0@î123KÿPWO 56àðý!t…—7€½”u1—89€]V‚—G/€HªJÿ/* * Project : tin - a Usenet reader * Module : strftime.c * Author : A.Robbins & I.Lea * Created : 01-02-91 * Updated : 15-08-93 * Notes : Relatively quick-and-dirty implemenation of ANSI library * routine for System V Unix systems. * It's written in old-style C for maximal portability. * If target system already has strftime() call the #define * HAVE_STRFTIME can be set to use it. * Example : time (&secs); * tm = localtime (&secs); * num = strftime (buf, sizeof (buf), "%a %d-%m-%y %H:%M:%S", tm); * Copyright : (c) Copyright 1991-93 by Arnold Robbins & Iain Lea * You may freely copy or redistribute this software, * so long as there is no profit made from its use, sale * trade or reproduction. You may not change this copy- * right notice, and it must be included in any copy made */ #include "tin.h" #ifdef SYSV extern int daylight; #endif #define SYSV_EXT 1 /* stuff in System V ascftime routine */ /* * strftime --- produce formatted time */ #if __STDC__ size_t my_strftime (char *s, size_t maxsize, char *format, struct tm *timeptr) #else size_t my_strftime (s, maxsize, format, timeptr) char *s; size_t maxsize; char *format; struct tm *timeptr; #endif { #ifdef HAVE_STRFTIME return strftime (s, maxsize, format, timeptr); #else char *endp = s + maxsize; char *start = s; char tbuf[100]; int i; /* * various tables, useful in North America */ static char *days_a[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", }; static char *days_l[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", }; static char *months_a[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", }; static char *months_l[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", }; static char *ampm[] = { "AM", "PM", }; if (s == NULL || format == NULL || timeptr == NULL || maxsize == 0) return 0; if (strchr(format, '%') == NULL && strlen(format) + 1 >= maxsize) return 0; #ifndef DONT_HAVE_TZSET tzset (); #endif #ifdef HAVE_SETTZ settz (); #endif for (; *format && s < endp - 1; format++) { tbuf[0] = '\0'; if (*format != '%') { *s++ = *format; continue; } switch (*++format) { case '\0': *s++ = '%'; goto out; case '%': *s++ = '%'; continue; case 'a': /* abbreviated weekday name */ strcpy(tbuf, days_a[timeptr->tm_wday]); break; case 'A': /* full weekday name */ strcpy(tbuf, days_l[timeptr->tm_wday]); break; #ifdef SYSV_EXT case 'h': /* abbreviated month name */ #endif case 'b': /* abbreviated month name */ strcpy(tbuf, months_a[timeptr->tm_mon]); break; case 'B': /* full month name */ strcpy(tbuf, months_l[timeptr->tm_mon]); break; case 'c': /* appropriate date and time representation */ sprintf(tbuf, "%s %s %2d %02d:%02d:%02d %d", days_a[timeptr->tm_wday], months_a[timeptr->tm_mon], timeptr->tm_mday, timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec, timeptr->tm_year + 1900); break; case 'd': /* day of the month, 01 - 31 */ sprintf(tbuf, "%02d", timeptr->tm_mday); break; case 'H': /* hour, 24-hour clock, 00 - 23 */ sprintf(tbuf, "%02d", timeptr->tm_hour); break; case 'I': /* hour, 12-hour clock, 01 - 12 */ i = timeptr->tm_hour; if (i == 0) i = 12; else if (i > 12) i -= 12; sprintf(tbuf, "%02d", i); break; case 'j': /* day of the year, 001 - 366 */ sprintf(tbuf, "%03d", timeptr->tm_yday + 1); break; case 'm': /* month, 01 - 12 */ sprintf(tbuf, "%02d", timeptr->tm_mon + 1); break; case 'M': /* minute, 00 - 59 */ sprintf(tbuf, "%02d", timeptr->tm_min); break; case 'p': /* am or pm based on 12-hour clock */ if (timeptr->tm_hour < 12) strcpy(tbuf, ampm[0]); else strcpy(tbuf, ampm[1]); break; case 'S': /* second, 00 - 61 */ sprintf(tbuf, "%02d", timeptr->tm_sec); break; case 'w': /* weekday, Sunday == 0, 0 - 6 */ sprintf(tbuf, "%d", timeptr->tm_wday); break; case 'x': /* appropriate date representation */ sprintf(tbuf, "%s %s %2d %d", days_a[timeptr->tm_wday], months_a[timeptr->tm_mon], timeptr->tm_mday, timeptr->tm_year + 1900); break; case 'X': /* appropriate time representation */ sprintf(tbuf, "%02d:%02d:%02d", timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec); break; case 'y': /* year without a century, 00 - 99 */ i = timeptr->tm_year % 100; sprintf(tbuf, "%d", i); break; case 'Y': /* year with century */ sprintf(tbuf, "%d", 1900 + timeptr->tm_year); break; #ifdef SYSV_EXT case 'n': /* same as \n */ tbuf[0] = '\n'; tbuf[1] = '\0'; break; case 't': /* same as \t */ tbuf[0] = '\t'; tbuf[1] = '\0'; break; case 'D': /* date as %m/%d/%y */ my_strftime(tbuf, sizeof tbuf, "%m/%d/%y", timeptr); break; case 'e': /* day of month, blank padded */ sprintf(tbuf, "%2d", timeptr->tm_mday); break; case 'r': /* time as %I:%M:%S %p */ my_strftime(tbuf, sizeof tbuf, "%I:%M:%S %p", timeptr); break; case 'R': /* time as %H:%M */ my_strftime(tbuf, sizeof tbuf, "%H:%M", timeptr); break; case 'T': /* time as %H:%M:%S */ my_strftime(tbuf, sizeof tbuf, "%H:%M:%S", timeptr); break; #endif default: tbuf[0] = '%'; tbuf[1] = *format; tbuf[2] = '\0'; break; } i = strlen(tbuf); if (i) if (s + i < endp - 1) { strcpy(s, tbuf); s += i; } else return 0; } out: if (s < endp && *format == '\0') { *s = '\0'; return (size_t) (s - start); } else return 0; #endif /* HAVE_STRFTIME */ } ð*[SRC.TIN-1_22]TAGS.;1+,ï.!//€ 4! J-d0ú123KÿPWO"56 óPhj†—7 ",yj†—89€]V‚—G/€HªJÿ* $1$dua4:[local.src.tin-1_22]active.c,715 backup_active 395,7830 check_for_any_new_groups 428,8407 cmp_group_p 28,780 cmp_notify_p 40,982 find_active_size_index 1297,30039 find_group_index 109,2329 get_active_num 54,1236 if 967,21654 if 979,21995 if 989,22262 if 999,22539 if 1008,22797 if 1017,23045 load_active_size_info 1249,29010 match_group_list 821,17775 my_strpbrk 1403,32034 parse_active_line 137,2694 parse_newsrc_active_line 192,3529 prompt_subscribe_group 758,16546 read_active_times_file 1173,27768 read_attributes_file 935,20988 read_motd_file 1320,30488 read_news_active_file 263,4771 resync_active_file 75,1592 set_default_attributes 880,18958 write_active_times_file 1226,28653 write_attributes_file 1087,24543 $1$dua4:[local.src.tin-1_22]actived.c,13 main 23,849 $1$dua4:[local.src.tin-1_22]amiga.c,290 chmod 43,975 closedir 205,3063 getenv 314,4895 getopt 213,3131 getpid 55,1101 joinpath 105,1733 make_post_cmd 357,5615 opendir 169,2581 pclose 158,2497 popen 137,2162 readdir 190,2862 setenv 345,5429 sleep 126,2016 stat 282,4165 system 265,3820 tputs 66,1211 tzset 89,1436 $1$dua4:[local.src.tin-1_22]art.c,453 artnum_comp 1480,31371 date_comp 1545,32811 do_update 1386,29243 find_base 34,930 find_index_file 1324,28085 from_comp 1525,32281 index_group 127,2640 input_pending 1607,33868 make_threads 392,8016 num_of_arts 81,1747 parse_headers 483,10190 purge_needed 102,2076 read_group 244,4881 read_xindex_file 837,18442 read_xover_file 1134,24038 set_article 1586,33463 subj_comp 1505,31739 valid_artnum 1659,34664 write_xindex_file 638,13959 $1$dua4:[local.src.tin-1_22]curses.c,521 ClearScreen 470,9263 CleartoEOLN 529,10072 CleartoEOS 544,10265 EndInverse 585,10804 EndWin 422,8612 InitScreen 160,3576 InitScreen 256,5910 InitWin 406,8421 MoveCursor 489,9545 MoveCursor 507,9789 Raw 629,11312 RawState(619,11209 ReadCh 701,13099 ReadCh 762,14067 ScreenSize 390,8069 StartInverse 568,10586 ToggleInverse 602,11023 int 30,791 outchar 808,14802 set_keypad_off 453,9005 set_keypad_on 439,8804 set_xclick_off 852,15375 set_xclick_on 842,15281 setup_screen 141,3317 xclick 819,14924 $1$dua4:[local.src.tin-1_22]debug.c,247 debug_nntp 24,584 debug_nntp_respcode 47,887 debug_print_active 218,4045 debug_print_active_hash 266,5674 debug_print_arts 60,1062 debug_print_base 193,3702 debug_print_comment 170,3393 debug_print_header 76,1237 debug_save_comp 126,2458 $1$dua4:[local.src.tin-1_22]envarg.c,50 count_args 19,580 envargs 41,828 main 118,2331 $1$dua4:[local.src.tin-1_22]feed.c,105 does_article_exist 655,15980 feed_articles 35,1215 get_post_proc_type 611,15161 print_file 573,14293 $1$dua4:[local.src.tin-1_22]getline.c,324 getline 90,2469 getline 93,2533 gl_addchar 210,4694 gl_addchar 213,4732 gl_del 266,5792 gl_del 269,5828 gl_fixup 326,6967 gl_fixup 329,7020 gl_kill 289,6144 gl_newline 237,5153 gl_redraw 304,6354 gl_tab 428,9803 gl_tab 431,9862 hist_add 465,10311 hist_init 455,10210 hist_next 512,11149 hist_prev 487,10752 $1$dua4:[local.src.tin-1_22]group.c,546 #define ART_ADJUST(42,1092 #define INDEX2LNUM(49,1322 #define INDEX2SNUM(47,1242 #define SNUM2LNUM(48,1283 bld_sline 1453,32347 clear_note_area 1306,29570 decr_tagged 52,1378 draw_sline 1514,33789 draw_subject_arrow 1230,28463 erase_subject_arrow 1246,28711 find_new_pos 1322,29903 fix_new_highest 1107,26491 group_page 66,1575 mark_screen 1351,30326 prompt_subject_num 1263,28941 set_subj_from_size 1380,30826 show_group_page 1124,26691 show_group_title 1560,34586 toggle_subject_from 1415,31455 update_group_page 1211,28200 $1$dua4:[local.src.tin-1_22]hashstr.c,79 add_string 79,1659 hash_init 97,1987 hash_reclaim 108,2107 hash_str 37,982 $1$dua4:[local.src.tin-1_22]help.c,105 display_info_page 365,5862 show_info_page 216,3443 show_mini_help 400,6641 toggle_mini_help 442,7639 $1$dua4:[local.src.tin-1_22]inews.c,115 get_from_name 289,6300 get_host_name 129,2731 get_user_info 240,5273 submit_file 381,8520 submit_inews 27,666 $1$dua4:[local.src.tin-1_22]init.c,150 char *GetConfigValue 656,19885 char *GetFQDN 648,19814 int create_mail_save_dirs 615,19154 void init_selfinfo 168,7321 void set_tindir 557,17762 $1$dua4:[local.src.tin-1_22]kill.c,309 #define IS_KILLED(26,799 #define IS_READ(25,750 #define SET_HOT(24,712 #define SET_KILLED(23,641 auto_select_articles 618,13805 get_choice 185,4169 get_choice 195,4288 kill_any_articles 476,10433 kill_art_menu 242,5004 read_kill_file 43,1066 unkill_all_articles 454,10121 write_kill_file 138,2933 $1$dua4:[local.src.tin-1_22]lang.c,0 $1$dua4:[local.src.tin-1_22]mail.c,160 read_groups_descriptions 220,4994 read_mail_active_file 22,621 read_mailgroups_file 150,3599 read_newsgroups_file 180,4169 write_mail_active_file 117,2859 $1$dua4:[local.src.tin-1_22]main.c,253 int check_for_any_new_news 395,9294 void main 26,656 int read_cmd_line_groups 546,13628 void read_cmd_line_options 181,3671 void save_or_mail_new_news 422,9816 void show_intro_page 507,11933 void update_index_files 444,10200 void usage 338,6833 $1$dua4:[local.src.tin-1_22]memory.c,465 expand_active 110,2958 expand_active_size 156,4021 expand_art 100,2710 expand_kill 126,3445 expand_save 136,3627 expand_spooldirs 146,3807 free_active_arrays 319,7732 free_active_size_array 437,10089 free_all_arrays 195,4806 free_art_array 250,5840 free_attributes_array 280,6430 free_kill_array 357,8561 free_save_array 377,8898 free_spooldirs_array 416,9710 init_alloc 54,1638 init_screen_array 166,4256 my_malloc 457,10475 my_realloc 471,10663 $1$dua4:[local.src.tin-1_22]misc.c,1124 #define FOLD_TO_UPPER(822,15670 void asfail 21,604 void base_name 581,11196 void cleanup_tmp_files 1637,30831 void copy_fp 54,1150 void create_index_lock_file 1143,21358 void draw_percent_mark 465,8719 char *eat_re 844,16079 int get_arrow_key 1031,19315 void get_author 973,18288 void get_cwd 1604,30480 char *get_val 80,1620 unsigned long hash_groupname 316,5997 long hash_s 871,16560 int invoke_cmd 425,8218 int invoke_editor 92,1853 int invoke_ispell 132,2664 int mail_check 622,11831 void mail_setup 605,11594 void make_group_path 1615,30593 void make_post_process_cmd 1649,31026 long my_atol 797,15404 int my_chdir 296,5753 int my_mkdir 274,5443 int my_stricmp 824,15746 void my_strncpy 887,16755 void parse_from 642,12161 void rename_file 353,6685 void rename_file 396,7757 void set_real_uid_gid 489,9179 void set_tin_uid_gid 535,10199 void shell_escape 160,3155 char *str_dup 412,8069 char *str_str 922,17181 int strfeditor 1305,24648 int strfpath 1410,26599 int strfquote 1183,22287 void tin_done 226,4295 void toggle_inverse_video 1016,19060 int untag_all_articles 901,16896 $1$dua4:[local.src.tin-1_22]newsrc.c,469 auto_subscribe_groups 24,724 backup_newsrc 57,1337 checknewsrc 252,5552 delete_group 571,12079 get_line_unread 1014,21246 mark_group_read 757,15422 parse_seq 818,16521 parse_unread 854,17220 pos_group_in_newsrc 1170,24676 print_newsrc_seq 1044,21743 print_seq 1090,22769 read_newsrc 84,1998 read_newsrc_line 292,6597 reset_newsrc 521,11080 rewrite_newsrc 195,4235 subscribe 449,9814 undel_group 629,12992 update_newsrc 353,7767 write_newsrc 172,3906 $1$dua4:[local.src.tin-1_22]nntplib.c,269 void close_server 718,17117 int get_dnet_socket 485,11888 int get_server 663,15969 int get_tcp_socket 238,5554 char *getserverbyfile 102,2578 int handle_server_response 562,13596 char *nntp_respcode 738,17442 void put_server 612,14797 int server_init 162,3774 $1$dua4:[local.src.tin-1_22]open.c,571 authorization 954,18582 base_comp 665,13293 get_respcode 798,15874 log_user 897,17450 nntp_close 149,3193 nntp_open 36,907 nntp_to_fp 869,17016 open_art_fp 581,11786 open_art_header 476,9638 open_mail_active_fp 164,3374 open_mailgroups_fp 323,6462 open_motd_fp 273,5494 open_newgroups_fp 238,4805 open_news_active_fp 175,3545 open_newsgroups_fp 336,6774 open_overview_fmt_fp 203,4101 open_subscription_fp 299,6023 open_xhdr_fp 630,12728 open_xindex_fp 365,7371 open_xover_fp 405,8164 setup_base 686,13604 stat_article 443,9006 stuff_nntp 818,16149 $1$dua4:[local.src.tin-1_22]os_2.c,409 backslash 69,1101 closedir 141,1874 endpwent 344,4486 fakepwent 250,3138 fgetpwent 355,4586 gethostname 221,2835 getlogin 444,6017 getopt 150,1942 getpwent 279,3749 getpwnam 316,4223 getpwuid 298,4032 getuid 457,6132 joinpath 86,1344 make_post_cmd 204,2629 opendir 125,1764 pclose 118,1715 popen 109,1645 putpwent 435,5941 readdir 133,1829 setpwent 335,4424 sleep 239,3040 tputs 46,840 $1$dua4:[local.src.tin-1_22]page.c,301 art_close 1087,24693 art_open 998,22461 match_header 1233,27199 prompt_response 1097,24812 redraw_page 620,15191 show_cont_header 958,21818 show_first_header 846,19636 show_last_page 1156,25758 show_mime_article 811,18976 show_note_page 637,15514 show_page 49,1671 yank_to_addr 1115,25053 $1$dua4:[local.src.tin-1_22]parsdate_tab.c,727 #define CTYPE(51,1671 Convert(1345,37109 DSTcorrect(1407,38686 #define ENDOF(49,1625 GetTimeInfo(1596,43115 #define HOUR(68,2076 #define IS7BIT(72,2143 LookupWord(1441,39435 RelativeMonth(1421,39000 #define SIZEOF(48,1563 ToSeconds(1322,36645 #define YYBACKUP(342,11466 #define YYRECOVERING(341,11426 #define YYTRANSLATE(159,3604 #define __yy_bcopy(409,12974 __yy_bcopy 416,13224 __yy_bcopy 434,13576 date_error(1314,36577 date_lex(1533,41675 if 968,24956 if 982,25209 if 1005,25827 if 1063,27103 if 1092,27914 if 1097,28031 if 1105,28150 if 1118,28397 if 1122,28461 if 1126,28566 else if 1133,28673 if 1136,28714 if 1140,28768 parsedate(1657,44686 yyparse(449,13785 $1$dua4:[local.src.tin-1_22]post.c,508 #define PRINT_LF(17,564 check_article_to_be_posted 157,4260 crosspost_article 1569,35812 delete_article 1420,32445 find_mail_header 1354,31164 find_reply_to_addr 1702,38849 insert_x_headers 1668,38044 mail_bug_report 1093,25337 mail_to_author 1244,28745 mail_to_someone 958,22301 post_article 591,13775 post_response 755,17474 quick_post_article 366,8838 reread_active_after_posting 1749,39925 setup_check_article_screen 349,8591 update_art_posted_file 106,2930 user_posted_messages 35,1280 $1$dua4:[local.src.tin-1_22]prompt.c,140 continue_prompt 185,3018 prompt_menu_string 89,1539 prompt_num 24,615 prompt_on_off 151,2445 prompt_string 58,1069 prompt_yn 113,1838 $1$dua4:[local.src.tin-1_22]rcfile.c,295 change_rcfile 415,17357 expand_rel_abs_pathname 942,31852 match_boolean 978,32361 match_number 994,32607 match_string 1010,32818 quote_dash_to_space 1035,33200 quote_space_to_dash 1052,33387 read_rcfile 28,651 show_menu_help 968,32206 show_rcfile_menu 825,28484 write_rcfile 251,7605 $1$dua4:[local.src.tin-1_22]save.c,549 add_to_save_list 628,13903 append_to_existing_file 471,10945 check_start_save_any_news 75,1838 create_path 505,11457 create_sub_dir 589,13331 delete_processed_files 1292,28649 get_archive_file 1250,27945 get_first_savefile 832,18457 get_last_savefile 874,19503 post_process_files 916,20550 post_process_sh 1160,26010 post_process_uud 952,21190 print_art_seperator_line 1319,29084 save_art_to_file 285,7120 save_comp 741,16425 save_filename 789,17305 save_regex_arts 422,10043 save_thread_to_file 363,8771 sort_save_list 729,16213 $1$dua4:[local.src.tin-1_22]screen.c,219 center_line 118,2046 clear_message 108,1951 draw_arrow 145,2373 erase_arrow 164,2644 error_message 48,1006 info_message 26,624 perror_message 70,1322 ring_bell 199,3182 show_title 180,2852 wait_message 38,858 $1$dua4:[local.src.tin-1_22]search.c,181 lcase 547,9592 make_lower 416,7567 search_art_body 509,9032 search_article 303,5502 search_author 43,1014 search_body 434,7716 search_group 130,2613 search_subject 218,4111 $1$dua4:[local.src.tin-1_22]select.c,494 int add_group 986,23282 void catchup_group 1071,24823 int choose_new_group 939,22449 void draw_group_arrow(926,22272 void erase_group_arrow 920,22175 void goto_next_group_on_screen 1268,29039 void group_selection_page 730,18019 void next_unread_group 1092,25354 int prompt_group_num 883,21601 int reposition_group 1022,23941 void selection_index 30,767 void set_groupname_len 1147,26516 void strip_line 1288,29327 void toggle_my_groups 1188,27338 void yank_active_file 932,22366 $1$dua4:[local.src.tin-1_22]sigfile.c,164 # define S_ISDIR(17,606 add_signature 32,800 if 193,4123 open_random_sig 102,2358 if ((dirp = opendir 183,3931 pick = rand 187,4004 thrashdir 133,2875 $1$dua4:[local.src.tin-1_22]signal.c,994 void art_resize 606,9529 void art_suspend 426,7160 void group_resize 677,10572 void group_suspend 506,8211 void help_resize 698,10871 void help_suspend 526,8474 void main_resize 623,9792 void main_suspend 446,7417 void page_resize 714,11104 void page_suspend 546,8734 void rcfile_suspend 586,9261 void select_resize 635,9959 void select_suspend 466,7677 void set_alarm_clock_off 155,3049 void set_alarm_clock_on 147,2952 void set_alarm_signal 129,2620 void set_signal_handlers 69,1383 void set_signals_art 325,5935 void set_signals_group 339,6099 void set_signals_help 353,6269 void set_signals_page 367,6436 void set_signals_select 381,6603 void set_signals_spooldir