home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.uv.es
/
2014.11.ftp.uv.es.tar
/
ftp.uv.es
/
pub
/
mvs
/
ggmvs.distrib.cntl
< prev
next >
Wrap
Text File
|
1993-01-26
|
819KB
|
10,114 lines
//JOBNAME JOB ACCOUNT,'NAME'
//*------------------------------------------------------------------*/
//* */
//* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
//* */
//* This software is provided on an "AS IS" basis. All warranties, */
//* including the implied warranties of merchantability and fitness, */
//* are expressly denied. */
//* */
//* Provided this copyright notice is included, this software may */
//* be freely distributed and not offered for sale. */
//* */
//* Changes or modifications may be made and used only by the maker */
//* of same, and not further distributed. Such modifications should */
//* be mailed to the author for consideration for addition to the */
//* software and incorporation in subsequent releases. */
//* */
//*------------------------------------------------------------------*/
//*
//* MVS GOPHER client
//*
//* Author: Steve Bacher <seb1525@mvs.draper.com>
//*
//* Date: July, 1992
//*
//*--------------------------------------------------------------------
//*
//* This job creates the GOPHER distribution libraries (PDS's).
//*
//* Run this JCL to create the PDS's, after customizing to suit.
//* (Obviously, put in a good JOB statement first.)
//* To customize the JCL, change the defaults on the //GGLOAD PROC
//* statement to your liking, particularly the PREFIX default.
//* You might also want to change the final qualifiers of the PDS's
//* created - to do this, find the // EXEC GGLOAD statements and
//* change the value of the TO parameter.
//*
//* See the $$README file (of the CNTL PDS, first in this stream)
//* for the rest of the installation instructions.
//*
//GGLOAD PROC CLS='*',BS='6160',U='3380',V='',
// TRK1='30',TRK2='10',DIR='35',RLSE='RLSE',
// PREFIX='GOPHER.INSTALL.'
//*
//IEBUPDTE EXEC PGM=IEBUPDTE,PARM=NEW
//SYSPRINT DD SYSOUT=&CLS
//SYSUT2 DD DISP=(NEW,CATLG,DELETE),DSN=&PREFIX.&TO,
// DCB=(RECFM=FB,LRECL=80,BLKSIZE=&BS),
// SPACE=(TRK,(&TRK1,&TRK2,&DIR),&RLSE),UNIT=&U,VOL=SER=&V
//*
// PEND
//CNTL EXEC GGLOAD,TRK1='4',TO='CNTL'
//SYSIN DD DATA,DLM='?!'
./ ADD NAME=$$README,SSI=010B0044
------------------------------------------------------------------------
Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992
MVS Gopher Server originally by Shawn Hart (Univ. of Delaware).
This software is provided on an "AS IS" basis. All warranties,
including the implied warranties of merchantability and fitness,
are expressly denied.
Provided this copyright notice is included, this software may
be freely distributed and not offered for sale.
Changes or modifications may be made and used only by the maker
of same, and not further distributed. Such modifications should
be mailed to the author for consideration for addition to the
software and incorporation in subsequent releases.
------------------------------------------------------------------------
MVS Gopher Client
Author: Steve Bacher <seb1525@mvs.draper.com>
MVS Gopher Server
Author: Shawn Hart <shawn.hart@mvs.udel.edu>
Enhancements: Steve Bacher <seb1525@mvs.draper.com>
------------------------------------------------------------------------
Contents of PDS's belonging to Gopher distribution:
Member PDS Type Description
$$README CNTL This file
ACCESS CNTL Sample server access file
ALLOAD CNTL JCL to allocate GOPHER load library
COMPILEC CNTL JCL to compile and link C source for client
COMPILES CNTL JCL to compile and link C source for server
GOPHERD CNTL JCL to run the GOPHER server in batch (No TSO)
GOPHERT CNTL JCL to run the GOPHER server in batch (w. TSO)
HELP CNTL TSO Help for Gopher client (with XPROC support)
HELQ CNTL TSO Help for Gopher client (without XPROC)
INSTALLC CNTL How to install the GOPHER MVS client
INSTALLS CNTL How to install the GOPHER MVS server
MENU CNTL Initial Gopher server menu
GOPHER CLIST Exec by which users invoke the Gopher client
NNMFIUCV CLIST Exec to check for multiple socket applications
GGM... PANEL ISPF regular panels
GG... H C headers for compilation
GG... C C source for compilation
ABOUT... ABOUT "About This Gopher" text
--------------------------------------------------------------------
Where to Go from Here:
To install the GOPHER MVS client, read member INSTALLC.
To install the GOPHER MVS server, read member INSTALLS.
Note:
You may install only the client, only the server, or both the
client and the server. It is purely up to what your needs are.
--------------------------------------------------------------------
Changes:
10/19/92 - Improvements in initial startup and GOPHERRC customization
--------------------------------------------------------------------
Questions? Comments? Suggestions? Gripes? Please email to...
Steve Bacher <seb@draper.com> or <seb1525@mvs.draper.com>
./ ADD NAME=ACCESS,SSI=01010008
!
! Format of entries:
!
! filename (fully qualified, all uppercase, no quotes)
! can be "DD:DDNAME" or "EXEC:EXECNAME"
!
! followed by names of hosts which are authorized to access the data.
! If no host name list is present, all hosts are authorized
!
! You may specify the same file name more than once, if you need
! more lines to put host names on.
!
! Individual PDS members must be specified separately. A PDS without
! a member name establishes access only to the PDS directory.
!
! Note that the default directory MUST be in this table.
!
! Also note that in the case of EXECs, the EXEC must live in the
! library allocated to GGEXEC in the Gopher server JCL.
!
! *** ANY DATA SET REFERENCED BY ANY EXEC IN THAT LIBRARY IS FULLY
! *** ACCESSIBLE TO GOPHER REGARDLESS OF THIS TABLE! USE THIS TABLE
! *** TO GOVERN CONTROL TO THE EXEC ITSELF!!!
!
! below is default directory spec, which MUST be in this table
!
DD:GGGOPHER
EXEC:CHECKLST support1 support2 mvs
EXEC:WAISDIR
EXEC:WAISLIST
EXEC:WAISSRCH
ANY.PUBLIC.SEQ.DS
ANY.SEMI.PUBLIC.SEQ.DS goodclient1 goodclient2
ANY.SEMI.PUBLIC.SEQ.DS goodclient3 goodclient4
! PDS without member name provides access to directory only
! All member names must be explicitly listed to be accessible.
ANY.PUBLIC.PDS
ANY.PUBLIC.PDS(MEMBER1)
ANY.PUBLIC.PDS(MEMBER2)
ANY.PUBLIC.PDS(MEMBER3)
ANY.PUBLIC.PDS(MEMBER4)
ANY.SEMI.PUBLIC.PDS goodclient1 goodclient2
ANY.SEMI.PUBLIC.PDS goodclient3 goodclient4
ANY.SEMI.PUBLIC.PDS(MEMBER1) goodclient1
ANY.SEMI.PUBLIC.PDS(MEMBER2) goodclient2
ANY.SEMI.PUBLIC.PDS(MEMBER3) goodclient3
ANY.SEMI.PUBLIC.PDS(MEMBER4) goodclient4
./ ADD NAME=ALLOAD,SSI=01010051
//JOBNAME JOB ACCOUNT,'NAME'
//* */
//* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
//* */
//* This software is provided on an "AS IS" basis. All warranties, */
//* including the implied warranties of merchantability and fitness, */
//* are expressly denied. */
//* */
//* Provided this copyright notice is included, this software may */
//* be freely distributed and not offered for sale. */
//* */
//* Changes or modifications may be made and used only by the maker */
//* of same, and not further distributed. Such modifications should */
//* be mailed to the author for consideration for addition to the */
//* software and incorporation in subsequent releases. */
//* */
//*
//* Allocate GOPHER load library before install
//*
//GGALLOC PROC BS='6233',U='3380',V='',
// PRI='100',SEC='100',DIR='35'
//*
//IEFBR14 EXEC PGM=IEFBR14
//ALLOCDD DD DISP=(NEW,CATLG,DELETE),DSN=&LIB,
// DCB=(RECFM=U,BLKSIZE=&BS),
// SPACE=(&BS,(&PRI,&SEC,&DIR)),UNIT=&U,VOL=SER=&V
//*
// PEND
//*
//* The following step allocates the load library from which the
//* executable program will be run. If you intend to place the
//* executable into an existing library, you can skip this step.
//* Otherwise, the name must match the name used on the LOADLIB
//* parameter of the GGLINK procedure in the COMPILE JCL.
//*
//* If you want separate libraries for the client and the server,
//* just dup this step and give 'em different lib names.
//*
//ALLOC1 EXEC GGALLOC,PRI=50,SEC=50,DIR=35,
// LIB='GOPHER.LOAD'
//*
./ ADD NAME=COMPILEC
//JOBNAME JOB ACCOUNT,'NAME'
//* */
//* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
//* */
//* This software is provided on an "AS IS" basis. All warranties, */
//* including the implied warranties of merchantability and fitness, */
//* are expressly denied. */
//* */
//* Provided this copyright notice is included, this software may */
//* be freely distributed and not offered for sale. */
//* */
//* Changes or modifications may be made and used only by the maker */
//* of same, and not further distributed. Such modifications should */
//* be mailed to the author for consideration for addition to the */
//* software and incorporation in subsequent releases. */
//* */
//*********************************************************************
//*
//* Compile some or all GOPHER C/370 sources to make the SYSLIN input
//* to the linkedit of the executable Gopher load module(s).
//*
//GGCC PROC MEMBER=,
// SRCLIB='GOPHER.C', GOPHER C source PDS
// HDRLIB='GOPHER.H', GOPHER C headers PDS
// COMMHDR='TCPIP.COMMMAC', C/370 TCP/IP headers
// C370HDR='SYS1.EDCHDRS', C/370 standard headers
// SYSMSGS='SYS1.EDCMSGS', C/370 messages file
// SYSMSGM='EDCMSGE', C/370 message member
// VIOUNIT=VIO, Temporary disk unit
// OUTCLAS='*', SYSOUT class
// CPARMS='SOURCE EXPMAC NOAGGR NOXREF', Compile parameters
// TEST=TEST TEST or NOTEST
//*
//CCOMP EXEC PGM=EDCCOMP,PARM='MARGINS(1,72) &TEST &CPARMS'
//SYSMSGS DD DISP=SHR,DSN=&SYSMSGS(&SYSMSGM)
//SYSIN DD DISP=SHR,DSN=&SRCLIB(&MEMBER)
//SYSLIB DD DISP=SHR,DSN=&COMMHDR
// DD DISP=SHR,DSN=&C370HDR
//USERLIB DD DISP=SHR,DSN=&HDRLIB
//SYSLIN DD DSN=&&LOADSET,UNIT=&VIOUNIT,DISP=(MOD,PASS),
// SPACE=(32000,(30,30)),DCB=(RECFM=FB,LRECL=80,BLKSIZE=3200)
//SYSPRINT DD SYSOUT=&OUTCLAS
//SYSCPRT DD SYSOUT=&OUTCLAS
//SYSUT1 DD DSN=&&SYSUT1,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
// SPACE=(32000,(30,30)),DCB=(RECFM=FB,LRECL=80,BLKSIZE=3200)
//SYSUT4 DD DSN=&&SYSUT4,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
// SPACE=(32000,(30,30)),DCB=(RECFM=FB,LRECL=80,BLKSIZE=3200)
//SYSUT6 DD DSN=&&SYSUT6,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
// SPACE=(32000,(30,30)),DCB=(RECFM=FB,LRECL=3200,BLKSIZE=12800)
//SYSUT7 DD DSN=&&SYSUT7,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
// SPACE=(32000,(30,30)),DCB=(RECFM=FB,LRECL=3200,BLKSIZE=12800)
//SYSUT8 DD DSN=&&SYSUT8,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
// SPACE=(32000,(30,30)),DCB=(RECFM=FB,LRECL=3200,BLKSIZE=12800)
//SYSUT9 DD DSN=&&SYSUT9,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
// SPACE=(32000,(30,30)),DCB=(RECFM=VB,LRECL=137,BLKSIZE=882)
//SYSUT10 DD SYSOUT=&OUTCLAS
//*
// PEND
//*
//*********************************************************************
//*
//* Linkedit an executable Gopher load module.
//*
//* Note: If C/370 V1R2 or higher, and you have therefore accepted
//* the "#define FETCH" in the GG header, you may delete
//* the line that includes the ISPLINK library.
//*
//* Note: If TCP/IP V2 or higher, remove the PASCAL link libraries
//* from the JCL and the AMPZMVSB card from the control deck.
//*
//GGLINK PROC LOADLIB='GOPHER.LOAD', Executable load library
// PLIBASE='SYS1.PLIBASE', PL/1 link library
// EDCBASE='SYS1.SEDCBASE', C/370 link library
// IBMBASE='SYS1.SIBMBASE', PL/1+C common library
// COMMTXT='TCPIP.COMMTXT', TCP/IP link library
// PASRUN3='SYS1.PAS.SAMPRUN3', PASCAL link library
// PASRUN1='SYS1.PAS.SAMPRUN1', PASCAL link library
// PASMSG1='SYS1.PAS.SAMPMSG1', PASCAL link library
// ISPLINK='ISP.V3R2M0.ISPLLIB', ISPLINK link library
// VIOUNIT=VIO, Temporary disk unit
// OUTCLAS='*', SYSOUT class
// LPARMS='LIST,LET,MAP', Linkedit parameters
// TEST=TEST TEST or NOTEST
//*
//LKED EXEC PGM=IEWL,PARM='AMODE(31),&TEST,&LPARMS'
//SYSPRINT DD SYSOUT=&OUTCLAS
//SYSLIB DD DISP=SHR,DSN=&PLIBASE
// DD DISP=SHR,DSN=&EDCBASE
// DD DISP=SHR,DSN=&IBMBASE
// DD DISP=SHR,DSN=&COMMTXT
// DD DISP=SHR,DSN=&PASRUN3 if TCP/IP V1 only
// DD DISP=SHR,DSN=&PASRUN1 if TCP/IP V1 only
// DD DISP=SHR,DSN=&PASMSG1 if TCP/IP V1 only
// DD DISP=SHR,DSN=&ISPLINK if C/370 V1R1 with #undef FETCH
//SYSLMOD DD DISP=SHR,DSN=&LOADLIB
//SYSUT1 DD DSN=&&SYSUT1,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
// SPACE=(32000,(30,30))
//*
// PEND
//*
//GGCLIENT EXEC GGCC,MEMBER=GGCLIENT
//GGMALLOC EXEC GGCC,MEMBER=GGMALLOC
//GGMBRIFC EXEC GGCC,MEMBER=GGMBRIFC
//GGMBRIFR EXEC GGCC,MEMBER=GGMBRIFR
//GGMCLRTX EXEC GGCC,MEMBER=GGMCLRTX
//GGMCONN EXEC GGCC,MEMBER=GGMCONN
//GGMDFAIL EXEC GGCC,MEMBER=GGMDFAIL
//GGMDIR EXEC GGCC,MEMBER=GGMDIR
//GGMDISC EXEC GGCC,MEMBER=GGMDISC
//GGMDISPL EXEC GGCC,MEMBER=GGMDISPL
//GGMDUMP EXEC GGCC,MEMBER=GGMDUMP
//GGMESRVR EXEC GGCC,MEMBER=GGMESRVR
//GGMFREEM EXEC GGCC,MEMBER=GGMFREEM
//GGMGETDS EXEC GGCC,MEMBER=GGMGETDS
//GGMGETM EXEC GGCC,MEMBER=GGMGETM
//GGMGOFOR EXEC GGCC,MEMBER=GGMGOFOR
//GGMGSRVL EXEC GGCC,MEMBER=GGMGSRVL
//GGMIERR EXEC GGCC,MEMBER=GGMIERR
//GGMIGET EXEC GGCC,MEMBER=GGMIGET
//GGMISPF EXEC GGCC,MEMBER=GGMISPF
//GGMIVGET EXEC GGCC,MEMBER=GGMIVGET
//GGMIVPUT EXEC GGCC,MEMBER=GGMIVPUT
//GGMMTFER EXEC GGCC,MEMBER=GGMMTFER
//GGMOUTS EXEC GGCC,MEMBER=GGMOUTS
//GGMOUTTX EXEC GGCC,MEMBER=GGMOUTTX
//GGMPMSG EXEC GGCC,MEMBER=GGMPMSG
//GGMPROC EXEC GGCC,MEMBER=GGMPROC
//GGMPTX EXEC GGCC,MEMBER=GGMPTX
//GGMSOCKT EXEC GGCC,MEMBER=GGMSOCKT
//GGMSOPT EXEC GGCC,MEMBER=GGMSOPT
//GGMSSRVR EXEC GGCC,MEMBER=GGMSSRVR
//GGMTNET EXEC GGCC,MEMBER=GGMTNET
//GGMTSO EXEC GGCC,MEMBER=GGMTSO
//GGMTYPE EXEC GGCC,MEMBER=GGMTYPE
//GGMUNALC EXEC GGCC,MEMBER=GGMUNALC
//GGMVTX EXEC GGCC,MEMBER=GGMVTX
//GGMWAIS EXEC GGCC,MEMBER=GGMWAIS
//GGMWHOIS EXEC GGCC,MEMBER=GGMWHOIS
//GGMXTX EXEC GGCC,MEMBER=GGMXTX
//*
//* Link GOPHER load module. Like SMP/E, expect return code 8 when
//* doing this from scratch. Additional one-or-two-module links
//* will just replace the corresponding parts of the load module.
//*
//GGLINK EXEC GGLINK
//LKED.SYSLIN DD DISP=(OLD,DELETE),DSN=&&LOADSET
// DD *
INCLUDE SYSLMOD(GGCLIENT) if included first time, RC = 8
INCLUDE SYSLIB(AMPZMVSB) include if TCP/IP V1 only
ENTRY CEESTART
NAME GGCLIENT(R)
/*
./ ADD NAME=COMPILES,SSI=01030011
//JOBNAME JOB ACCOUNT,'NAME'
//* */
//* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
//* */
//* This software is provided on an "AS IS" basis. All warranties, */
//* including the implied warranties of merchantability and fitness, */
//* are expressly denied. */
//* */
//* Provided this copyright notice is included, this software may */
//* be freely distributed and not offered for sale. */
//* */
//* Changes or modifications may be made and used only by the maker */
//* of same, and not further distributed. Such modifications should */
//* be mailed to the author for consideration for addition to the */
//* software and incorporation in subsequent releases. */
//* */
//*********************************************************************
//*
//* Compile some or all GOPHER C/370 sources to make the SYSLIN input
//* to the linkedit of the executable Gopher load module.
//*
//GGCC PROC MEMBER=,
// SRCLIB='GOPHER.C', GOPHER C source PDS
// HDRLIB='GOPHER.H', GOPHER C headers PDS
// COMMHDR='TCPIP.COMMMAC', C/370 TCP/IP headers
// C370HDR='SYS1.EDCHDRS', C/370 standard headers
// SYSMSGS='SYS1.EDCMSGS', C/370 messages file
// SYSMSGM='EDCMSGE', C/370 message member
// VIOUNIT=VIO, Temporary disk unit
// OUTCLAS='*', SYSOUT class
// CPARMS='SOURCE EXPMAC NOAGGR NOXREF', Compile parameters
// TEST=TEST TEST or NOTEST
//*
//CCOMP EXEC PGM=EDCCOMP,PARM='MARGINS(1,72) &TEST &CPARMS'
//SYSMSGS DD DISP=SHR,DSN=&SYSMSGS(&SYSMSGM)
//SYSIN DD DISP=SHR,DSN=&SRCLIB(&MEMBER)
//SYSLIB DD DISP=SHR,DSN=&COMMHDR
// DD DISP=SHR,DSN=&C370HDR
//USERLIB DD DISP=SHR,DSN=&HDRLIB
//SYSLIN DD DSN=&&LOADSET,UNIT=&VIOUNIT,DISP=(MOD,PASS),
// SPACE=(32000,(30,30)),DCB=(RECFM=FB,LRECL=80,BLKSIZE=3200)
//SYSPRINT DD SYSOUT=&OUTCLAS
//SYSCPRT DD SYSOUT=&OUTCLAS
//SYSUT1 DD DSN=&&SYSUT1,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
// SPACE=(32000,(30,30)),DCB=(RECFM=FB,LRECL=80,BLKSIZE=3200)
//SYSUT4 DD DSN=&&SYSUT4,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
// SPACE=(32000,(30,30)),DCB=(RECFM=FB,LRECL=80,BLKSIZE=3200)
//SYSUT6 DD DSN=&&SYSUT6,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
// SPACE=(32000,(30,30)),DCB=(RECFM=FB,LRECL=3200,BLKSIZE=12800)
//SYSUT7 DD DSN=&&SYSUT7,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
// SPACE=(32000,(30,30)),DCB=(RECFM=FB,LRECL=3200,BLKSIZE=12800)
//SYSUT8 DD DSN=&&SYSUT8,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
// SPACE=(32000,(30,30)),DCB=(RECFM=FB,LRECL=3200,BLKSIZE=12800)
//SYSUT9 DD DSN=&&SYSUT9,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
// SPACE=(32000,(30,30)),DCB=(RECFM=VB,LRECL=137,BLKSIZE=882)
//SYSUT10 DD SYSOUT=&OUTCLAS
//*
// PEND
//*
//*********************************************************************
//*
//* Linkedit the executable Gopher load modules.
//*
//* Note: If TCP/IP V2 or higher, remove the PASCAL link libraries
//* from the JCL and the AMPZMVSB card from the control deck.
//*
//GGLINK PROC LOADLIB='GOPHER.LOAD', Executable load library
// PLIBASE='SYS1.PLIBASE', PL/1 link library
// EDCBASE='SYS1.SEDCBASE', C/370 link library
// IBMBASE='SYS1.SIBMBASE', PL/1+C common library
// COMMTXT='TCPIP.COMMTXT', TCP/IP link library
// PASRUN3='SYS1.PAS.SAMPRUN3', PASCAL link library
// PASRUN1='SYS1.PAS.SAMPRUN1', PASCAL link library
// PASMSG1='SYS1.PAS.SAMPMSG1', PASCAL link library
// VIOUNIT=VIO, Temporary disk unit
// OUTCLAS='*', SYSOUT class
// LPARMS='LIST,LET,MAP', Linkedit parameters
// TEST=TEST TEST or NOTEST
//*
//LKED EXEC PGM=IEWL,PARM='AMODE(31),&TEST,&LPARMS'
//SYSPRINT DD SYSOUT=&OUTCLAS
//SYSLIB DD DISP=SHR,DSN=&PLIBASE
// DD DISP=SHR,DSN=&EDCBASE
// DD DISP=SHR,DSN=&IBMBASE
// DD DISP=SHR,DSN=&COMMTXT
// DD DISP=SHR,DSN=&PASRUN3 if TCP/IP V1 only
// DD DISP=SHR,DSN=&PASRUN1 if TCP/IP V1 only
// DD DISP=SHR,DSN=&PASMSG1 if TCP/IP V1 only
//SYSLMOD DD DISP=SHR,DSN=&LOADLIB
//SYSUT1 DD DSN=&&SYSUT1,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
// SPACE=(32000,(30,30))
//*
// PEND
//*
//GGMALLOC EXEC GGCC,MEMBER=GGMALLOC
//GGMDFAIL EXEC GGCC,MEMBER=GGMDFAIL
//GGMUNALC EXEC GGCC,MEMBER=GGMUNALC
//GGMOUTS EXEC GGCC,MEMBER=GGMOUTS
//GGMPROC EXEC GGCC,MEMBER=GGMPROC
//GGSTASK EXEC GGCC,MEMBER=GGSTASK
//*
//* Link GOPHER subtask module. Like SMP/E, expect return code 8
//* doing this from scratch. Additional one-or-two-module links
//* will just replace the corresponding parts of the load module.
//*
//GGLINKT EXEC GGLINK
//LKED.SYSLIN DD DISP=(OLD,DELETE),DSN=&&LOADSET
// DD *
INCLUDE SYSLMOD(GGSTASK) if included first time, RC = 8
INCLUDE SYSLIB(AMPZMVSB) include if TCP/IP V1 only
INCLUDE SYSLIB(IUCVFORC)
INCLUDE SYSLIB(EDCMTFS)
ENTRY CEESTART
NAME GGSTASK(R)
/*
//GGMMTFER EXEC GGCC,MEMBER=GGMMTFER
//GGSERVER EXEC GGCC,MEMBER=GGSERVER
//*
//* Link GOPHER server module. Like SMP/E, expect return code 8
//* doing this from scratch. Additional one-or-two-module links
//* will just replace the corresponding parts of the load module.
//*
//GGLINKS EXEC GGLINK
//LKED.SYSLIN DD DISP=(OLD,DELETE),DSN=&&LOADSET
// DD *
INCLUDE SYSLMOD(GGSERVER) if included first time, RC = 8
INCLUDE SYSLIB(AMPZMVSB) include if TCP/IP V1 only
ENTRY CEESTART
NAME GGSERVER(R)
/*
./ ADD NAME=GOPHERD,SSI=01040016
//GOPHERD PROC MODULE=GGSERVER, 00010000
// STEPLIB='GOPHER.LOAD', 00020000
// EXECLIB='GOPHER.EXEC', 00030000
// ACCESS='GOPHER.ACCESS', 00040000
// ABOUT='GOPHER.ABOUT', 00050000
// MENU='GOPHER.MENU' 00050000
//* 00060000
//********************************************************************* 00070000
//* * 00080000
//* GOPHER daemon, by Shawn Hart (U.Del.) and Steve Bacher (D.Lab.) * 00090000
//* * 00100000
//* Straight batch (no TSO access) * 00100000
//* * 00100000
//********************************************************************* 00110000
//* 00120000
//GOPHERD EXEC PGM=&MODULE 00150001
//STEPLIB DD DISP=SHR,DSN=&STEPLIB 00170000
//GGEXEC DD DISP=SHR,DSN=&EXECLIB 00181002
//SYSTSPRT DD UNIT=SYSVIO,SPACE=(TRK,(100,100)),RECFM=VBA,LRECL=255 00190000
//SYSERR DD SYSOUT=* 00200000
//SYSPRINT DD SYSOUT=* 00210000
//SYSTSIN DD DUMMY 00210000
//SYSIN DD DUMMY 00210000
//GGABOUT DD DISP=SHR,DSN=&ABOUT 00230000
//GGACCESS DD DISP=SHR,DSN=&ACCESS 00240000
//GGGOPHER DD DISP=SHR,DSN=&MENU 00250000
./ ADD NAME=GOPHERT,SSI=01020039
//GOPHERD PROC MODULE=GGSERVER, 00010000
// STEPLIB='GOPHER.LOAD', 00020000
// EXECLIB='GOPHER.EXEC', 00030000
// ACCESS='GOPHER.ACCESS', 00040000
// ABOUT='GOPHER.ABOUT', 00050000
// MENU='GOPHER.MENU' 00050000
//* 00060000
//********************************************************************* 00070000
//* * 00080000
//* GOPHER daemon, by Shawn Hart (U.Del.) and Steve Bacher (D.Lab.) * 00090000
//* * 00100000
//********************************************************************* 00110000
//* 00120000
//GOPHERD EXEC PGM=IKJEFT01,DYNAMNBR=128,REGION=8M, 00150001
// PARM='&MODULE' 00160000
//STEPLIB DD DISP=SHR,DSN=&STEPLIB 00170000
//GGEXEC DD DISP=SHR,DSN=&EXECLIB 00181002
//SYSTSPRT DD UNIT=SYSVIO,SPACE=(TRK,(100,100)),RECFM=VBA,LRECL=255 00190000
//SYSERR DD SYSOUT=* 00200000
//SYSPRINT DD SYSOUT=* 00210000
//SYSTSIN DD DUMMY 00220000
//SYSIN DD DUMMY 00230000
//GGABOUT DD DISP=SHR,DSN=&ABOUT 00230000
//GGACCESS DD DISP=SHR,DSN=&ACCESS 00240000
//GGGOPHER DD DISP=SHR,DSN=&MENU 00250000
./ ADD NAME=HELP,SSI=01000051
)F Function -
GOPHER is a distributed document delivery service, or, more generally,
a networked information retrieval service. It allows you to access
numerous types of data on various hosts in a transparent fashion.
GOPHER presents you with a hierarchical display of information sources
which are accessed via a client/server communications link.
There are GOPHER clients for all common hardware platforms. The MVS
version runs as an ISPF dialog application.
When you use the GOPHER client, information about your use of GOPHER
is stored in a data set called GOPHERRC. If you don't have one,
GOPHER will create it for you.
For more information on customizing your GOPHER environment, get
into Gopher and select "About This GOPHER".
)I GOPHLOC - local GOPHER help goes in member GOPHLOC
)X Syntax -
%GOPHER
LOCAL
SERVER(hostname)
PATH(pathname)
PORT(portnumber)
DESCRIPTION(text)
FORCE
DEBUG
TEST
Required: none
)O Operands -
))LOCAL
Specify LOCAL if you want to enter GOPHER in "serverless"
mode - i.e. start up with your private GOPHER menu.
Specifying LOCAL accomplishes two things:
(1) It sets the server to "-", meaning local access.
Therefore, you must also provide a path, either
via the PATH operand or via a "localmenu:" spec
in your GOPHERRC file.
(2) It allows you to use GOPHER even if there are
other TCP/IP socket applications active elsewhere
in your TSO session. However, it will not allow
you to connect to any GOPHER servers, even if you
have a local menu item that points to one.
For information on how to set up GOPHER menus, get into
GOPHER and select "About This Gopher".
))SERVER(hostname)
The host name (or IP address) of a Gopher server.
If this is not given, GOPHER looks in your GOPHERRC
to find what server to connect to. If it can't find
an appropriate specification, you will have to enter
a server name on the startup panel.
A server name of a single minus sign (-) is a special
case, signifying local (serverless) access to your
own private GOPHER data. In this case, you must tell
GOPHER where your menu is, either via the PATH operand
or in the GOPHERRC file.
))PATH(pathname)
The path name to be passed to the Gopher server, or
used in local access as your initial menu. Although
the exact interpretation of the pathname string varies
depending on the server, both the MVS server and the
local GOPHER access feature interpret the pathname
as the FULLY QUALIFIED WITHOUT QUOTES name of an MVS
data set containing a gopher menu. For information
about the format of a gopher menu, see operand MENU.
))PORT(portnumber)
You should never need to specify this field unless
someone has set up a special kind of Gopher server
that requires a unique port number.
))DESCRIPTION(text)
A text string giving the heading to be displayed for
the initial directory of Gopher goodies. Normally
either the Gopher server or the Gopher client will
have a default value for this, or you can specify
a description of your liking in your GOPHERRC file.
))FORCE
GOPHER tries to determine if there is a TCP/IP socket
application active elsewhere in your TSO environment
before starting up, to prevent TCP/IP errors. If it
tells you that there is another client active but in
truth there is none and you know it, you can use the
FORCE keyword to make GOPHER proceed whether it finds
this to be the case or not.
Using the LOCAL operand is one way to avoid this entire
scenario. However, that won't allow you to access any
Gopher servers on the network.
))DEBUG
Set debugging mode on. You must preallocate a file to
ddname GGDEBUG for this to work. This can be allocated
to the terminal or a log file. When debug mode is on,
messages describing memory allocation and deallocation
and GOPHER queries sent are dumped to the debug file.
))TEST
Activate C/370 interactive test (INSPECT). GOPHER must
have been compiled with the TEST option for this to be
effective. Note that you can also issue the TEST command
inside GOPHER to get to INSPECT, again provided that
GOPHER was compiled with the TEST option.
./ ADD NAME=HELQ,SSI=01000025
)F Function -
GOPHER is a distributed document delivery service, or, more generally,
a networked information retrieval service. It allows you to access
numerous types of data on various hosts in a transparent fashion.
GOPHER presents you with a hierarchical display of information sources
which are accessed via a client/server communications link.
There are GOPHER clients for all common hardware platforms. The MVS
version runs as an ISPF dialog application.
When you use the GOPHER client, information about your use of GOPHER
is stored in a data set called GOPHERRC. If you don't have one,
GOPHER will create it for you.
For more information on customizing your GOPHER environment, get
into Gopher and select "About This GOPHER".
)I GOPHLOC - local GOPHER help goes in member GOPHLOC
)X Syntax -
%GOPHER
LOCAL
FORCE
DEBUG
TEST
Required: none
)O Operands -
))LOCAL
Specify LOCAL if you want to enter GOPHER in "serverless"
mode - i.e. start up with your private GOPHER menu.
Specifying LOCAL accomplishes two things:
(1) It sets the server to "-", meaning local access.
Therefore, you must also provide a path via a
"localmenu:" spec in your GOPHERRC file.
(2) It allows you to use GOPHER even if there are
other TCP/IP socket applications active elsewhere
in your TSO session. However, it will not allow
you to connect to any GOPHER servers, even if you
have a local menu item that points to one.
For information on how to set up GOPHER menus, get into
GOPHER and select "About This Gopher".
))FORCE
GOPHER tries to determine if there is a TCP/IP socket
application active elsewhere in your TSO environment
before starting up, to prevent TCP/IP errors. If it
tells you that there is another client active but in
truth there is none and you know it, you can use the
FORCE keyword to make GOPHER proceed whether it finds
this to be the case or not.
Using the LOCAL operand is one way to avoid this entire
scenario. However, that won't allow you to access any
Gopher servers on the network.
))DEBUG
Set debugging mode on. You must preallocate a file to
ddname GGDEBUG for this to work. This can be allocated
to the terminal or a log file. When debug mode is on,
messages describing memory allocation and deallocation
and GOPHER queries sent are dumped to the debug file.
))TEST
Activate C/370 interactive test (INSPECT). GOPHER must
have been compiled with the TEST option for this to be
effective. Note that you can also issue the TEST command
inside GOPHER to get to INSPECT, again provided that
GOPHER was compiled with the TEST option.
./ ADD NAME=INSTALLC,SSI=01050029
Directions for Installing the GOPHER MVS Client
Assuming the PDS's have been created:
1. Customize the ALLOAD and COMPILEC JCL members to reflect your
local conventions. Note: If you intend to place the executable into
an existing library, you can suppress that part of the ALLOAD JCL.
The name of the data set created must match across both members.
2. Customize the GGUSER header file as shown by the comments therein.
Note in particular the defines for your TCP/IP and your C compiler.
There are changes to the linkedit JCL that are related to these.
3. Customize the GOPHER exec to define the names of the MVS libraries
to contain the panel and load library members. The load library must
be the one specified in the ALLOAD JCL, if you are creating it anew.
Observe the comments relating to the use of LIBDEF and ISPF APPLIDs.
It is in the GOPHER exec that you will also customize the name of the
default Gopher server. Note that the user's GOPHERRC file gets built
from the contents of this exec.
Note that if you install one of the REXX execs, you must also install
the NNMFIUCV exec in the same library. This exec implements a rude
check for an existing TCP/IP socket application (e.g. another GOPHER)
in a different PIE MultiTSO session. It prevents your users from
crashing TCP/IP, so it is highly recommended that you make use of it.
4. If you are running ISPF Version 2 or earlier, edit the GOPHER panels
whose names begin "GGMP...". These are popups, and will not work
under ISPF Version 2 unless you change the )BODY line. Remove the
WINDOW(...) parameter from the )BODY line of each panel so that the
line just says )BODY or )BODY EXPAND(``), as the case may be.
Now, to install:
5. Submit the ALLOAD JCL to allocate the load library from which the
executable program will be run. If you intend to place the executable
into an existing library, you can skip this step, but you should make
sure that there is no previous load module named GGCLIENT in the load
library of your choice before you proceed.
6. Submit the COMPILEC JCL to compile all the C sources and create
the executable Gopher load module.
The first time you run this you can expect a return code of 8 from
the linkedit. Like SMP/E, this is OK if the only reason is an IEW0342
because the "INCLUDE SYSLMOD(GGCLIENT)" did not find an existing load
module. If you get IEW0132 (unresolved external reference) or
IEW0241 (ESD type definition conflict), your linkedit went awry.
Don't use the resultant load module. Check the libraries you
specified on the link step to see what went wrong.
In the future, if you have to recompile individual modules, you can use
the same JCL to compile only those modules, and the link will include
the new modules in the existing executable load module.
Note: If you have defined C370V1 in the GGUSER header file, you must
also include the system linklist load library or libraries containing
ISPLINK, ISPEXEC and IKJEFF18 when linking. Otherwise you may delete
the lines from the linkedit JCL that reference them.
Note: You need not include the PASCAL libraries or the AMPZMVSB
module if you are using TCP/IP Version 2 or higher, in which case
you must also define TCPIPV2 in the GGUSER headerfile.
7. Copy all the members of the panel PDS into the ISPF panel library
specified in the GOPHER exec.
8. Copy one of the help members (HELP or HELQ) from the CNTL PDS into
your local TSO HELP library under the name GOPHER. You may also
create an additional HELP member called GOPHLOC containing
information local to your site, if you wish.
Which CNTL member should you use? If you don't have XPROC, use HELQ.
If you do have XPROC, use HELP. You will have to modify your GOPHER
clist either way. If you don't have XPROC, you should get it,
because you can specify more options on Gopher if you do. You can
get XPROC via USC's "MVS network server" code distribution service.
For more information about this, send an email message to
SERVICE@MVSA.USC.EDU - or SERVICE@USCMVSA, which will normally give
better results if you have a BITNET (NJE) return address.
9. Create the "About This Gopher" PDS from the ABOUT PDS. This has
all the text users should see when they select the "About This Gopher"
item from the MVS client. It also contains all the documentation you
need about setting up the client and the server, as well as creating
menus and REXX execs for use with MVS Gopher. You may have already
done this as part of the server install, but it should also be
available from the client in "local" (serverless) mode, so that is
why I mention it here.
--------------------------------------------------------------------
Note: Make sure that the C/370 run time library is available,
either in the system link list or in the ISPLLIB concatenation,
before attempting to run GOPHER.
If the C/370 runtime library is not in the link list or otherwise
available to ISPF at execution time, you may arrange for it to be
allocated via LIBDEF in the GOPHER exec (I haven't tried this).
./ ADD NAME=INSTALLS,SSI=01030048
Directions for Installing the GOPHER MVS Server
Assuming the PDS's have been created:
1. Customize the ALLOAD and COMPILES JCL members to reflect your
local conventions. Note: If you intend to place the executable into
an existing library, you can suppress that part of the ALLOAD JCL.
The name of the data set created must match across both members.
2. Customize the GGUSER header file as shown by the comments therein.
Note in particular the defines for your TCP/IP and your C compiler.
There are changes to the linkedit JCL that are related to these.
Now, to install:
3. Submit the ALLOAD JCL to allocate the load library from which the
executable program will be run. If you intend to place the executable
into an existing library, you can skip this step, but you should make
sure that there is no previous load module named GGSERVER or GGSTASK
in the load library of your choice before you proceed.
4. Submit the COMPILES JCL to compile all the C sources and create
the executable Gopher load modules.
The first time you run this you can expect return codes of 8 from
the linkedit. Like SMP/E, this is OK if the only reason is an IEW0342
because the "INCLUDE SYSLMOD(...)" did not find an existing load
module. If you get IEW0132 (unresolved external reference) or
IEW0241 (ESD type definition conflict), your linkedit went awry.
Don't use the resultant load module. Check the libraries you
specified on the link step to see what went wrong.
In the future, if you have to recompile individual modules, you can use
the same JCL to compile only those modules, and the link will include
the new modules in the existing executable load module.
Note: You need not include the PASCAL libraries or the AMPZMVSB
module if you are using TCP/IP Version 2 or higher, in which case
you must also define TCPIPV2 in the GGUSER headerfile.
5. Create the "About This Gopher" PDS from the ABOUT PDS. This has
all the text users should see when they select the "About This Gopher"
item from the MVS client. It also contains all the documentation you
need about setting up the client and the server, as well as creating
menus and REXX execs for use with MVS Gopher. You may have already
done this as part of the client install.
6. Create your Gopher access file. See the instructions in the
"About This Gopher" PDS for the format.
7. Create the MVS Gopher started task JCL from either of the samples
given in GOPHERD and GOPHERT. The GOPHERT is recommended so that you
can use REXX execs that issue TSO commands, but you may not want to
use this for security reasons. Either way, customize liberally.
--------------------------------------------------------------------
Note: Make sure that the C/370 run time library is available,
either in the system link list or in the STEPLIB concatenation,
before attempting to run GOPHER.
./ ADD NAME=MENU,SSI=01010042
gopher_menu
TYPE=FILE
NAME=About This Gopher
PATH=DD:GGABOUT(ABOUT)
HOST=+
END
TYPE=DIRECTORY
NAME=Library/Information Services
PATH=SYS0008.GOPHER.LIBRARY(LIBRS)
HOST=MVS.UDEL.EDU
END
TYPE=TELNET
NAME=UDINFO - University of Delaware Information
HOST=UDINFO.UDEL.EDU
END
TYPE=DIRECTORY
NAME=Network and System Services Computer Systems
PATH=SYS0008.GOPHER.DIR(UDTELNET)
HOST=MVS.UDEL.EDU
END
TYPE=DIRECTORY
NAME=Weather Across the Country
PATH=1/Weather
HOST=mermaid.micro.umn.edu
PORT=150
END
TYPE=DIRECTORY
NAME=Other Gopher and Information Servers
PATH=1/Other Gopher and Information Servers
HOST=gopher.micro.umn.edu
END
TYPE=DIRECTORY
NAME=How to use BITNET LISTSERV Servers
PATH=SYS0008.GOPHER.DIR(LISTSERV)
HOST=MVS.UDEL.EDU
END
TYPE=DIRECTORY
NAME=University of Delaware Newspapers
PATH=SYS0008.GOPHER.DIR(PAPERS)
HOST=MVS.UDEL.EDU
END
/*
./ ENDUP
?!
//ABOUT EXEC GGLOAD,TRK1='5',TO='ABOUT'
//SYSIN DD DATA,DLM='?!'
./ ADD NAME=ABOUT,SSI=01040045
gopher_menu
TYPE=FILE
NAME=What Is Gopher?
PATH=(ABOUTW)
HOST=+
END
TYPE=FILE
NAME=Gopher FAQ (Frequently Asked Questions) List
PATH=(FAQ)
HOST=+
END
TYPE=DIRECTORY
NAME=Using The Gopher MVS Client
PATH=(ABOUTC)
HOST=+
END
TYPE=DIRECTORY
NAME=Administering the Gopher MVS Server
PATH=(ABOUTS)
HOST=+
END
./ ADD NAME=ABOUTC,SSI=01030000
gopher_menu
TYPE=FILE
NAME=Overview - Using Gopher on MVS
PATH=(ABOUTCO)
HOST=+
END
TYPE=FILE
NAME=Directory Mode - Viewing a Gopher Directory
PATH=(ABOUTCD)
HOST=+
END
TYPE=FILE
NAME=File Mode - Browsing a Gopher File
PATH=(ABOUTCF)
HOST=+
END
TYPE=FILE
NAME=Query Mode - Executing a Gopher Query
PATH=(ABOUTCQ)
HOST=+
END
TYPE=FILE
NAME=Extracting Gopher Text
PATH=(ABOUTCX)
HOST=+
END
TYPE=DIRECTORY
NAME=Customizing Your Gopher Startup
PATH=(ABOUTCS)
HOST=+
END
./ ADD NAME=ABOUTCD,SSI=01000031
This text has not been written yet.
./ ADD NAME=ABOUTCF,SSI=01000042
This text has not been written yet.
./ ADD NAME=ABOUTCO,SSI=01000013
The following is modified from Allan Tuchman's XGOPHER help.
Gopher on MVS is an ISPF dialog interface to the Gopher
information delivery system from the University of Minnesota.
The initial panel asks you to specify the name of the Gopher server
host. Normally you leave the other input fields alone.
You may also specify a hostname of "-", which means that you want
to use your own private Gopher data without going through a server.
When you do this, you must provide the path name to your private
top-level menu (data set name, FULLY QUALIFIED, WITHOUT QUOTES).
Assuming that the top-level path points to a valid Gopher menu,
the initial display will show the top level directory of
gopher information available. Selecting an item from this
list will fetch the contents of a file, subdirectory, or
other information. The directory display may be updated to
show the new subdirectory.
To select an item, type "S" in front of it and press ENTER.
This puts you into ISPF BROWSE mode on the text of the item.
You may also type "Q" in front of an item to see it in text format
even if it is a directory. If you have retrieved an item, you may
type "E" in front of it to extract it into a file - but you may
do this more easily via the EXTract command from within BROWSE.
Some gopher file types are not supported by the current client.
These will not appear on your menus. Furthermore, you may not
be permitted to access some items, depending upon the server
and the host from which you are trying to access them. These
restrictions do not apply to local mode, where you can access
anything that you have local permission to read.
The Gopher MVS client is written by Steve Bacher at Draper Laboratory
(copyright 1992).
./ ADD NAME=ABOUTCQ,SSI=01000047
This text has not been written yet.
./ ADD NAME=ABOUTCS,SSI=01030002
gopher_menu
Type=FILE
Name=Customizing Your Gopher Startup
Path=(ABOUTCSC)
Host=+
End
Type=FILE
Name=What Happens When You Start Up Gopher
Path=(ABOUTCSW)
Host=+
End
Type=FILE
Name=Requesting Local (Serverless) Access
Path=(ABOUTCSL)
Host=+
End
Type=FILE
Name=The GOPHERRC File
Path=(ABOUTCSR)
Host=+
End
Type=FILE
Name=Defining GOPHER Menus
Path=(ABOUTCSM)
Host=+
End
Type=FILE
Name=REXX Exec Interface
Path=(ABOUTCSX)
Host=+
End
./ ADD NAME=ABOUTCSC,SSI=01010046
=======================================================================
Customizing Your Gopher Startup
=======================================================================
When you use the GOPHER client, information about your use of GOPHER
is stored in a data set called GOPHERRC. If you don't have one,
GOPHER will create it for you.
Your default startup menu will contain a single item pointing to a
GOPHER server on MVS, whether such a server is available or not.
However, you can ask GOPHER to display a different startup menu for
you. This startup menu may have entries for the GOPHER server
on MVS and one for your own private (local) data, which is accessed
without querying a server.
To get GOPHER to set up a different startup menu, you must edit the
GOPHERRC file. Note that you may set up the GOPHER startup menu to
include a pointer to your local data - but you have to create that
local data in order to use it.
Editing the GOPHERRC file should be easy. Just follow the
instructions in the comments of the file itself. For information
about the contents of GOPHERRC, see the HELP for operand GOPHERRC.
./ ADD NAME=ABOUTCSL,SSI=01000056
=======================================================================
Requesting Local (Serverless) Access
=======================================================================
The LOCAL operand on the GOPHER command is a convenient way of
requesting "local" serverless mode. Specify LOCAL on the GOPHER
command if you want to enter GOPHER in "serverless" mode - i.e.
start up with your private GOPHER menu. Specifying LOCAL
accomplishes two things:
(1) It sets the server to "-", meaning local access. Therefore, you
must also provide a path, either via the PATH operand on the
GOPHER command or via a "localmenu:" spec in your GOPHERRC file,
so that GOPHER knows where to look for your private data. The
path is a data set name, FULLY QUALIFIED WITHOUT QUOTES.
(2) It allows you to use GOPHER even if there are other TCP/IP socket
applications active elsewhere in your TSO session. However, it
will not allow you to connect to any GOPHER servers, even if you
have a local menu item that points to one.
If you do not specify a server and there is no specification in
your GOPHERRC file for one, then GOPHER will display a startup
ISPF panel asking you to specify a server name and, optionally,
a path name. (Don't touch the port number!)
./ ADD NAME=ABOUTCSM,SSI=01030019
=======================================================================
Defining Gopher Menus
=======================================================================
This is a description of how to define GOPHER menus that can be used
either for your own private data or by the GOPHER server administrator
on MVS to define publicly accessible data.
Bear in mind that the menu may be used to specify data meaningful to
a server other than MVS. Therefore, the descriptions here should be
interpreted in two ways:
(1) how to define MVS-resident information resources
(2) how to request information resources from other GOPHER servers
------------------------------------------------------------------------
How To Define MVS-Resident Information Resources
The Gopher server (and the Gopher client, in "local" mode) determines
how to return information to the client via menus. These menus are
plain MVS data sets with a particular structure.
An MVS gopher menu is a sequential data set or PDS member with the
following format:
* the first line contains the string GOPHER_MENU
(in upper, lower or mixed case)
* the rest of the file contains blocks of information like this:
TYPE=type
NAME=name
PATH=path
HOST=host
PORT=port
END
For compatibility with earlier versions of the MVS Gopher server,
the following are also accepted:
DISPLAY= is equivalent to NAME=
SELECTOR= is equivalent to PATH=
Explanations
TYPE=type
The type of Gopher entity (FILE, DIRECTORY, INDEX, etc.).
In other words, one of the following:
FILE - the item is an MVS data set with text to be displayed.
The path name is the file name or a REXX exec spec.
DIRECTORY - the item is another Gopher directory.
The path name is the file name or a REXX exec spec.
INDEX - the item is a full text search item, which means that
the client will query the user for a search string
which will be passed to the server along with the
pathname. For the MVS server. it only makes sense for
the pathname to be a REXX exec specification. The path
and the user's string are given to the host, which
returns a menu of selections. See also WHOIS.
TELNET - the item is a Telnet server.
The path name is ignored. The port number should be
omitted or set to 0, unless an alternate TELNET port
is required by the server referenced by HOST.
WHOIS - the item is a "whois" query. This is similar to the
INDEX type, except that the server returns a file
rather than a menu. This is not (yet) an official
part of the Gopher protocol, though it does appear in
certain (patched) versions of other implementations.
NAME=name
The descriptive string that will appear in the Gopher client's
display of menu selections for this item. Make this as human as
possible. Case is preserved.
PATH=path
The pathname to be passed to the Gopher server to retrieve the
item. See below for a fuller description.
HOST=host
The name of the Gopher server host that will process the request.
See below for a fuller description.
PORT=port
The TCP/IP port to connect to. For Gopher, this should always be
port 70 (except for a TELNET type, whose port defaults to the
standard TELNET port if zero or omitted). If this is omitted, then
the default port number is taken.
END
Required to keep menu entries separate.
Comment lines may be freely included, starting with '#' in
the first column of data.
More about Path Names
Note that the format of a path depends on which Gopher server is
going to be processing the entry, as defined by the HOST= field.
If the entry is going to a different Gopher server, then the
pathname format depends on that server. For example, a Unix server
would expect a Unix file name with a slash.
A path name for the MVS Gopher may be one of the following:
* A fully qualified MVS data set name, without quotes, identifying
a sequential text data set or PDS member. If TYPE=FILE, this is
text. If TYPE=DIRECTORY, this is a gopher menu as described above.
* A fully qualified MVS data set name, without quotes, identifying a
PDS (no member). This causes the MVS Gopher server to return a
list of member names of the PDS in Gopher directory format. This
is valid only with TYPE=DIRECTORY. Member aliases are included in
the resulting list.
* A member name enclosed in parentheses. This is treated as
a full PDS member. In other words, the MVS Gopher server will use
the name of the PDS in which the menu itself was found.
This allows you to move PDS's full of Gopher menus around without
having to worry about changing all the path names. This happens
only when the menu itself is a PDS member and the host is the
same as the local host (MVS for the server, - for local mode).
Specifying HOST=+ is recommended for this.
* A string "DD:ddname" or "DD:ddname(member)", identifying a file by
MVS ddname a la C/370. Valid with either TYPE=FILE or
TYPE=DIRECTORY, so the ddname can point to text or a menu.
However, if the ddname happens to be allocated to a PDS, it does
NOT work like a directory above - it's just illegal and will
probably cause lossage.
Each member is treated as a Gopher FILE. The NAME field is
set to the member name. If you want to do anything fancier
than this, you will have to construct your own Gopher menu.
* A string "EXEC:execname args", which specifies the name of a
REXX exec to be executed to return the data. Valid with any
and all types. To learn more about how to make use of this
feature, please go back to the "About This Gopher" tree and
read up on using REXX execs with MVS Gopher.
If you are using your own private GOPHER data via local access
and you want to run REXX execs, you must have a "localexec:"
line in your GOPHERRC file identifying your REXX exec library.
More About Host Names
You may find that some Gopher servers insist on appending the
network's domain name to local server hostnames. You should check
with your network gurus to make sure that this will work with your
TCP/IP host lookup. The MVS server will accept hostnames either
with or without the domain name appended - this applies to the
specification of hostnames in the Gopher access table as well -
but other Gopher servers may not.
Two special cases:
A plus sign (HOST=+) means that the host is the same host as the one
that is looking at the directory entry - i.e. the server that is
serving up this menu. The Gopher server simply plugs in its own host
name at that point. This is NOT part of the Gopher protocol, but
merely a server hack.
A minus sign (HOST=-) means that access to this item will be in
"local" (serverless) mode. This is recognized only by the MVS Gopher
client. It means that the client will do the retrieval itself,
without asking a server to do it.
The directory-processing code, when invoked in "local mode", will
treat HOST=+ as HOST=- since the current host is the local mode
operation in that case. Therefore, using HOST=+ is recommended
so that one can port one's local GOPHER menus to the public server
at some point.
A REXX exec that generates menus dynamically can use - as a hostname,
but not +.
------------------------------------------------------------------------
How To Request Information Resources From Other GOPHER Servers
Rather than describe the standard format of a Gopher menu here,
I recommend that you go to your nearest Unix box and type
man gopherd
That should tell you all you need to know about Unix gopher servers.
If your gopher server is on some other kind of machine, then go find
the documentation for that machine's Gopher menus.
The purpose of the above exercise is primarily to determine the format
of a path name understood by a given Gopher server. Once you know that,
you can build a Gopher menu the MVS Gopher will understand, according to
the format described in the top section. Set the host to point to
the other Gopher server, who will interpret the other items in the menu.
------------------------------------------------------------------------
Dynamic Generation of GOPHER Menus
If you want to be able to generate a Gopher menu dynamically,
you can do this via the REXX interface. You also must understand
the Gopher protocol. A Gopher menu is really a text representation
of the actual protocol, which goes like this:
filetype -tab- name -tab- path -tab- host -tab- port
where -tab- is the EBCDIC (on MVS) or ASCII (on other box) tab
character, and filetype is a single character. The filetypes
supported by the MVS Gopher server are:
0 - flat file
1 - directory
2 - error
7 - index
8 - TELNET
w - whois (experimental)
A REXX exec that wants to generate a Gopher menu must output lines
in this format. For more information, go back to the Gopher tree
for "About This Gopher" and look up information on the REXX interface.
./ ADD NAME=ABOUTCSR,SSI=01010039
=======================================================================
The GOPHERRC File
=======================================================================
When you use the GOPHER client, you need a file called GOPHERRC
which stores information about your use of GOPHER. If you don't
have one, GOPHER will create it for you. The file initially
contains:
the initial path/name/host/port specification, which tells
GOPHER what to display on startup. By default this is the
standard GOPHER server info on MVS. However, you can add
to your GOPHERRC a specification for local GOPHER by
editing GOPHERRC and activating one of the following:
- the other "initial:" spec which points to your own startup menu,
overriding the one you'd get otherwise
- the localmenu: and localexec: lines.
localmenu: is equivalent to specifying an alternate initial:
spec of host=- (dash) and path=localmenu_name. When you use
the LOCAL operand of the GOPHER command, localmenu: is what
GOPHER looks for as the pathname if you don't provide one on
the command.
localexec: is required if you want to use your own library of
GOPHER rexx execs. This is valid for LOCAL access only.
Some option defaults are stored in the GOPHERRC file.
Note that this is not yet implemented.
The GOPHER client will store bookmarks (as you create them)
at the end of your GOPHERRC file. Note that this feature
is not yet implemented.
If you have a newly created GOPHERRC file, you can read the
comments to guide you in customizing the file.
./ ADD NAME=ABOUTCSW,SSI=01000034
=======================================================================
What Happens When You Start Up GOPHER?
=======================================================================
What you see when you start up GOPHER depends on what you have
specified, either on the command line or in the GOPHERRC file.
In general, command operands override GOPHERRC specifications.
GOPHER does its thing by connecting to a Gopher server somewhere
on your network. If you do not specify otherwise, this server is
assumed to be MVS (the host where you are running this client).
The default GOPHERRC file specifies this as the server.
The startup menu you see is the one defined by the administrator
of that server.
You can request a different server or a different startup menu,
either by modifying the GOPHERRC file or by specifying command
operands. The SERVER operand tells GOPHER to get a startup menu
from a different server, and the PATH operand tells GOPHER what
startup menu to request (the contents of the path depend on what
server you point to and what it's looking for, but it is typically
the name of a file on that system that contains a Gopher menu).
You can also use GOPHER to access your own private data by requesting
"local" (serverless) mode. A server name of a single dash "-" means
local access. In this case, you must provide a path name so that
GOPHER knows where to look for your data. The path name is the name
of a data set containing your GOPHER menu - it must be FULLY QUALIFIED
AND WITHOUT QUOTES. The path name can be provided either as a command
operand or in the GOPHERRC file.
./ ADD NAME=ABOUTCSX,SSI=01020059
=======================================================================
REXX Exec Interface
=======================================================================
You can request the MVS Gopher server (or the MVS Gopher client, in
"local" (serverless) mode) to retrieve information dynamically by
executing a REXX exec. To request this, you define a menu entry
with the following PATH= field:
PATH=EXEC:execname args
In the case of EXEC:, the REXX exec identified by "execname" is
executed, along with the arguments "args" given. For example:
PATH=EXEC:MYEXEC ANY ARGS
will cause the MYEXEC exec to be executed with "ANY ARGS" as the
single argument string.
If the TYPE is INDEX, the search string submitted by the user will be
appended to the args separated by a blank. The exec must be able to
deal with this.
REXX Execs must be in a PDS allocated to DD GGEXEC. This ddname
needs to be allocated in the Gopher server's JCL. For local mode,
the GOPHER command will allocate the GGEXEC file to the REXX exec
library specified on the "localexec:" line in your GOPHERRC file,
if you have activated it. Otherwise you will not be able to use
REXX execs in local mode.
Note that you do not need the /* REXX */ comment at the beginning of
REXX execs used by gopher (though it does not hurt to include it!)
because they are invoked by the IRXEXEC facility and not the standard
TSO CLIST/EXEC search.
Now, how does the REXX exec return data to the Gopher server?
First of all, it depends on the TYPE that the exec is expected
to return, which has nothing to do with HOW the returning is done.
So, first let's talk about how the exec returns data, and then
about what it is expected to return.
How to return data
The REXX exec must return data by writing it to the SYSTSPRT DD.
Note that this is where normal TSO output goes when a REXX exec
is run in TSO batch. However, since REXX execs are invoked by
the IRXEXEC interface by the Gopher server, to prevent dependency
on a TSO environment, this default behavior of REXX/TSO cannot
be relied upon. Therefore, if you write a REXX exec to return
Gopher data, you must explicitly send the output to the SYSTSPRT
ddname. The Gopher server makes sure that it can read this data.
A typical approach is to queue all the output to the REXX data stack,
queue a final "" and then use EXECIO. Be careful not to queue null
lines in this case. Be sure to protect the stack in case of lossage.
Example:
"NEWSTACK"
do while more_data_to_get
some_data = get_some_data()
if some_data = "" then queue " "
else queue some_data
end
queue ""
"EXECIO * DISKW SYSTSPRT (FINIS)"
"DELSTACK"
You can also create a stem variable to hold the output, if you
want to avoid problems with null lines or nested stacks. Example:
do i = 1 to whatever
foo.i = get_some_data()
end
foo.0 = i
"EXECIO * DISKW SYSTSPRT (FINIS STEM FOO.)"
A downside is that if the REXX exec finds anomalous conditions
or executes a TSO command that barfs, standard TSO command output
will probably get lost. Therefore, try to use OUTTRAP to capture
command output and test for error codes, and write all captured
output or error messages to SYSTSPRT in such a way as to allow
the client to see them (but not treat them as normal directory
data or whatever).
A helpful hack is to use an EXECUTE exec to invoke other REXX
code or TSO commands that normally output via PUTLINE. e.g.:
/* REXX. Usage: EXECUTE exec args... */
parse arg real_exec_command
parse source sourceline
if word(sourceline,7) = "TSO" then do
x = outtrap("LINE.")
real_exec_command
arc = rc
x = outtrap("OFF")
"EXECIO * DISKW SYSTSPRT (FINIS STEM LINE.)"
end
else do
real_exec_command
arc = rc
end
return arc
I don't recommend this, though, because it's SLOW.
If the Gopher server is a TSO-in-batch job (i.e. EXEC PGM=IKJEFT01)
then you can issue TSO commands from the exec. To get the output,
though, you need to use OUTTRAP around them. If they issue TPUT's,
you are SOL. If they are PL/1 programs that write to SYSPRINT, or
FORTRAN or assembler, etc., allocate the SYSPRINT or FT06F001 or
whatever file to a temporary and copy the temporary to SYSTSPRT. If
it is a C/370 program that writes to stdout or stderr, you may be able
to use redirection:
CALL 'THEIR.LOAD(CPROG)' 'args > DD:SYSTSPRT'
for stdout
CALL 'THEIR.LOAD(CPROG)' 'args 2> DD:SYSTSPRT'
for stderr
(for multiple output, use >> instead of >)
If gopher server is run straight batch rather than as a TSO job, then
you cannot run REXX execs that require a TSO environment.
One more important word: Make sure that your SYSTSPRT file has a
large enough LRECL to handle the REXX output. If it is too short,
the REXX output will get folded. For TYPE=DIRECTORY in particular,
this is disastrous. Recommended JCL for executing the Gopher server
may be found elsewhere in the installation materials, or your MVS
system programmer has probably already installed a Gopher server in
'SYS1.PROCLIB' or the equivalent with the correct allocation.
What it is expected to return
OK - now the good stuff. This depends on the TYPE on the menu entry
that your exec is trying to fulfill. Some gopher protocol basics:
A Gopher menu is really a text representation of the actual protocol,
which goes like this:
filetype -tab- name -tab- path -tab- host -tab- port
where -tab- is the EBCDIC (on MVS) or ASCII (on other box) tab
character, and filetype is a single character. The filetypes
supported by the MVS Gopher server are:
0 - flat file
1 - directory
2 - error
7 - index
8 - TELNET
w - whois (experimental)
To generate the equivalent of a Gopher menu, you must output data
in the above format. Now for the details...
TYPE=FILE
Just return the straight data. Try to avoid null lines because C/370
believes they don't exist and will throw them away. We hate this, but
IBM is so hard to convince of reality sometimes... Change all null
lines to lines containing one blank as you write them out (you need to
do this anyway if you are queueing output on the stack for EXECIO) and
you will have no problems.
TYPE=DIRECTORY
You must return lines that fit the gopher protocol format as above.
For example, if you want to generate a Gopher menu on the fly that
is equivalent to this:
type=file
name=This is my description
path=some.gopher.path
host=sun1.sanjuan.com
port=70
then you output a line that looks like this:
0This is my description!some.gopher.path!sun1.sanjuan.com!70
(each ! is really a tab (EBCDIC hex 05) character)
where "0" is the type (file in this example, but would be "1" for
type=directory, "7" for typeindex, etc.)
Here's the REXX code that might do this:
name = "This is my description"
path = "some.gopher.path"
host = "sun1.sanjuan.com"
tab = '05'x
port = 70
queue "0"||name||tab||path||tab||host||tab||port
Assuming we write the queued lines to DD SYSTSPRT, as described.
Specifying the Right Host Name
Most of the time you will probably want to generate a menu item
that points back to your MVS host, not some other host. It may
even redrive your selfsame REXX exec with new arguments. And if
the exec was invoked in local (serverless) mode, you want the item
to get driven in the same mode, probably.
The question is - what's the easiest way to identify what
the "same server" is? One way is to hardcode the server name (e.g.
"MVS.DRAPER.COM"), but this is not sufficiently general because:
(1) the server name or location may change
(2) you can't distribute the exec to other Gopher users
(3) it won't work the same way in "local mode"
So, you need a way to know what the name of your selfsame host is.
The MVS Gopher server can use HOST=+, but you can't, as that isn't
part of the Gopher protocol. So what do you do?
Recommendation: call a function hostname() to return the current
host name. So in the above code segment, you might have:
host = hostname()
What is that hostname() function anyway?
Well, you create it.
Take your Gopher exec library (please) and include an exec
called HOSTNAME, which you set up to return the name
of the host that you want to be the "same host".
Note that a plus sign "+" will not work in this context.
The plus sign is a hack interpreted by the Gopher server
when it sees it on a menu. It is *not* part of the Gopher
protocol and therefore cannot be sent over.
However, the minus sign "-" will work, as the Gopher client
in local mode will interpret it at the protocol level
(which DOES NOT IMPLY THAT IT IS A PART OF THE STANDARD
GOPHER PROTOCOL, PROPOSED OR OTHERWISE - THIS IS JUST A
LOCAL HACK MODIFICATION).
Anyhow, what you ought to do is to have different Gopher
exec libraries for local (i.e.private) use and public
server use. The public server will have a HOSTNAME member
that says
return "MVS.DRAPER.COM"
or whatever the name of *YOUR* gopher server host is.
Your private exec library should have a HOSTNAME member
that says
return "-"
This is the best I can come up with right now. A future enhancement
may be to pass the hostname as the second arg to the REXX exec using
the IRXEXEC interface, e.g.
parse arg execargs, hostname
Then we could pass even more such arguments, like port, etc.
But that's all for now...
./ ADD NAME=ABOUTCX,SSI=01000051
This text has not been written yet.
./ ADD NAME=ABOUTS,SSI=01040038
gopher_menu
TYPE=FILE
NAME=Creating MVS Gopher Menus
PATH=(ABOUTCSM)
HOST=+
END
TYPE=FILE
NAME=MVS Gopher Access Table
PATH=(ABOUTSA)
HOST=+
END
TYPE=FILE
NAME=REXX Exec Interface
PATH=(ABOUTCSX)
HOST=+
END
./ ADD NAME=ABOUTSA,SSI=01020004
Format of entries in the Gopher Access Table:
filename (fully qualified, all uppercase, no quotes)
can be "DD:DDNAME" or "EXEC:EXECNAME"
followed by names of hosts which are authorized to access the data.
If no host name list is present, all hosts are authorized
You may specify the same file name more than once, if you need
more lines to put host names on.
Individual PDS members must be specified separately. A PDS without
a member name establishes access only to the PDS directory.
Note that the default directory MUST be in this table.
Also note that in the case of EXECs, the EXEC must live in the
library allocated to GGEXEC in the Gopher server JCL.
*** ANY DATA SET REFERENCED BY ANY EXEC IN THAT LIBRARY IS FULLY
*** ACCESSIBLE TO GOPHER REGARDLESS OF THIS TABLE! USE THIS TABLE
*** TO GOVERN CONTROL TO THE EXEC ITSELF!!!
./ ADD NAME=ABOUTW,SSI=01020053
What is Gopher?
For more information, read the FAQ, posted to USENET newsgroups
comp.infosystems.gopher and news.answers every two weeks.
The information contained here is borrowed therefrom in large part.
Gopher is a client/server protocol for building a distributed
information delivery service. While providing a delivery vehicle for
local information, Gopher also facilitates access to other Gopher and
information servers on the Internet.
Gopher servers and clients can be obtained via anonymous ftp to
boombox.micro.umn.edu. Look in the directory /pub/gopher.
There are clients for the following systems. For the latest
directory information, see the FAQ.
Unix Curses & Emacs
Xwindows
Macintosh Hypercard
Macintosh Application
DOS w/Clarkson Driver
NeXTstep
VM/CMS
VMS
MVS
There are also a number of public telnet login sites available.
See the FAQ for more information.
There are servers for the following systems. For the latest
directory information, see the FAQ.
Unix
VMS
Macintosh
VM/CMS
MVS
Papers and articles describing Gopher:
_The_Internet_Gopher_, "ConneXions", July 1992, Interop.
_Exploring_Internet_GopherSpace_ "The Internet Society News", v1n2 1992,
_The_Internet_Gopher_Protocol_, Proceedings of the Twenty-Third
IETF, CNRI, Section 5.3
_Internet_Gopher_, Proceedings of Canadian Networking '92
_The_Internet_Gopher_, INTERNET: Getting Started, SRI
International, Section 10.5.5
_Tools_help_Internet_users_discover_on-line_treasures, Computerworld,
July 20, 1992
Gopher will also be in two forthcoming O'Reilly Books:
"Administrating TCP/IP, and The Whole Internet"
./ ADD NAME=FAQ,SSI=01010032
Xref: news.draper.com comp.infosystems.gopher:119 news.answers:1134
From: gopher@boombox.micro.umn.edu (UofMN Gopher Team)
Newsgroups: comp.infosystems.gopher,news.answers
Subject: Gopher (comp.infosystems.gopher) Frequently Asked Questions (FAQ)
Summary: Common Questions and Answers about the Internet Gopher, a
client/server protocol for making a world wide information
service, with many implementations.
Date: 15 Aug 92 02:56:59 GMT
Sender: news@news2.cis.umn.edu (Usenet News Administration)
Followup-To: comp.infosystems.gopher
Organization: University of Minnesota
Archive-name: gopher-faq
Last-modified: 1992/08/14
Common Questions and Answers about the Internet Gopher, a
client/server protocol for making a world wide information service,
with many implementations. Posted to comp.infosystems.gopher and
news.answers every two weeks.
-------------------------------------------------------------------
Q0: What is Gopher?
A0: The Internet Gopher client/server provides a distributed
information delivery system around which a world/campus-wide
information system (CWIS) can readily be constructed. While
providing a delivery vehicle for local information, Gopher
facilitates access to other Gopher and information servers
throughout the world.
-------------------------------------------------------------------
Q1: Where can I get gopher?
A1: via anonymous ftp to boombox.micro.umn.edu. Look in the directory
/pub/gopher
--------------------------------------------------------------------
Q2: What do I need to access gopher?
A2: You will need a gopher "client" program that runs on your local PC
or workstation
There are clients for the following systems. The directory
following the name is the location of the client on the anonymous
ftp site boombox.micro.umn.edu (134.84.132.2) in the directory
/pub/gopher.
Unix Curses & Emacs : /pub/gopher/Unix/gopher1.02.tar.Z
Xwindows : /pub/gopher/Unix/xgopher1.1a.tar.Z
Macintosh Hypercard : /pub/gopher/Mac_client/
Macintosh Application : /pub/gopher/Mac_client/
DOS w/Clarkson Driver : /pub/gopher/PC_client/
NeXTstep : /pub/gopher/NeXT/
VM/CMS : /pub/gopher/Rice_CMS/ or /pub/gopher/Vienna_CMS/
VMS : /pub/gopher/VMS/
There are also a number of public telnet login sites available.
The University of Minnesota operates one on the machine
"consultant.micro.umn.edu" (134.84.132.4) See Q3 for more
information about this. It is recommended that you run the client
software instead of logging into the public telnet login sites. A
client uses the custom features of the local machine (mouse,
scroll bars, etc.) A local client is also faster.
---------------------------------------------------------------------
Q3: Where are there publicly available logins for gopher.
A3: Here is a short list, use the site closest to you to minimize
network lag.
Hostname IP# Login Area
------------------------- --------------- ------ -------------
consultant.micro.umn.edu 134.84.132.4 gopher North America
gopher.uiuc.edu 128.174.33.160 gopher North America
gopher.uwp.edu 131.210.1.4 gopher North America
panda.uiowa.edu 128.255.40.201 panda North America
info.anu.edu.au 150.203.84.20 info Australia
gopher.chalmers.se 129.16.221.40 gopher Sweden
It is recommended that you run the client software instead of
logging into the public telnet login sites. A client uses the
custom features of the local machine (mouse, scroll bars, etc.) A
local client is also faster.
---------------------------------------------------------------------
Q4: How can I add to the information in gopher?
A4: You can do this by running a gopher server. Servers are available
for a number of systems. Use anonymous ftp to
boombox.micro.umn.edu (134.84.132.2) and look in /pub/gopher. The
following servers are available there:
Unix : /pub/gopher/Unix/gopherxx.tar.Z
VMS : /pub/gopher/VMS/
Macintosh : /pub/gopher/Mac_server/
VM/CMS : /pub/gopher/Rice_CMS/ or /pub/gopher/Vienna_CMS/
MVS : /pub/gopher/mvs/
When you have your server ready you can publish it to the world by
sending e-mail to the maintainters of the "Other gophers" list:
gopher@boombox.micro.umn.edu
---------------------------------------------------------------------
Q5: Who Develops Gopher Software?
A5: Gopher was originally developed in April 1991 by the University
of Minnesota Microcomputer, Workstation, Networks Center to help
our campus find answers to their computer questions.
It has since grown into a full-fledged World Wide Information
System used by a large number of sites in the world.
Many people have contributed to the project, too numerous to
count.
The people behind the much of the gopher software can be reached
via e-mail at gopher@boombox.micro.umn.edu, or via paper mail:
Internet Gopher Developers
100 Union St. SE #132
Minneapolis, MN 55455 USA
---------------------------------------------------------------------
Q6: How can I set up a "CSO" phone book server? Where is the software?
A6: CSO phone book servers are also known as "qi" servers. The
software implementation can be gotten via anonymous ftp from
uxc.cso.uiuc.edu (128.174.5.50) as /pub/qi.tar.Z. You may also
see this referred to as "ph", which is what most of the clients
are called.
There is also an archive of the mailing list for qi/ph software on
the same machine. It's in /pub/info-ph.archive.
This software is supported by Steve Dorner <s-dorner@uiuc.edu>
Contact him for more information.
-------------------------------------------------------------------
Q7: Why can't I access the University of Minnesota's UPI news?
A7: The University of Minnesota has a site license for UPI news, we
are not allowed to distribute it off of our campus. We get our
UPI news from Clarinet. For more information about getting UPI
news send mail to info@clarinet.com. For information about
setting up your own gopher-UPI server search the gopher-news
archive for UPI.
-------------------------------------------------------------------
Q9: What are the type characters for the different Gopher Objects?
A9: Normal IDs.
0 Item is a file
1 Item is a directory
2 Item is a CSO (qi) phone-book server
3 Error
4 Item is a BinHexed Macintosh file.
5 Item is DOS binary archive of some sort.
6 Item is a UNIX uuencoded file.
7 Item is an Index-Search server.
8 Item points to a text-based telnet session.
9 Item is a binary file! Client must read until the connection
closes. Beware.
T TN3270 connection.
Experimental IDs.
s Sound type. Data stream is a mulaw sound.
M MIME type. Item contains MIME data.
h html type.
I Image type.
i "inline" text type.
-------------------------------------------------------------------
Q10: When I do full-text searches I always get every document back, Why?
A10: This is a problem occasionally encountered with Unix full-text
indexes. It is caused by setting up the link incorrectly to a
gindexd port.
The Path= field should be *blank* when pointing to a gindexd
index.
Otherwise the client will send the path to the gindexd daemon,
which interprets everything as a keyword. This path is
likely to contain a pathname that is common to all of the indexed
files. Thus a search generates hits on everything.
-------------------------------------------------------------------
Q11: When I try to build the UNIX software I get an error from make:
"Must be a separator on rules line #. Stop" Why?
A11: This is a problem with older makes that don't understand the "include"
keyword. One easy way to cope with this problem is compiling GNU
make, which does understand the include keyword.
If this is too difficult, remove the line:
include Makefile.config
from all the Makefiles and paste in a copy of Makefile.config at
the top of each Makefile.
-------------------------------------------------------------------
Q12: What is the relationship between Gopher and (WAIS, WWW, ftp)?
A12: Gopher is intimately intertwined with these two other systems.
As shipped the Unix gopher server has the capability to:
- Search local WAIS indices.
- Query remote WAIS servers and funnel the results to gopher
clients.
- Query remote ftp sites and funnel the results to gopher
clients.
- Be queried by WWW (World Wide Web) clients (either using
built in gopher querying or using native http querying.
-------------------------------------------------------------------
Q13: Are papers or articles describing gopher available?
A13: Yes. Here are some references:
_The_Internet_Gopher_, "ConneXions", July 1992, Interop.
_Exploring_Internet_GopherSpace_ "The Internet Society News", v1n2 1992,
_The_Internet_Gopher_Protocol_, Proceedings of the Twenty-Third
IETF, CNRI, Section 5.3
_Internet_Gopher_, Proceedings of Canadian Networking '92
_The_Internet_Gopher_, INTERNET: Getting Started, SRI
International, Section 10.5.5
_Tools_help_Internet_users_discover_on-line_treasures, Computerworld,
July 20, 1992
Gopher will also be in two forthcoming O'Reilly Books:
"Administrating TCP/IP, and The Whole Internet"
-------------------------------------------------------------------
Q14: On a DECstation I get the error message "/etc/svc.conf no such file
or directory" when running the gopherd server, why?
A14: This is caused by the chroot() call in gopherd. It can be easily
fixed by running gopherd with the -c option.
Alternatively you can copy /etc/svc.conf into a directory named
"etc" inside the gopher-data directory.
-------------------------------------------------------------------
Q15: The boolean searching terms don't work for my full-text index, why?
A15: This is probably because the searching is being provided by WAIS.
WAIS opts to return all documents that contain a search phrase
within certain limits. WAIS searches do return the documents with
the highest "score" at the top, those documents will have the
closest relevance.
-------------------------------------------------------------------
--
| Paul Lindner | lindner@boombox.micro.umn.edu | Slipping into madness
| | Computer & Information Services | is good for the sake
| GopherMaster | University of Minnesota | of comparision.
///// / / / /////// / / / / / / / / //// / / / / / / / /
./ ENDUP
?!
//C EXEC GGLOAD,TRK1='14',TO='C'
//SYSIN DD DATA,DLM='?!'
./ ADD NAME=GGCLIENT,SSI=01180054
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#ifdef SASC
#pragma runopts(EXECOPS)
#else
#pragma runopts(heap(8k,8k,anywhere,))
#pragma runopts(nospie,nostae)
#endif
#pragma csect(code, "GG@LIENT")
#pragma csect(static,"GG$LIENT")
#include "gg.h"
/*********************************************************************/
static char copyright_notice[] =
"Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 \n\
\n\
GOPHER server due to Shawn Hart at the University of Delaware. \n\
\n\
This software is provided on an 'AS IS' basis. All warranties, \n\
including the implied warranties of merchantability and fitness,\n\
are expressly denied. \n\
\n\
Provided this copyright notice is included, this software may \n\
be freely distributed and not offered for sale. \n\
\n\
Changes or modifications may be made and used only by the maker \n\
of same, and not further distributed. Such modifications should\n\
be mailed to the author for consideration for addition to the \n\
software and incorporation in subsequent releases.";
/*********************************************************************/
#ifdef I370
char * _style = "tso:";
#endif
/*********************************************************************/
static Bool
go_for_it(gp,ip)
struct ggcb *gp;
struct gopherinfo *ip;
{
char temp [32];
(void)GGMivget(gp,"GGHOST ",ip->host,sizeof(ip->host));
(void)GGMivget(gp,"GGPATH ",ip->path,sizeof(ip->path));
(void)GGMivget(gp,"GGDESC ",ip->desc,sizeof(ip->desc));
(void)GGMivget(gp,"GGPORT ",temp ,sizeof(temp) );
ip->type = INITIAL_TYPE;
if (!*ip->path) strcpy(ip->path,INITIAL_PATH);
if (!*ip->host) strcpy(ip->host,INITIAL_HOST);
if (!*ip->desc) strcpy(ip->desc,INITIAL_DESC);
ip->port = atoi(temp);
if (ip->port == 0) ip->port = INITIAL_PORT;
return GGMgofor(gp,ip,FALSE);
}
/*********************************************************************/
int
main(argc,argv)
int argc;
char **argv;
{
struct ggcb *gp;
struct gopherinfo *ip;
char *p;
int i;
int exit_return_code;
Bool bypass_startup;
struct ggcb gg;
char zerrsm [25];
char zerrlm [73];
exit_return_code = 0;
memset(&gg,0,sizeof(struct ggcb));
gp = ≫
/* set up top-level gopherinfo structure */
GETMAIN(ip, struct gopherinfo, 1, "top-level gopherinfo struct");
if (!ip) {
fprintf(stderr,"Not enough memory to start up GOPHER\n");
exit(16);
}
memset(ip,0,sizeof(struct gopherinfo));
gp->ginfo = ip;
gp->test_mode = FALSE;
gp->debug_mode = FALSE;
gp->local_mode = FALSE;
bypass_startup = FALSE;
for (i = 1; i < argc; i++) {
p = argv[i];
if (*p == '-') {
while (*++p) {
switch (toupper(*p)) {
case 'T': gp->test_mode = TRUE; break;
case 'D': gp->debug_mode = TRUE; break;
case 'L': gp->local_mode = TRUE; break;
case 'Q': bypass_startup = TRUE; break;
default: fprintf(stderr,"GGMVS: Bad parameter flag %c\n", *p);
exit_return_code = 8;
}
}
}
else {
fprintf(stderr,"GGMVS: Bad parameter string %s\n",p);
exit_return_code = 8;
}
}
if (gp->test_mode) __ctest(NULL);
if (gp->debug_mode) {
if (!(gp->debug_file = fopen("dd:ggdebug","w"))) {
perror("debug file (DD GGDEBUG)");
exit_return_code = 4;
}
}
else gp->debug_file = NULL;
gp->thdr.first_text_line = NULL;
GGMclrtx(gp,NULL); /* Clear text */
GGMclrtx(gp,ip); /* Clear text */
gp->g_bytes_returned = 0;
gp->g_buf_index = -1;
/* Determine the local path name. Done in GGMCONN when needed now */
strcpy(gp->ggserver,"");
gp->connected_to_server = FALSE;
gp->closing_connection = FALSE;
gp->reconnect_in_progress = FALSE;
gp->receiving_text = FALSE;
GETMAIN(gp->server_buf, char,SERVER_BUF_MSGSIZE+4,"server buffer");
GETMAIN(gp->client_buf, char,CLIENT_BUF_MSGSIZE+4,"client buffer");
GETMAIN(gp->gopher_command,char,CLIENT_BUF_MSGSIZE+4,"gopher command");
#ifdef FETCH
gp->isplink_pointer = (int (*) ())fetch("ISPLINK");
gp->ispexec_pointer = (int (*) ())fetch("ISPEXEC");
#endif
if (!GGMispf(gp,"CONTROL ERRORS RETURN")) exit_return_code = 20;
else {
exit_return_code = 0;
/* not done yet: set up command and selection code tables */
GGMsopt(gp,OPTION_ALL); /* set options */
if (bypass_startup) {
(void)GGMispf(gp,"VGET (GGHOST GGPATH GGDESC GGPORT) PROFILE");
(void)go_for_it(gp,ip);
}
else {
(void)GGMivput(gp,"ZCMD " ,"",-1);
while (GGMdispl(gp,"GGM ") == 0
&& !gp->quit
&& !go_for_it(gp,ip)) ;
}
}
if (gp->setmsg) {
(void)GGMivget(gp,"ZERRSM ",zerrsm, sizeof(zerrsm));
(void)GGMivget(gp,"ZERRLM ",zerrlm, sizeof(zerrlm));
fprintf(stderr,"%s: %s\n",zerrsm,zerrlm);
gp->setmsg = FALSE;
}
if (gp->connected_to_server) {
GGMdisc(gp); /* disconnect from news server */
}
FREEMAIN(gp->gopher_command,"gopher command");
FREEMAIN(gp->server_buf, "server buffer");
FREEMAIN(gp->client_buf, "client buffer");
FREEMAIN(gp->ginfo, "top-level gopherinfo struct");
#define FINAL_CLOSE(A,B) \
if (A) { \
if (fclose(A) < 0) fprintf(stderr,B); \
}
FINAL_CLOSE(gp->debug_file, "Error closing debug file\n");
exit(exit_return_code);
}
./ ADD NAME=GGMALLOC,SSI=01030039
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@ALLOC")
#pragma csect(static,"GG$ALLOC")
#include "gg.h"
/****** Allocate a data set. *****************************************/
enum data_set_type
GGMalloc(dsname,ddname,wanted_type,nitems)
char *dsname;
char *ddname;
enum data_set_type wanted_type;
int nitems;
{
int i;
int rc;
char *cp;
enum data_set_type return_type;
Bool try_new;
short primary_allocation ;
short secondary_allocation ;
short directory_blocks ;
short dsorg ;
__S99parms stuff99; /* No "struct", despite manual */
TEXTUNIT *tu [17];
TEXTUNIT tu_dsn;
TEXTUNIT tu_ddn;
TEXTUNIT tu_member;
TEXTUNIT tu_stat;
TEXTUNIT tu_disp;
TEXTUNIT tu_perm;
TEXTUNIT tu_rtddn;
TEXTUNIT tu_rtorg;
TEXTUNIT tu_block;
TEXTUNIT tu_prime;
TEXTUNIT tu_sec;
TEXTUNIT tu_dir;
TEXTUNIT tu_recfm;
TEXTUNIT tu_lrecl;
TEXTUNIT tu_blksz;
TEXTUNIT tu_dsorg;
char *lparp;
char *rparp;
char dsnseq [81];
char member [81];
char what_to_open[81];
FILE *mfile;
try_new = FALSE;
memset((char *)&stuff99,0,sizeof(__S99parms));
strcpy(member,"");
strcpy(dsnseq,dsname);
lparp = strchr(dsnseq,'(');
rparp = strchr(dsnseq,')');
if (lparp && rparp && (lparp < rparp) && (*(rparp+1) == '\0')) {
*lparp = '\0'; /* makes dsnseq the seq part only */
*rparp = '\0'; /* turns member into a string */
strcpy(member, lparp+1);
wanted_type = PDS;
}
for (;;) {
stuff99.__S99RBLN = 20;
stuff99.__S99VERB = S99VRBAL;
stuff99.__S99FLAG1 = S99NOCNV << 8;
stuff99.__S99ERROR = 0;
stuff99.__S99INFO = 0;
stuff99.__S99TXTPP = tu;
stuff99.__S99FLAG2 = 0;
i = 0;
tu[i++] = &tu_dsn;
tu_dsn.key = DALDSNAM;
tu_dsn.num = 1;
tu_dsn.ent.len = strlen(dsnseq);
strcpy(tu_dsn.ent.prm,dsnseq);
for (cp=tu_dsn.ent.prm; *cp; cp++) *cp = toupper(*cp);
tu[i++] = &tu_stat;
tu_stat.key = DALSTATS;
tu_stat.num = 1;
tu_stat.ent.len = 1;
*tu_stat.ent.prm = (try_new ? NEW : SHR);
tu[i++] = &tu_disp;
tu_disp.key = DALNDISP;
tu_disp.num = 1;
tu_disp.ent.len = 1;
*tu_disp.ent.prm = (try_new ? CATLG : KEEP);
tu[i++] = &tu_rtorg;
tu_rtorg.key = DALRTORG;
tu_rtorg.num = 1;
tu_rtorg.ent.len = 2;
if (*member) {
tu[i++] = &tu_member;
tu_member.key = DALMEMBR;
tu_member.num = 1;
tu_member.ent.len = strlen(member);
strcpy(tu_member.ent.prm,member);
for (cp=tu_member.ent.prm; *cp; cp++) *cp = toupper(*cp);
}
if (ddname && *ddname) {
tu[i++] = &tu_ddn;
tu_ddn.key = DALDDNAM;
tu_ddn.num = 1;
tu_ddn.ent.len = strlen(ddname);
strcpy(tu_ddn.ent.prm,ddname);
for (cp=tu_ddn.ent.prm; *cp; cp++) *cp = toupper(*cp);
tu[i++] = &tu_perm;
tu_perm.key = DALPERMA;
tu_perm.num = 0;
}
else {
tu[i++] = &tu_rtddn;
tu_rtddn.key = DALRTDDN;
tu_rtddn.num = 1;
tu_rtddn.ent.len = 8;
memset(tu_rtddn.ent.prm,' ',8);
}
if (try_new) {
switch (wanted_type) {
case PDS:
primary_allocation = (short)nitems;
secondary_allocation = primary_allocation;
directory_blocks = ((short)nitems/(12*36)+1) * 36;
dsorg = DSORG_PO;
break;
case SEQ:
default:
primary_allocation = (short)nitems;
secondary_allocation = primary_allocation;
directory_blocks = 0;
dsorg = DSORG_PS;
break;
}
tu[i++] = &tu_block;
tu_block.key = DALBLKLN;
tu_block.num = 1;
tu_block.ent.len = 3;
memset(tu_block.ent.prm,0,3);
*(short *)(tu_block.ent.prm+1) = 6233;
tu[i++] = &tu_prime;
tu_prime.key = DALPRIME;
tu_prime.num = 1;
tu_prime.ent.len = 3;
memset(tu_prime.ent.prm,0,3);
*(short *)(tu_prime.ent.prm+1) = primary_allocation;
tu[i++] = &tu_sec;
tu_sec.key = DALSECND;
tu_sec.num = 1;
tu_sec.ent.len = 3;
memset(tu_sec.ent.prm,0,3);
*(short *)(tu_sec.ent.prm+1) = secondary_allocation;
tu[i++] = &tu_dir;
tu_dir.key = DALDIR;
tu_dir.num = 1;
tu_dir.ent.len = 3;
memset(tu_dir.ent.prm,0,3);
*(short *)(tu_dir.ent.prm+1) = directory_blocks;
tu[i++] = &tu_recfm;
tu_recfm.key = DALRECFM;
tu_recfm.num = 1;
tu_recfm.ent.len = 1;
*tu_recfm.ent.prm = RECFM_VB;
tu[i++] = &tu_lrecl;
tu_lrecl.key = DALLRECL;
tu_lrecl.num = 1;
tu_lrecl.ent.len = 2;
*(short *)tu_lrecl.ent.prm = 259;
tu[i++] = &tu_blksz;
tu_blksz.key = DALBLKSZ;
tu_blksz.num = 1;
tu_blksz.ent.len = 2;
*(short *)tu_blksz.ent.prm = 6233;
tu[i++] = &tu_dsorg;
tu_dsorg.key = DALDSORG;
tu_dsorg.num = 1;
tu_dsorg.ent.len = 2;
*(short *)tu_dsorg.ent.prm = dsorg;
}
tu[i] = (void *)0x80000000;
rc = svc99(&stuff99);
if (rc == 0) {
if (!(ddname && *ddname)) {
memcpy(ddname,(char *)tu_rtddn.ent.prm,8);
*(ddname+8) = ' ';
*(strchr(ddname,' ')) = '\0';
}
switch (tu_rtorg.ent.prm[0]) {
case 0x40: return_type = SEQ; break;
case 0x02: return_type = PDS; break;
default: return_type = UNK; break;
}
if (wanted_type == SEQ && return_type != SEQ) {
fprintf(stderr,"%s: not a sequential data set\n",dsname);
}
if (wanted_type == PDS && return_type != PDS) {
fprintf(stderr,"%s: not a partitioned data set\n",dsname);
}
if (return_type == PDS && *member) return SEQ;
else return return_type;
}
else if (!try_new && nitems != 0 && stuff99.__S99ERROR == 0x1708) {
try_new = TRUE;
continue;
}
else {
GGMdfail(rc,&stuff99);
return UNK;
}
}
}
./ ADD NAME=GGMBRIFC,SSI=01020028
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@BRIFC")
#pragma csect(static,"GG$BRIFC")
#include "gg.h"
/****** BRIF primary command function. *******************************/
int
GGMbrifc(numptr,dialog_data_ptr)
int *numptr;
void *dialog_data_ptr;
{
Rstruc ggcb *gp = *(Rstruc ggcb **)dialog_data_ptr;
Rstruc gopherinfo *ip = gp->ginfo;
struct gopherinfo *ip1;
char zcmd[80];
char command[80];
char operand[80];
char *p;
int opoff;
/*
* For commands which are supposed to terminate the current BRIF
* (like NEXT and PREV), we return an invalid return code, which
* is documented to make BRIF itself return with a code of 16,
* which we treat as a normal end.
*/
(void)GGMivget(gp,"ZCMD ",zcmd,sizeof(zcmd));
strcpy(command,"");
strcpy(operand,"");
if (1 <= sscanf(zcmd,"%s %n",&command,&opoff)) {
for (p=command;*p;p++) *p = toupper(*p);
if ((EQUAL(command,"EXTRACT") || EQUAL(command,"EXT"))) {
if (!ip) (void)GGMivput(gp,"GGTNUM ","",-1);
gp->extract_file = NULL;
(void)GGMispf(gp,"CONTROL DISPLAY SAVE");
(void)GGMxtx(gp,ip); /* Extract text */
(void)GGMispf(gp,"CONTROL DISPLAY RESTORE");
return 0;
}
else
if (EQUAL(command,"PRT")) {
(void)GGMispf(gp,"CONTROL DISPLAY SAVE");
GGMptx(gp,ip); /* Print text */
(void)GGMispf(gp,"CONTROL DISPLAY RESTORE");
return 0;
}
else
if (EQUAL(command,"QUIT")) {
gp->quit = TRUE;
return 1;
}
else {
ERR1(
"The only non-BROWSE commands available are EXTract and PRT."
);
return 12;
}
}
return 4; /* ISPF-PDF should handle the command */
}
./ ADD NAME=GGMBRIFR,SSI=01000032
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@BRIFR")
#pragma csect(static,"GG$BRIFR")
#include "gg.h"
/****** BRIF read function. ******************************************/
int
GGMbrifr(dataptr,lenptr,recnoptr,dialog_data_ptr)
char **dataptr;
int *lenptr;
int *recnoptr;
void *dialog_data_ptr;
{
Rstruc textline *tp;
Rstruc ggcb *gp;
Rstruc texthdr *thp;
int return_value;
int current_recno;
int i;
gp = *(struct ggcb **)dialog_data_ptr;
thp = gp->brifp;
current_recno = *recnoptr;
return_value = 0;
tp = NULL;
if (current_recno == 99999999) { /* scroll down max request */
tp = NULL;
}
else if (thp->current_text_line != NULL &&
current_recno == gp->brif_previous_recno+1) {
tp = thp->current_text_line->next;
while (tp && tp->text_length < 0) tp = tp->next;
}
else {
for (i = 0, tp = thp->first_text_line; tp; tp = tp->next) {
if (tp->text_length >= 0) {
if (++i >= current_recno) break;
}
}
}
if (tp == NULL) {
*recnoptr = thp->text_line_count;
return_value = 8;
}
else {
thp->current_text_line = tp;
*dataptr = tp->tab_expanded_text;
*lenptr = tp->tab_expanded_text_length;
return_value = 0;
}
gp->brif_previous_recno = current_recno;
return return_value;
}
./ ADD NAME=GGMCLRTX,SSI=01000031
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@CLRTX")
#pragma csect(static,"GG$CLRTX")
#include "gg.h"
/****** Clear text. **************************************************/
void
GGMclrtx(gp,ip)
Rstruc ggcb *gp;
Rstruc gopherinfo *ip;
{
Rstruc texthdr *thp;
Rstruc textline *tp1;
Rstruc textline *tp2;
/* If info is not specified, use main ggcb, else info's text */
thp = (ip ? &ip->thdr : &gp->thdr);
tp1=thp->first_text_line;
while (tp1) {
tp2 = tp1->next;
FREEMAIN(tp1,"text line");
tp1 = tp2;
}
thp->text_body_line = NULL;
thp->first_text_line = NULL;
thp->current_text_line = NULL;
thp->last_text_line = NULL;
thp->text_line_count = 0;
thp->text_max_length = 0;
thp->text_max_tab_expanded_length = 0;
return;
}
./ ADD NAME=GGMCONN,SSI=01080009
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@CONN ")
#pragma csect(static,"GG$CONN ")
#include "gg.h"
#ifdef TCPIPV1
#define REPORT_TCP_ERROR /* */
#endif
#ifdef TCPIPV2
#define REPORT_TCP_ERROR tcperror(gp->ggserver)
#endif
/****** Internet address formatter. **********************************/
static void
format_ip_address(ia,is)
IPADDRESS ia;
char *is;
{
char *cp = (char *)&ia;
sprintf(is,"%d.%d.%d.%d",*cp,*(cp+1),*(cp+2),*(cp+3));
return;
}
/****** Get client hostname and IP address. **************************/
static Bool
get_client_hostname(gp)
Rstruc ggcb *gp;
{
struct hostent *client_hp;
int gethostnamerc;
gethostnamerc = gethostname(gp->client_hostname,MAXHOSTNAMELEN);
if (gethostnamerc < 0) {
fprintf(stderr,"GGMVS: gethostname() failed, don't know my name\n");
return FALSE;
}
client_hp = gethostbyname(gp->client_hostname);
if (!client_hp) {
fprintf(stderr,"GGMVS: gethostbyname() failed, can't get my name\n");
return FALSE;
}
strcpy(gp->ggclient,gp->client_hostname);
strcpy(gp->client_hostname, client_hp->h_name);
gp->client_ip_address = *(IPADDRESS *)client_hp->h_addr;
return TRUE ;
}
/****** Connect to news server. **************************************/
Bool
GGMconn(gp)
Rstruc ggcb *gp;
{
char *lp;
char *cp;
struct recvstruct *R;
struct hostent *server_hp;
struct sockaddr_in bindsock; /* socket used by bind */
struct sockaddr_in consock; /* socket used by connect */
int bindsocklen; /* size of bind socket */
int consocklen; /* size of connect socket */
int bindrc; /* the return code from bind */
int connrc; /* the return code from connect */
int ip_part_1;
int ip_part_2;
int ip_part_3;
int ip_part_4;
char tempdsn[L_tmpnam];
if (gp->connected_to_server) {
GGMdisc(gp); /* Disconnect from news server */
}
gp->closing_connection = FALSE;
if (!*gp->ggserver) {
ERR1(
"No host server defined in Gopher menu, Cannot make a connection."
);
return FALSE;
}
uppercase_in_place(gp->ggserver);
/* If server is "local hack", then establish local mode,
* open temporary file and return.
*/
if (!strcmp(gp->ggserver, LOCAL_HOST_FROB)) {
if (gp->ginfo->port != GOPHER_PORT_NUMBER) {
ERR3("Server name %s is permitted only with port number %d.",
LOCAL_HOST_FROB, GOPHER_PORT_NUMBER);
return FALSE;
}
GETMAIN(gp->recvp,struct recvstruct, 1, "local recv struct");
if (!gp->recvp) {
CRIT1("Can't get memory for local host struct");
return FALSE;
}
R = gp->recvp;
memset(R,0,sizeof(struct recvstruct));
if (!tmpnam(tempdsn)) {
CRIT1("Can't create temporary file for local access");
return FALSE;
}
/* Create temporary file for writing and reading. */
R->outfp = fopen(tempdsn,"w+,type=memory");
if (!R->outfp) {
perror(tempdsn);
CRIT1("Can't open temporary file for local access");
return FALSE;
}
gp->connected_to_server = TRUE;
gp->time_to_go_home = FALSE;
gp->connection_broken = FALSE;
GGMesrvr(gp);
return TRUE;
}
/* Determine the local path name. Do only if making net conn. */
if (!*gp->client_hostname) {
if (!get_client_hostname(gp)) return FALSE;
}
/* Disallow network connections if started up in local mode. */
if (gp->local_mode) {
ERR1("Network connections are not allowed in local mode.");
return FALSE;
}
/* Get server name and address. */
if (strchr(gp->ggserver,'.') &&
gp->ggserver[strspn(gp->ggserver,".0123456789")] == '\0') {
ip_part_1 = ip_part_2 = ip_part_3 = ip_part_4 = 32767;
strcpy(gp->server_hostname, gp->ggserver);
sscanf(gp->ggserver,"%d.%d.%d.%d",&ip_part_1,
&ip_part_2,
&ip_part_3,
&ip_part_4);
if (ip_part_1 > 255 ||
ip_part_2 > 255 ||
ip_part_3 > 255 ||
ip_part_4 > 255) {
ERR2("Syntax error in server network address: %s", gp->ggserver);
return FALSE;
}
gp->server_ip_address = (IPADDRESS) ((ip_part_1 << 24) +
(ip_part_2 << 16) +
(ip_part_3 << 8) +
(ip_part_4 ));
}
else {
server_hp = gethostbyname(gp->ggserver);
if (!server_hp) {
ERR2(
"Unknown host %s - gethostbyname() could not resolve the server name.",
gp->ggserver);
return FALSE;
}
strcpy(gp->server_hostname, server_hp->h_name);
gp->server_ip_address = *(IPADDRESS *)server_hp->h_addr;
}
format_ip_address(gp->server_ip_address, gp->server_ip_addrstr);
format_ip_address(gp->client_ip_address, gp->client_ip_addrstr);
(void)GGMivput(gp,"GGSERVER ",gp->ggserver,-1);
(void)GGMivput(gp,"GGSERVIP ",gp->server_ip_addrstr,-1);
(void)GGMivput(gp,"GGCLIENT ",gp->ggclient,-1);
(void)GGMivput(gp,"GGCLIEIP ",gp->client_ip_addrstr,-1);
consock.sin_family = AF_INET;
consock.sin_port = htons(gp->ginfo->port);
consock.sin_addr.s_addr = gp->server_ip_address;
bindsock.sin_family = AF_INET;
bindsock.sin_port = 0;
bindsock.sin_addr.s_addr = gp->client_ip_address;
gp->socknum = socket(AF_INET, SOCK_STREAM, 0);
if (gp->socknum < 0) {
REPORT_TCP_ERROR;
ERR2("TCP/IP error: socket() failed to make socket for server %s.",
gp->ggserver);
return FALSE;
}
bindsocklen = sizeof(bindsock);
bindrc = bind(gp->socknum, &bindsock, bindsocklen);
if (bindrc < 0) {
REPORT_TCP_ERROR;
ERR2("TCP/IP error: bind() failed to bind socket for server %s.",
gp->ggserver);
return FALSE;
}
(void)GGMispf(gp,"CONTROL DISPLAY LOCK");
(void)GGMispf(gp,"DISPLAY PANEL(GGMLCONN)");
if (gp->debug_file) {
fprintf(gp->debug_file,
"Client %s (%s) connecting to GOPHER server on %s (%s)\n",
gp->client_hostname,
gp->client_ip_addrstr,
gp->server_hostname,
gp->server_ip_addrstr);
}
consocklen = sizeof(consock);
connrc = connect(gp->socknum, &consock, consocklen);
if (connrc < 0) {
REPORT_TCP_ERROR;
ERR2("TCP/IP failure: connect() failed to connect to server %s.",
gp->ggserver);
return FALSE;
}
gp->connected_to_server = TRUE;
gp->time_to_go_home = FALSE;
gp->connection_broken = FALSE;
/* Clean up any stray responses from server. */
GGMesrvr(gp); /* End server read */
return TRUE;
}
./ ADD NAME=GGMDFAIL,SSI=01000005
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@DFAIL")
#pragma csect(static,"GG$DFAIL")
#include "gg.h"
/****** Retrieve allocation failure messages. ************************/
void
GGMdfail(rc,p99)
int rc;
__S99parms *p99;
{
int zero = 0;
unsigned int dfid = 0x40320000;
struct {
short first_level_msg_len;
short first_level_msg_offset;
char first_level_msg[251];
short second_level_msg_len;
short second_level_msg_offset;
char second_level_msg[251];
} dfbuffer;
static int (*ikjeff18_pointer)() = NULL;
#ifndef FETCH
extern int *ikjeff18();
#endif
if (!ikjeff18_pointer) {
#ifdef FETCH
ikjeff18_pointer = (int (*)())fetch("IKJEFF18");
#else
ikjeff18_pointer = (int (*)())ikjeff18;
#endif
}
dfbuffer.first_level_msg_len = 4;
dfbuffer.second_level_msg_len = 4;
if (ikjeff18_pointer) {
if ((*ikjeff18_pointer)(p99,&rc,&zero,&dfid,&zero,&dfbuffer)) {
fprintf(stderr,"IKJEFF18 returned a nonzero return code\n");
}
if (dfbuffer.first_level_msg_len > 0) {
fprintf(stderr,"%*.*s\n",
dfbuffer.first_level_msg_len-4,
dfbuffer.first_level_msg_len-4,
dfbuffer.first_level_msg);
}
if (dfbuffer.second_level_msg_len > 0) {
fprintf(stderr,"%*.*s\n",
dfbuffer.second_level_msg_len-4,
dfbuffer.second_level_msg_len-4,
dfbuffer.second_level_msg);
}
}
else {
#ifdef FETCH
fprintf(stderr,"GGMVS: Cannot fetch IKJEFF18\n");
#else
fprintf(stderr,"Cannot call IKJEFF18, not linked with GGMVS\n");
#endif
}
return;
}
./ ADD NAME=GGMDIR,SSI=01280045
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@DIR ")
#pragma csect(static,"GG$DIR ")
#include "gg.h"
/*********************************************************************/
static Bool
valid_code(c)
char c;
{
switch (c) {
case GOPHER_FILE:
case GOPHER_DIRECTORY:
case GOPHER_TELNET:
case GOPHER_WAIS:
case GOPHER_WHOIS:
return TRUE;
default: return FALSE;
}
}
/*********************************************************************/
static Bool
process_s_selection(gp,ip)
Rstruc ggcb *gp;
Rstruc gopherinfo *ip;
{
GGMgofor(gp,ip,FALSE);
return TRUE;
}
/*********************************************************************/
static Bool
process_e_selection(gp,ip)
Rstruc ggcb *gp;
Rstruc gopherinfo *ip;
{
if (ip->thdr.first_text_line) {
GGMxtx(gp,ip);
return TRUE;
}
else {
ERR1("Extract must be preceded by Select.");
return FALSE;
}
}
/*********************************************************************/
static Bool
process_q_selection(gp,ip)
Rstruc ggcb *gp;
Rstruc gopherinfo *ip;
{
GGMgofor(gp,ip,TRUE);
return TRUE;
}
/*********************************************************************/
static Bool
display_dynamic_area(gp,ip,infoarray,entrycount)
Rstruc ggcb *gp;
Rstruc gopherinfo *ip;
Rstruc gopherinfo *infoarray;
int entrycount;
{
struct gopherinfo *iap;
int depth;
int ggglvl;
int dynsize;
int topitem;
int bottomitem;
int last_item_selected;
int dti;
int gii;
int l;
int prc;
int command_index;
int zscrolln;
Bool selection_processed_ok;
Bool command_processed_ok;
Bool is_max;
char *gggdyna;
char *rowp;
char *cp;
char gggcmd [72];
char zverb [9];
char zscrolla [9];
char command [COMMANDSIZE];
char ggghead [81];
char rowmessage [81];
/* Get depth of dynamic area (number of rows to display on screen) */
(void)GGMispf(gp,
"PQUERY PANEL(GGMDIR) AREANAME(GGGDYNA) DEPTH(GGGDEPTH)");
if (gp->ispfrc != 0) return FALSE;
depth = GGMiget(gp,"GGGDEPTH ");
/* Get storage for ISPF dynamic area variable to be constructed. */
dynsize = 80*depth;
GETMAIN(gggdyna, char, dynsize, "GGGDYNA buffer");
if (!gggdyna) return FALSE;
/* Loop displaying the panel until END pressed. */
topitem = 0;
last_item_selected = -1;
strcpy(gggcmd,"");
do {
/* Fill in the dynamic area with rows, one for each gopher item. */
memset(gggdyna,' ',dynsize);
for (dti = 0, gii = topitem, rowp = gggdyna;
dti < depth && gii < entrycount;
dti++, gii++, rowp += 80) {
iap = &infoarray[gii];
rowp[ 0] = DATAIN_HIGH; /* selection code attribute */
rowp[ 1] = ' '; /* selection code field */
rowp[ 2] = DATAOUT_GREEN; /* icon attribute */
memcpy(&rowp[ 3],GGMtype(iap->type),9);
rowp[12] = DATAOUT_HIGH; /* description attribute */
l = strlen(iap->desc);
memcpy(&rowp[13],iap->desc,l > 67 ? 67 : l);
}
if (rowp < gggdyna + dynsize) {
rowp[0] = DATAOUT_HIGH;
memset(&rowp[1], '-',79);
}
bottomitem = gii - 1;
if (topitem > bottomitem) strcpy(rowmessage,"");
else sprintf(rowmessage, " %d-%d of %d",
topitem + 1, bottomitem + 1, entrycount);
memset(ggghead,' ',79);
ggghead[79] = '\0';
strcpy(ggghead,"GOPHER - ");
strncpy(ggghead+9,ip->desc,70);
*strchr(ggghead,'\0') = ' ';
memcpy(ggghead+79-strlen(rowmessage),rowmessage,strlen(rowmessage));
(void)GGMivput(gp,"GGGHEAD ",ggghead,79);
(void)GGMivput(gp,"GGGDYNA ",gggdyna, dynsize);
(void)GGMivput(gp,"GGGCMD " ,gggcmd, -1);
prc = GGMdispl(gp,"GGMDIR ");
if (prc > 8) break;
(void)GGMivget(gp,"GGGDYNA " , gggdyna, dynsize);
(void)GGMivget(gp,"ZVERB " , zverb, sizeof(zverb));
(void)GGMivget(gp,"ZSCROLLA ", zscrolla, sizeof(zscrolla));
zscrolln = GGMiget(gp,"ZSCROLLN ");
ggglvl = GGMiget(gp,"GGGLVL ");
last_item_selected = -1;
/* Process selections. */
for (gii = topitem, rowp = gggdyna;
gii <= bottomitem;
gii++, rowp += 80) {
iap = &infoarray[gii];
switch (rowp[1]) {
case ' ': continue;
case 's':
case 'S': selection_processed_ok = process_s_selection(gp,iap);
break;
case 'e':
case 'E': selection_processed_ok = process_e_selection(gp,iap);
break;
case 'q':
case 'Q': selection_processed_ok = process_q_selection(gp,iap);
break;
default:
ERR1("Unknown selection code. Type one of the listed codes.");
selection_processed_ok = FALSE;
break;
}
if (selection_processed_ok) last_item_selected = gii;
if (gp->quit) break;
}
/* Process command if any. */
strcpy(gggcmd,"");
(void)GGMivget(gp,"GGGCMD ",gggcmd,sizeof(gggcmd));
if (*gggcmd) {
memset(command,' ',COMMANDSIZE);
command_index = 0;
for (cp = gggcmd; *cp && !isspace(*cp); cp++) {
if (cp >= gggcmd+COMMANDSIZE) {
ERR1("Invalid command name.");
command_processed_ok = FALSE;
}
command[command_index++] = toupper(*cp);
}
while (*cp && isspace(*cp)) cp++;
if (memcmp(command,"QUIT ",8) == 0) {
gp->quit = TRUE;
}
else {
ERR2("Unknown command name: %8.8s",command);
}
command_processed_ok = FALSE;
if (command_processed_ok) strcpy(gggcmd,"");
}
if (gp->quit) break;
if (last_item_selected >= 0 && gp->autoscroll) {
topitem = last_item_selected;
}
/* Process scroll request if any. */
is_max = EQUAL(zscrolla,"MAX");
if (EQUAL(zverb,"DOWN")) {
if (is_max) topitem = entrycount - ggglvl;
else topitem += zscrolln;
}
else if (EQUAL(zverb,"UP")) {
if (is_max) topitem = 0;
else topitem -= zscrolln;
}
else if (EQUAL(zverb,"RETURN")) {
gp->quit = TRUE;
break;
}
if (topitem < 0)
topitem = 0;
if (topitem > entrycount)
topitem = entrycount;
} while (prc == 0);
return;
}
/****** Gopher a directory. ******************************************/
Bool
GGMdir(gp,ip,as_file)
Rstruc ggcb *gp;
Rstruc gopherinfo *ip;
Fool as_file;
{
int entrycount;
int i;
int copysize;
char typechar;
char savechar;
char *p;
char *q;
char *r;
struct textline *tp;
struct gopherinfo *infoarray;
struct gopherinfo *iap;
char temp[16];
if (as_file) {
GGMvtx(gp,ip,as_file); /* if as a file, display text as is */
return TRUE;
}
/* The text chain contains the data from the server, which should be
* in the following format:
*
* nDescription^Path^foo^bar
*
* where the "n" in the beginning is a digit and ^ means a tab char.
*
* Logic:
*
* Build an array of gopherinfo structs from the text records.
*
* Display them as an ISPF dynamic area pseudotable.
*
* Let the user select them, and run GGMgofor on each one
* with a struct gopherinfo built from the contents.
*
*/
/* Determine size of array of gopherinfo structs. This is equal to
* the number of text records with a valid code in the first byte.
*/
entrycount = 0;
for (tp = ip->thdr.first_text_line; tp; tp = tp->next) {
if (valid_code(tp->text[0])) entrycount++;
}
if (entrycount == 0) {
ERR1("There seems to be no information in this directory.\n");
return FALSE;
}
/* Allocate an array of structs to hold the stuff. */
GETMAIN(infoarray, struct gopherinfo, entrycount,"gopherinfo array");
if (!infoarray) {
ERR2("Not enough memory for %d gopher directory entries\n",
entrycount);
return FALSE;
}
/* Build the array entries. */
iap = infoarray;
for (tp = ip->thdr.first_text_line; tp; tp = tp->next) {
typechar = tp->text[0];
if (valid_code(typechar)) {
r = &tp->text[tp->text_length];
savechar = *r;
*r = '\t';
memset(iap,0,sizeof(struct gopherinfo));
iap->port = GOPHER_PORT_NUMBER;
iap->type = (gophertype)typechar;
p = &tp->text[1];
q = strchr(p,'\t');
copysize = sizeof(iap->desc)-1;
if (copysize > q-p) copysize = q-p;
memcpy(iap->desc,p,copysize);
if (q < r) {
p = q+1;
q = strchr(p,'\t');
copysize = sizeof(iap->path)-1;
if (copysize > q-p) copysize = q-p;
memcpy(iap->path,p,copysize);
if (q < r) {
p = q+1;
q = strchr(p,'\t');
copysize = sizeof(iap->host)-1;
if (copysize > q-p) copysize = q-p;
memcpy(iap->host,p,copysize);
if (q < r) {
p = q+1;
q = strchr(p,'\t');
memset(temp,0,sizeof(temp));
copysize = sizeof(temp)-1;
if (copysize > q-p) copysize = q-p;
memcpy(temp,p,copysize);
iap->port = atoi(temp);
}
}
}
*r = savechar;
iap++;
}
}
if (gp->debug_mode) {
for (iap = infoarray, i = entrycount; i > 0; iap++, i--) {
fprintf(gp->debug_file,"GGMdir: type = %d\n",iap->type);
fprintf(gp->debug_file,"GGMdir: port = %d\n",iap->port);
fprintf(gp->debug_file,"GGMdir: path = %s\n",iap->path);
fprintf(gp->debug_file,"GGMdir: host = %s\n",iap->host);
fprintf(gp->debug_file,"GGMdir: desc = %s\n",iap->desc);
fprintf(gp->debug_file,"\n");
}
}
display_dynamic_area(gp,ip,infoarray,entrycount);
FREEMAIN(infoarray,"gopherinfo array");
return TRUE;
}
./ ADD NAME=GGMDISC,SSI=01050033
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@DISC ")
#pragma csect(static,"GG$DISC ")
#include "gg.h"
/****** Disconnect from gopher server. ********************************/
void
GGMdisc(gp)
Rstruc ggcb *gp;
{
int closerc;
struct recvstruct *R;
/* If local mode, close temporary file and return. */
if ((R=gp->recvp)) {
if (R->outfp) {
if (fclose(R->outfp) < 0) {
CRIT1("Error closing local mode temporary file");
}
R->outfp = NULL;
}
gp->connected_to_server = FALSE;
FREEMAIN(gp->recvp,"local mode recv struct");
gp->recvp = NULL;
return;
}
gp->reconnect_in_progress = FALSE;
gp->closing_connection = TRUE;
if (gp->connection_broken) {
if (gp->debug_file) {
fprintf(gp->debug_file,
"Client %s (%s) connection with gopher server on %s (%s) was lost\n",
gp->client_hostname,
gp->client_ip_addrstr,
gp->server_hostname,
gp->server_ip_addrstr);
}
gp->connected_to_server = FALSE;
}
else {
/* In case of some kind of protocol error, don't let things hang. */
GGMesrvr(gp); /* End server read */
if (gp->debug_file) {
fprintf(gp->debug_file,
"Client %s (%s) disconnecting from gopher server on %s (%s)\n",
gp->client_hostname,
gp->client_ip_addrstr,
gp->server_hostname,
gp->server_ip_addrstr);
}
(void)GGMivput(gp,"GGSOLDER ",gp->server_hostname,-1);
(void)GGMivput(gp,"GGSOLDIP ",gp->server_ip_addrstr,-1);
(void)GGMispf(gp,"CONTROL DISPLAY LOCK");
(void)GGMispf(gp,"DISPLAY PANEL(GGMLDISC)");
/* In case of some kind of protocol error, don't let things hang. */
GGMesrvr(gp); /* End server read */
gp->connected_to_server = FALSE;
TCP_DEBUG_ON;
closerc = close(gp->socknum);
TCP_DEBUG_OFF;
if (closerc < 0) {
ERR2("TCP/IP error: close() failed to disconnect from server %s.",
gp->ggserver);
}
}
return;
}
./ ADD NAME=GGMDISPL,SSI=01000005
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
/********************************************************************/
#pragma csect(code, "GG@DISPL")
#pragma csect(static,"GG$DISPL")
#include "gg.h"
#define VL_BIT(X) ((unsigned int)(X) | 0x80000000)
/****** Display ISPF panel. ******************************************/
int
GGMdispl(gp,pan8)
Rstruc ggcb *gp;
char *pan8;
{
if (gp->setmsg) {
gp->ispfrc = ISPLINK("DISPLAY ", pan8, VL_BIT("ISRZ002 "));
}
else {
gp->ispfrc = ISPLINK("DISPLAY ", VL_BIT(pan8));
}
if (gp->ispfrc > 8) GGMierr(gp); /* display ISPF error */
gp->setmsg = FALSE;
return gp->ispfrc;
}
./ ADD NAME=GGMDUMP,SSI=01000036
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@DUMP ")
#pragma csect(static,"GG$DUMP ")
#include "gg.h"
/****** Dump some data. **********************************************/
void
GGMdump(struct ggcb *gp, char *label, char *p,int r)
{
int i;
if (!gp->debug_file) return;
if (r == -2) {
fprintf(gp->debug_file,"%s: %d\n",label,(int)p);
return;
}
if (r == -1) r = strlen(p);
fprintf(gp->debug_file,"%s: (%d characters)\n",label,r);
for (i=0;i<77;i++) fprintf(gp->debug_file,"-");
fprintf(gp->debug_file,"\n");
for (i=0;i<r;i++) {
char c = *(p+i);
if (isprint(c)) fprintf(gp->debug_file,"%c",c);
else fprintf(gp->debug_file,"<0x%2.2x>",c);
}
fprintf(gp->debug_file,"\n");
for (i=0;i<77;i++) fprintf(gp->debug_file,"-");
fprintf(gp->debug_file,"\n");
return;
}
./ ADD NAME=GGMESRVR,SSI=01020000
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@ESRVR")
#pragma csect(static,"GG$ESRVR")
#include "gg.h"
/****** End server read. *********************************************/
void
GGMesrvr(gp)
Rstruc ggcb *gp;
{
char *lp;
Bool found_more_server_data = FALSE;
GGMclrtx(gp,NULL); /* Clear text */
if (gp->recvp) return; /* Skip if non-socket */
do {
if (GGMgsrvl(gp,&lp)) { /* Get server line */
if (lp) {
found_more_server_data = TRUE;
(void)GGMouttx(gp,lp,NULL); /* Output text line */
}
}
} while (lp);
if (found_more_server_data) {
ERR1(
"More data was returned by the GOPHER server than GOPHER expected."
);
GGMvtx(gp,NULL,TRUE); /* View text */
}
return;
}
./ ADD NAME=GGMFREEM,SSI=01000001
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@FREEM")
#pragma csect(static,"GG$FREEM")
#include "gg.h"
/****** Free memory. *************************************************/
void
GGMfreem(gp,stuff,whatfor)
Rstruc ggcb *gp;
char *stuff;
char *whatfor;
{
free(stuff);
if (gp->debug_file) {
fprintf(gp->debug_file,"GGMfreem: freed memory for %s\n", whatfor);
}
return;
}
./ ADD NAME=GGMGETDS,SSI=01020011
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
/********************************************************************/
#pragma csect(code, "GG@GETDS")
#pragma csect(static,"GG$GETDS")
#include "gg.h"
#define DUMMY_FILE_POINTER_FOR_PDS (FILE *)(-1)
/****** Prompt user for the name of a data set to extract into. ******/
FILE *
GGMgetds(gp,ep)
Rstruc ggcb *gp;
Rstruc extraction *ep;
{
FILE *xfp;
Bool asked_for;
char ggexdsn[65]; /* data set name for extraction */
char ggexapp [4]; /* YES or NO for append mode */
char ggextab [4]; /* YES or NO for tab expansion */
char ggexblk [4]; /* YES or NO for blank after sep*/
char ggexsep[81]; /* Separator line (optional) */
char ggexan1[16]; /* From article number */
char ggexan2[16]; /* To article number */
char ggexpmp [9]; /* PDS member name prefix */
char ddname [9];
char member [9];
char pdspec [32];
char quoted_dsname [67];
char formatted_number [11];
/* Display panel asking for data set name into which to extract. */
xfp = NULL;
asked_for = TRUE;
(void)GGMispf(gp,"ADDPOP");
while (xfp == NULL) {
/* Keep asking for a dsname until one works or END pressed. */
if (GGMdispl(gp,ep->panelname) > 0) {
asked_for = FALSE;
xfp = NULL;
break;
}
(void)GGMivget(gp,"GGEXDSN ",ggexdsn,sizeof(ggexdsn));
(void)GGMivget(gp,"GGEXTAB ",ggextab,sizeof(ggextab));
(void)GGMivget(gp,"GGEXAN1 ",ggexan1,sizeof(ggexan1));
(void)GGMivget(gp,"GGEXAN2 ",ggexan2,sizeof(ggexan2));
if (ep->mode == PDS) {
(void)GGMivget(gp,"GGEXPMP ",ggexpmp,sizeof(ggexpmp));
}
else {
(void)GGMivget(gp,"GGEXAPP ",ggexapp,sizeof(ggexapp));
(void)GGMivget(gp,"GGEXBLK ",ggexblk,sizeof(ggexblk));
(void)GGMivget(gp,"GGEXSEP ",ggexsep,sizeof(ggexsep));
}
if (ep->mode == PDS) {
ep->appending = FALSE;
ep->blanking = FALSE;
strcpy(ep->separator,"");
strcpy(ep->ddname,"");
strcpy(ep->member_prefix,ggexpmp);
/* Note: panel forces fully-qualified name to pass to allocate */
/* check if the PDS already exists */
if (ggexdsn[0] != '\'') {
strcpy(quoted_dsname,"'");
strcat(quoted_dsname,ggexdsn);
strcat(quoted_dsname,"'");
}
else strcpy(quoted_dsname,ggexdsn);
/* Check if PDS already exists. */
if (gp->warn_overwrite) {
xfp = fopen(quoted_dsname,"r");
if (xfp) {
(void)fclose(xfp);
xfp = NULL;
if (GGMdispl(gp,"GGMPEXPW") > 0) {
WARN1("Operation cancelled, because you pressed END.");
break;
}
}
}
if (GGMalloc(ggexdsn,ep->ddname,PDS,ep->count) != PDS) {
ERR2("Allocation failed for data set %s.", ggexdsn);
xfp = NULL;
continue;
}
strcpy(ep->dsname, ggexdsn);
}
else {
strcpy(ep->separator, ggexsep);
strcpy(ep->dsname, ggexdsn);
ep->appending = (ggexapp[0] == 'Y');
ep->blanking = (ggexblk[0] == 'Y');
}
ep->tab_expanding = (ggextab[0] == 'Y');
if (*ggexan1) ep->from_number = atoi(ggexan1);
else ep->from_number = 0;
if (*ggexan2) ep->to_number = atoi(ggexan2);
else ep->to_number = INT_MAX;
/* check if the dataset already exists */
/* (Wonder if this will compile. Have fun, "cc"...) */
if (ep->appending ? gp->warn_append : gp->warn_overwrite) {
xfp = fopen(ggexdsn,"r");
if (xfp) {
(void)fclose(xfp);
xfp = NULL;
if (GGMdispl(gp,"GGMPEXOW") > 0) {
WARN1("Operation cancelled, because you pressed END.");
break;
}
}
}
if (ep->mode == PDS) {
xfp = DUMMY_FILE_POINTER_FOR_PDS;
break;
}
xfp = OPEN_TEXT_FILE_FOR_WRITE_OR_APPEND(ggexdsn,ep->appending);
if (!xfp) {
perror(ggexdsn);
ERR2("Cannot open data set %s.", ep->dsname);
}
}
(void)GGMispf(gp,"REMPOP");
return xfp;
}
./ ADD NAME=GGMGETM,SSI=01000052
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@GETM ")
#pragma csect(static,"GG$GETM ")
#include "gg.h"
/****** Get memory. **************************************************/
void
GGMgetm(gp,pointer,howmuch,whatfor)
Rstruc ggcb *gp;
char **pointer;
int howmuch;
char *whatfor;
{
*pointer = (char *)malloc(howmuch);
if (*pointer == NULL) {
fprintf(stderr,"GGMgetm: Cannot obtain %d bytes of memory for %s\n",
howmuch,whatfor);
}
else if (gp->debug_file) {
fprintf(gp->debug_file,"GGMgetm: got %d bytes of memory for %s\n",
howmuch,whatfor);
}
return;
}
./ ADD NAME=GGMGOFOR,SSI=01180001
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@GOFOR")
#pragma csect(static,"GG$GOFOR")
#include "gg.h"
/********************************************************************/
static Bool
connect_to_gopher_server(gp,ip)
Rstruc ggcb *gp;
Rstruc gopherinfo *ip;
{
char *lp;
Bool got_some;
strcpy(gp->ggserver,ip->host); /* Specify server to connect to */
strcpy(gp->gopher_command,ip->path); /* Specify command to issue */
gp->ginfo = ip;
gp->receiving_text = FALSE;
if (!GGMconn(gp)) return FALSE; /* Connect to gopher server */
if (!GGMsockt(gp)) return FALSE; /* Send socket command to server */
GGMclrtx(gp,ip); /* Clear text */
gp->receiving_text = TRUE;
got_some = FALSE;
do {
if (GGMgsrvl(gp,&lp)) /* Get server line */
if (lp) {
got_some = TRUE;
(void)GGMouttx(gp,lp,ip); /* Output text line */
}
} while (lp); /* until no more lines */
if (!got_some) {
WARN2("No data available from server %s.\n",gp->ggserver);
return FALSE;
}
return TRUE;
}
/****** Gopher it. ***************************************************/
Bool
GGMgofor(gp,ip,as_file)
Rstruc ggcb *gp;
Rstruc gopherinfo *ip;
Fool as_file;
{
Bool goconnect;
Bool (*gofun)(struct ggcb *,struct gopherinfo *,Fool);
/* (1) send initial path string to initial host
* (2) get back data from host
* (3) if it is a gopher directory, then do:
* - display "table" of items
* - for each item selected, call GGMgofor recursively
* else browse the file data
* (4) bye
*/
if (gp->debug_mode) {
fprintf(gp->debug_file,"GGMgofor: type = %d\n",ip->type);
fprintf(gp->debug_file,"GGMgofor: port = %d\n",ip->port);
fprintf(gp->debug_file,"GGMgofor: path = %s\n",ip->path);
fprintf(gp->debug_file,"GGMgofor: host = %s\n",ip->host);
fprintf(gp->debug_file,"GGMgofor: desc = %s\n",ip->desc);
}
switch (ip->type) {
case GOPHER_FILE: gofun = GGMvtx; goconnect = TRUE; break;
case GOPHER_DIRECTORY: gofun = GGMdir; goconnect = TRUE; break;
case GOPHER_TELNET: gofun = GGMtnet; goconnect = FALSE; break;
case GOPHER_WAIS: gofun = GGMwais; goconnect = FALSE; break;
case GOPHER_WHOIS: gofun = GGMwhois; goconnect = FALSE; break;
default:
ERR2("Sorry, access via %s not supported", GGMtype(ip->type));
return FALSE;
}
if (goconnect) {
if (!connect_to_gopher_server(gp,ip)) return FALSE;
}
/* Insure no connection is active once we do the real thing. */
if (gp->connected_to_server) {
(void)GGMdisc(gp); /* Disconnect from gopher server */
}
return (gofun)(gp,ip,as_file);
}
./ ADD NAME=GGMGSRVL,SSI=010F0030
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@GSRVL")
#pragma csect(static,"GG$GSRVL")
#include "gg.h"
/****** Input one character from the server. *************************/
static int
socket_getchar(gp)
Rstruc ggcb *gp;
{
int readrc;
if (gp->g_buf_index == -1 ||
gp->g_buf_index >= gp->g_bytes_returned - 1) {
gp->g_buf_index = -1;
if (gp->dont_read) return(SOCKET_NO_MORE);
else {
TCP_DEBUG_ON;
readrc = read(gp->socknum, gp->g_buf, READ_BYTES);
TCP_DEBUG_OFF;
if (readrc == -1) {
gp->connection_broken = TRUE;
return SOCKET_GETCHAR_ERROR;
}
else if (readrc == 0) {
gp->connection_broken = FALSE;
return SOCKET_READ_NOTHING;
}
else {
#ifdef MVS
int i;
for (i=0;i<readrc;i++) gp->g_buf[i] = atoe(gp->g_buf[i]);
#endif
gp->g_bytes_returned = readrc;
}
}
}
return gp->g_buf[++gp->g_buf_index];
}
/****** Input one data line at a time from the server. ***************/
static enum socket_retval
socket_from_server(gp)
Rstruc ggcb *gp;
{
char *s_buf;
int s_bytes;
int s_buf_index;
int character;
int previous_character;
s_buf = gp->server_buf;
s_bytes = SERVER_BUF_MSGSIZE;
/* Get characters from the server until CRLF is reached. */
s_buf_index = 0;
previous_character = -1;
for (;;) {
character = socket_getchar(gp);
/*
if (character == LINE_FEED && previous_character == CARRIAGE_RETURN)
break;
*/
if (character == LINE_FEED) break;
if (character == SOCKET_GETCHAR_ERROR) return(SERVER_READ_ERROR);
if (character == SOCKET_NO_MORE) return(SERVER_NO_MORE);
if (character == SOCKET_READ_NOTHING) return(SERVER_READ_NOTHING);
previous_character = character;
if (s_buf_index >= s_bytes) {
fprintf(stderr,"Error: gp->server_buf overflowed.\n");
fprintf(stderr,
"More than %d bytes collected without CR/LF seen.\n",
s_bytes);
if (gp->debug_file) {
GGMdump(gp,"Data collected so far",gp->server_buf,s_bytes);
}
return(SERVER_BUFFER_ERROR);
}
if (character == '\0') {
fprintf(stderr,
"Warning: null character found in data from server, changed to blank\n"
);
character = ' ';
}
s_buf[s_buf_index++] = (unsigned char)character;
}
s_buf[s_buf_index] = '\0';
return(SERVER_READ_OK);
}
/****** Get server line. *********************************************/
Bool
GGMgsrvl(gp,pointer)
Rstruc ggcb *gp;
char **pointer;
{
char *sbufp;
char *p;
int scan_count;
Bool something_to_print;
struct recvstruct *R;
*pointer = NULL;
/* If local mode, read from temporary file until EOF. */
if ((R=gp->recvp)) {
if (!R->outfp) {
CRIT1("Can't read data locally, non-socket not connected\n");
return FALSE;
}
fgets(gp->server_buf, SERVER_BUF_MSGSIZE, R->outfp);
if (ferror(R->outfp)) {
CRIT1("Error reading local non-socket data\n");
gp->time_to_go_home = TRUE;
return FALSE;
}
if (feof(R->outfp)) return FALSE;
if ((p=strchr(gp->server_buf,'\n'))) *p = '\0';
*pointer = gp->server_buf;
return TRUE;
}
if (!gp->receiving_text) return TRUE;
if (gp->server_finished_replying) gp->dont_read = TRUE;
switch (socket_from_server(gp)) {
case SERVER_READ_OK: break;
case SERVER_READ_NOTHING: gp->time_to_go_home = TRUE;
break;
case SERVER_READ_ERROR: ERR2(
"Lost server connection. Failure reading data from server %s.",
gp->ggserver);
gp->time_to_go_home = TRUE;
break;
case SERVER_BUFFER_ERROR: ERR2(
"Read error. No linefeed character found in data from server %s.",
gp->ggserver);
gp->time_to_go_home = TRUE;
break;
case SERVER_NO_MORE: gp->server_has_something_pending = FALSE;
break;
}
if (gp->time_to_go_home == TRUE) return FALSE;
if (gp->dont_read == TRUE &&
gp->server_has_something_pending == FALSE) return TRUE;
something_to_print = TRUE;
sbufp = gp->server_buf;
if (gp->sending_text) {
if (*sbufp == '.') {
switch (*(sbufp+1)) {
case CARRIAGE_RETURN:
case LINE_FEED:
case '\0':
gp->server_finished_replying = TRUE;
something_to_print = FALSE;
break;
case '.':
break;
default:
GGMdump(gp,"Warning, bad period in line from server",
sbufp,strlen(sbufp));
break;
}
}
}
gp->sending_text = TRUE;
if (something_to_print) {
/* Last character of output buffer is a CR without LF. */
p = sbufp + strlen(sbufp)-1;
if (p >= sbufp) {
if (*p == CARRIAGE_RETURN) *p = '\0';
else {
/* Last character of output buffer had better be a LF. */
if (gp->debug_file) {
fprintf(gp->debug_file,
"Warning: No carriage return in data from server (%d bytes):\n%s\n",
strlen(sbufp), sbufp);
}
CRIT2(
"Carriage return expected but not seen in data from server %s.",
gp->ggserver);
}
*(p+1) = '\0';
}
*pointer = sbufp;
}
if (gp->time_to_go_home) return FALSE;
else return TRUE;
}
./ ADD NAME=GGMIERR,SSI=01000000
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@IERR ")
#pragma csect(static,"GG$IERR ")
#include "gg.h"
/****** ISPF error handler. ******************************************/
void
GGMierr(gp)
Rstruc ggcb *gp;
{
char errbuf[] = "DISPLAY PANEL(ISPTERM)";
int errlen;
errlen = strlen(errbuf);
switch (ISPEXEC(&errlen,errbuf)) {
case 0:
case 4:
case 8:
return;
default:
fprintf(stderr,
"\n*** Severe ISPF error, cannot even display ISPTERM error panel.\n");
fprintf(stderr,
"\n*** Return code from ISPF service is %d\n",gp->ispfrc);
return;
}
}
./ ADD NAME=GGMIGET,SSI=01000045
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@IGET ")
#pragma csect(static,"GG$IGET ")
#include "gg.h"
/****** Retrieve the value of an ISPF variable into an integer. ******/
int
GGMiget(gp,varname)
Rstruc ggcb *gp;
char *varname;
{
char varbuf[16];
int vcopy_length;
if (!strchr(varname,' ')) {
fprintf(stderr,"GGMiget: no blank passed in var name\n");
return FALSE;
}
vcopy_length = sizeof(varbuf);
gp->ispfrc = ISPLINK("VCOPY",varname,&vcopy_length,varbuf,"MOVE");
switch (gp->ispfrc) {
case 0:
varbuf[vcopy_length] = '\0';
return atoi(varbuf);
case 8:
return 0;
case 16:
fprintf(stderr,
"Error: ISPF variable buffer too short to get %s\n",
varname);
return 0;
default:
GGMierr(gp); /* handle ISPF error */
return 0;
}
}
./ ADD NAME=GGMISPF,SSI=01000016
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@ISPF ")
#pragma csect(static,"GG$ISPF ")
#include "gg.h"
/****** Call ISPF service. *******************************************/
Bool
GGMispf(gp,ispfbuf)
Rstruc ggcb *gp;
char *ispfbuf;
{
int ispflen;
ispflen = strlen(ispfbuf);
gp->ispfrc = ISPEXEC(&ispflen,ispfbuf);
if (gp->ispfrc > 8) {
/* Ignore ADDPOP and REMPOP errors, especially if they are due to
ISPF V3 not being active. */
if (gp->ispfrc == 20
&& gp->debug_mode == FALSE
&& ispflen > 6
&& (memcmp(ispfbuf,"ADDPOP",6) == 0
|| memcmp(ispfbuf,"REMPOP",6) == 0)) {
return TRUE;
}
GGMierr(gp); /* handle ISPF error */
return FALSE;
}
return TRUE;
}
./ ADD NAME=GGMIVGET,SSI=01000024
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@IVGET")
#pragma csect(static,"GG$IVGET")
#include "gg.h"
/****** Retrieve the value of an ISPF variable. **********************/
Bool
GGMivget(gp,varname,varbuf,varbuflen)
Rstruc ggcb *gp;
char *varname;
char *varbuf;
int varbuflen;
{
int vcopy_length;
if (!strchr(varname,' ')) {
fprintf(stderr,"GGMivget: no blank passed in var name\n");
return FALSE;
}
/*
* If varbuflen is negative, that means that the value is not to be
* treated as a C string, and the null character is not to be
* appended to the resulting value. This is used for hex values
* (like addresses) that are stored in ISPF table row variables.
*/
if (varbuflen < 0) vcopy_length = -varbuflen;
else vcopy_length = varbuflen;
/* Note that on entry, vcopy_length is an integer that contains
the length of the buffer. On return it is updated to the length
of the value returned. Since we have to stick a null character
on the end of it for C, the actual buffer passed must be at least
one character longer than the length as defined to ISPF.
*/
gp->ispfrc = ISPLINK("VCOPY",varname,&vcopy_length,varbuf,"MOVE");
switch (gp->ispfrc) {
case 0:
if (varbuflen >= 0)
varbuf[vcopy_length] = '\0';
return TRUE;
case 8:
strcpy(varbuf,"");
return TRUE;
case 16:
fprintf(stderr,
"Error: ISPF variable buffer too short to get %s\n",
varname);
return FALSE;
default:
GGMierr(gp); /* handle ISPF error */
return FALSE;
}
}
./ ADD NAME=GGMIVPUT,SSI=01000024
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@IVPUT")
#pragma csect(static,"GG$IVPUT")
#include "gg.h"
/****** Set the value of an ISPF variable. ***************************/
Bool
GGMivput(gp,varname,varbuf,varlen)
Rstruc ggcb *gp;
char *varname;
char *varbuf;
int varlen;
{
int vreplace_length;
vreplace_length = (varlen<0 ? strlen(varbuf) : varlen);
gp->ispfrc = ISPLINK("VREPLACE",varname,&vreplace_length,varbuf);
switch (gp->ispfrc) {
case 0:
return TRUE;
case 16:
fprintf(stderr,
"Error: ISPF variable buffer too short to put %s\n",
varname);
return FALSE;
default:
GGMierr(gp); /* handle ISPF error */
return FALSE;
}
}
./ ADD NAME=GGMMTFER,SSI=01030000
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@MTFER")
#pragma csect(static,"GG$MTFER")
#include "gg.h"
/*********************************************************************/
void
GGMmtfer(
int retcode,
char *kind)
{
char *ermsg;
switch (retcode) {
case MTF_OK:
ermsg = NULL;
break;
case EINACTIVE:
ermsg = "MTF is inactive";
break;
case ESUBCALL:
ermsg = "The MTF call was issued from a subtask";
break;
case EWRONGOS:
ermsg = "MTF is not supported under CMS, IMS, CICS, or DB2";
break;
case EACTIVE:
ermsg = "MTF has already been initialized and is active";
break;
case ENAME2LNG:
ermsg = "The parallel module name is longer than 8 characters";
break;
case ETASKNUM:
ermsg = "The number of tasks specified is invalid";
break;
case ENOMEM:
ermsg = "Insufficient storage for MTF internal areas";
break;
case EMODFIND:
ermsg = "The parallel load module was not found";
break;
case EMODREAD:
ermsg = "The parallel load module was not sucessfully read";
break;
case EMODFMT:
ermsg = "The parallel load module format is invalid";
break;
case EAUTOALC:
ermsg = "Automatic allocation of standard stream DD failed";
break;
case ETASKFAIL:
ermsg = "The attempt to attach task(s) has failed";
break;
case ETASKABND:
ermsg = "One or more subtasks have abnormally terminated";
break;
case EBADLNKG:
ermsg = "TSCHED has been invoked via invalid linkage";
break;
case ETASKID:
ermsg = "The task ID specified is not valid";
break;
case EENTRY:
ermsg = "The parallel function was not in the parallel module";
break;
default:
ermsg = "Unknown MTF error";
break;
}
if (ermsg) {
fprintf(stderr,"GGSERVER: %s error code %d:\n %s\n",
kind, retcode, ermsg);
}
return;
}
./ ADD NAME=GGMOUTS,SSI=01030000
/********************************************************************/
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@MOUTS")
#pragma csect(static,"GG$MOUTS")
#include "gg.h"
/*
***********************************************************************
* *
* This is a Gopher server routine that outputs data to a socket. *
* *
* If the "socket" is actually a file pointer, then output is *
* written to the file pointer. *
* *
***********************************************************************
*/
/*=================================================================*/
Bool
GGMouts(struct recvstruct *R,
char *text)
{
int len;
int reallen;
Bool rc;
char outbuf[515]; /* hold an output character string */
if (R->outfp) { /* if using non-socket interface */
if (fputs(text,R->outfp) < 0) {
fprintf(stderr,"Error writing to output file\n");
return FALSE;
}
if (fputc('\n',R->outfp) < 0) {
fprintf(stderr,"Error writing to output file\n");
return FALSE;
}
return TRUE;
}
if (text == NULL) {
outbuf[0] = '.';
len = 1;
}
else {
len = strlen(text);
if (len >= sizeof(outbuf)-3) len = sizeof(outbuf)-3;
if (text[0] == '.') {
outbuf[0] = '.';
memcpy(outbuf+1,text,len);
len++;
}
else {
memcpy(outbuf,text,len);
}
}
outbuf[len ] = CARRIAGE_RETURN;
outbuf[len+1] = LINE_FEED;
outbuf[len+2] = '\0';
reallen = len + 2;
ebdtoasc(outbuf);
rc = TRUE;
if (R->outlen + reallen > sizeof(R->sockbuf)) {
if (write(R->sockfd,R->sockbuf,R->outlen) < 0) {
tcperror("SEND");
rc = FALSE;
}
R->outlen = 0;
}
memcpy(R->sockbuf + R->outlen, outbuf, reallen);
R->outlen += reallen;
if (text == NULL) { /* flush socket */
if (write(R->sockfd,R->sockbuf,R->outlen) < 0) {
tcperror("SEND");
rc = FALSE;
}
}
return rc;
}
./ ADD NAME=GGMOUTTX,SSI=01010057
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@OUTTX")
#pragma csect(static,"GG$OUTTX")
#include "gg.h"
/****** Output a line of text retrieved from the server. *************/
struct textline *
GGMouttx(gp,line,ip)
Rstruc ggcb *gp;
char *line;
Rstruc gopherinfo *ip;
{
struct texthdr *thp;
struct textline *tp;
short line_length;
short total_text_length;
short tab_expansion_length;
Bool tabs_present;
char *p;
char *q;
char *t;
int e;
int u;
static char tab_expansion_buffer[8*TEXT_BYTES];
thp = (ip ? &ip->thdr : &gp->thdr);
/* If line starts with double period, make it a single period. */
if (ip && memcmp(line,"..",2) == 0) line++;
/* Add this line to the current queue of server text lines. */
/* First, expand tabs in the line. */
line_length = strlen(line);
t = strchr(line,'\t');
if (t == NULL) {
tabs_present = FALSE;
total_text_length = line_length + 1;
}
else { /* expand tabs */
tabs_present = TRUE;
p = line;
q = line + line_length;
e = 0;
memset(tab_expansion_buffer,' ',sizeof(tab_expansion_buffer));
while (TRUE) {
u = t-p;
if (u > 0) {
memcpy(tab_expansion_buffer+e,p,u);
e += u;
}
if (t == q) break;
e = e / 8 * 8 + 8;
p = t+1;
t = strchr(p,'\t');
if (t == NULL) t = q;
}
tab_expansion_length = e;
tab_expansion_buffer[tab_expansion_length] = '\0';
total_text_length = line_length + tab_expansion_length + 1;
}
GETMAIN(tp, char, offsetof(struct textline, text) + total_text_length,
"text line");
if (tp == NULL) {
ERR1("There is not enough virtual storage to process server text.");
return NULL;
}
tp->next = NULL;
tp->text_length = line_length;
strcpy(tp->text,line);
if (tabs_present) {
tp->tab_expanded_text_length = tab_expansion_length;
tp->tab_expanded_text = tp->text + line_length;
strcpy(tp->tab_expanded_text,tab_expansion_buffer);
}
else {
tp->tab_expanded_text_length = line_length;
tp->tab_expanded_text = tp->text;
}
if (thp->last_text_line == NULL) {
thp->first_text_line = tp;
thp->text_body_line = tp;
thp->current_text_line = tp;
}
else thp->last_text_line->next = tp;
thp->last_text_line = tp;
thp->text_line_count++;
if (thp->text_max_length < tp->text_length)
thp->text_max_length = tp->text_length;
if (thp->text_max_tab_expanded_length < tp->tab_expanded_text_length)
thp->text_max_tab_expanded_length = tp->tab_expanded_text_length;
return tp;
}
./ ADD NAME=GGMPMSG,SSI=01000057
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#define SUPPRESS_V_DECLARATION
#pragma csect(code, "GG@PMSG ")
#pragma csect(static,"GG$PMSG ")
#include "gg.h"
/****** Set an ISPF message, or write to SYSOUT if batch mode. *******/
void
GGMpmsg(gp,msgtype,msghelp,msgformat) /* also ... for sprintf args */
Rstruc ggcb *gp;
int msgtype;
char *msghelp;
char *msgformat;
{
va_list argp;
char *cp;
char zerrsm [25];
char zerrhm [9];
char zerralrm [4];
char zerrlm [73];
char buf [257];
va_start(argp,msgformat);
vsprintf(buf,msgformat,argp);
va_end(argp);
cp = strchr(buf,';');
if (cp) {
*cp = '\0';
strncpy(zerrsm,buf, sizeof(zerrsm));
strncpy(zerrlm,cp+1,sizeof(zerrlm));
}
else {
strcpy(zerrsm,"");
strncpy(zerrlm,buf,sizeof(zerrlm));
}
zerrsm[sizeof(zerrsm)-1] = '\0';
zerrlm[sizeof(zerrlm)-1] = '\0';
if (msghelp) strcpy(zerrhm, msghelp);
else strcpy(zerrhm, "*" );
switch (msgtype) {
case NOTIFY_MSG: strcpy(zerralrm,"NO "); break;
case WARNING_MSG:
case CRITICAL_MSG:
default: strcpy(zerralrm,"YES"); break;
}
(void)GGMivput(gp,"ZERRSM ", zerrsm, -1);
(void)GGMivput(gp,"ZERRLM ", zerrlm, -1);
(void)GGMivput(gp,"ZERRHM ", zerrhm, -1);
(void)GGMivput(gp,"ZERRALRM ",zerralrm, -1);
if (gp->brifp) {
(void)GGMispf(gp,"SETMSG MSG(ISRZ002)");
}
else {
gp->setmsg = TRUE;
}
return;
}
./ ADD NAME=GGMPROC,SSI=010F0022
/********************************************************************/
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@MPROC")
#pragma csect(static,"GG$MPROC")
#pragma linkage(IRXEXEC,OS)
#include "gg.h"
/*=================================================================*/
/*******************************************************************/
/* This routine cleans up a token. It converts all chars to */
/* upper case and removes any leading spaces. Note that the */
/* string is assumed to be null terminated. */
/* */
/* INPUT token pointer to token string. */
/* OUTPUT *token string upcased, blanks removed. */
/*******************************************************************/
static char *
uppercase_and_trim_leading_space(char *token)
{
uppercase_in_place(token);
return token + strspn(token," ");
};
/*=================================================================*/
/****************************************************/
/* This routine "cleans" a string by removing the */
/* leading spaces and trailing spaces+non-printable */
/* characters. */
/****************************************************/
static char *
trim_leading_and_trailing_space(char *string)
{
char *str;
char *ptr;
/* first clean up the beginning of the string... */
str = string + strspn(string," \t");
/* now look at the end of the string... */
ptr = str+strlen(str)-1;
while (!isgraph(*ptr) && ptr >=str) ptr--;
*(ptr+1)=0;
return str;
}
/*=================================================================*/
/****************************************************/
/* This routine "cleans" an output line by removing */
/* trailing spaces and non-printable characters. */
/****************************************************/
static void
trim_trailing_space(char *string)
{
char *ptr;
ptr = string;
/* look at the end of the string... */
ptr = string+strlen(string)-1;
while (isgraph(*ptr)==0 && ptr >=string) ptr--;
*(ptr+1)=0;
}
/*=================================================================*/
static void
gbarf(struct recvstruct *R,
char *message)
{
char temp[257];
/* the number should be 2 (ERROR) but some clients may not show it
* |
* |
* |
* V
*/
sprintf(temp, "1Sorry, %s.\t0\t0\t0", message);
(void)GGMouts(R,temp);
return;
}
/*=================================================================*/
static Bool
insure_my_name(struct recvstruct *R)
{
/* Determine the local path name, if not already set. */
if (!*R->myname) {
if (gethostname(R->myname,MAXHOSTNAMELEN) < 0) {
fprintf(stderr,"GOPHER:gethostname() failed, can't get my name\n");
gbarf(R,"the GOPHER server had an attack of amnesia");
return FALSE;
}
}
return TRUE;
}
/*=================================================================*/
static Bool
authorized_file(struct recvstruct *R)
{
char *cp;
FILE *afp;
int n;
int hostcount;
Bool rc;
char filetest[RBUFSIZE];
char accline [RBUFSIZE];
char accfile [RBUFSIZE];
char acchost [RBUFSIZE];
/* If non-socket interface, bypass the authorization check. */
if (R->outfp) return TRUE;
/* Check that the server is allowed to return data from the file
* specified in R->fileptr. Note that this could be the name of
* an exec. The name will be (dataset), EXEC:execname, or DD:file
* - we look at only the first part, whitespace-delimited.
* Entries in the file authorization table look as above.
*/
rc = FALSE;
filetest[0] = '\0';
sscanf(R->fileptr,"%s",filetest);
/* Read authorization file. */
afp = fopen(ACCESS_TABLE,"r");
if (!afp) {
perror(ACCESS_TABLE);
fflush(stderr);
return FALSE;
}
for (;;) {
fgets(accline, sizeof(accline), afp);
if (ferror(afp)) {
fprintf(stderr,"Error reading access table %s\n",ACCESS_TABLE);
fflush(stderr);
break;
}
if (feof(afp)) break;
/* format of line is: filename machine(s) */
uppercase_in_place(accline);
cp = accline; /* Start scan pointer */
*accfile = '\0'; /* Clear access file name */
sscanf(cp,"%s %n",accfile,&n); /* Get file name, bump scan */
if (!strcmp(filetest,accfile)) { /* If file name matches */
hostcount = 0; /* Clear access host count */
for (;;) { /* Loop over access host ids */
cp += n; /* Bump to next word in file */
*acchost = '\0'; /* Clear word before scanf */
sscanf(cp,"%s %n",acchost,&n); /* Get next word, bump scan */
if (!*acchost) break; /* exit loop if no more hosts */
hostcount++; /* increment access host count*/
if (!strcmp(R->hostname,acchost)
|| !strcmp(R->hosttest,acchost)) { /* if hostname matches */
rc = TRUE; /* access is allowed */
break;
}
}
if (!rc) { /* If no matching host found */
if (hostcount == 0) rc = TRUE; /* if no access hosts, say OK */
}
if (rc) break; /* if access OK, finished */
/* If access is not permitted, we keep checking because
* there may be more than one entry in the access table
* for this file, so that many host names can be given.
*/
}
}
(void)fclose(afp);
if (!rc) {
fprintf(stderr,"Not authorized from %s: '%s'\n",
R->hosttest, filetest);
}
fflush(stderr);
return rc;
}
/*=================================================================*/
/*******************************************************************/
/* This routine determines what type of gopher file */
/* we've opened. We'll return the file type to the */
/* caller. */
/* */
/* INPUT: ident pointer to first line of file */
/* */
/* OUTPUT: MENU file type is a menu */
/* FILE file type is a file */
/* INDEX file type is an INDEX (not done) */
/*******************************************************************/
static char
getftype(char *ident)
{
int x; /* loop counter */
char buffer[RBUFSIZE];
char *bufptr;
/**********/
/* first, convert the string to upper case... */
/*********/
strcpy(buffer,ident);
bufptr = uppercase_and_trim_leading_space(buffer);
/**********/
/* return the type of file. */
/*********/
if(strcmp(bufptr,MENUIDENT)==0) return(MENU);
if(strcmp(bufptr,INDEXIDENT)==0) return(INDEX);
/**********/
/* don't know, so assume it's a "file" file... */
/*********/
return(GFILE);
}
/*=================================================================*/
/*******************************************************************/
/* This routine figures out what type of parm line */
/* the current line is. We'll return the token */
/* type to the caller. */
/* */
/* INPUT: buffer pointer to first line of file */
/* (Note: string must be null terminated! */
/* OUTPUT: Type of token. (See in include file...) */
/*******************************************************************/
static int
menukeywd(char *buffer,
char *token,
char *operand)
{
int x; /* loop counter */
char *tokval;
char *oprval;
char *tokptr;
char tokstr[256];
strcpy(tokstr,buffer);
tokval=strtok(tokstr,"=");
oprval=strtok(NULL,"");
strcpy(token,tokval);
strcpy(operand,oprval);
tokptr = uppercase_and_trim_leading_space(token);
/*********/
/* now look at the tokens to see if we have a weener... */
/*********/
if(strcmp(tokptr,TOKTYPE)==0) return(TYPETOK);
if(strcmp(tokptr,TOKNAME)==0) return(NAMETOK);
if(strcmp(tokptr,TOKPATH)==0) return(PATHTOK);
if(strcmp(tokptr,TOKHOST)==0) return(HOSTTOK);
if(strcmp(tokptr,TOKPORT)==0) return(PORTTOK);
if(strcmp(tokptr,TOKEND)==0) return(ENDTOK);
/* for back compatibility with the old MVS GOPHER server */
if(strcmp(tokptr,TOKDISPLAY)==0) return(DISPLAYTOK);
if(strcmp(tokptr,TOKSELECT)==0) return(SELECTTOK);
return(COMMENTTOK);
}
/*=================================================================*/
/*******************************************************************/
/* This routine reads a line from the specified file. */
/* if a read error occurs, an error message is printed and */
/* FALSE is returned. */
/* */
/* INPUT buffer pointer to buffer to place line */
/* readfile file structure to read from */
/* */
/* OUTPUT buffer line that was read from the file */
/* TRUE read worked ok */
/* FALSE read failed! */
/*******************************************************************/
static Bool
readaline(struct recvstruct *R)
{
memset(R->buffer,0,RBUFSIZE);
fread(R->buffer,RBUFSIZE,1,R->readfile);
if (ferror(R->readfile)) {
/* perror("FREAD"); */
fprintf(stderr,"GGSTASK: Error reading file\n");
return(FALSE);
}
trim_trailing_space(R->buffer); /* Remove trailing whitespace */
return(TRUE);
}
/*=================================================================*/
/*******************************************************************/
/* This routine sends a file to the calling client. */
/* It assumes the file is a text formatted file. */
/* INPUT: buffer pointer to the already read line... */
/* readfile file we're going to read from.. */
/* maxlen size of the buffer. */
/* sockfd socket descriptor for client. */
/* */
/* OUTPUT: send the file to the client */
/*******************************************************************/
static void
sendafile(struct recvstruct *R)
{
int x;
char *moveit;
/*******/
/* send the first line (cause we already read it) */
/*******/
if (!GGMouts(R,R->buffer)) return;
/*******/
/* get the rest of the lines of the file and send them... */
/*******/
for (;;) {
if (!readaline(R)) {
(void)GGMouts(R,"<<<*** I/O ERROR ON MVS FILE ***>>>");
return;
}
if (feof(R->readfile)) break;
if (!GGMouts(R,R->buffer)) return;
}
}
/*=================================================================*/
/*******************************************************************/
/* This routine formats a menu file into gopher data & sends it */
/* to the client. */
/* INPUT: buffer pointer to the already read line... */
/* readfile file we're going to read from.. */
/* maxlen size of the buffer. */
/* sockfd socket descriptor for client */
/* */
/* OUTPUT: send the menu to the client */
/*******************************************************************/
#define MENU_STUFF_SIZE GOPHER_DESC_LENGTH + \
GOPHER_PATH_LENGTH + \
GOPHER_HOST_LENGTH + 20
static void
sendamenu(struct recvstruct *R)
{
char *moveit;
char *operptr;
char *typeoftype; /*pointer for strtok */
char *cp;
int kindotoken;
int x; /* loop counter */
char token [133];
char operand [133];
char outbuf [MENU_STUFF_SIZE];
struct menuitem menu;
memset(&menu,0,sizeof menu );
for (;;) {
if (!readaline(R)) break;
if (feof(R->readfile)) break;
if (!*R->buffer) continue;
kindotoken = menukeywd(R->buffer,token,operand);
switch(kindotoken) {
case TYPETOK:
operptr = uppercase_and_trim_leading_space(operand);
typeoftype = strtok(operptr," ");
if (strlen(typeoftype) == 1) menu.type = *typeoftype;
else
if (EQUAL(typeoftype,TYPEFILE)) menu.type = GFILE;
else
if (EQUAL(typeoftype,TYPEMENU)) menu.type = MENU;
else
if (EQUAL(typeoftype,TYPEINDEX)) menu.type = INDEX;
else
if (EQUAL(typeoftype,TYPETELNET)) menu.type = TELNET;
else
if (EQUAL(typeoftype,TYPEWHOIS)) menu.type = WHOIS;
else menu.type = ERROR;
break;
case NAMETOK:
case DISPLAYTOK:
strncpy(menu.desc, operptr, sizeof(menu.desc));
break;
case PATHTOK:
case SELECTTOK:
strncpy(menu.select, operptr, sizeof(menu.select));
break;
case HOSTTOK:
if (EQUAL(operptr,IDENT_HOST_FROB)) { /* HOST=+ */
if (insure_my_name(R)) {
strncpy(menu.hostname, R->myname, sizeof(menu.hostname));
}
}
else {
strncpy(menu.hostname, operptr, sizeof(menu.hostname));
}
break;
case PORTTOK:
if (EQUAL(operptr,IDENT_HOST_FROB)) { /* PORT=+ */
menu.port = SERV_TCP_PORT;
}
else {
menu.port=atoi(operptr);
}
break;
case ENDTOK:
if (menu.type==TELNET && menu.port==0) menu.port=0; /* ??? */
else if (menu.port==0) menu.port=GOPHER_PORT_NUMBER;
/* If host is local and path is in the form "(member)",
* and current dsname is a PDS, then use same PDS:
* i.e. turn PATH=(FOOBAR) into PATH=AA.BB.CC(FOOBAR)
*/
if (*R->myname
&& EQUAL(menu.hostname,R->myname)
&& *menu.select == '(' /* ) */
&& (cp = strchr(R->dsname,'(' /* ) */ ))) {
memcpy(outbuf, R->dsname, (cp-R->dsname));
strcpy(outbuf+(cp-R->dsname), menu.select);
strncpy(menu.select, outbuf, sizeof(menu.select));
}
if (*menu.desc && *menu.hostname) {
sprintf(outbuf,"%c%s\t%s\t%s\t%d",
menu.type,menu.desc,
menu.select,menu.hostname,menu.port);
if (!GGMouts(R,outbuf)) return;
}
fflush(stdout);
memset(&menu,0,sizeof menu );
break;
default:
break;
}
}
}
/*=================================================================*/
static Bool
get_directory(struct recvstruct *R)
{
FILE *dirfile;
int i;
short block_count;
short bump_amount;
Bool reject;
Bool no_more;
char *cp;
char *mp;
char dirblk [256];
char pdsspec [256];
char entry [256];
/* The local path name is required for this function. */
if (!insure_my_name(R)) return FALSE;
if ((dirfile=fopen(R->buffer,"rb,recfm=u,lrecl=256")) == NULL) {
perror(R->buffer);
printf("Can't open PDS directory:%s\n",R->dsname);
gbarf(R,"the GOPHER server can't open the directory");
return(FALSE);
}
while (!feof(dirfile)) {
no_more = FALSE;
do {
memset(dirblk,0x00,256);
fread(dirblk,256,1,dirfile);
if (feof(dirfile)) break;
if (ferror(dirfile)) {
printf("Can't read PDS directory:%s\n", R->fileptr);
gbarf(R,"the GOPHER server can't read the directory");
fclose(dirfile);
return FALSE;
}
mp = dirblk;
block_count = *(short *)mp - 2; /* # bytes in dir block */
mp += 2; /* addr of dir block data */
while (block_count > 0) {
if (memcmp(mp,"\xff\xff\xff\xff\xff\xff\xff\xff",8)==0) break;
reject = FALSE;
/*
* Uncomment this if you want to skip aliases.
* It is recommended that you let aliases through, since
* they often have better names (e.g. TSO HELP files)
*
* if ((mp[11] & 0x80) != 0) {
* fprintf(stderr,"Skipping alias: %-8.8s\n",mp);
* reject = TRUE;
* }
*/
if (!reject) {
strcpy(pdsspec, R->dsname);
cp = strchr(pdsspec, '\0');
*(cp++) = '(';
for (i = 0; i < 8 && mp[i] != ' '; cp++, i++) *cp = mp[i];
*(cp++) = ')';
*cp = '\0';
sprintf(entry,"0%8.8s\t%s\t%s\t%d",
mp, pdsspec, R->myname, SERV_TCP_PORT);
(void)GGMouts(R,entry);
}
bump_amount = 12 + ((mp[11] & 0x1f) * 2);
mp += bump_amount;
block_count -= bump_amount;
}
} while(!no_more);
}
fclose(dirfile);
return TRUE;
}
/*=================================================================*/
static Bool
get_flat_file(struct recvstruct *R)
{
int x; /* loop counter*/
int numread; /* number of items read... */
char filetype; /* type of file we're dealing with*/
if ((R->readfile=fopen(R->buffer,"rb,type=record")) == NULL) {
perror(R->buffer);
printf("INVALID! requested:%s\n",R->fileptr);
gbarf(R,"the GOPHER server couldn't open the file");
return(FALSE);
}
/************/
/* get the first line and see what type of file we've got. */
/************/
if (readaline(R) && !feof(R->readfile)) {
filetype=getftype(R->buffer);
/************/
/* Now let's go do whatever we need to for this file type. */
/************/
switch(filetype) {
case MENU:
sendamenu(R);
break;
case GFILE:
default:
sendafile(R);
break;
}
}
if(fclose(R->readfile) < 0) {
/* perror("PROCESS CLOSE"); */
fprintf(stderr,"GGSTASK: Error closing file %s\n",R->fileptr);
gbarf(R,"the GOPHER server couldn't close the file");
return FALSE;
}
return TRUE;
}
/*=================================================================*/
#define PARAMETER unsigned int
#define LASTPARM(X) ((unsigned int)(X) | 0x80000000)
static Bool
get_exec_data(struct recvstruct *R)
{
char *command;
char *commandargs;
unsigned int bitflags;
int rexxrc;
int irxexecrc;
int commandlength;
int scan_count;
int i;
Bool rc;
int (*irxexec)();
FILE *fp;
char exectest[RBUFSIZE];
PARAMETER parameter[11];
struct {
/* repeat this block for each argument */
char *argstring_ptr;
int argstring_length;
/* end repeat this block for each argument */
int argstring_end;
} arguments;
struct {
char acryn[8]; /* "IRXEXECB" */
int length;
int reserved1;
char member[8];
char ddname[8];
char subcom[8];
char *dsnptr;
int dsnlen;
} execblk;
/*
* Menu item should look like this:
*
* exec:rexxname any args
*
* The exec should write output to SYSTSPRT. Normal TSO command
* output will be captured by the SYSTSPRT allocation only if
* the Gopher server is run as a batch job.
*
* If this was sent by the client with a type 7 or type w, then
* additional args will appear at the end delimited by a space.
*/
irxexec = NULL;
rc = TRUE;
scan_count = 0;
if (R->wargptr) {
commandlength = strlen(R->fileptr) + strlen(R->wargptr) + 4;
command = (char *)malloc(commandlength);
if (!command) {
printf("Cannot allocate %d bytes of memory for exec\n",
commandlength);
gbarf(R,"the GOPHER server ran out of memory");
return FALSE;
}
else sprintf(command,"%s %s",R->fileptr,R->wargptr);
}
else {
commandlength = 0;
command = R->fileptr;
}
*exectest = '\0';
sscanf(command, "%s %n", exectest, &scan_count);
if (strlen(exectest) > 8) {
gbarf(R,"name of exec is too long");
return FALSE;
}
commandargs = command + scan_count;
if (rc) {
irxexec = (int(*)())fetch("IRXEXEC");
if (!irxexec) {
printf("Cannot fetch IRXEXEC\n");
rc = FALSE;
}
}
/* Give the exec an empty SYSTSPRT file to write into.
* Then when we read it we can see only what was added.
* Since IRXEXEC doesn't close SYSTSPRT, we can't remove it
* and reallocate it.
*/
if (rc) {
fp = fopen("DD:SYSTSPRT","w");
if (!fp) {
perror("DD:SYSTSPRT");
printf("Cannot open SYSTSPRT to prepare for REXX exec\n");
rc = FALSE;
}
/* Open for write + close = clear it out */
else if (fclose(fp) < 0) {
printf("Cannot close SYSTSPRT to prepare for REXX exec\n");
rc = FALSE;
}
}
/* Set up parameters for IRXEXEC:
*
* Param 1 - address of EXECBLK
* Param 2 - address of arguments
* Param 3 - bitflags
* Param 4 - address of INSTBLK
* Param 5 - address of CPPL
* Param 6 - address of EVALBLOCK
* Param 7 - address of 8-byte work area
* Param 8 - address of user field
* Param 9 - address of environment block
* Param 10 - return code
*
*/
if (rc) {
/* set up exec block */
memset (&execblk, 0, sizeof(execblk));
execblk.length = sizeof(execblk);
memcpy (execblk.acryn, "IRXEXECB", 8);
strncpy(execblk.member,exectest,8);
for (i=0;i<8;i++) {
if (execblk.member[i] == '\0')
execblk.member[i] = ' ';
}
/* We may have just clobbered this, so do this after... */
memcpy (execblk.ddname, REXX_EXEC_LIBRARY_DDNAME, 8);
memcpy (execblk.subcom, REXX_EXEC_SUBCOM, 8);
/* set up arguments */
arguments.argstring_ptr = commandargs;
arguments.argstring_length = strlen(commandargs);
arguments.argstring_end = 0xffffffff;
/* Invoke the rexx exec */
if (!R->outfp) printf("Executing:%s\n", command);
#define INVOKE_EXEC_AS_COMMAND (unsigned int)0x80000000
#define INVOKE_EXEC_AS_EXTERNAL_FUNCTION (unsigned int)0x40000000
#define INVOKE_EXEC_AS_SUBROUTINE (unsigned int)0x20000000
#define RETURN_EXTENDED_RETURN_CODES (unsigned int)0x10000000
rexxrc = 0;
bitflags = (unsigned int)(INVOKE_EXEC_AS_COMMAND +
RETURN_EXTENDED_RETURN_CODES);
parameter[ 1] = (PARAMETER)&execblk;
parameter[ 2] = (PARAMETER)&arguments;
parameter[ 3] = (PARAMETER)bitflags;
parameter[ 4] = (PARAMETER)NULL; /* no INSTBLK */
parameter[ 5] = (PARAMETER)NULL; /* no CPPL */
parameter[ 6] = (PARAMETER)NULL; /* no eval block */
parameter[ 7] = (PARAMETER)NULL; /* no work area */
parameter[ 8] = (PARAMETER)NULL; /* no user field, last parm */
parameter[ 9] = (PARAMETER)NULL; /* no environment block */
parameter[10] = (PARAMETER)0; /* return code */
irxexecrc = (*irxexec) (
¶meter[1],
¶meter[2],
¶meter[3],
¶meter[4],
¶meter[5],
¶meter[6],
¶meter[7],
LASTPARM(¶meter[8]), /* old REXX */
¶meter[9],
LASTPARM(¶meter[10]) /* new REXX */
);
if (irxexecrc != 0) {
fprintf(stderr,"Return code from IRXEXEC is %d\n", irxexecrc);
gbarf(R,"the Gopher server was unable to run the exec");
rc = FALSE;
}
else {
rexxrc = parameter[10];
if (!R->outfp) printf("Return code from exec is %d\n", rexxrc);
/* Read what the exec wrote. */
strcpy(R->buffer,"DD:SYSTSPRT");
R->fileptr = R->buffer;
rc = get_flat_file(R);
}
}
else {
gbarf(R,"the GOPHER server had a problem with the exec");
}
if (irxexec) release((void (*)())irxexec);
if (commandlength > 0) free(command);
return rc;
}
/*=================================================================*/
/*******************************************************************/
/* This routine Processes the file the user requested. */
/* If it's a menu, we'll form a menu line, if it's a */
/* file, we'll just send it as is. */
/* */
/* INPUT: filename pointer to the file name to open */
/* sockfd socket descriptor for the client */
/* */
/* OUTPUT: print "gopher" lines. */
/* TRUE - file printed ok. */
/* FALSE - Error reading or writing */
/*******************************************************************/
Bool
GGMproc(struct recvstruct *R)
{
int x; /* loop counter*/
int numread; /* number of items read... */
int hacksize; /* length of hack prefix before : */
Bool rc; /* return value */
enum data_set_type dstype; /* SEQ, PDS or UNK */
char *p;
char *q;
char *tabptr;
char *colonptr;
char ddname [ 9];
char hackprefix[ 17];
*ddname = '\0';
*hackprefix = '\0';
/************/
/* First, strip off any "bad" characters from the arguments. */
/************/
/*
* Break the argument up into one or two pieces delimited by tab.
*/
R->fileptr = R->buffer; /* filename passed in buffer */
tabptr = strchr(R->fileptr,'\t');
if (tabptr) {
*tabptr = '\0';
R->fileptr = trim_leading_and_trailing_space(R->fileptr);
R->wargptr = trim_leading_and_trailing_space(tabptr+1);
}
else {
R->fileptr = trim_leading_and_trailing_space(R->fileptr);
R->wargptr = NULL;
}
if (!*R->fileptr) {
R->fileptr = DEFAULT_DIRECTORY;
}
/* If first character is numeric, assume it's a gopher type.
* Later we will actually support different types...
*/
switch (*R->fileptr) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9': R->fileptr++; break;
default: break;
}
if (!R->outfp) printf("%s: requested:%s;\n",R->hostname,R->fileptr);
/*
* Process special hacks here.
*
* For example, if the file name begins with "exec:", then
* execute the specified REXX exec.
*
* Hackless names are processed as files. "dd:" is not a
* special hack but the normal C/370 DDname reference.
*
*/
colonptr = strchr(R->fileptr,':');
if (colonptr) {
hacksize = colonptr - R->fileptr;
if (hacksize > 0 && hacksize < sizeof(hackprefix)) {
for (p = hackprefix, q = R->fileptr;
hacksize > 0;
p++, q++, hacksize--) *p = toupper(*q);
*p = '\0';
}
}
if (EQUAL(hackprefix,"EXEC")) {
/*
* REXX exec, which must reside in SYSEXEC DD.
*/
if (!authorized_file(R)) {
gbarf(R,"the GOPHER server won't run the exec for you");
rc = FALSE;
}
else {
R->fileptr = colonptr + 1; /* point to exec itself */
rc = get_exec_data(R);
}
}
else
if (EQUAL(hackprefix,"DD")) {
/*
* C/370 style ddname. Assume sequential file - cannot be a PDS
* because I don't feel like trying to determine that right now.
*/
if (!authorized_file(R)) {
gbarf(R,"the GOPHER server won't read the DD for you");
rc = FALSE;
}
else {
strcpy(R->buffer,R->fileptr); /* still points to "DD:xxxxxxxx" */
dstype = SEQ;
rc = get_flat_file(R);
}
}
else {
/* Regular file name without ":" hack, or with invalid ":" hack.
* Check to see that the file name is on our "official" list.
*/
if (!authorized_file(R)) {
gbarf(R,"the GOPHER server won't let you see the file");
rc = FALSE;
}
else {
/* Dynamically allocate data set and use generated ddname.
* Note that we have to allocate the data set name to a ddname and
* then open the ddname to prevent C/370 from barfing on otherwise
* valid data set names like those with hyphens in them. But this
* also lets us determine if the data set is sequential or a PDS.
*/
strcpy(R->dsname,R->fileptr);
dstype = GGMalloc(R->dsname,ddname,UNK,0);
sprintf(R->buffer,"DD:%s",ddname);
switch (dstype) {
case SEQ: rc = get_flat_file(R); break;
case PDS: rc = get_directory(R); break;
default:
printf("INVALID! requested:%s\n",R->fileptr);
gbarf(R,"the GOPHER server couldn't allocate the file");
rc = FALSE;
}
}
}
GGMunalc(ddname); /* free the ddname if set */
if (!rc) {
fflush(stdout);
fflush(stderr);
}
return rc;
}
./ ADD NAME=GGMPTX,SSI=01000029
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@PTX ")
#pragma csect(static,"GG$PTX ")
#include "gg.h"
/****** Print the lines of server text. ******************************/
void
GGMptx(gp,ip)
Rstruc ggcb *gp;
Rstruc gopherinfo *ip;
{
FILE *pfp;
struct texthdr *thp;
struct textline *tp;
thp = (ip ? &ip->thdr : &gp->thdr);
pfp = stdout;
/* Article must be specified (cannot be null). */
for (tp=thp->first_text_line;tp;tp=tp->next) {
if (tp->text_length >= 0) {
char *p = tp->tab_expanded_text;
while (*p) {
if isprint(*p) fprintf(pfp,"%c",*p);
else fprintf(pfp,"?");
p++;
}
fprintf(pfp,"\n");
}
}
fprintf(pfp,"\n");
return;
}
./ ADD NAME=GGMSOCKT,SSI=01090005
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@SOCKT")
#pragma csect(static,"GG$SOCKT")
#include "gg.h"
/****** Output one data line for the server. *************************/
Bool
GGMsockt(gp)
Rstruc ggcb *gp;
{
int gopher_bytes;
int writrc;
int j;
char *s_buf;
Bool procok;
struct recvstruct *R;
/* Before sending a request to the server, do a cleanup operation
* to make sure that no more responses are coming from the server.
*/
GGMesrvr(gp); /* End server read */
/* If local mode, call server subtask processor with command. */
if ((R=gp->recvp)) {
if (!R->outfp) {
CRIT1("Can't send data locally, non-socket not connected");
return FALSE;
}
strncpy(R->buffer, gp->gopher_command, sizeof(R->buffer)-1);
strcpy(R->myname, LOCAL_HOST_FROB); /* used by PDS feature */
/* allocate SYSTSPRT file, used by REXX EXEC interface */
if (GGMtso(
"ALLOC FI(SYSTSPRT) T SP(100 100) REL REU DEL"
" RECFM(V B) LRECL(1024) BLKSIZE(32760)"
) != 0) {
fprintf(stderr,
"Warning: Cannot allocate temporary SYSTSPRT file.\n");
fprintf(stderr,
" Some interfaces may not work properly.\n");
}
procok = GGMproc(R);
/* free SYSTSPRT file, used by REXX EXEC interface */
(void)GGMunalc("SYSTSPRT");
/* Prepare to read from the beginning of the file */
if (fseek(R->outfp, 0, SEEK_SET) != 0) {
CRIT1("Can't reposition to start of local file");
return FALSE;
}
return procok;
}
gopher_bytes = strlen(gp->gopher_command);
memcpy(gp->client_buf,gp->gopher_command,gopher_bytes);
gp->client_buf[gopher_bytes] = CARRIAGE_RETURN;
gp->client_buf[gopher_bytes+1] = LINE_FEED;
if (gp->receiving_text &&
gopher_bytes == 1 &&
gp->client_buf[0] == '.') {
gp->receiving_text = FALSE;
}
if (gp->debug_mode)
GGMdump(gp,"Writing to server",gp->client_buf,gopher_bytes+2);
#ifdef MVS
for (j=0;j<gopher_bytes+2;++j) {
gp->client_buf[j] = etoa(gp->client_buf[j]);
}
#endif
writrc = write(gp->socknum, gp->client_buf, gopher_bytes+2);
if (writrc < 0) {
gp->connection_broken = TRUE;
CRIT2("TCP/IP error: write() failed to send data to server %s.",
gp->ggserver);
return FALSE;
}
/* Prepare server for read. */
gp->server_has_something_pending = TRUE;
gp->server_finished_replying = FALSE;
gp->sending_text = FALSE;
gp->dont_read = FALSE;
return TRUE;
}
./ ADD NAME=GGMSOPT,SSI=01000036
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@SOPT ")
#pragma csect(static,"GG$SOPT ")
#include "gg.h"
#define BOOLOPTSET(A,B,C) \
switch (A[0]) { \
case 'n': \
case 'N': B = FALSE; break; \
case 'y': \
case 'Y': B = TRUE; break; \
case '\0': \
default: B = C; break; \
}
/****** Set options that are stored in ISPF profile. *****************/
void
GGMsopt(gp,which)
Rstruc ggcb *gp;
enum user_option which;
{
int arrows;
char ggextpow[ 4];
char ggextpap[ 4];
char ggscroll[ 4];
if (which == OPTION_ALL) {
GGMispf(gp, "VGET (GGMUPDTF GGEXTPOW GGEXTPOP GGSCROLL) PROFILE");
}
if (which == OPTION_ALL || which == OPTION_OTHER) {
(void)GGMivget(gp,"GGEXTPOW ", ggextpow, sizeof(ggextpow));
(void)GGMivget(gp,"GGEXTPAP ", ggextpap, sizeof(ggextpap));
BOOLOPTSET(ggextpow, gp->warn_overwrite, TRUE);
BOOLOPTSET(ggextpap, gp->warn_append, TRUE);
}
if (which == OPTION_ALL || which == OPTION_VIEW) {
(void)GGMivget(gp,"GGSCROLL ", ggscroll, sizeof(ggscroll));
BOOLOPTSET(ggscroll, gp->autoscroll, TRUE);
}
return;
}
./ ADD NAME=GGMSSRVR,SSI=01010032
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@SSRVR")
#pragma csect(static,"GG$SSRVR")
#include "gg.h"
/****** Start server read. *******************************************/
void
GGMssrvr(gp)
Rstruc ggcb *gp;
{
gp->server_has_something_pending = TRUE;
gp->server_finished_replying = FALSE;
gp->sending_text = FALSE;
gp->dont_read = FALSE;
return;
}
./ ADD NAME=GGMTNET,SSI=01040000
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@TNET ")
#pragma csect(static,"GG$TNET ")
#include "gg.h"
/****** Gopher TELNET interface. *************************************/
Bool
GGMtnet(gp,ip,as_file)
Rstruc ggcb *gp;
Rstruc gopherinfo *ip;
Fool as_file;
{
int tsorc;
char tsocmd[256];
if (as_file) {
ERR1("TELNET interface cannot be viewed as a file.");
return FALSE;
}
GGMispf(gp,"CONTROL DISPLAY LINE");
fprintf(stderr,"Note: Login as user: %s\n\n", ip->path);
sprintf(tsocmd,"%s %s %d", TELNET_COMMAND_NAME,
ip->host,
ip->port);
if ((tsorc = GGMtso(tsocmd)) != 0) {
ERR3("%s command returned code %d", TELNET_COMMAND_NAME, tsorc);
}
GGMispf(gp,"CONTROL DISPLAY REFRESH");
return TRUE;
}
./ ADD NAME=GGMTSO,SSI=01000051
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
/********************************************************************/
/* */
/* Thanks to Michael Van Norman for this code. */
/* */
/********************************************************************/
#pragma csect(code, "GG@TSO ")
#pragma csect(static,"GG$TSO ")
#include "gg.h"
#pragma linkage(ikjeftsr,OS)
#define _IKJEFTSR_FLAGS_AUTH 0x00000000
#define _IKJEFTSR_FLAGS_COMMAND 0x00000001
#define _IKJEFTSR_FLAGS_DUMP 0x00000100
#define _IKJEFTSR_FLAGS_NODUMP 0x00000000
#define _IKJEFTSR_FLAGS_PROGRAM 0x00000002
#define _IKJEFTSR_FLAGS_UNAUTH 0x00010000
/****** Issue TSO command. *******************************************/
int
GGMtso(command)
char *command;
{
int flags = _IKJEFTSR_FLAGS_COMMAND +
_IKJEFTSR_FLAGS_UNAUTH;
int commandLength = strlen(command);
int rc = 0;
int returnCode = 0;
int reasonCode = 0;
int abendCode = 0;
static int (*ikjeftsr)() = NULL;
if (!ikjeftsr) {
int tsoEntryAddress;
tsoEntryAddress = 0x00000010; /* Address of CVT */
tsoEntryAddress = *(int *)(tsoEntryAddress);
tsoEntryAddress += 0x9C;/* /* Offset of TVT in CVT */
tsoEntryAddress = *(int *)(tsoEntryAddress);
tsoEntryAddress += 0x10;/* /* TSVTASF-TSVT (from IKJTSVT) */
tsoEntryAddress = *(int *)(tsoEntryAddress);
ikjeftsr = (int (*)())(tsoEntryAddress);
}
if (!ikjeftsr) {
fprintf(stderr,
"Cannot execute TSO commands, can't fetch IKJEFTSR.\n");
return -2;
}
rc = (*ikjeftsr)(&flags, command, &commandLength,
&returnCode, &reasonCode,
(int *)((int)(&abendCode) | 0x80000000));
if (rc != 0) {
if (rc > 4) {
fprintf(stderr,"Command failed:%s\n",command);
if (rc == 20 && reasonCode == 40)
fprintf(stderr,"Command was not found.\n");
else fprintf(stderr,
"rc=%d,returncode=%d,reasoncode=%d,abendcode=%8.8x\n",
rc, returnCode, reasonCode, abendCode);
}
if (abendCode != 0) rc = -1;
else rc = returnCode;
}
return rc;
}
./ ADD NAME=GGMTYPE,SSI=01030020
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@TYPE ")
#pragma csect(static,"GG$TYPE ")
#include "gg.h"
/*********************************************************************/
char *
GGMtype(gophertype t)
{
switch (t) {
case GOPHER_FILE: return "File ";
case GOPHER_DIRECTORY: return "Directory";
case GOPHER_CSO: return "Cso ";
case GOPHER_ERROR: return "Error ";
case GOPHER_MAC_BINHEX: return "Binhex ";
case GOPHER_DOS_BINARCH: return "Binarch ";
case GOPHER_UUENCODE: return "Uuencode ";
case GOPHER_WAIS: return "Index ";
case GOPHER_TELNET: return "Telnet ";
case GOPHER_BINARY: return "Binary ";
case GOPHER_REDUNDANT: return "Redundant";
case GOPHER_WHOIS: return "Whois ";
default: return "Unknown ";
}
}
./ ADD NAME=GGMUNALC,SSI=01000040
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@UNALC")
#pragma csect(static,"GG$UNALC")
#include "gg.h"
/****** Unallocate a data set. ***************************************/
Bool
GGMunalc(ddname)
char *ddname;
{
__S99parms stuff99; /* The manual has it wrong. No "struct". */
int rc;
char *cp;
TEXTUNIT *tu [2];
TEXTUNIT tu_ddn;
TEXTUNIT tu_una;
if (!ddname ||
!*ddname) return TRUE; /* if no ddname to free, do nothing */
memset((char *)&stuff99,0,sizeof(__S99parms));
stuff99.__S99RBLN = 20;
stuff99.__S99VERB = S99VRBUN;
stuff99.__S99FLAG1 = 0;
stuff99.__S99ERROR = 0;
stuff99.__S99INFO = 0;
stuff99.__S99TXTPP = tu;
stuff99.__S99FLAG2 = 0;
tu[0] = &tu_ddn;
tu[1] = &tu_una;
*(int *)&tu[1] |= 0x80000000;
tu_ddn.key = DUNDDNAM;
tu_ddn.num = 1;
tu_ddn.ent.len = strlen(ddname);
strcpy(tu_ddn.ent.prm,ddname);
tu_una.key = DUNUNALC;
tu_una.num = 0;
for (cp=tu_ddn.ent.prm; *cp; cp++) *cp = toupper(*cp);
rc = svc99(&stuff99);
if (rc == 0) return TRUE;
else if (stuff99.__S99ERROR == 0x0438) /* not freed, is not allocated*/
return TRUE;
else {
GGMdfail(rc,&stuff99);
return FALSE;
}
}
./ ADD NAME=GGMVTX,SSI=01050014
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@VTX ")
#pragma csect(static,"GG$VTX ")
#include "gg.h"
/****** BRIF fakeout. ************************************************/
static void
fake_out_for_brif(fpp,codebuf)
void **fpp;
char *codebuf;
#ifndef I370
/* The purpose of this is to put a wrapper around the actual
function pointed to by the argument, so that FORTRAN-style
return codes (in register 0) get put into register 15.
Source code:
USING *,15
ST 14,save_14
L 15,realcode
DROP 15
BALR 14,15
USING *,14
L 14,save_14
DROP 14
LR 15,0
BR 14
SPACE 1
save_14 DS F
realcode DS F
*** Warning: As written, this fake-out code is not reentrant. ***
*/
{
static char fake_out_code[32] = {
0x50,0xE0,0xF0,0x14,0x58,0xF0,0xF0,0x18,
0x05,0xEF,0x58,0xE0,0xE0,0x0A,0x18,0xF0,
0x07,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
memcpy(codebuf,fake_out_code,32);
memcpy(codebuf+0x18,(char *)fpp,4);
#else
/* The purpose of this is to put a wrapper around the actual
function pointed to by the argument, so that the C Runtime
Anchor Block pointer (in register 12) can be saved/restored.
*/
{
#define FAKE_BUF_SIZE 48 /* */
static short fake_out_code[FAKE_BUF_SIZE/2] =
{ /* USING *,15 */
0x50C0,0xF020, /* +00 ST 14,save_12 */
0x50E0,0xF024, /* +04 ST 12,save_14 */
0x58C0,0xF02C, /* +08 L 12,crab */
0x58F0,0xF028, /* +0C L 15,realcode */
/* DROP 15 */
0x58F0,0xF000, /* +10 L 15,0(,15) */
0x05EF, /* +14 BALR 14,15 */
/* USING *,14 */
0x58C0,0xE00A, /* +16 L 12,save_12 */
0x58E0,0xE00E, /* +1A L 14,save_14 */
/* DROP 14 */
0x07FE, /* +1E BR 14 */
0x0000,0x0000, /* +20 save_12 */
0x0000,0x0000, /* +24 save_14 */
0x0000,0x0000, /* +28 realcode */
0x0000,0x0000 /* +2C crab */
};
memcpy( codebuf, fake_out_code, FAKE_BUF_SIZE );
memcpy( codebuf+0x28, (char *)fpp, 4 );
_ldregs( R2, codebuf+0x2C ), /* get -> crab in fakeout buff */
_code ( 0, 0x50C0, 0x2000 ); /* save -> CRAB */
#endif
*fpp = (void *)codebuf;
return;
}
/****** Print text lines. ********************************************/
static void
print_text_lines(fp,textp)
FILE *fp;
struct textline *textp;
{
struct textline *tp;
char *p;
for (tp=textp; tp; tp=tp->next) {
if (tp->text_length >= 0) {
p = tp->tab_expanded_text;
while (*p) {
if isprint(*p) fprintf(fp,"%c",*p);
else fprintf(fp,"?");
p++;
}
fprintf(fp,"\n");
}
}
fprintf(fp,"\n");
return;
}
/****** View the lines of text retrieved from the server. ************/
Bool
GGMvtx(gp,ip,as_file)
Rstruc ggcb *gp;
Rstruc gopherinfo *ip;
Fool as_file; /* ignored */
{
int brif_max_reclen;
int i;
char *p;
char *q;
struct texthdr *texthdrp;
void *dialog_data_ptr;
void *read_function_ptr;
void *command_function_ptr;
char read_fakeout_buffer [32];
char command_fakeout_buffer [32];
char brif_title [81];
texthdrp = (ip ? &ip->thdr : &gp->thdr);
if (gp->brifp) {
printf("Cannot use ISPF BROWSE now, displaying in line mode:\n\n");
print_text_lines(stdout,texthdrp->first_text_line);
return TRUE;
}
gp->brifp = texthdrp;
gp->brif_previous_recno = -1;
if (!ip) sprintf(brif_title, "GopherServer:%s ",gp->ggserver);
else {
/* BRIF doesn't like blanks in the title */
for (p=ip->desc,q=brif_title,i=sizeof(brif_title)-1;
i > 0 && *p;
p++,q++,i--) {
*q = (*p == ' ' ? '_' : *p);
}
*q = ' ';
*(q+1) = '\0';
}
brif_max_reclen = gp->brifp->text_max_tab_expanded_length;
dialog_data_ptr = (void *)gp;
read_function_ptr = (void *)&GGMbrifr;
command_function_ptr = (void *)&GGMbrifc;
fake_out_for_brif(&read_function_ptr,read_fakeout_buffer);
fake_out_for_brif(&command_function_ptr,command_fakeout_buffer);
if (gp->test_mode) {
printf("Here are the %d lines BRIF should be displaying:\n\n",
gp->brifp->text_line_count);
print_text_lines(stdout,gp->brifp->first_text_line);
gp->brifp = NULL;
return TRUE;
}
if (gp->setmsg) {
(void)GGMispf(gp,"SETMSG MSG(ISRZ002)");
gp->setmsg = FALSE;
}
gp->ispfrc = ISPLINK("BRIF ",
brif_title,
"V ", /* variable record format */
&brif_max_reclen,
&read_function_ptr,
&command_function_ptr,
&dialog_data_ptr,
" ", /* use IBM's browse panel */
" ", /* no format */
"NO "); /* default sbcs data */
gp->brifp = NULL;
switch (gp->ispfrc) {
case 0:
break;
case 12:
ERR1("There is no data returned from the gopher host to be browsed.");
break;
case 16:
break;
default:
GGMierr(gp); /* handle ISPF error */
break;
}
return TRUE;
}
./ ADD NAME=GGMWAIS,SSI=01060010
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@WAIS ")
#pragma csect(static,"GG$WAIS ")
#include "gg.h"
/****** Gopher WAIS interface. *************************************/
Bool
GGMwais(gp,ip,as_file)
Rstruc ggcb *gp;
Rstruc gopherinfo *ip;
Fool as_file;
{
char *lp;
char ggwaisq[256];
strcpy(gp->ggserver,ip->host); /* Specify server to connect to */
strcpy(ggwaisq,"");
GGMispf(gp,"VGET (GGWAISQ) PROFILE");
if (GGMdispl(gp,"GGMPWAIS") > 0) return FALSE;
GGMivget(gp,"GGWAISQ ",ggwaisq, sizeof(ggwaisq));
if (!*ip->path) strcpy(gp->gopher_command, ggwaisq);
else sprintf(gp->gopher_command,"%s\t%s",ip->path,ggwaisq);
gp->ginfo = ip;
gp->receiving_text = FALSE;
if (!GGMconn(gp)) return FALSE; /* Connect to gopher server */
if (!GGMsockt(gp)) return FALSE; /* Send socket command to server */
GGMclrtx(gp,ip); /* Clear text */
gp->receiving_text = TRUE;
do {
if (GGMgsrvl(gp,&lp)) /* Get server line */
if (lp)
(void)GGMouttx(gp,lp,ip); /* Output text line */
} while (lp); /* until no more lines */
if (gp->time_to_go_home) {
WARN2("No data available from server %s.\n",gp->ggserver);
return FALSE;
}
if (gp->connected_to_server) {
(void)GGMdisc(gp); /* Disconnect from gopher server */
}
GGMdir(gp,ip,as_file); /* display entries returned from WAIS server */
return TRUE;
}
./ ADD NAME=GGMWHOIS,SSI=01020013
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@WHOIS")
#pragma csect(static,"GG$WHOIS")
#include "gg.h"
/****** Gopher WHOIS/FINGER interface. *****************************/
Bool
GGMwhois(gp,ip,as_file)
Rstruc ggcb *gp;
Rstruc gopherinfo *ip;
Fool as_file; /* ignored */
{
char *lp;
Bool got_some;
char ggwhoisq[256];
strcpy(gp->ggserver,ip->host); /* Specify server to connect to */
strcpy(ggwhoisq,"");
GGMispf(gp,"VGET (GGWHOISQ) PROFILE");
if (GGMdispl(gp,"GGMPWHOI") > 0) return FALSE;
GGMivget(gp,"GGWHOISQ ",ggwhoisq, sizeof(ggwhoisq));
if (!*ip->path) strcpy(gp->gopher_command, ggwhoisq);
else sprintf(gp->gopher_command,"%s\t%s",ip->path,ggwhoisq);
gp->ginfo = ip;
gp->receiving_text = FALSE;
if (!GGMconn(gp)) return FALSE; /* Connect to gopher server */
if (!GGMsockt(gp)) return FALSE; /* Send socket command to server */
GGMclrtx(gp,ip); /* Clear text */
gp->receiving_text = TRUE;
got_some = FALSE;
do {
if (GGMgsrvl(gp,&lp)) { /* Get server line */
if (lp) {
got_some = TRUE;
(void)GGMouttx(gp,lp,ip); /* Output text line */
}
}
} while (lp); /* until no more lines */
if (!got_some) {
WARN2("No data available from server %s.\n",gp->ggserver);
return FALSE;
}
if (gp->connected_to_server) {
(void)GGMdisc(gp); /* Disconnect from gopher server */
}
GGMvtx(gp,ip,as_file); /* display text from WHOIS/FINGER server */
return TRUE;
}
./ ADD NAME=GGMXTX,SSI=01050051
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GG@XTX ")
#pragma csect(static,"GG$XTX ")
#include "gg.h"
/****** Extract the lines of server text into a data set. ************/
Bool
GGMxtx(gp,ip)
Rstruc ggcb *gp;
Rstruc gopherinfo *ip;
{
FILE *xfp;
struct texthdr *thp;
struct textline *tp;
struct extraction *ep;
int l;
char *cp;
char formatted_number [11];
struct extraction the_extraction;
thp = (ip ? &ip->thdr : &gp->thdr);
/* Set article data for message. */
if (ip) {
sprintf(formatted_number,"%d",ip->type);
(void)GGMivput(gp,"GGTNUM ", formatted_number, -1);
(void)GGMivput(gp,"GGTSUBJ ", ip->desc, -1);
}
if (gp->extract_file) {
(void)GGMispf(gp,"CONTROL DISPLAY LOCK");
(void)GGMispf(gp,"DISPLAY PANEL(GGMLEXN2)");
xfp = gp->extract_file;
}
else {
ep = &the_extraction;
memset(ep,0,sizeof(struct extraction));
ep->mode = SEQ;
strcpy(ep->panelname,"GGMPEXDS");
if (!((xfp=GGMgetds(gp,ep)))) return FALSE;
gp->extract_tab_expanding = ep->tab_expanding;
gp->extract_appending = ep->appending;
gp->extract_blank_before_separator = ep->blanking;
gp->extract_separator_line = ep->separator;
}
/* If append mode, and a separator line was specified, use it. */
gp->extract_write_error = FALSE;
gp->extract_close_error = FALSE;
while (gp->extract_appending && gp->extract_separator_line &&
*gp->extract_separator_line) {
if (fprintf(xfp,"%s\n",gp->extract_separator_line) < 0) {
gp->extract_write_error = TRUE; break;
}
if (gp->extract_blank_before_separator) {
if (fprintf(xfp,"\n") < 0) {
gp->extract_write_error = TRUE; break;
}
}
break;
}
for (tp = thp->first_text_line;
tp && !gp->extract_write_error;
tp = tp->next) {
if (tp->text_length == 0) {
if (fputc('\n',xfp) == EOF) {
gp->extract_write_error = TRUE; break;
}
}
else if (tp->text_length > 0) {
if (gp->extract_tab_expanding) {
cp = tp->tab_expanded_text;
l = tp->tab_expanded_text_length;
}
else {
cp = tp->text;
l = tp->text_length;
}
for (; l > 0; cp += 251, l -= 251) {
fwrite(cp,(l>251 ? 251 : l),1,xfp);
if (ferror(xfp)) {
gp->extract_write_error = TRUE; break;
}
if (fputc('\n',xfp) == EOF) {
gp->extract_write_error = TRUE; break;
}
}
}
}
if (!gp->extract_write_error && ferror(xfp))
gp->extract_write_error = TRUE;
if (!gp->extract_appending || !gp->extract_file) {
if (fclose(xfp) < 0) {
/* perror(nnexdsn); */
ERR2("An error occurred closing data set %s.", ep->dsname);
gp->extract_close_error = TRUE;
return FALSE;
}
}
if (!gp->extract_file) {
if (gp->extract_write_error) {
ERR2("An error occurred writing to data set %s.", ep->dsname);
gp->extract_write_error = TRUE;
}
else if (ip) {
WARN2("Current item extracted into file %s.",
ep->dsname);
}
else {
WARN2("Displayed text has been extracted into file %s.",
ep->dsname);
}
}
if (gp->extract_write_error) return FALSE;
else return TRUE;
}
./ ADD NAME=GGSERVER,SSI=010E0026
/*
***********************************************************************
* *
* GOPHER server, based on the simple TCP/IP server from Shawn Hart at *
* the University of Delaware. *
* *
***********************************************************************
*
* This server follows the GOPHER protocols defined by UMN.
* For more information, see the ANONYMOUS FTP site at
* BOOMBOX.MICRO.UMN.EDU.
*
*/
#pragma csect(code, "GG@ERVER")
#pragma csect(static,"GG$ERVER")
#include "gg.h" /* All system file includes needed. */
/********************************************************************/
static int
tcpsetup(int port,
int qlen)
{
int tinitrc; /* loop counter*/
int sockfd; /* loop counter*/
int x; /* loop counter*/
struct linger l; /* linger for setsockopt */
struct sockaddr_in server; /*server address information */
/* initialize the MTF environment. */
#ifdef DEBUGMTF
fprintf(stderr,"tinit...\n");
#endif
tinitrc = tinit("GGSTASK", MTF_TASKS);
if (tinitrc != MTF_OK) {
GGMmtfer(tinitrc, "TINIT");
return -1;
}
/* open a TCP socket... */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
tcperror("SOCKET - ");
return -1;
};
/* set the linger option on so we wait for data to be sent... */
l.l_onoff = 1;
l.l_linger =100; /* wait 100 seconds before giving up */
if (setsockopt(sockfd,SOL_SOCKET,SO_LINGER,(char *)&l,sizeof(l))
< 0) {
tcperror("SETSOCKOPT - ");
return -1;
}
/* now bind our local address so that the client can send to us */
memset((char *)&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(port);
if (bind(sockfd, &server, sizeof(server)) < 0) {
tcperror("BIND - ");
return -1;
}
/* now set length of the connection queue... */
if (listen(sockfd,qlen) != 0) {
tcperror("LISTEN -");
return -1;
}
return sockfd;
}
/********************************************************************/
/*
* This routine waits for an exception on the socket. When one
* occurs (by a subtask's "TAKESOCKET"!) we'll close our (the main
* task's) connection to it.
*
* INPUT s pointer to socket descripter.
* OUTPUT rc -1 = connection timed out...
* 0 = an excption occured!
*/
/********************************************************************/
static int
closesock(int newsockfd)
{
int temps;
struct sockaddr clientaddress;
int addrlen;
int maxfdpl;
struct fd_set readmask;
struct fd_set writmask;
struct fd_set exepmask;
int rc;
struct timeval time;
temps = newsockfd;
time.tv_sec = CONNECT_TIME_OUT;
time.tv_usec = 0;
maxfdpl = temps + 1;
FD_ZERO(&readmask);
FD_ZERO(&writmask);
FD_ZERO(&exepmask);
FD_SET(temps, &exepmask);
rc = select(maxfdpl, &readmask, &writmask, &exepmask, &time);
if (rc < 0) {
tcperror("SELECT - ");
return rc;
}
else {
if (rc == 0) fprintf(stderr,"The GIVESOCKET timed out!\n");
if (close(newsockfd) < 0) tcperror("CLOSE -");
return rc;
}
}
/********************************************************************/
/*
* This routine starts a subtask, passing control of a socket
* to it. It then waits for the subtask to take the socket and
* then closes the socket.
*
* INPUT: newsockfd - socket descriptor to give to subtask.
*/
/********************************************************************/
static Bool
spawn(
int newsockfd)
{
int tschedrc;
struct clientid clid;
char mysname[8];
if(getclientid(AF_INET,&clid) < 0) {
tcperror("GETCLIENTID");
return FALSE;
}
clid.domain = AF_INET;
memcpy(mysname,clid.subtaskname,8);
memcpy(clid.subtaskname," ",8);
if(givesocket(newsockfd,&clid) != 0) {
tcperror("GIVESOCKET");
return FALSE;
}
memcpy(clid.subtaskname,mysname,8);
#ifdef DEBUGMTF
fprintf(stderr,"tsched...\n");
#endif
tschedrc = tsched(MTF_ANY,"GGSRECV",newsockfd,clid);
if (tschedrc != 0) {
GGMmtfer(tschedrc,"TSCHED");
return FALSE;
}
if (closesock(newsockfd) < 0) {
tcperror("close socket");
return FALSE;
}
return TRUE;
}
/******************************************************************/
int
main(int argc,
char **argv)
{
int trc; /* return code */
int x; /* loop counter*/
int sockfd; /* connection socket...*/
int newsockfd; /* new connection socket...*/
int clientlen; /* new connection socket...*/
struct sockaddr_in client; /* client address information */
struct clientid clid; /* client info for givesocket */
char buffer[255]; /* buffer for input/output*/
/******************************************************************/
/* set up the connection to the socket... */
/******************************************************************/
sockfd = tcpsetup(SERV_TCP_PORT,TCP_QUEUE_LENGTH);
if (sockfd < 0) {
fprintf(stderr,"Could not set up the TCP/IP environment!\n");
exit(16);
}
/******************************************************************/
/* Now loop, waiting for a connection request. */
/******************************************************************/
clientlen = sizeof(client);
x = 0;
for (;;) {
if ((newsockfd=accept(sockfd,&client,&clientlen)) == -1) {
tcperror("ACCEPT - ");
exit(8);
}
x++;
if (!spawn(newsockfd)) {
fprintf(stderr,"spawn failed for socket %d\n",newsockfd);
exit(8);
}
else {
#ifdef DEBUGMTF
fprintf(stderr,"spawn OK for socket %d\n",newsockfd);
#endif
}
}
/******************************************************************/
/* Wait for all pending tasks to complete (should never */
/* run, since I haven't added PURGE support yet...) */
/* then shut down subtasks. */
/******************************************************************/
#ifdef DEBUGMTF
fprintf(stderr,"tsyncro...\n");
#endif
trc = tsyncro(MTF_ALL);
if (trc != 0) {
GGMmtfer(trc,"TSYNCRO");
}
#ifdef DEBUGMTF
fprintf(stderr,"tterm...\n");
#endif
trc = tterm();
if (trc != 4) {
GGMmtfer(trc,"TTERM");
exit(8);
}
exit(0);
}
./ ADD NAME=GGSTASK,SSI=01530040
/********************************************************************/
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
#pragma csect(code, "GGSTASK ")
#pragma csect(static,"GG$TASK ")
#include "gg.h"
/*=================================================================*/
/*******************************************************************/
/* */
/* this is a debugging routine; it looks at the status of a */
/* socket. */
/*******************************************************************/
static void
lookatsocket(int sockfd)
{
int rc; /* return code */
int length; /* length variable */
int option;
int x;
struct linger l; /* linger structure */
char buffer[RBUFSIZE];
length = sizeof(l);
if (getsockopt(sockfd,SOL_SOCKET, SO_LINGER,&l,&length)==0) {
printf("l_onoff=%d\n",l.l_onoff);
printf("l_linger=%d\n",l.l_linger);
}
else tcperror("GETSOCKOPT");
length = sizeof(option);
if (getsockopt(sockfd,SOL_SOCKET, SO_ERROR,&option,&length)==0) {
printf("so_error=%d\n",option);
}
else tcperror("GETSOCKOPT");
if (fcntl(sockfd,F_SETFL,FNDELAY)!=0) tcperror("FCNTL");
length = recv(sockfd,buffer,sizeof(buffer)-1,0);
if (length == -1) {
if (errno != EWOULDBLOCK) tcperror("recv");
}
else {
buffer[sizeof(buffer)-1] = 0;
printf("buffer =%s\n",buffer);
for (x=0;x<length;x++) printf("%x ",buffer[x]);
printf("\n");
}
}
/*******************************************************************/
/**************************************************************/
/* this routine processes the data once a connection */
/* has been accepted. It just takes the data sent by the */
/* client and prints it to sysprint, then sends it back */
/* to the client. */
/* */
/* INPUT: newsockfd - socket descriptor */
/* clid - takesocket structure... */
/**************************************************************/
void
GGSrecv(
int newsockfd,
struct clientid clid
)
{
struct recvstruct *R;
struct hostent *hostentp;
char *bufptr; /* pointer into buffer strings */
char *hp;
char **halias;
int retcode; /* return code */
int len; /* length of the buffer we're sent */
int x; /* loop counter */
int addrlen; /* length of client address socket */
int hostlen;
int domslen;
struct sockaddr_in clientaddress; /* address of client */
struct recvstruct r;
time_t timeval;
struct tm *tmp;
char outbuf[RBUFSIZE]; /* hold an output string */
char timestamp[20];
memset(&r, 0, sizeof(struct recvstruct));
R = &r;
R->sockfd = takesocket(&clid,newsockfd);
if(R->sockfd < 0) {
tcperror("TAKESOCKET");
return;
}
time(&timeval);
tmp = localtime(&timeval);
sprintf(timestamp,"%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d",
tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_year,
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
addrlen = sizeof(clientaddress);
if(getpeername(R->sockfd,&clientaddress,&addrlen)!=0) {
tcperror("GETPEERNAME");
printf("could not determine client address\n");
}
/* Try to get the name of the client host. */
strcpy(R->hostname,"{UNKNOWN HOST NAME}");
hostentp = gethostbyaddr(&clientaddress.sin_addr,
sizeof(clientaddress.sin_addr),
AF_INET);
if (hostentp && hostentp->h_name) {
memcpy(&R->clienthostent, hostentp, sizeof(struct hostent));
strcpy(R->hostname,hostentp->h_name);
uppercase_in_place(R->hostname);
}
strcpy(R->hosttest,R->hostname);
hostlen = strlen(R->hosttest);
domslen = sizeof(MY_DOMAIN_SUFFIX) - 1;
if (hostlen > domslen) {
hp = R->hosttest + hostlen - domslen;
if (!memcmp(hp, MY_DOMAIN_SUFFIX, domslen)) {
*hp = '\0';
}
}
printf("%s Connection from %s (%s, aka %s).\n",
timestamp,
inet_ntoa(clientaddress.sin_addr), R->hostname, R->hosttest);
for (halias = R->clienthostent.h_aliases; *halias; halias++) {
printf(" Host alias:'%s'\n",*halias);
}
R->buffer[0] = '\0';
bufptr = R->buffer;
/***********************/
/* NOTE: sometimes, if timing is right, RECV can return a 0 length */
/* record when a connection is closed by the client!! below is a */
/* hack to check for a 0 length record, and then terminate this */
/* connection if we got one. */
/***********************/
for (;;) {
if ((len=recv(R->sockfd,outbuf,sizeof(R->buffer)-1,0)) <= 0) {
tcperror("RECV - ");
printf("tcp error! len=%d\n",len);
break;
}
*(outbuf+(len))=0; /*make sure it's null terminated...*/
/* printf("len=%d;",len); */
asctoebd(outbuf);
if (strlen(R->buffer) + strlen(outbuf) >= sizeof(R->buffer)) {
printf("\nError: More than %d bytes seen without CRLF\n",
sizeof(R->buffer)-1);
len = 0;
break;
}
strcat(R->buffer,outbuf);
bufptr=R->buffer+(strlen(R->buffer)-2);
if (*bufptr == CARRIAGE_RETURN && *(bufptr+1) == LINE_FEED) break;
}
/* Note: no \n required, data line already has CRLF in it */
fprintf(stderr,"%s Client data:%s", timestamp, R->buffer);
if (len < 0) return;
else if (len == 0) {
(void)GGMouts(R,
"1Sorry, the GOPHER server couldn't hear you. Try again.\t0\t0\t0");
}
else (void)GGMproc(R);
(void)GGMouts(R,NULL); /* send terminating dot */
fflush(stdout);
fflush(stderr);
/* lookatsocket(R->sockfd); */
if(close(R->sockfd)<0) tcperror("CLOSE - ");
}
./ ENDUP
?!
//CLIST EXEC GGLOAD,TRK1='4',TO='CLIST'
//SYSIN DD DATA,DLM='?!'
./ ADD NAME=GOPHER,SSI=010F0028
/* REXX. GOPHER client. */
/* *** Customize the following lines for your installation.
* If ggmpanel is set to "", it will not be LIBDEF'd.
*/
ggmprefix = "GOPHER"
ggmpanelsuffix = "PANELS"
ggmloadsuffix = "LOAD"
ggmlmod = "GGCLIENT"
ggmpanel = ggmprefix"."ggmpanelsuffix
ggmload = ggmprefix"."ggmloadsuffix
ggmappl = "" /* ISPF applid (e.g. ISR) */
ggmdefaulthost = "gopher.micro.umn.edu" /* to initialize GOPHERRC */
gophermeister = "" /* TSOid of Gopher's Big Brother */
xprocavailable = 0 /* set to 1 if XPROC is available */
trace off
signal on novalue
stacked = 0
libdeffed = 0
parse arg args
"ISPQRY"
if rc > 0 then do
parse source . . execname . execds .
if execds = "?" then
icmd = "%"execname args
else
icmd = "EX '"execds"("execname")'" quote(args)
call startispf ggmappl, icmd
exit
end
if xprocavailable then do
save_prompt = prompt("ON")
"XPROC 0 TEST DEBUG FORCE LOCAL SERVER() PORT() PATH() DESCRIPTION()"
if rc <> 0 then exit rc
call prompt save_prompt
end
else do /* XPROC not available */
server = ""
port = 70
path =
description =
local =
force =
test =
debug =
uargs = translate(args)
if wordpos("LOCAL",uargs) > 0 then local = "LOCAL"
if wordpos("FORCE",uargs) > 0 then force = "FORCE"
if wordpos("TEST" ,uargs) > 0 then test = "TEST"
if wordpos("DEBUG",uargs) > 0 then debug = "DEBUG"
end
signal on failure
signal on halt
call check_for_other_socket_app
call read_gopherrc
call validate_operands
call libdef
call let_me_know
call ggm_dialog
call unlibdef
cleanup:
if libdeffed then call unlibdef
if stacked then "DELSTACK"
exit
error:failure:halt:say "GOPHER: Severe lossage."
say "Statement:" sourceline(sigl)
exit
/*********************************************************************/
validate_operands:
/*
* Logic that determines what to display on startup:
* If gopherrc file does not exist, create it from default
* (default has everything commented out except for a
* one-item "initial" menu pointing to the MVS server)
* Read gopherrc (in case operands need fields therein)
* Command operands override gopherrc specs:
* if LOCAL given then server = "-", see below for SERVER(-)
* if SERVER(host) given then startup host=SERVER, path=PATH, etc.
* (no gopherrc referenced)
* if SERVER(-) given then either PATH must be given or
* the gopherrc's localmenu: must be given,
* otherwise look at gopherrc
* if LOCAL given and initial: present then extract startup menu
* but remember that there will be no server access possible
* else nothing given, this is an error, barf
* if no SERVER, look at gopherrc:
* if initial: given then extract startup menu from there
* else if localmenu: given then use that menu (SERVER=-)
* else nothing given, display ISPF panel asking for host/path
*/
if local = "LOCAL" then do
if server <> "" then do
say "GOPHER: SERVER cannot be specified when LOCAL is specified."
exit 12
end
server = "-"
end
ggpath = ""
gghost = ""
ggport = port
ggdesc = description
if server <> "" then do
if server = "-" then do
gghost = server
if path <> "" then do
ggpath = path
end
else if localmenu <> "" then do
ggpath = localmenu
if ggdesc = "" then ggdesc = "Local Private Gopher Menu"
end
else if local = "LOCAL" & initial <> "" then do
gghost = ""
call use_initial_spec
if gghost <> "-" then do
say "Gopher: Cannot determine path for local access."
say " Either specify PATH(pathname), activate"
say " the localmenu: line in GOPHERRC, or set"
say " the initial: line in GOPHERRC for local access."
exit 12
end
end
else do
say "Gopher: Cannot determine path for local access."
say " Either specify PATH(pathname) or activate"
say " the localmenu: or initial: line in GOPHERRC."
exit 12
end
end
else do
gghost = server
ggpath = path
ggdesc = description
ggport = port
nop /* use provided server, host, path, etc. */
end
end
else do /* no server given on command */
if localmenu <> "" then do
gghost = "-"
ggpath = localmenu
if ggdesc = "" then ggdesc = "Local Private Gopher Menu"
end
else if initial <> "" then do
call use_initial_spec
end
else do
/* this is nominally illegal, but should cause gopher to
display the hackish startup menu */
gghost = ""
ggpath = ""
end
end
return
/*********************************************************************/
use_initial_spec:
if initial = "*temp*" then do
/* we're eventually not going to do it this way really */
/* initial_type is ignored - only "DIRECTORY" is valid anyway */
if initial_name <> "" & ggdesc = "" then ggdesc = initial_name
if initial_host <> "" & gghost = "" then gghost = initial_host
if initial_path <> "" & ggpath = "" then ggpath = initial_path
if initial_port <> "" & ggport = "" then ggport = initial_port
end
else do
ggpath = initial
if ggdesc = "" then ggdesc = "Local Private Gopher Menu"
end
return
/*********************************************************************/
read_gopherrc:
localmenu = ""
localexec = ""
initial = ""
initial_type = ""
initial_name = ""
initial_host = ""
initial_path = ""
initial_port = ""
new_gopherrc = 0
gopherrc = "'"userid()".GOPHERRC'"
gopherdcb = "RECFM(V B) LRECL(255) BLKSIZE(6233) DSORG(PS)"
gopherrc_status = sysdsn(gopherrc)
select
when gopherrc_status = "OK" then nop
when gopherrc_status = "DATASET NOT FOUND" then do
address TSO "ALLOC DA("gopherrc") T SP(1 1)" gopherdcb
if rc <> 0 then do
say "Error: Cannot create" gopherrc
exit rc
end
new_gopherrc = 1
end
otherwise do
say "Error: Cannot access" gopherrc":" gopherrc_status
exit 16
end
end
address TSO "ALLOC FI(GOPHERRC) DA("gopherrc") OLD REU"
if rc <> 0 then exit rc
if new_gopherrc = 0 then do
"EXECIO * DISKR GOPHERRC (FINIS STEM GOPHERRC.)"
execiorc = rc
if execiorc <> 0 then do
say "Error: Cannot read" gopherrc
address TSO "FREE FI(GOPHERRC)"
exit execiorc
end
if gopherrc.0 = 0 then new_gopherrc = 1
end
if new_gopherrc then call initialize_gopherrc
address TSO "FREE FI(GOPHERRC)"
collecting_initial = 0
do i = 1 to gopherrc.0
gline = gopherrc.i
if gline = "" then iterate
if left(gline,1) = '#' then iterate
parse var gline ghead ":" gtext
ghead = translate(strip(ghead,"B"))
gtext = strip(gtext,"B")
if collecting_initial then do
parse var gline ghead "=" gtext
ghead = translate(strip(ghead,"B"))
gtext = strip(gtext,"B")
select
when ghead = "TYPE" then initial_type = gtext
when ghead = "NAME" then initial_name = gtext
when ghead = "PATH" then initial_path = gtext
when ghead = "HOST" then initial_host = gtext
when ghead = "PORT" then initial_port = gtext
when ghead = "END" then do
collecting_initial = 0
initial = "*temp*"
end
otherwise do
say "Error in "gopherrc": INITIAL: not terminated by END"
say "Line where error was detected:"
say gline
exit 8
end
end
end
else select
when ghead = "LOCALMENU" then localmenu = gtext
when ghead = "LOCALEXEC" then localexec = gtext
when ghead = "INITIAL" then do
if gtext = "" then collecting_initial = 1
else initial = gtext
end
otherwise do
say "Warning, gopherrc field ignored:" ghead
end
end
end
return
/*********************************************************************/
ggm_dialog:
vputvars = "GGHOST GGPORT GGPATH GGDESC"
if vputvars <> "" then do
address ISPEXEC "VPUT ("vputvars") PROFILE"
if rc <> 0 then do; call ispf_error rc; exit rc; end
end
parm = ""
if test = "TEST" then parm = parm "-t"
if debug = "DEBUG" then parm = parm "-d"
if local = "LOCAL" then parm = parm "-l"
if gghost <> "" then parm = parm "-q"
zerrmsg = ""
zerrsm = ""
zerrlm = ""
if ggmappl = "" then applsource = ""
else applsource = "NEWAPPL("ggmappl") PASSLIB"
if ggmload = "" then selstring = "PGM("ggmlmod") PARM("parm")"
else selstring = "CMD(CALL '"ggmload"("ggmlmod")'" quote(parm)")"
address ISPEXEC "SELECT" applsource selstring
if rc <> 0 then say "Return code from" ggmlmod "program is" rc
address ISPEXEC "VGET (ZERRSM ZERRLM)"
if zerrsm <> "" then do
say zerrmsg":" zerrsm
say zerrlm
end
return
/*********************************************************************/
libdef:
if ggmpanel <> "" then do
address ISPEXEC "LIBDEF ISPPLIB DATASET ID('"ggmpanel"')"
if rc <> 0 then do; call ispf_error rc; exit rc; end
end
if localexec <> "" then do
address TSO "ALLOC FI(GGEXEC) SHR REU DA('"localexec"')"
if rc <> 0 then exit rc
end
libdeffed = 1
return
/*********************************************************************/
unlibdef:
if localexec <> "" then do
address TSO "FREE FI(GGEXEC)"
end
if ggmpanel <> "" then do
address ISPEXEC "LIBDEF ISPPLIB DATASET"
if rc <> 0 then call ispf_error rc
end
libdeffed = 0
return
/*********************************************************************/
initialize_gopherrc:
say "Initializing new GOPHERRC file..."
do i = sigl while sourceline(i) <> "_BEGIN_"
end
gx = 0
do i = i+1 by 1
gline = sourceline(i)
if gline = "_END_" then leave
gpos = pos("ggmdefaulthost",gline)
if gpos > 0 then do
gline = substr(gline,1,gpos-1) || ggmdefaulthost
end
gx = gx + 1
gopherrc.gx = gline
end
gopherrc.0 = gx
"EXECIO * DISKW GOPHERRC (FINIS STEM GOPHERRC.)"
say "New GOPHERRC file initialized."
return
/*
_BEGIN_
#
#
# Default "gopherrc" file, created by the MVS Gopher client.
#
# Uncomment desired fields by removing the initial "# " from them.
#
# Beware - the Gopher client may update this file with bookmarks.
# You can delete it at any time and it will be recreated
# from the default settings, but you'll lose your bookmarks.
#
######################################################################
#
# If you want local (serverless) gopher access, then use the following
# lines, specifying full qualified (no quotes) data set names:
#
# localmenu: name_of_initial_gopher_menu
# localexec: name_of_pds_of_rexx_execs
#
# Specifying localmenu: is equivalent to specifying an initial: section
# with host set to "-" and path set to the value of localmenu.
#
# You cannot use your own REXX execs, however, unless you specify
# localexec: as above. You don't need one to use the other, though.
#
######################################################################
#
# The following is used by the Gopher client at startup to determine
# how the initial menu will appear.
#
# You may want to change the host to the one appropriate for your site.
#
initial:
#
Type=DIRECTORY
Name=Primary (Root) Gopher Menu
Path=
Host=ggmdefaulthost
Port=70
End
#
# Alternatively, if you want your own private Gopher data:
#
# initial:
#
# Type=0
# Name=My Own Private Gopherhole
# Path=userid.GOPHER.MENU
# Host=-
# End
#
# In which case you should create a data set called userid.GOPHER.MENU
# (or whatever name you choose that appears in the "Path=" line above)
# that looks like this. (NOT in the gopherrc file!)
#
#
# gopher_menu
#
# TYPE=DIRECTORY
# NAME=Public GOPHER Server at ggmdefaulthost
# PATH=
# HOST=ggmdefaulthost
# END
#
# TYPE=DIRECTORY
# NAME=Private GOPHER
# PATH=userid.ANOTHER.GOPHER.MENU
# HOST=-
# END
#
# and then you need yet another menu, similar in format to this one,
# in userid.ANOTHER.GOPHER.MENU. Get the idea?
#
######################################################################
#
# These fields may be used by the Gopher client for local purposes
# in the future. Currently they are ignored.
#
# Printercmd: lpr
# Telnetcmd: telnet
# Mailcmd: mail
# Playcmd: play -v 40 -
# TN3270cmd: tn3270
# MIMEcmd: metamail -p
#
######################################################################
_END_
*/
/*********************************************************************/
check_for_other_socket_app:
if local = "LOCAL" then return
call nnmfiucv /* FIND IUCVMULT in another PIE MultiTSO session */
if result = 0 then return
say,
"A TCP/IP socket application appears active in another PIE session."
if force = "FORCE" then do
say "Proceeding anyhow, because you said FORCE."
return
end
say "To proceed at this point would be potentially disastrous."
say "If you want to use GOPHER anyway, use one of these operands:"
say " FORCE - if I'm mistaken and it's really safe to make a"
say " TCP/IP connection."
say " LOCAL - if you just want local (serverless) access."
say "Terminating."
exit 16
/*********************************************************************/
ispf_error: parse arg ispfrc
say "GOPHER: ISPF dialog service error detected on line" sigl
say sourceline(sigl)
say
say zerrmsg":" zerrsm
say zerrlm
say
return ispfrc
/*********************************************************************/
/*
* The following function starts ISPF from READY mode.
* Beware: splitting the screen starts up an identical copy of the
* application, which may not be desirable.
*/
startispf: parse arg startappl, startcmd
if startappl = "" then,
"ISPSTART CMD("startcmd")"
else,
"ISPSTART NEWAPPL("startappl") CMD("startcmd")"
return
/* The following function implements Big Brother mode. */
let_me_know:
if gophermeister = "" | gophermeister = userid() then return
parse source . . execname . execds .
call outtrap "X."
address TSO,
"SEND" quote(execds"("execname")" date("U") time()" "),
"U("gophermeister") LOGON"
call outtrap "OFF"
return
/* The following function enquotes a string. */
quote: parse arg string
ix = 1
do forever
ix = pos("'",string,ix)
if ix = 0 then return "'"string"'"
string = insert("'",string,ix)
ix=ix+2
end
./ ADD NAME=NNMFIUCV,SSI=01000017
/* REXX. This exec scans the job pack queues for IUCVMULT and returns
* with an error code if IUCVMULT is already loaded under a
* different TCB. This can only happen under PIE MultiTSO or a
* similar product that makes multiple job step TCB's.
*/
trace off
signal on novalue
search_name = "IUCVMULT"
count = 0
foundtcb. = ""
current_tcb = getword24("21C")
current_job_step_tcb = getword24(current_tcb,"7C")
current_ascb = getword24("224")
current_asxb = getword31(current_ascb,"6C")
first_tcb = getword24(current_asxb,"4")
tcb = first_tcb
motherflag = 0
do forever
if motherflag = 0 then do
call process
daughter_tcb = getword24(tcb,"88")
if daughter_tcb \= "00000000" then do
tcb = daughter_tcb
iterate
end
end
motherflag = 0
sister_tcb = getword24(tcb, "80")
if sister_tcb \= "00000000" then do
tcb = sister_tcb
iterate
end
mother_tcb = getword24(tcb, "84")
if mother_tcb \= "00000000" then do
tcb = mother_tcb
motherflag = 1
iterate
end
leave
end
if count = 0 then return 0
problem = 0
do i = 1 to count
if foundtcb.i = current_job_step_tcb then do
/*
say search_name "is already loaded under current TCB at "foundtcb.i"."
*/
end
else do
/*
say search_name "is loaded under different TCB at "foundtcb.i"."
*/
problem = 1
end
end
if problem = 1 then return 1
else return 0
process:
jpq = getword31(tcb,"2C")
cde = jpq
do while cde \= "00000000"
cde_contents = storage(cde,32)
cde_name = substr(cde_contents,9,8)
cde_epa = substr(cde_contents,9,8)
if search_name = cde_name then do
count = count + 1
foundtcb.count = tcb
end
cde = getword31(cde,"0")
end
return
getword31: parse arg addr, offset
temp1 = x2d(addr)
if offset = "" then temp2 = 0
else temp2 = x2d(offset)
return c2x(storage(d2x(temp1+temp2),4))
getword24: parse arg addr, offset
temp1 = x2d(addr)
if offset = "" then temp2 = 0
else temp2 = x2d(offset)
return "00"c2x(storage(d2x(temp1+temp2+1),3))
./ ENDUP
?!
//H EXEC GGLOAD,TRK1='4',TO='H'
//SYSIN DD DATA,DLM='?!'
./ ADD NAME=GG,SSI=01330001
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
/* --------------------- "gg.h" include member --------------------- */
#pragma linkage(GGMbrifr,FORTRAN)
#pragma linkage(GGMbrifc,FORTRAN)
#pragma linkage(ispexec,OS)
#pragma linkage(isplink,OS)
#pragma linkage(ikjeff18,OS)
/****** Installation-customized defines. *****************************/
#include "gguser.h"
#ifndef C370V1
#ifndef C370V2
#ifndef SASC
install_error_neither_C370V1_C370V2_nor_SASC_was_defined;
#endif
#endif
#endif
#ifndef TCPIPV1
#ifndef TCPIPV2
install_error_neither_TCPIPV1_nor_TCPIPV2_was_defined;
#endif
#endif
#define MVS
/****** Clean up compiler warnings BEFORE time.h gets 'em ************/
#ifndef SASC
#define localtime LOCALTIM
#endif
/****** Include all header files that are necessary. *****************/
#include <manifest.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/uio.h>
#include <sys/ioctl.h>
#include <tcperrno.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <time.h>
/*
#include <signal.h>
*/
#ifndef SASC
#include <ctest.h>
#endif
#ifdef SASC
#include "ggsasc.h"
#endif
#undef ENOMEM
#include <mtf.h>
/****** Version-dependent stuff **************************************/
#ifdef C370V1
#undef FETCH
#endif
#ifdef C370V2
#define FETCH
#endif
#ifdef TCPIPV1
#define TCP_DEBUG tcp_debug
#endif
#ifdef TCPIPV2
#define TCP_DEBUG sock_debug
#endif
#ifdef DEBUG
#define TCP_DEBUG_ON TCP_DEBUG(1)
#define TCP_DEBUG_OFF TCP_DEBUG(0)
#else
#define TCP_DEBUG_ON /* */
#define TCP_DEBUG_OFF /* */
#endif
/****** Preprocessor bookkeeping *************************************/
#define Bool char
#define Fool unsigned int /* for function arguments */
#define COMMANDSIZE 12
#define GOPHER_FILE '0'
#define GOPHER_DIRECTORY '1'
#define GOPHER_CSO '2'
#define GOPHER_ERROR '3'
#define GOPHER_MAC_BINHEX '4'
#define GOPHER_DOS_BINARCH '5'
#define GOPHER_UUENCODE '6'
#define GOPHER_WAIS '7'
#define GOPHER_TELNET '8'
#define GOPHER_BINARY '9'
#define GOPHER_REDUNDANT '+'
#define GOPHER_WHOIS 'w'
#define READ_BYTES 1024
#define SERVER_BUF_MSGSIZE 1024
#define CLIENT_BUF_MSGSIZE 1024
#define TEXT_BYTES 1024
#define INTERNET_SIZE 256
#define RBUFSIZE 256
#define OUTBUFSIZE 1024
#define GOPHER_PORT_NUMBER 70
#define GOPHER_HOST_LENGTH MAXHOSTNAMELEN
#define GOPHER_PATH_LENGTH 512
#define GOPHER_DESC_LENGTH 256
#define SOCKET_GETCHAR_ERROR (-1)
#define SOCKET_NO_MORE (-2)
#define SOCKET_READ_NOTHING (-3)
#define NO_VALUE (-1)
#define Rstruc register struct
#define EQUAL !strcmp
#define UNEQUAL strcmp
#define CARRIAGE_RETURN ('\r')
#ifdef MVS
#ifdef I370
#define LINE_FEED (0x15)
#else
#define LINE_FEED (0x25)
#endif
#else
#define LINE_FEED (0x0a)
#endif
#ifdef MVS
#ifndef I370
#define etoa(x) ebcdictoascii[x]
#define atoe(x) asciitoebcdic[x]
#define ebcdictoascii ebcdicto
#define asciitoebcdic asciitoe
#else
#define etoa htoncs
#define atoe ntohcs
#endif
#endif
#ifdef FETCH
#define ISPLINK (gp->isplink_pointer)
#define ISPEXEC (gp->ispexec_pointer)
#else
#define ISPLINK isplink
#define ISPEXEC ispexec
#endif
#define DATAOUT_LOW 0x01
#define DATAOUT_HIGH 0x02
#define DATAIN_LOW 0x03
#define DATAIN_HIGH 0x04
#define DATAOUT_BLUE DATAOUT_LOW
#define DATAOUT_GREEN 0x05
#define DATAOUT_PINK 0x06
#define DATAOUT_RED 0x07
#define DATAOUT_TURQ 0x08
#define DATAOUT_WHITE DATAOUT_HIGH
#define DATAOUT_YELLOW 0x09
#define DATAIN_BLUE 0x0a
#define DATAIN_GREEN DATAIN_LOW
#define DATAIN_PINK 0x0b
#define DATAIN_RED DATAIN_HIGH
#define DATAIN_TURQ 0x0c
#define DATAIN_WHITE 0x0d
#define DATAIN_YELLOW 0x0e
#define S99VRBAL 0x01 /* ALLOCATION */
#define S99VRBUN 0x02 /* UNALLOCATION */
#define S99VRBCC 0x03 /* CONCATENATION */
#define S99VRBDC 0x04 /* DECONCATENATION */
#define S99VRBRI 0x05 /* REMOVE IN-USE */
#define S99VRBDN 0x06 /* DDNAME ALLOCATION */
#define S99VRBIN 0x07 /* INFORMATION RETRIEVAL */
#define S99NOCNV 0x40 /* ALLOC FUNCTION-DO NOT USE AN */
/* EXISTING ALLOCATION TO SATISFY*/
/* THE REQUEST */
#define DALDDNAM 0x0001 /* DDNAME */
#define DALDSNAM 0x0002 /* DSNAME */
#define DALMEMBR 0x0003 /* MEMBER NAME */
#define DALSTATS 0x0004 /* DATA SET STATUS */
#define DALNDISP 0x0005 /* DATA SET DISPOSITION */
#define DALBLKLN 0x0009 /* BLOCK LENGTH */
#define DALPRIME 0x000a /* PRIMARY SPACE ALLOCATION */
#define DALSECND 0x000b /* SECONDARY SPACE ALLOCATION */
#define DALDIR 0x000c /* DIRECTORY BLOCK ALLOCATION */
#define DALBLKSZ 0x0030 /* DCB BLOCKSIZE */
#define DALDSORG 0x003c /* DATA SET ORGANIZATION */
#define DALLRECL 0x0042 /* DCB LOGICAL RECORD LENGTH */
#define DALRECFM 0x0049 /* DCB RECORD FORMAT */
#define DALPERMA 0x0052 /* PERMANENTLY ALLOCATED ATTRIB */
#define DALRTDDN 0x0055 /* RETURN DDNAME */
#define DALRTDSN 0x0056 /* RETURN DSNAME */
#define DALRTORG 0x0057 /* RETURN D.S. ORGANIZATION */
#define DUNDDNAM 0x0001 /* DDNAME */
#define DUNDSNAM 0x0002 /* DSNAME */
#define DUNUNALC 0x0007 /* UNALLOC OPTION */
#define SHR 0x08
#define NEW 0x04
#define MOD 0x02
#define OLD 0x01
#define KEEP 0x08
#define DELETE 0x04
#define CATLG 0x02
#define UNCATLG 0x01
#define RECFM_F 0x80
#define RECFM_V 0x40
#define RECFM_U 0xc0
#define RECFM_D 0x20
#define RECFM_T 0x20
#define RECFM_B 0x10
#define RECFM_S 0x08
#define RECFM_A 0x04
#define RECFM_M 0x02
#define RECFM_FB (RECFM_F | RECFM_B)
#define RECFM_VB (RECFM_V | RECFM_B)
#define DSORG_PS 0x4000
#define DSORG_PO 0x0200
/****** Data and structure definitions. ******************************/
typedef struct _textunit TEXTUNIT;
typedef unsigned int IPADDRESS;
typedef char gophertype;
enum socket_retval {
SERVER_READ_OK,
SERVER_READ_ERROR,
SERVER_BUFFER_ERROR,
SERVER_NO_MORE,
SERVER_READ_NOTHING
};
enum data_set_type {
PDS,
SEQ,
UNK
};
enum user_option {
OPTION_ALL,
OPTION_VIEW,
OPTION_OTHER
};
struct textline {
struct textline *next;
short text_length;
short tab_expanded_text_length;
char *tab_expanded_text;
char text[1]; /* dummy */
};
struct texthdr {
int text_line_count;
struct textline *text_body_line;
short text_max_length;
short text_max_tab_expanded_length;
struct textline *first_text_line;
struct textline *current_text_line;
struct textline *last_text_line;
};
struct cmddesc {
char command_name[COMMANDSIZE];
Bool (*command_processor)();
};
struct seldesc {
char selection_code;
Bool (*selection_processor)();
};
struct tabledesc {
char *command_variable;
struct cmddesc *first_cmddesc;
struct seldesc *first_seldesc;
};
struct _textunit {
unsigned short key;
unsigned short num;
struct {
unsigned short len;
char prm[80];
} ent;
};
struct extraction {
int from_number;
int to_number;
int count;
enum data_set_type mode;
Bool appending;
Bool blanking;
Bool tab_expanding;
char panelname [9];
char dsname [65];
char separator [81];
char member_prefix [9];
char ddname [9];
};
struct gopherinfo {
gophertype type;
int port;
struct texthdr thdr;
char path [GOPHER_PATH_LENGTH+1];
char host [GOPHER_HOST_LENGTH+1];
char desc [GOPHER_DESC_LENGTH+1];
};
struct recvstruct {
int sockfd; /* socket descriptor for socket call */
int outlen;
FILE *outfp; /* used by local (non-socket) interface*/
char *fileptr;
char *wargptr;
FILE *readfile; /* declare the file... */
struct hostent clienthostent;
char myname [MAXHOSTNAMELEN+1];
char hostname[MAXHOSTNAMELEN+1]; /* client host name */
char hosttest[MAXHOSTNAMELEN+1]; /* client host name */
char buffer [RBUFSIZE]; /* client's character string */
char dsname [RBUFSIZE];
char sockbuf [OUTBUFSIZE]; /* socket output buffer */
};
struct menuitem {
char type; /* type of record to send */
char desc [GOPHER_DESC_LENGTH+1];
char select [GOPHER_PATH_LENGTH+1];
char hostname [GOPHER_HOST_LENGTH+1];
int port; /* host port to connect to */
};
struct ggcb {
char *server_buf;
char *client_buf;
char *gopher_command;
struct recvstruct *recvp;
char *extract_separator_line;
#ifdef FETCH
int (*isplink_pointer)();
int (*ispexec_pointer)();
#endif
int ispfrc;
int socknum;
int g_bytes_returned;
int g_buf_index;
int brif_previous_recno;
FILE *debug_file;
FILE *extract_file;
struct texthdr *brifp;
struct texthdr thdr;
struct gopherinfo *ginfo;
Bool test_mode;
Bool debug_mode;
Bool quit;
Bool time_to_go_home;
Bool server_has_something_pending;
Bool server_finished_replying;
Bool sending_text;
Bool receiving_text;
Bool local_mode;
Bool dont_read;
Bool connected_to_server;
Bool connection_broken;
Bool closing_connection;
Bool reconnect_in_progress;
Bool extract_tab_expanding;
Bool extract_appending;
Bool extract_blank_before_separator;
Bool extract_write_error;
Bool extract_close_error;
Bool warn_overwrite;
Bool warn_append;
Bool setmsg;
Bool autoscroll;
IPADDRESS client_ip_address;
IPADDRESS server_ip_address;
char ggserver [MAXHOSTNAMELEN+1];
char ggclient [MAXHOSTNAMELEN+1];
char client_hostname [MAXHOSTNAMELEN+1];
char client_ip_addrstr [16];
char server_hostname [MAXHOSTNAMELEN+1];
char server_ip_addrstr [16];
char g_buf [READ_BYTES];
};
#ifdef MVS
#ifndef I370
extern char ebcdictoascii[];
extern char asciitoebcdic[];
#endif
#endif
#ifndef FETCH
extern int isplink();
extern int ispexec();
#endif
#define NOTIFY_MSG 1
#define WARNING_MSG 2
#define CRITICAL_MSG 3
#define WARN1(X) GGMpmsg(gp,NOTIFY_MSG,NULL,X)
#define WARN2(X,Y) GGMpmsg(gp,NOTIFY_MSG,NULL,X,Y)
#define WARN3(X,Y,Z) GGMpmsg(gp,NOTIFY_MSG,NULL,X,Y,Z)
#define WARN4(X,Y,Z,W) GGMpmsg(gp,NOTIFY_MSG,NULL,X,Y,Z,W)
#define ERR1(X) GGMpmsg(gp,WARNING_MSG,NULL,X)
#define ERR2(X,Y) GGMpmsg(gp,WARNING_MSG,NULL,X,Y)
#define ERR3(X,Y,Z) GGMpmsg(gp,WARNING_MSG,NULL,X,Y,Z)
#define ERR4(X,Y,Z,W) GGMpmsg(gp,WARNING_MSG,NULL,X,Y,Z,W)
#define CRIT1(X) GGMpmsg(gp,CRITICAL_MSG,NULL,X)
#define CRIT2(X,Y) GGMpmsg(gp,CRITICAL_MSG,NULL,X,Y)
#define CRIT3(X,Y,Z) GGMpmsg(gp,CRITICAL_MSG,NULL,X,Y,Z)
#define GETMAIN(Ptr,Typ,Siz,For) \
GGMgetm(gp,(char **)&(Ptr),(sizeof(Typ))*(Siz),For)
#define FREEMAIN(Ptr,For) if (Ptr) {GGMfreem(gp,(char *)Ptr,For);}
#ifndef I370
#define OPEN_TEXT_FILE_FOR_WRITE(F) \
fopen((F),"w,recfm=vb,lrecl=259,blksize=6233")
#define OPEN_TEXT_FILE_FOR_APPEND(F) \
fopen((F),"a,recfm=vb,lrecl=259,blksize=6233")
#define OPEN_TEXT_FILE_FOR_WRITE_OR_APPEND(F,B) \
fopen((F),(B) ? "a,recfm=vb,lrecl=259,blksize=6233" \
: "w,recfm=vb,lrecl=259,blksize=6233")
#else
#define OPEN_TEXT_FILE_FOR_WRITE(F) \
afopen((F),"w","seq","recfm=v,lrecl=255,blksize=6233")
#define OPEN_TEXT_FILE_FOR_APPEND(F) \
afopen((F),"a","seq","recfm=v,lrecl=255,blksize=6233")
#define OPEN_TEXT_FILE_FOR_WRITE_OR_APPEND(F,B) \
afopen((F),(B)?"a":"w","seq","recfm=v,lrecl=255,blksize=6233")
#endif
#define ebdtoasc(C) {char *__cp;\
for(__cp = C;*__cp;__cp++) *__cp = etoa(*__cp);}
#define asctoebd(C) {char *__cp;\
for(__cp = C;*__cp;__cp++) *__cp = atoe(*__cp);}
#define uppercase_in_place(C) {char *__cp;\
for(__cp=C;*__cp;__cp++) *__cp = toupper(*__cp);}
#define lowercase_in_place(C) {char *__cp;\
for(__cp=C;*__cp;__cp++) *__cp = tolower(*__cp);}
/****** Procedure and function declarations. *************************/
extern enum data_set_type GGMalloc(char *, char *, enum data_set_type,
int);
extern int GGMbrifr(char **, int *, int *, void *);
extern int GGMbrifc(int *, void *);
extern void GGMbtext(struct ggcb *, struct texthdr *,
FILE *);
extern void GGMclrtx(struct ggcb *,struct gopherinfo *);
extern Bool GGMconn (struct ggcb *);
extern char *GGMcopy (struct ggcb *, char *);
extern void GGMdfail(int,__S99parms *);
extern Bool GGMdir (struct ggcb *,struct gopherinfo *,
Fool);
extern void GGMdisc (struct ggcb *);
extern int GGMdispl(struct ggcb *, char *);
extern void GGMdump (struct ggcb *,char *, char *, int);
extern void GGMesrvr(struct ggcb *);
extern void GGMfreem(struct ggcb *,char *,char *);
extern FILE *GGMgetds(struct ggcb *,struct extraction *);
extern void GGMgetm (struct ggcb *,char **,int,char *);
extern Bool GGMgofor(struct ggcb *,struct gopherinfo *,
Fool);
extern Bool GGMgsrvl(struct ggcb *, char **);
extern void GGMierr (struct ggcb *);
extern int GGMiget (struct ggcb *, char *);
extern void GGMimsg (struct ggcb *, char *);
extern Bool GGMispf (struct ggcb *, char *);
extern Bool GGMivget(struct ggcb *, char *, char *,int);
extern Bool GGMivput(struct ggcb *, char *, char *,int);
extern void GGMmtfer(int, char*);
extern struct textline *GGMouttx(struct ggcb *, char *,
struct gopherinfo *);
extern Bool GGMouts (struct recvstruct *, char *);
extern Bool GGMproc (struct recvstruct *);
extern void GGMrbfm (struct ggcb *);
extern void GGMrperr(struct ggcb *);
extern Bool GGMsockt(struct ggcb *);
extern void GGMsopt (struct ggcb *,enum user_option);
extern char *GGMstrlc(char *, char *);
extern Bool GGMtnet (struct ggcb *,struct gopherinfo *,
Fool);
extern int GGMtso (char *);
extern char *GGMtype (gophertype);
extern Bool GGMunalc(char *);
extern Bool GGMvtx (struct ggcb *,struct gopherinfo *,
Fool);
extern Bool GGMwais (struct ggcb *,struct gopherinfo *,
Fool);
extern Bool GGMwhois(struct ggcb *,struct gopherinfo *,
Fool);
extern Bool GGMxlist(struct ggcb *,char *);
extern Bool GGMxtx (struct ggcb *,struct gopherinfo *);
#ifndef SUPPRESS_V_DECLARATION
extern void GGMpmsg (struct ggcb *,int,char *,char *,
...);
#endif
./ ADD NAME=GGSASC,SSI=01000043
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* SAS modifications due to Dale Ingold at SAS Institute, Inc. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
/* ------------------- "ggsasc.h" include member ------------------- */
#ifdef SASC
#define I370
#include <dynam.h>
#define FETCH
__inline void (*fetch( const char *modname ))()
{
void (*fpp)();
loadm( modname, &fpp );
return( fpp );
}
__inline int (*release( void (*fpp)() ))
{
unloadm( fpp );
return( 0 );
}
#ifndef __SVC99
#define __SVC99 1
#include <code.h>
struct __S99struc
{
unsigned char __S99RBLN; /* length of request block..20 */
unsigned char __S99VERB; /* verb code */
unsigned short __S99FLAG1; /* FLAGS1 field of SVC99 Req Block */
unsigned short __S99ERROR; /* error code field */
unsigned short __S99INFO; /* information reason code */
void *__S99TXTPP; /* address of text unit pointer list*/
int __reserved; /* reserved..will always be 0 */
unsigned int __S99FLAG2; /* FLAGS2 field..can only be filled */
/* in by APF authorized programs */
};
typedef struct __S99struc __S99parms;
__inline int svc99(__S99parms* svc99parmlist)
{ return( (_ldregs(R1, &svc99parmlist),
_code(0, 0x0a63),
_stregs(R15) ) );
}
#endif
#define FALSE 0
#define TRUE 1
#include <lcio.h>
#define MAXHOSTNAMELEN 64
#define __ctest(X) fprintf(stderr,\
"GGMVS: CTEST is not supported by this compiler.")
#endif
./ ADD NAME=GGUSER,SSI=01140048
/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 */
/* */
/* GOPHER server due to Shawn Hart at the University of Delaware. */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/
/* ------------------- "gguser.h" include member ------------------- */
/* Include file for locally customized values. */
/* Define levels of C/370 and TCP/IP. This controls support for
* fetching of non-C load modules and socket error reporting.
*/
/* #define C370V1 /* define this if C/370 Version 1 */
#define C370V2 /* define this if C/370 Version 2 or higher */
/* #define SASC /* define this if SAS/C compiler */
/* #define TCPIPV1 /* define this if TCP/IP Version 1 */
#define TCPIPV2 /* define this if TCP/IP Version 2 or higher */
/* Define the following defaults for your installation. */
/* Use XTELNET if you like the CSOCK package from UCLA. */
#define TELNET_COMMAND_NAME "TELNET"
/* #define TELNET_COMMAND_NAME "XTELNET" */
/*
* Turn on for TCP-level debugging output (you probably don't want to
* unless your TCP/IP stuff is really broken and I can't help you).
*/
/* #define DEBUG */
#undef DEBUG
/*
* Turn on for MTF-level debugging output.
*/
/* #define DEBUGMTF */
#undef DEBUGMTF
/* Server and MTF stuff. */
#define MTF_TASKS 8
#define TCP_QUEUE_LENGTH 20
#define SERV_TCP_PORT 70
#define CONNECT_TIME_OUT 60
#define DEFAULT_DIRECTORY "DD:GGGOPHER"
#define ACCESS_TABLE "DD:GGACCESS"
#define MY_DOMAIN_SUFFIX ".DRAPER.COM"
/* note: could get MY_DOMAIN_SUFFIX from TCPIP startup - what call? */
/* Client stuff. */
#define INITIAL_TYPE GOPHER_DIRECTORY
#define INITIAL_PORT GOPHER_PORT_NUMBER
#define INITIAL_PATH ""
#define INITIAL_HOST "MVS.DRAPER.COM"
#define INITIAL_DESC "Root"
/* Server and client stuff. */
#define IDENT_HOST_FROB "+"
#define LOCAL_HOST_FROB "-"
/********************************************************************/
/* The following defines the module name for the MTF subtask. */
/********************************************************************/
#define GOPHER_PARALLEL_TASK "GGSTASK"
/********************************************************************/
/* following are "gopher" record types. */
/********************************************************************/
#define GFILE '0'
#define MENU '1'
#define ERROR '2'
#define INDEX '7'
#define TELNET '8'
#define WHOIS 'w'
/********************************************************************/
/* following are MVS file type identifiers. They must appear at the
beginning of the file they're identifying. */
/********************************************************************/
#define MENUIDENT "GOPHER_MENU"
#define INDEXIDENT "GOPHER_INDEX"
/********************************************************************/
/* following are tokens for menu GOPHER identifiers. */
/********************************************************************/
#define TOKTYPE "TYPE"
#define TYPETOK 0
#define TOKNAME "NAME"
#define NAMETOK 1
#define TOKPATH "PATH"
#define PATHTOK 2
#define TOKHOST "HOST"
#define HOSTTOK 3
#define TOKPORT "PORT"
#define PORTTOK 4
#define TOKEND "END"
#define ENDTOK 5
#define TOKCOMMENT "*"
#define COMMENTTOK 6
#define TOKDISPLAY "DISPLAY"
#define DISPLAYTOK 7
#define TOKSELECT "SELECTOR"
#define SELECTTOK 8
/********************************************************************/
/* types of "types" - operands of the TYPE keyword in directories.*/
/********************************************************************/
#define TYPEFILE "FILE"
#define TYPEMENU "DIRECTORY"
#define TYPEINDEX "INDEX"
#define TYPETELNET "TELNET"
#define TYPEWHOIS "WHOIS"
/********************************************************************/
/* used by the REXX Interface */
/********************************************************************/
/* Be sure to include all 8 bytes, including blanks, in below */
#define REXX_EXEC_LIBRARY_DDNAME "GGEXEC "
#define REXX_EXEC_SUBCOM " "
./ ENDUP
?!
//PANELS EXEC GGLOAD,TRK1='4',TO='PANELS'
//SYSIN DD DATA,DLM='?!'
./ ADD NAME=GGM,SSI=01060053
)ATTR
/* /*
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 /*
/* /*
/* This software is provided on an "AS IS" basis. All warranties, /*
/* including the implied warranties of merchantability and fitness, /*
/* are expressly denied. /*
/* /*
/* Provided this copyright notice is included, this software may /*
/* be freely distributed and not offered for sale. /*
/* /*
/* Changes or modifications may be made and used only by the maker /*
/* of same, and not further distributed. Such modifications should /*
/* be mailed to the author for consideration for addition to the /*
/* software and incorporation in subsequent releases. /*
/* /*
^ TYPE(INPUT) INTENS(HIGH) COLOR(GREEN) CAPS(OFF)
! TYPE(TEXT) INTENS(HIGH) COLOR(RED)
)BODY EXPAND(``)
%-`-`- MVS Gopher Client -`-`-
%COMMAND ===>_ZCMD
+
%Gopher server host name+(or IP address) %===>_GGHOST
+
%Initial path%===>^GGPATH
%Port number %===>_GGPORT
+
+Note: You may specify a dash%-+as the Gopher server host name if
you want to use your own private Gopher data without making
a connection to a server. If you do, you must specify the
name of your private Gopher menu in the initial path.
This name must be UNQUOTED AND FULLY QUALIFIED.
Alternatively, you may allocate your initial Gopher menu
to file GGGOPHER.
Any menu entries must also specify a dash in the host field;
otherwise they will require server access, as usual.
To use the REXX interface, you must allocate file GGEXEC to
your library of Gopherable REXX execs.
+Press!END+key to leave this menu.
)INIT
&ZCMD = &Z
IF (&GGPORT = &Z) &GGPORT = 70
)PROC
IF (&ZCMD ^= &Z) .MSG = ISPZ001
VER (&GGHOST,NB)
VER (&GGPORT,NUM)
VPUT (GGHOST GGPATH GGPORT) PROFILE
)END
./ ADD NAME=GGMDIR,SSI=01020021
)ATTR
/* /*
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 /*
/* /*
/* This software is provided on an "AS IS" basis. All warranties, /*
/* including the implied warranties of merchantability and fitness, /*
/* are expressly denied. /*
/* /*
/* Provided this copyright notice is included, this software may /*
/* be freely distributed and not offered for sale. /*
/* /*
/* Changes or modifications may be made and used only by the maker /*
/* of same, and not further distributed. Such modifications should /*
/* be mailed to the author for consideration for addition to the /*
/* software and incorporation in subsequent releases. /*
/* /*
~ TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
^ TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
! TYPE(OUTPUT) INTENS(LOW) CAPS(OFF) JUST(RIGHT) COLOR(YELLOW)
# TYPE(OUTPUT) INTENS(LOW) CAPS(OFF) JUST(RIGHT) COLOR(BLUE)
@ TYPE(OUTPUT) INTENS(HIGH) CAPS(OFF) JUST(RIGHT) COLOR(PINK)
? TYPE(OUTPUT) INTENS(LOW) CAPS(OFF) JUST(LEFT) COLOR(TURQ) PAD('.')
| AREA(DYNAMIC) EXTEND(ON) SCROLL(ON)
\ AREA(DYNAMIC) EXTEND(OFF) SCROLL(OFF)
01 TYPE(DATAOUT) INTENS(LOW)
02 TYPE(DATAOUT) INTENS(HIGH)
03 TYPE(DATAIN) INTENS(LOW)
04 TYPE(DATAIN) INTENS(HIGH)
05 TYPE(DATAOUT) COLOR(GREEN)
06 TYPE(DATAOUT) COLOR(PINK)
07 TYPE(DATAOUT) COLOR(RED)
08 TYPE(DATAOUT) COLOR(TURQ)
09 TYPE(DATAOUT) COLOR(YELLOW)
0A TYPE(DATAIN) COLOR(BLUE)
0B TYPE(DATAIN) COLOR(PINK)
0C TYPE(DATAIN) COLOR(TURQ)
0D TYPE(DATAIN) COLOR(WHITE)
0E TYPE(DATAIN) COLOR(YELLOW)
)BODY EXPAND(``)
%&GGGHEAD
%COMMAND ===>~GGGCMD %SCROLL ===>^GAMT+
+
+%S+Select%Q+Query%E+Extract
-------------------------------------------------------------------------------
|GGGDYNA |
)INIT
IF (&GAMT = &Z) &GAMT = CSR
)PROC
&GGGLVL = LVLINE(GGGDYNA)
VPUT (GAMT) PROFILE
)END
./ ADD NAME=GGMLCONN,SSI=01000059
)ATTR
/* /*
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 /*
/* /*
/* This software is provided on an "AS IS" basis. All warranties, /*
/* including the implied warranties of merchantability and fitness, /*
/* are expressly denied. /*
/* /*
/* Provided this copyright notice is included, this software may /*
/* be freely distributed and not offered for sale. /*
/* /*
/* Changes or modifications may be made and used only by the maker /*
/* of same, and not further distributed. Such modifications should /*
/* be mailed to the author for consideration for addition to the /*
/* software and incorporation in subsequent releases. /*
/* /*
^ TYPE(TEXT) INTENS(HIGH) COLOR(BLUE) HILITE(REVERSE)
@ TYPE(TEXT) INTENS(HIGH) COLOR(PINK)
# TYPE(TEXT) INTENS(LOW) COLOR(TURQ)
\ TYPE(TEXT) INTENS(HIGH) COLOR(YELLOW)
! TYPE(TEXT) INTENS(HIGH) COLOR(RED)
$ TYPE(TEXT) INTENS(LOW) COLOR(GREEN)
~ TYPE(TEXT) INTENS(HIGH) COLOR(WHITE)
)BODY EXPAND(``)
%-`-`- MVS Gopher Server Connection -`-`-
+
+ Client name: &GGCLIENT Client IP address: &GGCLIEIP
+
+
+ Connection is in progress for Gopher server at:
&GGSERVER (&GGSERVIP)
+
+
% Please wait.
+
+
)INIT
)PROC
)END
./ ADD NAME=GGMLDISC,SSI=01000024
)ATTR
/* /*
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 /*
/* /*
/* This software is provided on an "AS IS" basis. All warranties, /*
/* including the implied warranties of merchantability and fitness, /*
/* are expressly denied. /*
/* /*
/* Provided this copyright notice is included, this software may /*
/* be freely distributed and not offered for sale. /*
/* /*
/* Changes or modifications may be made and used only by the maker /*
/* of same, and not further distributed. Such modifications should /*
/* be mailed to the author for consideration for addition to the /*
/* software and incorporation in subsequent releases. /*
/* /*
^ TYPE(TEXT) INTENS(HIGH) COLOR(BLUE) HILITE(REVERSE)
@ TYPE(TEXT) INTENS(HIGH) COLOR(PINK)
# TYPE(TEXT) INTENS(LOW) COLOR(TURQ)
\ TYPE(TEXT) INTENS(HIGH) COLOR(YELLOW)
! TYPE(TEXT) INTENS(HIGH) COLOR(RED)
$ TYPE(TEXT) INTENS(LOW) COLOR(GREEN)
~ TYPE(TEXT) INTENS(HIGH) COLOR(WHITE)
)BODY EXPAND(``)
%-`-`- MVS Gopher Server Connection -`-`-
+
+
+ Disconnection is in progress from the Gopher server at:
&GGSOLDER (&GGSOLDIP)
+
+
% Please wait.
+
+
)INIT
)PROC
)END
./ ADD NAME=GGMLEXN2,SSI=01000018
)ATTR
/* /*
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 /*
/* /*
/* This software is provided on an "AS IS" basis. All warranties, /*
/* including the implied warranties of merchantability and fitness, /*
/* are expressly denied. /*
/* /*
/* Provided this copyright notice is included, this software may /*
/* be freely distributed and not offered for sale. /*
/* /*
/* Changes or modifications may be made and used only by the maker /*
/* of same, and not further distributed. Such modifications should /*
/* be mailed to the author for consideration for addition to the /*
/* software and incorporation in subsequent releases. /*
/* /*
^ TYPE(TEXT) INTENS(HIGH) COLOR(BLUE) HILITE(REVERSE)
@ TYPE(TEXT) INTENS(HIGH) COLOR(PINK)
\ TYPE(TEXT) INTENS(HIGH) COLOR(YELLOW)
! TYPE(TEXT) INTENS(HIGH) COLOR(RED)
$ TYPE(TEXT) INTENS(LOW) COLOR(GREEN)
~ TYPE(TEXT) INTENS(HIGH) COLOR(WHITE)
)BODY EXPAND(``)
%-`-`- MVS Gopher Server Connection -`-`-
+
+Description: &GGTSUBJ
+
+Extracting to: &GGEXDSN
+&MEMSTUFF
+
% Please wait.
+
)INIT
IF (&GGEXMEM = &Z) &MEMSTUFF = &Z
ELSE &MEMSTUFF = 'Member: &GGEXMEM'
)PROC
)END
./ ADD NAME=GGMLRCON,SSI=01000048
)ATTR
/* /*
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 /*
/* /*
/* This software is provided on an "AS IS" basis. All warranties, /*
/* including the implied warranties of merchantability and fitness, /*
/* are expressly denied. /*
/* /*
/* Provided this copyright notice is included, this software may /*
/* be freely distributed and not offered for sale. /*
/* /*
/* Changes or modifications may be made and used only by the maker /*
/* of same, and not further distributed. Such modifications should /*
/* be mailed to the author for consideration for addition to the /*
/* software and incorporation in subsequent releases. /*
/* /*
^ TYPE(TEXT) INTENS(HIGH) COLOR(BLUE) HILITE(REVERSE)
@ TYPE(TEXT) INTENS(HIGH) COLOR(PINK)
# TYPE(TEXT) INTENS(LOW) COLOR(TURQ)
\ TYPE(TEXT) INTENS(HIGH) COLOR(YELLOW)
! TYPE(TEXT) INTENS(HIGH) COLOR(RED)
$ TYPE(TEXT) INTENS(LOW) COLOR(GREEN)
~ TYPE(TEXT) INTENS(HIGH) COLOR(WHITE)
)BODY EXPAND(``)
%-`-`- MVS Gopher Server Connection -`-`-
+
+Connection has apparently been lost to the Gopher server at:
&GGSERVER (&GGSERVIP)
+
+Reconnection to the server is in progress.
+
% Please wait.
+
+
)INIT
)PROC
)END
./ ADD NAME=GGMPEXDS,SSI=01000044
)ATTR
/* /*
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 /*
/* /*
/* This software is provided on an "AS IS" basis. All warranties, /*
/* including the implied warranties of merchantability and fitness, /*
/* are expressly denied. /*
/* /*
/* Provided this copyright notice is included, this software may /*
/* be freely distributed and not offered for sale. /*
/* /*
/* Changes or modifications may be made and used only by the maker /*
/* of same, and not further distributed. Such modifications should /*
/* be mailed to the author for consideration for addition to the /*
/* software and incorporation in subsequent releases. /*
/* /*
^ TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
)BODY WINDOW(77,16)
+
%Command ===>^ZCMD
+
%&SUBJECT
+
+Save to data set ===>_GGEXDSN
+Expand tab characters? ===>_Z +
+(Note: Data set will be RECFM=VB, LRECL=259, BLKSIZE=6233.)
+Append to end of data set? ===>_Z +
+Blank line after separator? ===>_Z +
+Separator line between items (append mode only...blank for none):
+>^Z +<
+Press%&END (END)+to cancel the extract request.
)INIT
.ZVARS = '(GGEXTAB GGEXAPP GGEXBLK GGEXSEP)'
.CURSOR = GGEXDSN
&ZWINTTL = 'Extract text'
&SUBJECT = '&GGTSUBJ'
&END = PFK(END)
&ZCMD = &Z
VGET (GGEXDSN GGEXTAB GGEXAPP GGEXBLK GGEXSEP) PROFILE
&GGEXTAB = TRANS(&GGEXTAB Y,YES N,NO ' ',NO)
&GGEXAPP = TRANS(&GGEXAPP Y,YES N,NO ' ',NO)
&GGEXBLK = TRANS(&GGEXBLK Y,YES N,NO ' ',NO)
)PROC
IF (&ZCMD ^= &Z) .MSG = ISPZ001
VER(&GGEXDSN,NB,DSNAME)
&GGEXTAB = TRUNC(&GGEXTAB,1)
VER(&GGEXTAB,NB,LIST,Y,N)
&GGEXAPP = TRUNC(&GGEXAPP,1)
VER(&GGEXAPP,NB,LIST,Y,N)
&GGEXBLK = TRUNC(&GGEXBLK,1)
VER(&GGEXBLK,NB,LIST,Y,N)
VPUT (GGEXDSN GGEXTAB GGEXAPP GGEXBLK GGEXSEP) PROFILE
)END
./ ADD NAME=GGMPEXNG,SSI=01000027
)ATTR
/* /*
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 /*
/* /*
/* This software is provided on an "AS IS" basis. All warranties, /*
/* including the implied warranties of merchantability and fitness, /*
/* are expressly denied. /*
/* /*
/* Provided this copyright notice is included, this software may /*
/* be freely distributed and not offered for sale. /*
/* /*
/* Changes or modifications may be made and used only by the maker /*
/* of same, and not further distributed. Such modifications should /*
/* be mailed to the author for consideration for addition to the /*
/* software and incorporation in subsequent releases. /*
/* /*
^ TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
)BODY WINDOW(77,14)
+
%Command ===>^ZCMD
+
+Save to data set ===>_GGEXDSN
+(Note: Data set will be RECFM=VB, LRECL=259, BLKSIZE=6233.)
+Append to end of data set? ===>_Z +
+Blank line after separator? ===>_Z +
+Separator line between items (append mode only...blank for none):
+>^Z +<
+Press%&END (END)+to cancel the extract request.
)INIT
.ZVARS = '(GGEXAPP GGEXBLK GGEXSEP)'
.CURSOR = GGEXDSN
&ZWINTTL = 'Extract item listing'
&END = PFK(END)
&ZCMD = &Z
VGET (GGEXDSN GGEXAPP GGEXBLK GGEXSEP) PROFILE
&GGEXAPP = TRANS(&GGEXAPP Y,YES N,NO ' ',NO)
&GGEXBLK = TRANS(&GGEXBLK Y,YES N,NO ' ',NO)
)PROC
IF (&ZCMD ^= &Z) .MSG = ISPZ001
VER(&GGEXDSN,NB,DSNAME)
&GGEXAPP = TRUNC(&GGEXAPP,1)
VER(&GGEXAPP,NB,LIST,Y,N)
&GGEXBLK = TRUNC(&GGEXBLK,1)
VER(&GGEXBLK,NB,LIST,Y,N)
VPUT (GGEXDSN GGEXAPP GGEXBLK GGEXSEP) PROFILE
)END
./ ADD NAME=GGMPEXNP,SSI=01000026
)ATTR
/* /*
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 /*
/* /*
/* This software is provided on an "AS IS" basis. All warranties, /*
/* including the implied warranties of merchantability and fitness, /*
/* are expressly denied. /*
/* /*
/* Provided this copyright notice is included, this software may /*
/* be freely distributed and not offered for sale. /*
/* /*
/* Changes or modifications may be made and used only by the maker /*
/* of same, and not further distributed. Such modifications should /*
/* be mailed to the author for consideration for addition to the /*
/* software and incorporation in subsequent releases. /*
/* /*
^ TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
)BODY EXPAND(``) WINDOW(77,14)
+
%Command ===>^ZCMD
+
+Data set name%===>_GGEXPDS
+Member prefix%===>_GGEXPMP + (item number appended - default is%#+)
+Note: The dataset must be a PDS (old or new) with RECFM=VB and LRECL=259.
+Expand tab characters? %===>_Z +
+From item number%===>_GGEXAN1 + (blank for first item in table)
+To item number%===>_GGEXAN2 + (blank for last item in table)
+Press%&END (END)+to cancel the extract request.
)INIT
.ZVARS = '(GGEXTAB)'
.CURSOR = ZCMD
&ZWINTTL = 'Log text of items to PDS members'
&END = PFK(END)
&ZCMD = &Z
VGET (GGEXPDS GGEXPMP GGEXTAB) PROFILE
&GGEXTAB = TRANS(&GGEXTAB Y,YES N,NO ' ',NO)
IF (&GGEXPMP = &Z) &GGEXPMP = '#'
&GGEXAN1 = &Z
&GGEXAN2 = &Z
)PROC
IF (&ZCMD ^= &Z) .MSG = ISPZ001
&GGEXTAB = TRUNC(&GGEXTAB,1)
VER(&GGEXTAB,NB,LIST,Y,N)
VER(&GGEXPDS,NB,DSNAME)
&TEMP1 = TRUNC(&GGEXPDS,1)
&TEMP2 = .TRAIL
IF (&TEMP1 = '''')
&GGEXDSN = TRUNC(&TEMP2,'''')
ELSE
&GGEXDSN = '&ZPREFIX..&GGEXPDS'
VER(&GGEXPMP,NB,NAME)
VER(&GGEXAN1,NUM)
VER(&GGEXAN2,NUM)
VPUT (GGEXPDS GGEXPMP GGEXTAB) PROFILE
)END
./ ADD NAME=GGMPEXNS,SSI=01000057
)ATTR
/* /*
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 /*
/* /*
/* This software is provided on an "AS IS" basis. All warranties, /*
/* including the implied warranties of merchantability and fitness, /*
/* are expressly denied. /*
/* /*
/* Provided this copyright notice is included, this software may /*
/* be freely distributed and not offered for sale. /*
/* /*
/* Changes or modifications may be made and used only by the maker /*
/* of same, and not further distributed. Such modifications should /*
/* be mailed to the author for consideration for addition to the /*
/* software and incorporation in subsequent releases. /*
/* /*
^ TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
)BODY EXPAND(``) WINDOW(77,17)
+
%Command ===>^ZCMD
+
+Data set name%===>_GGEXSEQ
+(Note: Data set will be RECFM=VB, LRECL=259, BLKSIZE=6233.)
+
+Expand tab characters? %===>_Z +
+
+Append to end of data set? %===>_Z +
+Blank line after separator? %===>_Z +
+Separator line before each item (leave blank for none):
+>^Z +<
+From item number%===>_GGEXAN1 + (blank for first item in table)
+To item number%===>_GGEXAN2 + (blank for last item in table)
+Press%&END (END)+to cancel the extract request.
)INIT
.ZVARS = '(GGEXTAB GGEXAPP GGEXBLK GGEXSEP)'
.CURSOR = ZCMD
&ZWINTTL = 'Log text of items to sequential file'
&END = PFK(END)
&ZCMD = &Z
VGET (GGEXSEQ GGEXTAB GGEXAPP GGEXBLK GGEXSEP) PROFILE
&GGEXTAB = TRANS(&GGEXTAB Y,YES N,NO ' ',NO)
&GGEXAPP = TRANS(&GGEXAPP Y,YES N,NO ' ',NO)
&GGEXBLK = TRANS(&GGEXBLK Y,YES N,NO ' ',NO)
&GGEXAN1 = &Z
&GGEXAN2 = &Z
)PROC
IF (&ZCMD ^= &Z) .MSG = ISPZ001
VER(&GGEXSEQ,NB,DSNAME)
&GGEXDSN = &GGEXSEQ
&GGEXTAB = TRUNC(&GGEXTAB,1)
VER(&GGEXTAB,NB,LIST,Y,N)
&GGEXAPP = TRUNC(&GGEXAPP,1)
VER(&GGEXAPP,NB,LIST,Y,N)
&GGEXBLK = TRUNC(&GGEXBLK,1)
VER(&GGEXBLK,NB,LIST,Y,N)
VER(&GGEXAN1,NUM)
VER(&GGEXAN2,NUM)
VPUT (GGEXSEQ GGEXTAB GGEXAPP GGEXBLK GGEXSEP) PROFILE
)END
./ ADD NAME=GGMPEXNT,SSI=01000035
)ATTR
/* /*
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 /*
/* /*
/* This software is provided on an "AS IS" basis. All warranties, /*
/* including the implied warranties of merchantability and fitness, /*
/* are expressly denied. /*
/* /*
/* Provided this copyright notice is included, this software may /*
/* be freely distributed and not offered for sale. /*
/* /*
/* Changes or modifications may be made and used only by the maker /*
/* of same, and not further distributed. Such modifications should /*
/* be mailed to the author for consideration for addition to the /*
/* software and incorporation in subsequent releases. /*
/* /*
^ TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
)BODY WINDOW(77,10)
+
%Command ===>^ZCMD
+
+Move cursor to choice (or type%S+next to choice) and press%ENTER+to select:
+
_A%1+- List%titles+of items in table
_B%2+- Log %text +of items to%sequential file+
_C%3+- Log %text +of items to%members of PDS+
+
+Press%&END (END)+to cancel the extract request.
)INIT
.CURSOR = ZCMD
&ZWINTTL = 'Extract Gopher items - titles or text'
&END = PFK(END)
&ZCMD = &Z
&A = &Z
&B = &Z
&C = &Z
)PROC
VER(&ZCMD,LIST,1,2,3)
IF (&ZCMD ^= &Z)
&GGCHOICE = TRANS(&ZCMD 1 1 2 2 3 3 * ?)
ELSE
&TEMP = '&A/&B/&C'
IF (&TEMP = '//')
&GGCHOICE = TRANS(.CURSOR A 1 B 2 C 3 * ?)
ELSE
&GGCHOICE = TRANS(&TEMP 'S//' 1
'1//' 1
'/S/' 2
'/2/' 2
'//S' 3
'//3' 3
* ?
)
)END
./ ADD NAME=GGMPEXN1,SSI=01000007
)ATTR
/* /*
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 /*
/* /*
/* This software is provided on an "AS IS" basis. All warranties, /*
/* including the implied warranties of merchantability and fitness, /*
/* are expressly denied. /*
/* /*
/* Provided this copyright notice is included, this software may /*
/* be freely distributed and not offered for sale. /*
/* /*
/* Changes or modifications may be made and used only by the maker /*
/* of same, and not further distributed. Such modifications should /*
/* be mailed to the author for consideration for addition to the /*
/* software and incorporation in subsequent releases. /*
/* /*
^ TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
)BODY WINDOW(77,14)
+
%Command ===>^ZCMD
+
+Save to data set ===>_GGEXDSN
+(Note: Data set will be RECFM=VB, LRECL=259, BLKSIZE=6233.)
+Append to end of data set? ===>_Z +
+Blank line after separator? ===>_Z +
+Separator line between items (append mode only...blank for none):
+>^Z +<
+Press%&END (END)+to cancel the extract request.
)INIT
.ZVARS = '(GGEXAPP GGEXBLK GGEXSEP)'
.CURSOR = GGEXDSN
&ZWINTTL = 'Extract Gopher item listing'
&END = PFK(END)
&ZCMD = &Z
VGET (GGEXDSN GGEXAPP GGEXBLK GGEXSEP) PROFILE
&GGEXAPP = TRANS(&GGEXAPP Y,YES N,NO ' ',NO)
&GGEXBLK = TRANS(&GGEXBLK Y,YES N,NO ' ',NO)
)PROC
IF (&ZCMD ^= &Z) .MSG = ISPZ001
VER(&GGEXDSN,NB,DSNAME)
&GGEXAPP = TRUNC(&GGEXAPP,1)
VER(&GGEXAPP,NB,LIST,Y,N)
&GGEXBLK = TRUNC(&GGEXBLK,1)
VER(&GGEXBLK,NB,LIST,Y,N)
VPUT (GGEXDSN GGEXAPP GGEXBLK GGEXSEP) PROFILE
)END
./ ADD NAME=GGMPEXOW,SSI=01000030
)ATTR
/* /*
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 /*
/* /*
/* This software is provided on an "AS IS" basis. All warranties, /*
/* including the implied warranties of merchantability and fitness, /*
/* are expressly denied. /*
/* /*
/* Provided this copyright notice is included, this software may /*
/* be freely distributed and not offered for sale. /*
/* /*
/* Changes or modifications may be made and used only by the maker /*
/* of same, and not further distributed. Such modifications should /*
/* be mailed to the author for consideration for addition to the /*
/* software and incorporation in subsequent releases. /*
/* /*
^ TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
)BODY WINDOW(58,10)
+
%Command ===>^ZCMD
+
+Dataset already exists:
+
%&GGEXDSN
+
+Press%ENTER+to%&ACTION
+Press%&END (END)+to cancel the request.
+
)INIT
.ALARM = YES
&ZWINTTL = 'Extract To Existing Data Set'
&END = PFK(END)
&APP = TRUNC(&GGEXAPP,1)
IF (&APP = Y) &ACTION = 'append to the end of the data set.'
ELSE &ACTION = 'overwrite the current data set.'
)PROC
IF (&ZCMD ^= &Z) .MSG = ISPZ001
)END
./ ADD NAME=GGMPEXPW,SSI=01000053
)ATTR
/* /*
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 /*
/* /*
/* This software is provided on an "AS IS" basis. All warranties, /*
/* including the implied warranties of merchantability and fitness, /*
/* are expressly denied. /*
/* /*
/* Provided this copyright notice is included, this software may /*
/* be freely distributed and not offered for sale. /*
/* /*
/* Changes or modifications may be made and used only by the maker /*
/* of same, and not further distributed. Such modifications should /*
/* be mailed to the author for consideration for addition to the /*
/* software and incorporation in subsequent releases. /*
/* /*
^ TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
)BODY WINDOW(58,13)
+
%Command ===>^ZCMD
+
+Paritioned dataset already exists:
+
%&GGEXDSN
+
+If member names are generated that match existing members
+of this PDS, they will be%overwritten.+
+
+Press%ENTER+to proceed to use this PDS.
+Press%&END (END)+to cancel the request.
+
)INIT
.ALARM = YES
&ZWINTTL = 'Extract To Members of Existing PDS'
&END = PFK(END)
)PROC
IF (&ZCMD ^= &Z) .MSG = ISPZ001
)END
./ ADD NAME=GGMPWAIS,SSI=01020012
)ATTR
/* /*
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 /*
/* /*
/* This software is provided on an "AS IS" basis. All warranties, /*
/* including the implied warranties of merchantability and fitness, /*
/* are expressly denied. /*
/* /*
/* Provided this copyright notice is included, this software may /*
/* be freely distributed and not offered for sale. /*
/* /*
/* Changes or modifications may be made and used only by the maker /*
/* of same, and not further distributed. Such modifications should /*
/* be mailed to the author for consideration for addition to the /*
/* software and incorporation in subsequent releases. /*
/* /*
^ TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
)BODY WINDOW(58,10)
+
%Command ===>^ZCMD
+
+Enter index search query:
+
%===>^GGWAISQ
+Press%ENTER+to submit search request.
+Press%&END (END)+to cancel the request.
+
)INIT
&ZWINTTL = 'GOPHER Full Text Index Search'
&END = PFK(END)
.CURSOR = GGWAISQ
)PROC
IF (&ZCMD ^= &Z) .MSG = ISPZ001
VER (&GGWAISQ,NB)
VPUT (GGWAISQ) PROFILE
)END
./ ADD NAME=GGMPWHOI,SSI=01000019
)ATTR
/* /*
/* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992 /*
/* /*
/* This software is provided on an "AS IS" basis. All warranties, /*
/* including the implied warranties of merchantability and fitness, /*
/* are expressly denied. /*
/* /*
/* Provided this copyright notice is included, this software may /*
/* be freely distributed and not offered for sale. /*
/* /*
/* Changes or modifications may be made and used only by the maker /*
/* of same, and not further distributed. Such modifications should /*
/* be mailed to the author for consideration for addition to the /*
/* software and incorporation in subsequent releases. /*
/* /*
^ TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
)BODY WINDOW(58,10)
+
%Command ===>^ZCMD
+
+Enter name to search for:
+
%===>^GGWHOISQ
+Press%ENTER+to submit search request.
+Press%&END (END)+to cancel the request.
+
)INIT
&ZWINTTL = 'WHOIS/FINGER User Name Search'
&END = PFK(END)
.CURSOR = GGWHOISQ
)PROC
IF (&ZCMD ^= &Z) .MSG = ISPZ001
VER (&GGWHOISQ,NB)
VPUT (GGWHOISQ) PROFILE
)END
./ ENDUP
?!