home *** CD-ROM | disk | FTP | other *** search
- /*
- * Name: GOPCLISX REXX
- * CMS Gopher client TCP/IP (sockets; "sox") function
- * Author: Rick Troth, Rice University, Information Systems
- * Date: 1992-Dec-23
- *
- * Input: one or more gopher menu lines
- * Output 0: zero or more blocks of raw (may be ASCII) data
- * Output 1: status messages and/or error messages
- *
- * Note: input is "plain text" (EBCDIC), while output
- * may be anything. If output is "plain text" (ASCII),
- * the following stage must handle translation.
- */
-
- /*
- * Copyright 1992 Richard M. Troth. This software was developed
- * with resources provided by Rice University and is intended
- * to serve Rice's user community. Rice has benefitted greatly
- * from the free distribution of software, therefore distribution
- * of unmodified copies of this material is not restricted.
- * You may change your own copy as needed. Neither Rice
- * University nor any of its employees or students shall be held
- * liable for damages resulting from the use of this software.
- */
-
- Trace "OFF"
-
- /* sync with input so that 'CALLPIPE COMMAND' will work */
- 'PEEKTO'
-
- 'CALLPIPE COMMAND GLOBALV SELECT GOPHER GET GOPHER'
- If gopher = "" Then gopher = "Gopher"
- quit = 0
-
- Parse Arg . '(' opts ')' .
-
- trans = 0
- Do While opts ^= ""
- Parse Var opts op opts
- Upper op
- Select /* op */
- When Abbrev("TRANSLATE",op,4) Then trans = 1
- When Abbrev("NOTRANSLATE",op,6) Then trans = 0
- Otherwise Address "COMMAND" 'XMITMSG 3 OP (ERRMSG'
- End /* Select op */
- End /* Do While */
-
- If trans Then crlf = '0D25'x
- Else crlf = '0D0A'x
-
- /*
- * Initialize RXSOCKET
- */
- maxdesc = Socket('Initialize', gopher)
- If maxdesc = "-1" Then Do
- If errno ^= "ESUBTASKALREADYACTIVE" Then Do
- /* Call STATUS tcperror() */
- Exit -1
- End /* If .. Do */
- rc = Socket('Terminate')
- maxdesc = Socket('Initialize', gopher)
- If maxdesc = "-1" Then Do
- Call STATUS tcperror()
- Exit -1
- End /* If .. Do */
- End /* If .. Do */
-
- /* L O O P */
-
- Do Forever
-
- 'PEEKTO ITEM'
- If rc ^= 0 Then Leave
-
- Parse Var item 1 type 2 name '05'x path '05'x host ,
- '05'x port '05'x xtra
- port = Strip(port) /* for robustness */
- If type = '7' Then path = path || '05'x || xtra
-
- /* Call STATUS "Connecting ... press ENTER twice to abort" */
- /* Call STATUS "Connecting to" host "port" port */
- Call STATUS 22 '"' || host || '"' '"' || port || '"'
-
- /*
- * Request a new socket descriptor (TCP protocol)
- */
- socket = Socket('Socket', 'AF_INET', 'Sock_Stream')
- If socket = "-1" Then Do
- Call STATUS tcperror()
- Exit -1
- End /* If .. Do */
-
- If trans Then Do
- /*
- * Enable ASCII<->EBCDIC Translation Option
- */
- rc = Socket('SetSockOpt', socket, 'SOL_SOCKET', 'SO_EBCDIC', 1)
- If rc = "-1" Then Do
- Call STATUS tcperror()
- Exit -1
- End /* If .. Do */
- End /* If .. Do */
-
- /*
- * Connect to the server
- */
- Parse Var host h1 '.' h2 '.' h3 '.' h4 '.' .
- If Datatype(h1,'N') &,
- Datatype(h2,'N') &,
- Datatype(h3,'N') &,
- Datatype(h4,'N') Then
- hisaddr = d2c(h1) || d2c(h2) || d2c(h3) || d2c(h4)
- Else Do
- hisaddr = Socket('GetHostByName', host)
- If hisaddr = "-1" Then Do
- Call STATUS tcperror()
- Exit -1
- End /* If .. Do */
- End /* Else Do */
-
- /* Parse Var hisaddr h1 +1 h2 +1 h3 +1 h4 +1 . */
-
- name = AF_INET || Htons(port) || hisaddr
-
- /*
- * Set this socket to non-blocking mode
- */
- rc = Socket('Ioctl', socket, 'FIONBIO', 1)
- If rc="-1" Then Do
- Call STATUS tcperror()
- Exit -1
- End /* If .. Do */
-
- /*
- * Connect to the host
- */
- rc = Socket('Connect', socket, name)
- If rc = "-1" Then ,
- If errno ^= "EINPROGRESS" Then Do
- Call STATUS tcperror()
- If errno = "ECONNREFUSED" Then ,
- Call STATUS 23 '"' || host || '"' '"' || port || '"'
- Exit -1
- End /* If .. Do */
-
- rc = FD_ZERO('readmask')
- rc = FD_ZERO('writemask')
- rc = FD_SET(socket,'writemask')
- rc = FD_SET('0', 'readmask')
-
- rc = Socket('Select', socket+1, 'readmask', 'writemask', 0, 20)
- If rc="-1" Then Do
- Call STATUS tcperror()
- Exit -1
- End /* If .. Do */
-
- If FD_ISSET('0', 'readmask')<>0 Then Do
- rc = Socket('Close', socket)
- /* Call STATUS "Connection canceled by user request" */
- Call STATUS 28
- Exit -1
- End
-
- If FD_ISSET(socket, 'writemask')=0 Then Do
- rc = Socket('Close', socket)
- /* Call STATUS "Connection canceled by TIMEOUT" */
- Call STATUS 29
- Exit -1
- end
-
- /* Return to standard mode
- rc = Socket('Ioctl', socket, 'FIONBIO', 0)
- */
-
- /* TRANSlate option will affect both writing to, as well as *
- * reading from, the socket. So if the socket is set for *
- * TRANSLATE, then we need not translate the path from EBCDIC *
- * to ASCII. But if not, then we must do so as follows: */
- If ^trans Then
- 'CALLPIPE VAR PATH | TCPE2A' gopher '| VAR PATH'
-
- /*
- * Send the "query" to the server
- */
- bytes_out = Socket('Write', socket, path || crlf)
- If bytes_out = "-1" Then Do
- If errno = 'EPIPE' Then ,
- 'OUTPUT' "ECONNREFUSED"
- If errno = 'EPIPE' Then ,
- Call STATUS 23 '"' || host || '"' '"' || port || '"'
- Else Call STATUS tcperror()
- Exit -1
- End /* If .. Do */
-
- /* Call STATUS "Reading ... press ENTER twice to abort" */
- /* Call STATUS "Reading ... " */
- /* Call STATUS 24 */
-
- totbytes = 0
- prevtot = 0
- /*
- * Loop, reading response and sending to the next pipeline stage
- */
- Do Forever
- /* Set up to trap console ENTER key */
- rc = FD_ZERO('readmask')
- rc = FD_SET('0','readmask')
- rc = FD_SET(socket,'readmask')
-
- /* Wait for something to happen */
- rc = Socket('Select',socket+1,'readmask',0,0)
- /* If console input, clear 'socket' and return */
- If FD_ISSET('0','readmask')<>0 Then Do
- /* Call STATUS "Request ABORTED" */
- Call STATUS 27
- rc = Socket('Close', socket)
- Leave
- End
-
- bytes_in = Socket('Read', socket, 'pack')
- If bytes_in = "-1" Then
- Call STATUS tcperror()
- If bytes_in < 1 Then Leave
-
- totbytes = totbytes + bytes_in
- If prevtot/totbytes < 0.9 Then /* adjust the 0.9 factor to taste */
- Do
- Call STATUS 26 '"' || totbytes || '"'
- prevtot = totbytes
- End
- 'OUTPUT' pack
- If rc ^= 0 Then Leave
-
- End /* Do Forever */
-
- If rc ^= 0 Then Leave
-
- /*
- * All done, relinquish our socket descriptor
- */
- rc = Socket('Close', socket)
- If rc = "-1" Then Do
- Call STATUS tcperror()
- Leave
- End /* If .. Do */
-
- 'READTO'
-
- End /* Do Forever */
-
- /*
- * Tell RXSOCKET that we are done with this IUCV path
- */
- rc = Socket('Terminate')
- If rc = "-1" Then Do
- Call STATUS tcperror()
- Exit -1
- End
-
- /* an empty line as last in status stream indicates success */
- /* Call STATUS " " */
-
- Exit
-
-
-
- /* -------------------------------------------------------------- STATUS
- * Write "status messages" to the secondary stream, if connected.
- * This routine saves & restores the current stream selection.
- * (though there are presently no other streams used besides 1 and 0)
- */
- STATUS: Procedure
- Parse Arg string
-
- /* note the current stream (should be zero) */
- 'STREAMNO OUTPUT'
- If rc < 0 Then Return
- stream = rc
-
- /* select secondary stream and output the string */
- 'SELECT OUTPUT 1'
- If rc ^= 0 Then Return
- If Datatype(Word(string,1),'N') Then
- 'CALLPIPE COMMAND XMITMSG' string '(APPLID GOP CALLER TCP ERRMSG | *:'
- Else 'OUTPUT' string
- 'SELECT OUTPUT' stream
-
- Return
-
-