home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / com / bbs / maxiftp / maxiftp.cmd < prev    next >
OS/2 REXX Batch file  |  1994-02-03  |  66KB  |  2,069 lines

  1. /*------------------------------------------------------------------
  2.  * miniftp.cmd :
  3.  *------------------------------------------------------------------
  4.  * 03-16-93 originally by Patrick J. Mueller & Cliff Nadler
  5.  *------------------------------------------------------------------
  6.  * maxiftp.cmd:
  7.  *------------------------------------------------------------------
  8.  * 10-27-93  modified by Albert Crosby <acrosby@uafhp.uark.edu>
  9.  * v2 11-5-93
  10.  *
  11.  * Some changes and suggestions were added from Al Dhir's sFTP
  12.  *
  13.  *  Second release:
  14.  *     Fixed a bug in handling filenames on FAT partitions
  15.  *     Added some additional extensions to the BINARIES list
  16.  *     Removed some debugging code
  17.  *     Changed "colon mode" to MGET instead of GET
  18.  *     Changed the prompt to display directory
  19.  *     Added highlighting
  20.  *     Added a new help screen for MAXIFTP ?
  21.  *     Added the status command
  22.  *     Changed default to NODISPLAY
  23.  *     Added TOGGLE command and some settings
  24.  *     Added command line options
  25.  *     Added the nifty new TOUCH command!
  26.  *     Get now accepts wildcards! (psuedo fn completion...)
  27.  *     Added quoted strings
  28.  *     Added a CREATE command
  29.  *     Now uses the NETRC file
  30.  *     Added a LCD command to change local directory.
  31.  * Version 3
  32.  *     Fixed TOUCH for VM and Windows_NT
  33.  *     Added a SET command to change string variables
  34.  *     Display pager in the SHOW command
  35.  *     Allow user defined prompt
  36.  *     Added more binary types
  37.  *     Fixed getpasswd to allow spaces
  38.  *     Now prompts before exiting if Ctrl-C is pressed
  39.  *     Added MORE as an alias for the PAGE command
  40.  *     Shell now uses COMSPEC rather than always CMD
  41.  *     Initial comments in NETRC are treated as commands to MaxiFTP
  42.  *     Comments after a machine command in NETRC are queued as commands
  43.  *     Uses EA's to store history and longname
  44.  *     Redial mode added
  45.  *     BELL added to ring a bell at connect and after a file transfer completes
  46.  *     VISUAL mode began.  Very primitive.
  47.  *------------------------------------------------------------------ */
  48.  
  49. /*------------------------------------------------------------------
  50.  * set up call
  51.  *------------------------------------------------------------------*/
  52. call on halt
  53.  
  54. parse arg xargs
  55.  
  56. /* Add anything in the environment variable MAXIFTP */
  57. xargs=strip(value('MAXIFTP',,'OS2ENVIRONMENT')||" "||xargs)
  58.  
  59. /* Build a blank delimited list of command line options */
  60.  
  61. args=" "
  62.  
  63. if pos(left(xargs,1),"/-")<>0 then
  64.    do
  65.    rest=xargs
  66.    do until pos(left(rest,1),"/-")=0
  67.       parse var rest argument rest
  68.       if pos('"',argument)<>0 then
  69.          do
  70.          parse var rest remainder'"' rest
  71.          argument=argument||' '||remainder||'"'
  72.          end
  73.       args=args||" "||substr(argument,2)
  74.       rest=strip(rest)
  75.    end
  76.    parse var rest host rest
  77.    if pos('"',host)<>0 then
  78.       do
  79.       parse var rest rest'"' user pass .
  80.       host=host||" "||rest||'"'
  81.       end
  82.    else parse var rest user pass .
  83.    end
  84. else
  85.    do
  86.    parse var xargs host rest
  87.    if pos('"',host)<>0 then
  88.       do
  89.       parse var rest rest'"' user pass .
  90.       host=host||" "||rest||'"'
  91.       end
  92.    else parse var rest user pass .
  93.    end
  94.  
  95. call LoadFunctions
  96.  
  97. parse value SysTextScreenSize() with rows cols
  98.  
  99. debug=0
  100.  
  101. "@echo off"
  102. "ansi on > nul"
  103.  
  104. trace off
  105.  
  106. version="MaxiFTP version 3 BETA revision 153"
  107. credits.0=3
  108. credits.1="by Albert Crosby, 02/03/94"
  109. credits.2="(based on original code by Patrick J. Mueller & Cliff Nadler of IBM"
  110. credits.3="    and additional suggestions from Al Dhir's sFTP)"
  111. /* List of filetypes currently assumed to be binary for get and put */
  112. binaries=value("BINARIES",,"OS2ENVIRONMENT")
  113. if binaries="" then
  114.    binaries="EXE COM ZIP SYS DLL DEV ARJ ARC Z TAR GZ BIN DSK LZH ARK LBR JPG JPEG GIF PCX "
  115. asciis=value("ASCIIS",,"OS2ENVIRONMENT")
  116. if asciis="" then
  117.    asciis="TXT"
  118.  
  119. hostname=""
  120. phost=""
  121. origdir=directory()
  122. mode="ASCII"
  123. delay=20
  124. clobber=0
  125. hostlist.0=0
  126. prompt=1
  127. display=0
  128. unique=0
  129. quiet=0
  130. touch=0
  131. netrc=1
  132. visual=0
  133. macros=1
  134. retries=1
  135. longname=1
  136. history=1
  137. bell=1
  138. dircmd="dir"
  139. viscmd="get"
  140. greenonblack=d2c(27)||"[1;32m"
  141. normvideo=d2c(27)||"[0m"
  142. inversevideo=d2c(27)||"[7m"
  143. boldvideo=d2c(27)||"[1m"
  144. promptstr='progname||" ["||boldvideo||phost||":"||dirname||normvideo"] "'
  145.  
  146. stem.0=1
  147. stem.1="No directory has been transferred - issue a ls or dir command."
  148.  
  149. pager=value('pager',,'os2environment')
  150. if pager="" then pager=more
  151.  
  152. parse source . . name
  153. parse value filespec('name',name) with progname".".
  154.  
  155. call ProcessINI filespec('drive',name)||filespec('path',name)||progname||'.ini' 
  156.  
  157. if translate(progname)=="VISFTP" then visual=1
  158.  
  159. if RxFuncQuery("SockLoadFuncs")=0 then /* RxSock is loaded... */
  160.    do
  161.       /* Get info about this machine - this is the only useage of rxSock... */
  162.       addr = SockGetHostId()
  163.       rc   = SockGetHostByAddr(addr,"host.!")
  164.       hostname=host.!name
  165.    end
  166. if hostname="" | hostname="HOST.!NAME" then hostname=value("HOSTNAME",,"OS2ENVIRONMENT")
  167.  
  168. anonpass="os2user"||"@"||hostname
  169.  
  170. netrcfile=stream('netrc','c','query exists')
  171. if netrcfile="" then
  172.    netrcfile=value("ETC",,"OS2ENVIRONMENT")||"\NETRC"
  173.  
  174. if pos(" N-",args)=0 then Call ProcessNETRC
  175.  
  176. call ProcessArgs args
  177.  
  178. if \quiet then call Credits
  179.  
  180. if (host="?") then
  181.    do
  182.    call Usage "INTRO"
  183.    exitcode=0
  184.    signal done
  185.    end
  186.  
  187. oq=quiet; 
  188. quiet=1
  189. call Mode mode
  190. quiet=oq
  191.  
  192. if pos("@",host)<>0 then
  193.    do
  194.    pass=user
  195.    parse var host user"@"host
  196.    end
  197.  
  198. request=""
  199.  
  200. if pos(":",host)<>0 then parse var host host":"request
  201. if pos('"',request)<>0 then parse var request '"'request'"'
  202.  
  203. if visual & (request="") then 
  204.    do
  205.    visual=visinit()
  206.    if visual then signal visftp
  207.    end
  208.  
  209. if host = "" then
  210.    do
  211.    say "Welcome to "version
  212.    say
  213.    say "Type HELP for more information and HELP NEWS for an overview"
  214.    say
  215.    call Usage "CONNECT"
  216.    say
  217.    end
  218.  
  219. if (host <> "") then
  220.    call Connect
  221.  
  222. if request<>"" then
  223.    do
  224.    if host="" then exit -1;
  225.    prompt=0
  226.    clobber=1
  227.    /* Reprocess args to handle different defaults for colon-mode */
  228.    oquiet=quiet
  229.    quiet=1
  230.    call ProcessArgs args
  231.    quiet=oquiet
  232.  
  233.    if display then call QueryStatus
  234.  
  235.    /* If request contains wildcards, do an mget */
  236.    if verify(request,"*?","MATCH")<>0 then
  237.       err=mget(request)
  238.    else err=get(request)
  239.    exitcode=err
  240.    signal done
  241.    end
  242.  
  243. do while (cmd <> "QUIT")
  244.  
  245.  
  246. /* Modified so default directory is not queried if not connected to
  247.    a host.  This seemed rather pointless to me... */
  248.  
  249.  
  250.    if (host = "") then
  251.       do
  252.          status = "not connected to a host"
  253.          dir = ""
  254.          phost="not connected"
  255.       end
  256.    else status = "connected to" user"@"host
  257.  
  258. if display then Call DisplayStatus
  259.  
  260. /* Moved displaying the prompt until AFTER the status is displayed. */
  261.  
  262.    /*---------------------------------------------------------------
  263.     * print prompt
  264.     *---------------------------------------------------------------*/
  265.    Call SysCurState("ON")
  266.    if pos('"',dir)<>0 then parse var dir '"'dirname'"'.
  267.    else dirname=dir
  268.  
  269.    if queued()=0 then interpret "Call Charout," promptstr
  270.  
  271.    /*---------------------------------------------------------------
  272.     * get command
  273.     *---------------------------------------------------------------*/
  274.    parse pull cmd cmdargs
  275.  
  276.    err=ProcessCMD(cmd, cmdargs)
  277.  
  278.    if (cmd="CD") | (cmd="CDUP") then
  279.       err = FtpPwd('dir')
  280.  
  281.    /*------------------------------------------------------------------
  282.     * check error
  283.     *------------------------------------------------------------------*/
  284.    /* Appears to be an error in error handling....  err may be -1 with
  285.       FTPERRNO of 0 */
  286.    if (err <> 0) & (ftperrno <>0) then
  287.       do
  288.       say "Error from FTP:" english(FTPERRNO) "["err"]"
  289.       if ftperrno="FTPCONNECT" then
  290.          do
  291.          say "Remote server closed connection."
  292.          host=""
  293.          phost=""
  294.          dir=""
  295.          end
  296.       end
  297.  
  298. end
  299.  
  300. /*------------------------------------------------------------------
  301.  * quit
  302.  *------------------------------------------------------------------*/
  303.  
  304. exitcode=0
  305.  
  306. done:
  307. rc = FtpSetUser("X","X","X")
  308. rc = FtpLogoff()
  309. call directory origdir
  310. /* Empty the queue in case any macro commands are pending. */
  311. do queued()
  312.    parse pull .
  313. end
  314. exit exitcode
  315.  
  316. /*------------------------------------------------------------------
  317.  * break condition
  318.  *------------------------------------------------------------------*/
  319. halt:
  320.    say
  321.    call Charout, "Do you really want to quit (yes|no)? "
  322.    do until pos(translate(key),"YN")<>0
  323.       key=SysGetKey("NoECHO")
  324.    end
  325.    say key
  326.    if translate(key)="N" then return;
  327.    say "Terminating ..."
  328.    exitcode=-1
  329.    signal done
  330.  
  331. getpasswd: procedure
  332.  
  333. key=SysGetKey("NoEcho")
  334. word=""
  335. do until key=d2c(13)
  336.    if (key=d2c(8)) & (length(word)>0) then
  337.       do
  338.       word=substr(word,1,length(word)-1)
  339.       call Charout, d2c(8)||" "||d2c(8)
  340.       end
  341.    else if (key<>d2c(8)) then do; call Charout, "*"; word=word||key; end
  342.    key=SysGetKey("NoEcho")
  343. end
  344. say
  345. return word
  346.  
  347. get: procedure expose debug binaries file2 clobber quiet touch dir longname history host user bell visual asciis
  348.  
  349. parse arg remotefile, localfile, mode
  350.  
  351. curdir=dir
  352. globbed=0
  353. pipe=0
  354.  
  355. if remotefile=localfile then localfile=""
  356.  
  357. if translate(localfile)="CON" | translate(localfile)="CON:" then
  358.    localfile="-"
  359.  
  360. if verify(remotefile,"*?","MATCH")<>0 then /* It's a wildcard request */
  361.    do
  362.    err=FtpLS(remotefile,'files.')
  363.    if files.0=0 then
  364.       do
  365.       if \quiet then say "No files matching "remotefile" can be found."
  366.       return -2
  367.       end
  368.    remotefile=files.1
  369.    end
  370.  
  371. if wordpos(extension(remotefile),binaries)\=0 then
  372.    if mode="" then mode="BINARY"
  373.  
  374. if wordpos(extension(remotefile),asciis)\=0 then
  375.    if mode="" then mode="ASCII"
  376.  
  377. if remotefile="." then
  378.    do
  379.    call charout, "Remote file: "
  380.    parse pull remotefile
  381.    if remotefile="" then return -1
  382.    call charout, "Local file: "
  383.    parse pull localfile
  384.    end
  385.  
  386. if left(localfile,1)="|" then 
  387.    do 
  388.    pipe=1
  389.    destination=substr(localfile,2)
  390.    localfile=systempfilename("tmp?????")
  391.    end
  392.  
  393. if left(localfile,1)=">" then
  394.    do
  395.    say "Redirection not supported.  Use GET remotefile localfile instead."
  396.    return -2
  397.    end
  398.  
  399. ndir = filespec('drive',remotefile)||filespec('path',remotefile)
  400. if ndir<>"" then
  401.    do
  402.    err=FtpPWD('olddir')
  403.    err=FtpChDir(ndir)
  404.    err=FtpPWD('curdir')
  405.    if pos('"',olddir)<>"" then parse var olddir '"'olddir'"'.
  406.    if pos('"',curdir)<>"" then parse var curdir '"'curdir'"'.
  407.    end
  408. request=remotefile
  409. remotefile=filespec('name',remotefile)
  410.  
  411. err=FtpDir(remotefile,'files.')
  412. if files.0=0 then
  413.    do
  414.    if dir<>"" then junk=FtpChDir(olddir)
  415.    say "Remote file "request" does not exist."
  416.    return -2
  417.    end
  418.  
  419. if localfile="" then localfile=remotefile
  420.  
  421. if \pipe then
  422. do
  423. "dir "localfile" 1>nul 2>nul"
  424. if (rc=123) | (rc=206) then /* File name isn't valid... */
  425.    do
  426.    if left(localfile,1)="." then localfile="_"||substr(localfile,2)
  427.    if pos('.',localfile)<>0 then
  428.       localfile=translate(translate(strip(left(left(localfile,lastpos('.',localfile)-1),8)),'__','. ')||"."||strip(left(extension(localfile),3)))
  429.    else localfile=translate(translate(strip(left(localfile,8)),'__','. '))
  430.    if stream(localfile,'c','query exists')<>"" then
  431.       do
  432.       say "Unable to generate a unique local name for the transfer."
  433.       say "Specify a local name on the get command and try again."
  434.       return -1
  435.       end
  436.    globbed=1
  437.    end
  438.  
  439. if \quiet & localfile\="-" then say "Transferring "request" as "localfile" ..."
  440. else if \quiet then say "Contents of "request":"
  441. end
  442. else if \quiet then say "Piping "request" to "destination" ..."
  443.  
  444. file2=localfile
  445.  
  446. if (\clobber) & (stream(localfile,"C","QUERY EXISTS")<>"") then
  447.    if \visual then
  448.       do
  449.       call Charout, localfile || " already exists.  Replace (yes|no)? "
  450.       do until pos(translate(key),"YN")<>0
  451.          key=SysGetKey("NoECHO")
  452.       end
  453.       say key
  454.       if translate(key)="N" then return 1;
  455.       end
  456.    else if vmsg("File Exists",localfile || " already exists.  Replace?  ",6)=="NO" then return 1;
  457.  
  458. call time "r"
  459.  
  460. if mode\="" then
  461.    err=FtpGet(localfile,remotefile,mode)
  462. else err=FtpGet(localfile,remotefile)
  463.  
  464. elapsed = strip(format(time("e"),10,2))
  465. bytes = stream(localfile,"C","QUERY SIZE")
  466. if \quiet & (elapsed<>0) & (datatype(bytes)="NUM") then
  467.    say "Recieved" bytes "bytes in" elapsed "seconds:" strip(format(bytes/elapsed,10,2))  "bytes/second."
  468. if \quiet & bell then call beep 278,200
  469.  
  470. if ndir<>"" then junk=FtpChDir(olddir)
  471.  
  472. if \pipe then
  473. do
  474. if stream(localfile,"C","QUERY EXISTS")="" then return -2
  475. if touch then
  476.    call touch files.1, localfile
  477.  
  478. if globbed & longname then
  479.     call PutLong localfile, remotefile
  480.  
  481. if history then
  482.    call PutComment localfile, user, host, curdir, remotefile
  483. end
  484.  
  485. if pipe then
  486.    do
  487.    call stream localfile,'C','CLOSE'
  488.    destination||"<"||localfile
  489.    call SysFileDelete localfile
  490.    end
  491.  
  492. return err
  493.  
  494. put: procedure expose debug binaries unique quiet bell visual
  495.  
  496. parse arg localfile, remotefile, lunique
  497.  
  498. if remotefile="" then remotefile=localfile
  499. if remotefile="" | remotefile="." then
  500.    do
  501.    say "You must specify a file name!"
  502.    return
  503.    end
  504. remotefile=filespec('name',remotefile)
  505. if \quiet then say "Transferring "localfile" as "remotefile" ..."
  506.  
  507. call time "r"
  508.  
  509. if (unique) | (lunique=1) then
  510.    if wordpos(extension(localfile),binaries)=0 then
  511.       err = FtpPutUnique(localfile,remotefile)
  512.    else err=FtpPutUnique(localfile,remotefile,"BINARY")
  513. else if wordpos(extension(localfile),binaries)=0 then
  514.       err = FtpPut(localfile,remotefile)
  515.    else err=FtpPut(localfile,remotefile,"BINARY")
  516.  
  517. elapsed = strip(format(time("e"),10,2))
  518. bytes = stream(localfile,"C","QUERY SIZE")
  519. if \quiet & (elapsed<>0) & (datatype(bytes)="NUM") then
  520.    say "Transmitted" bytes "bytes in" elapsed "seconds:" strip(format(bytes/elapsed,10,2))  "bytes/second."
  521.  
  522. if \quiet & bell then call beep 278,200
  523.  
  524. return err
  525.  
  526. extension: procedure
  527.  
  528. arg filename
  529. /* If no period or only period is first char, then return "" */
  530. if lastpos(".",filename)<2 then return ""
  531. return substr(right(filename,pos(".",reverse(filename))),2)
  532.  
  533. mget: procedure expose debug binaries file2 clobber quiet touch dir longname history host user prompt bell visual
  534.  
  535. parse arg spec
  536.  
  537. if \quiet then say "Transferring file list..."
  538. if spec="" then spec="."
  539. err=FtpLS(spec,'files.')
  540. if \quiet then say files.0 "files requested."
  541. all=\prompt
  542. do i=1 to files.0
  543.    if prompt & \all then
  544.       do
  545.       if \visual then
  546.       do
  547.          Call Charout, "Get "files.i" (yes|no|all|quit)? "
  548.          do until pos(translate(key),"YNAQ")<>0
  549.             key=SysGetKey("NoEcho")
  550.          end
  551.          say key
  552.          key=translate(key)
  553.          select
  554.             when key="Y" | key="A" then
  555.                do
  556.                err=get(files.i)
  557.                if key="A" then all=\all
  558.                end
  559.             when key="Q" then leave
  560.             otherwise nop;
  561.          end
  562.       end
  563.       else if vmsg("Multiple File Request","Get "||files.i||"? ",6)=="YES" then err=get(files.i)
  564.       end
  565.    else err=get(files.i)
  566. end
  567. if \quiet then say "Transfer complete."
  568. return 0
  569.  
  570. mput: procedure expose debug prompt clobber unique quiet bell visual
  571.  
  572. parse arg spec
  573.  
  574. if \quiet then say "Obtaining file list..."
  575. if spec="" then spec="."
  576. if spec="." then spec="*"
  577. rc=SysFileTree(spec, "files.", "FO")
  578. if \quiet then say files.0 "files to be transferred."
  579. all=\prompt
  580. do i=1 to files.0
  581.    if prompt & \all then
  582.       do
  583.       if \visual then
  584.          do
  585.          Call Charout, "Put "files.i" (yes|no|all|quit)? "
  586.          do until pos(translate(key),"YNAQ")<>0
  587.             key=SysGetKey("NoEcho")
  588.          end
  589.          say key
  590.          key=translate(key)
  591.          select
  592.             when key="Y" | key="A" then
  593.                do
  594.                err=put(files.i)
  595.                if key="A" then all=\all
  596.                end
  597.             when key="Q" then leave
  598.             otherwise nop;
  599.          end
  600.          end
  601.       else if vmsg("Multiple File Request","Put "||files.i||"? ",6)=="YES" then err=get(files.i)
  602.       end
  603.    else err=put(files.i)
  604. end
  605. if \quiet then say "Transfer complete."
  606. return 0
  607.  
  608. english: procedure
  609.  
  610. arg code
  611.  
  612. select
  613.    when code="FTPSERVICE"     then phrase="unknown service"
  614.    when code="FTPHOST"        then phrase="unknown host"
  615.    when code="FTPSOCKET"      then phrase="unable to obtain socket"
  616.    when code="FTPCONNECT"     then phrase="unable to connect to server"
  617.    when code="FTPLOGIN"       then phrase="login failed"
  618.    when code="FTPABORT"       then phrase="transfer aborted"
  619.    when code="FTPLOCALFILE"   then phrase="problem openning local file"
  620.    when code="FTPDATACONN"    then phrase="problem initializing data connection"
  621.    when code="FTPCOMMAND"     then phrase="command failed"
  622.    when code="FTPPROXYTHIRD"  then phrase="proxy server does not support third party transfers"
  623.    when code="FTPNOPRIMARY"   then phrase="no primary connection for proxy transfer"
  624.    when code="0"              then phrase="no error (possibly unknown error)"
  625. otherwise
  626.    phrase="unknown error condition "||code||" - contact author"
  627. end
  628.  
  629. return phrase
  630.  
  631. /*------------------------------------------------------------------
  632.  * some help
  633.  *------------------------------------------------------------------*/
  634. Usage: procedure expose debug binaries version credits. pager
  635.  
  636. arg cmd .
  637.  
  638. select
  639.    when cmd="!" then say "!     issue a command to OS/2"
  640.    when cmd="CONNECT" | cmd="OPEN" then
  641.       do
  642.       say "connect host [user [password]]"
  643.       say "connect user@host [password]"
  644.       say "open host [user [password]]"
  645.       say "open user@host [password]"
  646.       say
  647.       say "Connect to a remote host.  If user is not specified, anonymous"
  648.       say "is selected as the default."
  649.       end
  650.    when cmd="CLOSE" then say "close     Close the remote session"
  651.    when cmd="LCD"   then say "lcd       Change the local working directory"
  652.    when cmd="SITE"  then say "site command      Issue a site specific command to the remote host"
  653.    when cmd="VERSION"  then say "version      Display information about the version of MaxiFTP"
  654.    when cmd="QUOTE"  then say "quote command      execute the command on the remote host"
  655.    when cmd="REDIR" then say "redir     redisplay the last dir or ls results"
  656.    when cmd="PREDIR" then say "predir     redisplay the last dir or ls results through the pager"
  657.    when cmd="PAGER" then
  658.       do
  659.       say "By default, MaxiFTP uses MORE as the pager.  If you prefer a different pager, put it's"
  660.       say "name (and path information) in the PAGER environment variable."
  661.       end
  662.    when cmd="VISUAL" then
  663.       do
  664.       say "VISUAL"
  665.       say
  666.       say "Enter MaxiFTP's VISUAL FTP mode."
  667.       say
  668.       say "In visual mode, MaxiFTP presents a scrollable list of files and directories from the"
  669.       say "remote host in a PM dialog box.  You can choose a file to transfer or a directory to"
  670.       say "enter by clicking with your mouse.  Choosing CANCEL will exit MaxiFTP.  You can also"
  671.       say "issue any MaxiFTP command, and output will be displayed in the window where MaxiFTP"
  672.       say "started."
  673.       say
  674.       say "VISUAL mode may be selected by typing the command VISUAL at the MaxiFTP prompt, or"
  675.       say "starting MaxiFTP with the /V option.  If you rename MaxiFTP to VisFTP, VISUAL mode"
  676.       say "will be the default."
  677.       end
  678.    when (cmd="DIR") | (cmd="LS")  | (cmd="PDIR") then
  679.       do
  680.       say "dir [pattern] [|command]"
  681.       say "pdir [pattern]"
  682.       say "ls [pattern] [|command]"
  683.       say
  684.       say "  Display a directory listing for the remote host"
  685.       say "  The output can be piped into another program."
  686.       say "  ls displays a short listing, dir displays a long format listing"
  687.       say "  pdir displays a directory using the more command."
  688.       say "Examples:"
  689.       say "  dir"
  690.       say "  ls *.exe"
  691.       say '  dir "|head -20"'
  692.       end
  693.    when (cmd="TYPE") | (cmd="PAGE") | (cmd="MORE") then
  694.       do
  695.       say "type filename [|command]"
  696.       say "page filename"
  697.       say
  698.       say "Display a remote file on the screen."
  699.       say "The page command uses MORE as a pager.  The output from type can"
  700.       say "optionally be piped to another program."
  701.       end
  702.   when (cmd="GET") | (cmd="PUT") then
  703.       do
  704.       say "get remotefile [localfile]"
  705.       say "aget remotefile [localfile]"
  706.       say "bget remotefile [localfile]"
  707.       say "put localfile [remotefile]"
  708.       say "uput localfile [remotefile]"
  709.       say
  710.       say "GET transfers a file from a remote host to the PC."
  711.       say "AGET transfers a file from a remote host to the PC in ASCII mode."
  712.       say "BGET transfers a file from a remote host to the PC in BINARY mode."
  713.       say "PUT transfers a file from the PC to a remote host."
  714.       say "UPUT transfers a file from the PC to a remote host, ensuring a unique name."
  715.       say
  716.       say "There are two transfer modes - ASCII and BINARY.  You can set the"
  717.       say "default mode with the ASCII and BINARY commands.  This client will"
  718.       say "assume binary mode for the following extensions: "binaries
  719.       say
  720.       say "GET also ensures that the file transferred has a valid local name.  It creates"
  721.       say "a valid local name from the remote name if necessary."
  722.       end
  723.   when (cmd="RENAME") then  say "rename oldname newname       rename a remote file"
  724.   when (cmd="DELETE") then  say "delete filename     delete a remote file"
  725.   when (cmd="SYS") then  say "sys       Display information about remote host"
  726.   when (cmd="QUIT") then say "quit      Leave MaxiFTP"
  727.   when (cmd="ASCII") then say "ascii     set default transfer mode to 7-bit ASCII"
  728.   when (cmd="BINARY") then say "binary    set default transfer mode to 8-bit BINARY"
  729.   when (cmd="PWD") then say "pwd       display remote working directory"
  730.   when (cmd="MD") then say "md       create a new directory on the remote host"
  731.   when (cmd="CDUP") then say "cdup       change to a the parent of the current remote working directory"
  732.   when (cmd="RD") then say "rd       remove an existing directory on the remote host"
  733.   when (cmd="APPEND") then say "append      transfer an ASCII file and append to an existing local file"
  734.   when (cmd="SHOW") then say "show       display information about the current connection"
  735.   when (cmd="CREATE") then say "create      create an empty file on the remote host"
  736.   when (cmd="CD") then
  737.      do
  738.      say "cd directory"
  739.      say "directory"
  740.      say
  741.      say "Change to the specified directory on the remote host.  If you type a"
  742.      say "directory name by itself that does not match a MaxiFtp command,"
  743.      say "MaxiFtp assumes the CD command."
  744.      end
  745.   when (cmd="MGET")|(cmd="MPUT") then
  746.      do
  747.      say "mget filespec"
  748.      say "mput filespec"
  749.      say
  750.      say "Transfer a group of files at once."
  751.      say "If PROMPT is set (default), you will be asked to confirm each transfer."
  752.      say "The values of CLOBBER and UNIQUE will affect local and remote filenames."
  753.      end
  754.   when (cmd="NETRC") then
  755.      do
  756.      say "MaxiFTP will use the TCP/IP NETRC file to obtain information about a host"
  757.      say "and connections.  MaxiFTP uses the hostname, username, and password fields."
  758.      say "At present, it ignores any other values."
  759.      say
  760.      say "By default, when you issue a connection command, MaxiFTP will look for an"
  761.      say "entry in your NETRC file and use those values, unless you have specified"
  762.      say "different values at the command line or MaxiFTP prompt."
  763.      say
  764.      say "MaxiFTP looks for a NETRC file first in your current directory and then"
  765.      say "in the directory pointed to by the %etc% variable."
  766.      say
  767.      say "If you wish MaxiFTP to ignore the NETRC file, you can issue the"
  768.      say "TOGGLE NETRC command or place the -n- option on the command line or in the"
  769.      say "MAXIFTP environment variable."
  770.      end
  771.   when (cmd="TOGGLE") then
  772.      do
  773.      say "toggle [setting]"
  774.      say
  775.      say "where setting is one of the following:"
  776.      say
  777.      say "CLOBBER  controls whether or not MaxiFTP will automatically overwrite existing"
  778.      say "         files."
  779.      say "PROMPT   determines whether or not MaxiFTP will prompt during mget and mput."
  780.      say "DISPLAY  toggles displaying a status bar at the top of the screen."
  781.      say "UNIQUE   determines whether or not remote file targets during put will be"
  782.      say "         forced to be unique."
  783.      say "QUIET    determines whether messages will be displayed about command success"
  784.      say "         and failure."
  785.      say "TOUCH    make the timestamp on files transferred with get/mget match the remote"
  786.      say "         filesystem."
  787.      say "NETRC    use the NETRC file for information about a connection."
  788.      say "LONGNAME store the real name in the .LONGNAME extended attribute on a FAT"
  789.      say "         partition if the name is globbed."
  790.      say "HISTORY  store information in the .HISTORY extended attribute."
  791.      say "BELL     ring a bell after connecting and after a transfer."
  792.      end
  793.   when (cmd="COLON-MODE") then
  794.      do
  795.      say "MaxiFTP implements a simple, automated FTP transfer.  You can invoke MaxiFTP"
  796.      say "with a colon in the host name, followed by the name of the file to transfer."
  797.      say "MaxiFTP will attempt (one time) to connect to the remote host, transfer the "
  798.      say "file, and close the connection."
  799.      say "The filename can include a wildcard.  CLOBBER and NOPROMPT are assumed"
  800.      say "for automated transfers."
  801.      say "You can also specify a user name with or without a password to identify the"
  802.      say "user account on the remote host."
  803.      end
  804.   when (cmd="TOUCH") then
  805.      do
  806.      say "MaxiFTP has a special option called TOUCH that is not included in most FTP"
  807.      say "clients.  In TOUCH mode, MaxiFTP will attempt to make the timestamp on a"
  808.      say "transferred file match the timestamp on the remote system."
  809.      say
  810.      say "This requires having a TOUCH program compatible with the Unix TOUCH command"
  811.      say "installed on your system.  One source for such a program is the GNU File"
  812.      say "Utilities for OS/2 available from ftp-os2.cdrom.com and other anonymous"
  813.      say "FTP sites."
  814.      say
  815.      end
  816.   when (cmd="NEWS") then
  817.      do
  818.      parse source . . name
  819.      news=filespec('drive',name)||filespec('path',name)||"maxiftp.new"
  820.      if stream(news,"C","QUERY EXISTS")<>"" then
  821.         pager " <"news
  822.      else say "No news available."
  823.      end
  824.   when (cmd="CREDITS") then
  825.      do
  826.      say version credits.1
  827.      say
  828.      say "MaxiFTP is based on the MiniFTP client included with the RxFTP package"
  829.      say "from the IBM Employee Written Software Program (EWS)."
  830.      say
  831.      say "Special thanks to Al Dhir for suggesting several features."
  832.      say
  833.      say "My warmest thanks go to Micheal Gleason, author of the NcFTP program"
  834.      say "for Unix.  His program is the inspiration for many of the features found"
  835.      say "in MaxiFTP, and, with his permission, the manual for MaxiFTP is based upon"
  836.      say "the NcFTP manual."
  837.      say
  838.      say "Other ideas for MaxiFTP features have came from the OS/2 internet community."
  839.      say "If you have any suggestions, please mail them to me!"
  840.      say
  841.      say "Albert Crosby - acrosby@comp.uark.edu"
  842.      end
  843.   when (cmd="PROMPT") then
  844.      do
  845.      say "The MaxiFTP prompt can be customized.  The command to use is:"
  846.      say "    set prompt=promptstring"
  847.      say
  848.      say "Special information can be inserted in the prompt using the following"
  849.      say "codes:"
  850.      say "@D         Inserts the current remote directory."
  851.      say "@L         Inserts the current local directory."
  852.      say "@H         Inserts the name of the remote host."
  853.      say "@0         Inserts the name of the calling program."
  854.      say "@B         Turns on boldface mode."
  855.      say "@Cfb       Set color to foreground f on background b"
  856.      say "@I or @R   Turns on inverse (reverse) video mode."
  857.      say "@N         Inserts a newline character."
  858.      say "@P         Turns off any video modes you might have set with @B, @I, or @R"
  859.      say "@T         Inserts the current time."
  860.      say '@S         Inserts the current connection status.'
  861.      say "@_         Inserts a blank."
  862.      say "@@         Inserts an at sign."
  863.      say "@E         Inserts the most recent FTP Error code."
  864.      say
  865.      say "The default prompt is  set prompt=@0@S[@B@H:@D@P]@S"
  866.      say
  867.      say "See MaxiFTP.MAN for more information."
  868.      end
  869.   when (cmd="COLORS") then
  870.      do
  871.      say "The @C code in the SET PROMPT command uses colors in the following"
  872.      say "fashion:"
  873.      say
  874.      say " @Cfb Set color to foreground f on background b; where f and b"
  875.      say "      are numbers between 0 and 7.  0 is black; 1 is red; 2 is green; 3"
  876.      say "      is yellow; 4 is blue; 5 is magenta; 6 is cyan; 7 is white."
  877.      end
  878.   when (cmd="OPTIONS") then
  879.      do
  880.      say "MaxiFTP has several command line options which can be specified when starting"
  881.      say "the program, preceeded by a dash ('-') or in the environment variable MAXIFTP."
  882.      say "These are:"
  883.      say
  884.      say " option  type     desc"
  885.      say " ------  -------  -----------------------------------------"
  886.      say " b               default to binary file transfer mode"
  887.      say " a       string  anonymous ftp password"
  888.      say " h       string  display help on a topic"
  889.      say " q       t/f     quiet mode"
  890.      say " d       t/f     display the status banner"
  891.      say " c       t/f     set CLOBBER mode"
  892.      say " p       t/f     set PROMPT mode"
  893.      say " u       t/f     set UNIQUE mode"
  894.      say " t       t/f     set TOUCH mode"
  895.      say " n       t/f     use/do not use NETRC for connection info"
  896.      say " l       string  set the default local directory"
  897.      say ' m       t/f     use "#macros" from netrc file'
  898.      say ' x       t/f     use rxSock to determine hostname'
  899.      say " r       n:s     Retry N times with S second pause between tries"
  900.      say
  901.      say "The t/f (true/false) options default to true.  If followed by a '-',"
  902.      say "they set the value to false.  The string options must be followed"
  903.      say "immeadiately by a string (with no blanks) that sets the value."
  904.      end
  905. otherwise
  906.    say version credits.1
  907.    say
  908.    say "   Commands available are:"
  909.    say "       !       cdup     dir   mget    put    redir   toggle   set"
  910.    say "       ?       close    get   open    pwd    rename  type     echo"
  911.    say "       append  connect  help  page    quit   show    uput     aget"
  912.    say "       ascii   create   ls    pdir    quote  site    version  bget"
  913.    say "       cd      delete   md    predir  rd     sys     lcd      addhost"
  914.    say
  915.    say "Additional topics:  colon-mode  intro  options  touch  netrc credits"
  916.    say "                    prompt"
  917.    say
  918.    say "Enter HELP COMMAND for more information or HELP NEWS for news."
  919.    say "Refer to MaxiFTP.MAN for additionl information on MaxiFTP."
  920.    if cmd="INTRO" then
  921.       do
  922.       say
  923.       say "MaxiFTP may be called with [user@]host:filename to transfer a file and exit."
  924.       say
  925.       say "See MaxiFTP.NEW for additional information or the online help."
  926.       say
  927.       say "Syntax: "
  928.       say "   MaxiFTP [-options] [host[:filename] [user [password]]]"
  929.       say "   MaxiFTP [-options] [user@host[:filename] [password]]"
  930.       end
  931. end
  932.  
  933.    return 0
  934.  
  935. displaystatus: procedure expose debug host dir rows cols mode clobber prompt status unique quiet touch bell
  936.  
  937.    /*---------------------------------------------------------------
  938.     * print status
  939.     *---------------------------------------------------------------*/
  940.    say
  941.    say
  942.    say
  943.    parse value SysCurPos(0,0) with row col
  944.  
  945.    do i = 1 to 5
  946.       call SysCurPos i-1, 0
  947.       say copies(" ",cols)
  948.    end
  949.    call SysCurPos 0,0
  950.  
  951.  
  952.    say d2c(218) || copies(d2c(196),cols-3) || d2c(191)
  953.    say d2c(179) || left(" MaxiFtp: "||time()||" "||status,cols-3) || d2c(179)
  954.    say d2c(179) || left(" directory: "||dir,cols-3) || d2c(179)
  955.    line=" " || left(mode,7)
  956.    if clobber then line=line||"CLOBBER   "
  957.    else line=line||"NOCLOBBER "
  958.    if prompt then line=line||"PROMPT   "
  959.    else line=line||"NOPROMPT "
  960.    if quiet then line=line||"QUIET   "
  961.    if touch then line=line||"TOUCH   "
  962.    if unique then line=line||"UNIQUE"
  963.    say d2c(179) || left(line,cols-3) || d2c(179)
  964.    say d2c(192) || copies(d2c(196),cols-3) || d2c(217)
  965.  
  966. if row>6 then call SysCurPos row-2, col
  967. else Call SysCurPos 5, col
  968.  
  969. return
  970.  
  971. querystatus:
  972.  
  973. say version credits.1
  974. vsn="Junk"
  975. junk=FtpVersion('vsn')
  976. say "rxFTP version "vsn
  977. if host<>"" then
  978.    do
  979.    say "Remote host: "host
  980.    say "Remote directory: "dir
  981.    say "Remote system type: "sys
  982.    end
  983. else say "Not connected to a remote host."
  984. say "Default transfer mode: "mode
  985. say "Local directory: "directory()
  986. say "Anonymous password: "anonpass
  987. say "Pager: "pager
  988. say "Prompt: "promptstr
  989. say "NETRC file: "netrcfile
  990. if clobber then
  991.    say "CLOBBER is ON (local files are overwritten)"
  992. else say "CLOBBER is OFF (local files are not overwritten)"
  993. if prompt then
  994.    say "MPROMPT is ON (you will be prompted during mget and mput"
  995. else say "MPROMPT is OFF (you will not be prompted during mget and mput"
  996. if display then
  997.    say "DISPLAY is ON (status bar is displayed)"
  998. else say "DISPLAY is OFF (status bar is not displayed)"
  999. if unique then
  1000.    say "UNIQUE is ON (remote files during put will be forced to unique names)"
  1001. else say "UNIQUE is OFF (remote files during put will not be forced to unique names)"
  1002. if quiet then
  1003.    say "QUIET is ON (messages will not be displayed)"
  1004. else say "QUIET is OFF (messages will be displayed)"
  1005. if touch then
  1006.    say "TOUCH is ON (files received will be stamped with the remote timestamp)"
  1007. else say "TOUCH is OFF (files received will not be stamped with the remote timestamp)"
  1008. if netrc then
  1009.    say "NETRC is ON (the NETRC file will be searched for connection info)"
  1010. else say "NETRC is OFF (the NETRC file will not be searched for connection info)"
  1011. if macros then
  1012.    say "MACROS is ON (NETRC macros will be processed for hosts in the NETRC)"
  1013. else say "MACROS is OFF (NETRC macros will not be processed for hosts in the NETRC)"
  1014. if visual then
  1015.    say "VISUAL mode is ON (VREXX will be used for directory lists & dialogs)"
  1016. else say "VISUAL mode is OFF (VREXX will not be used.)"
  1017. say "File types automatically transferred in binary mode:"
  1018. say "   "binaries
  1019. say "File types automatically transferred in ASCII mode:"
  1020. say "   "asciis
  1021.  
  1022. return
  1023.  
  1024. connect: procedure expose debug host user pass phost anonpass quiet netrc sys dir retries delay bell visual needdir netrcfile hostlist. hostnetrcline
  1025.  
  1026. if visual then needdir=1
  1027. if (host="") then
  1028.    if visual then 
  1029.       do
  1030.       host=VListNETRC()
  1031.       if host="" then call GetHost
  1032.       end
  1033.    else
  1034.       do
  1035.       call Usage "CONNECT"
  1036.       return -1
  1037.       end
  1038. if netrc then Call LookUpNETRC hostnetrcline
  1039. do attempt=1 to retries
  1040.          if pos("@",host)<>0 then
  1041.             do
  1042.             pass=user
  1043.             parse var host user"@"host
  1044.             end
  1045.          if pos(":",host)<>0 then
  1046.             do
  1047.             end
  1048.          if netrc & (newhost<>"") then host=newhost
  1049.          if netrc & (user="") & (newuser<>"") then
  1050.             do
  1051.             user=newuser
  1052.             pass=newpass
  1053.             end
  1054.          if (user="") then user="anonymous"
  1055.          if (translate(user)="ANONYMOUS") & (pass="") then pass=anonpass
  1056.          if (translate(user)<>"ANONYMOUS") & (pass="") then
  1057.             if visual then call GetHost
  1058.             else
  1059.                do
  1060.                call charout ,"Enter the password: "
  1061.                pass=getpasswd()
  1062.                end
  1063.          if pos(".",host)="" then phost=host
  1064.          else parse var host phost".".
  1065.          if \quiet then say "Connecting to "user"@"host"..."
  1066.          call FtpSetUser host, user, pass
  1067.          sys=""
  1068.          err = FtpSYS('sys')
  1069.          if err<>0 & FTPERRNO<>0 & FTPERRNO<>"FTPCOMMAND" then
  1070.             do
  1071.             if attempt=retries then
  1072.                do;
  1073.                if \quiet then say "Connection failed: "english(FTPERRNO)
  1074.                host=""
  1075.                phost=""
  1076.                user=""
  1077.                do queued()
  1078.                   parse pull .
  1079.                end
  1080.                leave
  1081.                end
  1082.             else
  1083.                do
  1084.                if \quiet then say "Connection failed: "english(FTPERRNO) "retrying... (try "attempt")"
  1085.                call SysSleep Delay
  1086.                iterate
  1087.                end
  1088.             end
  1089.          if word(sys,1)="VM" then
  1090.             do
  1091.             if visual then
  1092.                do
  1093.                end
  1094.             else
  1095.             do;
  1096.             say "Remote system is VM/CMS.  Please enter the minidisk password:"
  1097.             account=getpasswd()
  1098.             end
  1099.             call FtpSetUser host, user, pass, account
  1100.             end
  1101.          err = FtpPWD('dir')
  1102.          if err<>0 & FTPERRNO<>0 then
  1103.             do
  1104.             if attempt=retries then
  1105.                do;
  1106.                say "Connection failed: "english(FTPERRNO)
  1107.                host=""
  1108.                phost=""
  1109.                user=""
  1110.                do queued()
  1111.                   parse pull .
  1112.                end
  1113.                end
  1114.             else
  1115.                do
  1116.                if \quiet then say "Connection failed: "english(FTPERRNO) "retrying... (try "attempt")"
  1117.                call SysSleep Delay
  1118.                end
  1119.             end
  1120.          else 
  1121.             do
  1122.             if \quiet & bell then call beep 278,200
  1123.             leave;
  1124.             end
  1125. end
  1126. return  err
  1127.  
  1128. toggle: procedure expose debug prompt clobber display unique quiet touch netrc longname history bell
  1129. arg toggles
  1130.  
  1131. do i=1 to words(toggles)
  1132. toggle=word(toggles,i)
  1133. select
  1134.    when (toggle="PROMPT") | (toggle="MPROMPT") then prompt=\prompt
  1135.    when toggle="CLOBBER" then clobber=\clobber
  1136.    when toggle="STATUS" | toggle="DISPLAY" then display=\display
  1137.    when toggle="UNIQUE" then unique=\unique
  1138.    when toggle="QUIET" then quiet=\quiet
  1139.    when toggle="TOUCH" then touch=\touch
  1140.    when toggle="NETRC" then netrc=\netrc
  1141.    when toggle="HISTORY" then history=\history
  1142.    when toggle="LONGNAME" then longname=\longname
  1143.    when toggle="BELL" then bell=\bell
  1144. otherwise
  1145.    say "Unknown option: "toggle
  1146.    return
  1147. end
  1148. end
  1149. return
  1150.  
  1151. processargs:
  1152.  
  1153. parse arg args
  1154.  
  1155. do until length(args)=0
  1156.    tf=1
  1157.    key=translate(left(args,1))
  1158.    args=substr(args,2)
  1159.    if key=" " then iterate
  1160.    if key='"' then
  1161.       do
  1162.       parse var args '"'.'"'args
  1163.       iterate
  1164.       end
  1165.    if left(args,1)="-" then
  1166.       do
  1167.       tf=0
  1168.       args=substr(args,2)
  1169.       end
  1170.    select
  1171.       when key="B" then if tf then mode="BINARY" else mode="ASCII"
  1172.       when key="A" then /* Anonymous password */
  1173.          if left(args,1)<>" " then
  1174.             do
  1175.             if left(args,1)='"' then
  1176.                parse var args '"'anonpass'"'args
  1177.             else
  1178.                do
  1179.                anonpass=subword(args,1,1)
  1180.                args=subword(args,2)
  1181.                end
  1182.             end
  1183.       when key="R" then /* speficy retries[:delay] */
  1184.          do
  1185.          time=subword(args,1,1)
  1186.          args=subword(args,2)
  1187.          parse var time retries":"delay
  1188.          if \datatype(delay,"W") then delay=60
  1189.          if \datatype(retries,"W") then retries=1
  1190.          end
  1191.       when key="L" then /* change local directory */
  1192.          if left(args,1)<>" " then
  1193.             do
  1194.             if left(args,1)='"' then
  1195.                parse var args '"'ldir'"'args
  1196.             else
  1197.                do
  1198.                ldir=subword(args,1,1)
  1199.                args=subword(args,2)
  1200.                end
  1201.             call directory ldir
  1202.             end
  1203.       when key="H" |key="?" then /* Help */
  1204.          do
  1205.          if \quiet then call Credits
  1206.          if left(args,1)<>" " then
  1207.             do
  1208.             if left(args,1)='"' then
  1209.                parse var args '"'topic'"'args
  1210.             else
  1211.                do
  1212.                topic=subword(args,1,1)
  1213.                args=subword(args,2)
  1214.                end
  1215.             Call Usage topic
  1216.             end
  1217.          else if host<>"" then call Usage host
  1218.          else Call Usage "INTRO"
  1219.          exitcode=0
  1220.          signal done
  1221.          end
  1222.       when key="U" then unique=tf
  1223.       when key="C" then clobber=tf
  1224.       when key="P" then prompt=tf
  1225.       when key="D" then display=tf
  1226.       when key="Q" then quiet=tf
  1227.       when key="T" then touch=tf
  1228.       when key="N" then netrc=tf
  1229.       when key="X" then nop;
  1230.       when key="V" then 
  1231.          do
  1232.          visual=tf
  1233.          if visual then visual=1
  1234.          end
  1235.    otherwise
  1236.       if \quiet then say "Invalid option: "key
  1237.    end
  1238. end
  1239.  
  1240. return
  1241.  
  1242. Credits:
  1243.  
  1244. do
  1245.    call charout, greenonblack
  1246.  
  1247.    if translate(progname)<>"MAXIFTP" then say name "is ..."
  1248.    say version
  1249.    do i=1 to credits.0
  1250.    say credits.i
  1251.    end
  1252.    junk=FtpVersion('vsn')
  1253.    say "Using RxFTP version "vsn normvideo
  1254. end
  1255. return
  1256.  
  1257. LoadFunctions:
  1258.  
  1259. /*------------------------------------------------------------------
  1260.  * load functions, if needed
  1261.  *------------------------------------------------------------------*/
  1262. if RxFuncQuery("FtpLoadFuncs") then
  1263.    do
  1264.    rc = RxFuncAdd("FtpLoadFuncs","RxFtp","FtpLoadFuncs")
  1265.    if rc\=0 then
  1266.       do
  1267.       say "Error loading the rxFtp package.  rxFtp is an extension to REXX"
  1268.       say "that allows it to utilize the FTP protocol and API. You can"
  1269.       say "obtain rxSock via anonymous FTP from software.watson.ibm.com or"
  1270.       say "ftp-os2.cdrom.com."
  1271.       end
  1272.    rc = FtpLoadFuncs()
  1273.    end
  1274.  
  1275. if RxFuncQuery("SysLoadFuncs") then
  1276.    do
  1277.    rc = RxFuncAdd("SysLoadFuncs","RexxUtil","SysLoadFuncs")
  1278.    rc = SysLoadFuncs()
  1279.    end
  1280.  
  1281. if pos(" X-",translate(args))=0 & RxFuncQuery("SockLoadFuncs") then
  1282.    do
  1283.    rc = RxFuncAdd("SockLoadFuncs","RxSock","SockLoadFuncs")
  1284.    if rc\=0 then
  1285.       do
  1286.       hostname=value("HOSTNAME",,"OS2ENVIRONMENT")
  1287.       end
  1288.    else rc = SockLoadFuncs()
  1289.    end
  1290. else hostname=value("HOSTNAME",,"OS2ENVIRONMENT")
  1291.  
  1292. return
  1293.  
  1294. touch: procedure
  1295.  
  1296. parse arg direntry, file
  1297.  
  1298. sys=""
  1299. err=FtpSYS('sys')
  1300. sys=word(sys,1)
  1301.  
  1302. if right(file,1)=":" then return 0
  1303. if wordpos(translate(file),"NUL CON LPT1 LPT2 LPT3 LPT4 PRN -") then return 0
  1304.  
  1305. select
  1306.    when sys="Netware" then
  1307.       do
  1308.       parse var direntry . 42 time 57 .
  1309.       time=subword(time,1,2)||", "||subword(time,3)
  1310.       end
  1311.    when sys="Windows_NT" | sys="UNIX" | left(direntry,1)="-" then
  1312.       do
  1313.       time=subword(direntry,words(direntry)-3,3)
  1314.       if pos(":",time)=0 then
  1315.          time=subword(time,1,2)||", "||subword(time,3)
  1316.       end
  1317.    when sys="OS/2" then
  1318.       do;
  1319.       parse var direntry . 36 time 52 .
  1320.       months="Jan Feb Mar Apr May June July Aug Sep Oct Nov Dec"
  1321.       parse var time month"-"day"-"year time
  1322.       time=word(months,month)||" "||day||", "||year||" "||time
  1323.       end
  1324.    when sys="Windows_NT" then parse var direntry . 45 time 57 .
  1325.    when sys="VM" then parse var direntry . 54 time 71 .
  1326. otherwise
  1327.    say "Cannot determine timestamp for operating system "SYS
  1328.    say "If you would like to have TOUCH updated for this OS, contact the author"
  1329.    say "with the OS information and the contents of the next line."
  1330.    say direntry
  1331.    say file
  1332.    return -1
  1333. end
  1334.  
  1335. 'touch -d "'strip(time)'"' file
  1336. if rc=1041 then say "The TOUCH mode requires a TOUCH program compatible with the UNIX touch command."
  1337. if rc<>0 then say "TOUCH appears to have failed.  You may want to contact the author for assistance."
  1338.  
  1339. return 0
  1340.  
  1341. create: procedure expose debug quiet bell
  1342.  
  1343. parse arg fn
  1344.  
  1345. if \quiet then say "Creating message "fn
  1346. tempfile=systempfilename("tmp?????")
  1347. call lineout tempfile
  1348. call stream tempfile,'C','CLOSE'
  1349. oq=quiet
  1350. quiet=1
  1351. unique=0
  1352. binaries=""
  1353. err=put(tempfile,fn)
  1354. quiet=oq
  1355. call SysFileDelete tempfile
  1356. return 1
  1357.  
  1358. lookupnetrc: procedure expose debug host newhost newuser newpass netrcfile hostlist.
  1359.  
  1360. newhost=""
  1361. newuser=""
  1362. newpass=""
  1363.  
  1364. if host="" then return 0
  1365.  
  1366. do i=1 to hostlist.0
  1367.    if \abbrev(translate(word(hostlist.i,1)),translate(host)) then iterate
  1368.    host=word(hostlist.i,1)
  1369.    leave
  1370. end
  1371.  
  1372. if SysFileSearch(host, netrcfile,'hits.','N')<>0 then
  1373.    return -1
  1374. if hits.0=0 then return 0
  1375. if datatype(arg(1),'W') then hits.1=arg(1)
  1376. do i=1 to word(hits.1,1)-1
  1377.    call linein netrcfile
  1378. end
  1379.  
  1380. found=0
  1381. do while (stream(netrcfile,'s')="READY")
  1382.    line=linein(netrcfile)
  1383.    if \found & (left(line,1)="#") | (left(line,1)=";") | (length(line)=0) then iterate
  1384.    if (substr(line,2,1)="#") | (substr(line,2,1)=";") then iterate
  1385.    tline=translate(line)
  1386.    if \found & pos('MACHINE',tline)=0 then iterate;
  1387.    if pos("MACHINE",tline)<>0 then
  1388.       if found then leave
  1389.       else machinename=word(line,wordpos("MACHINE",tline)+1)
  1390.    if \abbrev(translate(machinename),translate(host)) then iterate
  1391.    found=1
  1392.    if (left(line,1)<>"#") & (left(line,1)<>";") then
  1393.       do
  1394.       if pos("LOGIN",tline)<>0 then newuser=word(line,wordpos("LOGIN",tline)+1)
  1395.       if pos("PASSWORD",tline)<>0 then newpass=word(line,wordpos("PASSWORD",tline)+1)
  1396.       end
  1397.    else
  1398.       do
  1399.       parse var line 2 cmd cmdargs
  1400.       Queue cmd cmdargs
  1401.       end
  1402. end
  1403. call Stream netrcfile, 'c', 'close'
  1404. if found then newhost=machinename
  1405. return found
  1406.  
  1407. dir: procedure expose stem. pager sys host dir phost status quiet bell visual dircmd
  1408.  
  1409. parse arg cmd, mask, dest
  1410.  
  1411.    if cmd="" then cmd="DIR"
  1412.    if mask="" then mask="."
  1413.  
  1414.    if ((cmd="DIR")|(cmd="PDIR")) & left(mask,1)<>"-" then
  1415.       do
  1416.       if cmd="PDIR" then cmd="P"||translate(word(dircmd,1))
  1417.       else cmd=translate(word(dircmd,1))
  1418.       mask=subword(dircmd,2) mask
  1419.  
  1420.       end
  1421.  
  1422.    err=0
  1423.    select
  1424.    when (cmd="LS") | (cmd="PLS") then
  1425.       if (mask=".") & (pos("UNIX",translate(sys))<>0)
  1426.          then err=FtpLS("-CF",'stem.')
  1427.          else err=FtpLS(mask,'stem.')
  1428.    when (cmd="DIR")| (cmd="PDIR") then err=FtpDIR(mask,'stem.')
  1429.    when (cmd='ls') then err=FtpLS(mask,'stem.')
  1430.    when (cmd="REDIR") | (cmd="PREDIR") then nop;
  1431.    otherwise return -1
  1432.    end
  1433.  
  1434.    if (left(cmd,1)<>"P") & (left(dest,1)<>'|') & (left(dest,1)<>'>') then
  1435.       do i = 1 to stem.0
  1436.          say stem.i
  1437.       end
  1438.    else
  1439.       do
  1440.       if left(cmd,1)="P" then dest="|"||pager
  1441.       tempfile=systempfilename("ftp?????")
  1442.       if left(dest,2)='>>' then tempfile=substr(dest,3)
  1443.       else if left(dest,1)='>' then
  1444.          do;
  1445.          tempfile=substr(dest,2)
  1446.          call SysFileDelete tempfile
  1447.          end;
  1448.       do i = 1 to stem.0
  1449.          call lineout tempfile, stem.i
  1450.       end
  1451.       if left(dest,1)="|" then substr(dest,2) "<" tempfile
  1452.       call stream tempfile,'C','CLOSE'
  1453.       if left(dest,1)<>'>' then call SysFileDelete tempfile
  1454.       end
  1455.    if (err <> 0) & (ftperrno <>0) then
  1456.       do
  1457.       say "Error from FTP:" english(FTPERRNO)
  1458.       if ftperrno="FTPCONNECT" then
  1459.          do
  1460.          say "Remote server closed connection."
  1461.          host=""
  1462.          phost=""
  1463.          dir=""
  1464.          end
  1465.       end
  1466. return err
  1467.  
  1468. ProcessCMD:
  1469.  
  1470. parse arg cmd, cmdargs
  1471.  
  1472.    if cmd="" then return 0
  1473.  
  1474.    if left(cmdargs,1)='"' then
  1475.       parse var cmdargs '"'file1'"' rest
  1476.    else parse var cmdargs file1 rest
  1477.    if left(cmdargs,1)='"' then
  1478.       parse var rest '"'file2'"' rest
  1479.    else parse var rest file2 rest
  1480.  
  1481.    if (left(file1,1)="|") then
  1482.       do
  1483.       rest=file2||" "||rest
  1484.       file2=file1
  1485.       file1=""
  1486.       end
  1487.    if (left(file1,1)=">") then
  1488.       do
  1489.       rest=file2||" "||rest
  1490.       file2=file1
  1491.       file1=""
  1492.       end
  1493.    if (file1 = "") then file1 = "."
  1494.    if (file2 = "") then file2 = file1
  1495.  
  1496.    /*------------------------------------------------------------------
  1497.     * sanity check
  1498.     *------------------------------------------------------------------*/
  1499.    origcmd=cmd
  1500.    cmd = translate(cmd)
  1501.  
  1502.    if (host="") & (left(cmd,1)<>"!") & (wordpos(cmd,"CONNECT FTP OPEN VERSION ? HELP QUIT TOGGLE SHOW ASCII LCD SET BINARY VISUAL ECHO CREDITS ADDHOST")=0) then
  1503.       do
  1504.       say "You have not provided host, userid, and password information."
  1505.       say "Use the CONNECT command to provide this information."
  1506.       return 0
  1507.       end
  1508.  
  1509.    /*---------------------------------------------------------------
  1510.     * run command
  1511.     *---------------------------------------------------------------*/
  1512.    err = 0
  1513.    select
  1514.       when left(cmd,1)="!"   then
  1515.          do
  1516.          if cmd="!" then value("COMSPEC",,"OS2ENVIRONMENT")
  1517.          else substr(origcmd,2) cmdargs
  1518.          end
  1519.       when (cmd = "MGET")    then  err=mget(file1)
  1520.       when (cmd = "ECHO")    then say cmdargs
  1521.       when (cmd = "MPUT")    then err=mput(file1)
  1522.       when (cmd = "QUIT")    then return 0
  1523.       when (cmd = "SET")     then Call Set cmdargs
  1524.       when (cmd = "BINARY")  then err = Mode("BINARY")
  1525.       when (cmd = "ASCII")   then err = Mode("ASCII")
  1526.       when (cmd = "GET")     then err = Get(file1,file2)
  1527.       when (cmd = "AGET")     then err = Get(file1,file2,"ASCII")
  1528.       when (cmd = "BGET")     then err = Get(file1,file2,"BINARY")
  1529.       when (cmd = "PUT")     then err = Put(file1,file2)
  1530.       when (cmd = "UPUT")    then err = Put(file1,file2,1)
  1531.       when (cmd = "CREATE")  then err = Create(file1)
  1532.       when (cmd = "DELETE")  then err = FtpDelete(file1)
  1533.       when (cmd = "RENAME")  then err = FtpRename(file1,file2)
  1534.       when (cmd = "APPEND")  then err = FtpAppend(file1,file2,"ASCII")
  1535.       when (cmd = "MODE")    then err = Mode(file1)
  1536.       when (cmd = "QUOTE")   then err = FtpQuote(cmdargs)
  1537.       when (cmd = "SITE")    then err = FtpSite(cmdargs)
  1538.       when (cmd = "CD")      then err = FtpChDir(file1)
  1539.       when (cmd = "CDUP")    then err = FtpChDir('..')
  1540.       when (cmd = "MD")      then err = FtpMkDir(file1)
  1541.       when (cmd = "RD")      then err = FtpRmDir(file1)
  1542.       when (cmd = "CREDITS") then call Credits
  1543.       when (cmd = "ADDHOST") then
  1544.          do
  1545.          hostlist.0=hostlist.0+1
  1546.          i=hostlist.0
  1547.          hostlist.i=cmdargs
  1548.          end
  1549.       when (cmd = "VISUAL")  then 
  1550.          if \visual then 
  1551.             do; 
  1552.             visual=visinit(); 
  1553.             if visual then call visftp; 
  1554.             end
  1555.       when (cmd = "TOGGLE")  then Call toggle cmdargs
  1556.       when (cmd = "VERSION") then say version credits.1
  1557.       when (cmd = "SHOW")    then Call QueryStatus
  1558.       when (cmd="DIR") | (cmd="PDIR") | (cmd="REDIR") | (cmd="PREDIR") | (cmd="LS")
  1559.                              then err = Dir(cmd,file1,file2)
  1560.       when (cmd = "?") | (cmd="HELP")
  1561.                              then call Usage file1
  1562.  
  1563.       when (cmd = "TYPE")|(cmd = "PAGE")|(cmd="MORE")    then
  1564.          if file2==file1 then
  1565.             do
  1566.             if cmd="TYPE" then err=get(file1,"-")
  1567.             else err=get(file1,"|"||pager)
  1568.             end
  1569.          else err=get(file1,file2)
  1570.  
  1571.       when (cmd = "CONNECT") | (cmd="OPEN") | (cmd="FTP") then
  1572.          do
  1573.          if left(cmdargs,1)='"' then
  1574.             parse var cmdargs '"'host'"' rest
  1575.          else parse var cmdargs host rest
  1576.          if left(cmdargs,1)='"' then
  1577.             parse var rest '"'user'"' rest
  1578.          else parse var rest user rest
  1579.          parse var rest pass
  1580.          err=Connect()
  1581.          end
  1582.  
  1583.       when (cmd = "LCD") then
  1584.          do
  1585.          ldir=directory(file1)
  1586.          if \quiet then say "Local working directory is now "ldir
  1587.          end
  1588.  
  1589.       when (cmd = "CLOSE")   then
  1590.          do
  1591.          if host="" then return
  1592.          rc = FtpLogoff()
  1593.          host = ""
  1594.          user = ""
  1595.          pass = ""
  1596.          end
  1597.  
  1598.       when (cmd = "PWD")     then
  1599.          do
  1600.          junk = FtpPwd('dir')
  1601.          say "Current Remote Directory :" dir
  1602.          end
  1603.  
  1604.       when (cmd = "SYS")     then
  1605.          do
  1606.          sys=""
  1607.          junk = FtpSys('sys')
  1608.          say "Remote operating system is:" sys
  1609.          end
  1610.  
  1611.       otherwise /* Try changing to a directory with the name of command. */
  1612.          err = FtpChDir(origcmd)
  1613.          if (err<>0) then
  1614.             do
  1615.             say "Invalid command. Use ? for help."
  1616.             return 0
  1617.             end
  1618.          else 
  1619.             do
  1620.             err=FtpPWD('dir')
  1621.             if visual then needdir=1
  1622.             end
  1623.          return err
  1624.    end
  1625.  
  1626. if debug then say sourceline() "Error code is "err "/ftp error no. "ftperrno "["english(FTPERRNO)"]"
  1627.  
  1628. return err
  1629.  
  1630. ProcessNETRC:
  1631.  
  1632. call stream netrcfile, 'c', 'open read'
  1633. do while (stream(netrcfile,'s')="READY")
  1634.    line=linein(netrcfile)
  1635.    if (left(line,1)<>"#") & (left(line,1)<>";") then leave
  1636.    if (substr(line,2,1)="#") | (substr(line,2,1)=";") then iterate
  1637.    parse var line 2 cmd cmdargs
  1638.    if (translate(cmd)="VISUAL") then visual=1
  1639.    else Call ProcessCMD cmd, cmdargs
  1640. end
  1641. call Stream netrcfile, 'c', 'close'
  1642. return
  1643.  
  1644. ProcessINI:
  1645.  
  1646. arg inifile
  1647.  
  1648. call stream inifile, 'c', 'open read'
  1649. do while (stream(inifile,'s')="READY")
  1650.    line=linein(inifile)
  1651.    if (left(line,1)="#") | (left(line,1)=";") then iterate
  1652.    parse var line cmd cmdargs
  1653.    if (translate(cmd)="VISUAL") then visual=1
  1654.    else Call ProcessCMD cmd, cmdargs
  1655. end
  1656. call Stream inifile, 'c', 'close'
  1657. return
  1658.  
  1659. set:
  1660. parse arg command
  1661.  
  1662. if (pos('=',command)<>0) then parse var command var"="parm
  1663. else parse var command var parm
  1664. var=translate(var)
  1665. if left(parm,1)='"' then parse var parm '"'parm'"'
  1666.  
  1667. select
  1668.    when (var='BINARIES') then binaries=parm
  1669.    when (var='ASCIIS') then asciis=parm
  1670.    when (var='ANONPASS') then anonpass=parm
  1671.    when (var='VISCMD') then viscmd=parm
  1672.    when (var='PAGER') then pager=parm
  1673.    when (var='DIRCMD') then dircmd=parm
  1674.    when (var='LDIR') then ldir=directory(parm)
  1675.    when (var='MODE') then Call Mode(parm)
  1676.    when (var='NETRCFILE') then
  1677.       do
  1678.       oldnetrc=netrcfile
  1679.       netrcfile=stream(parm,'c','query exists')
  1680.       if netrcfile="" then netrcfile=oldnetrcfile
  1681.       end
  1682.    when (var='MPROMPT') then
  1683.       do
  1684.       if parm=1 then prompt=1
  1685.       if parm=0 then prompt=0
  1686.       end
  1687.    when wordpos(var,"TOUCH UNIQUE CLOBBER DISPLAY QUIET TOUCH NETRC MACROS")<>0 then
  1688.       do
  1689.       if parm=1 then interpret var||'=1'
  1690.       if parm=0 then interpret var||'=0'
  1691.       end
  1692.    when (var='PROMPT') then
  1693.       do
  1694.       promptstr='""'
  1695.       do while (length(parm)>0)
  1696.          char=left(parm,1)
  1697.          parm=substr(parm,2)
  1698.          if char='@' then
  1699.             do
  1700.             var=translate(left(parm,1))
  1701.             parm=substr(parm,2)
  1702.             select
  1703.                when var="B" then promptstr=promptstr||'||boldvideo'
  1704.                when var="0" then promptstr=promptstr||'||progname'
  1705.                when var="D" then promptstr=promptstr||'||dirname'
  1706.                when var="U" then promptstr=promptstr||'||user'
  1707.                when var="L" then promptstr=promptstr||'||directory()'
  1708.                when var="H" then promptstr=promptstr||'||phost'
  1709.                when (var="I") | (var="R")
  1710.                             then promptstr=promptstr||'||inversevideo'
  1711.                when var="N" then promptstr=promptstr||'||d2c(13)||d2c(10)'
  1712.                when var="P" then promptstr=promptstr||'||normvideo'
  1713.                when var="T" then promptstr=promptstr||'||time()'
  1714.                when var="S" then promptstr=promptstr||'||status'
  1715.                when var="E" then promptstr=promptstr||'||FTPERRNO'
  1716.                when var="_" then promptstr=promptstr||'||" "'
  1717.                when var="@" then promptstr=promptstr||'||"@"'
  1718.                when var="C" then
  1719.                   do
  1720.                   colors=left(parm,2)
  1721.                   if (length(colors)=2) & (verify(colors,"01234567")=0) then
  1722.                      do
  1723.                      parm=substr(parm,3)
  1724.                      promptstr=promptstr||'||d2c(27)||"['||left(colors,1)+30||';'||right(colors,1)+40||'m"'
  1725.                      end
  1726.                   end
  1727.             otherwise nop
  1728.             end
  1729.             end
  1730.          else if char='"' then promptstr=promptstr||'||""""'
  1731.          else promptstr=promptstr||'||"'char'"'
  1732.       end
  1733.       end
  1734.    when (var="") then nop
  1735.    otherwise
  1736.       do
  1737.       say "You cannot set the value of "var
  1738.       return 0
  1739.       end
  1740. end
  1741. return 1
  1742.  
  1743. mode: procedure expose mode quiet
  1744.  
  1745. parse upper arg modename
  1746.  
  1747. err=0
  1748. if modename="ASCII" then
  1749.     err = FtpSetBinary("ASCII")
  1750. else if modename="BINARY" then err= FtpSetBinary("BINARY")
  1751. else
  1752.    do
  1753.    if \quiet then say "Invalid value for mode: "modename
  1754.    return 0
  1755.    end
  1756. mode=modename
  1757. if \quiet then say "File transfer mode set to "mode "("err")"
  1758.  
  1759. return 0
  1760.  
  1761. PutComment: procedure
  1762.  
  1763. parse arg file, user, remotehost, remotedir, remotename
  1764.  
  1765. if pos('"',remotedir)<>0 then parse var remotedir '"'remotedir'"'.
  1766.  
  1767. message="Transferred from "user"@"remotehost":"remotedir
  1768.  
  1769. if pos(right(message,1),"/\")=0 then message=message||'/'
  1770.  
  1771. message=translate(message,'/','\')||remotename||" at "||time()||" on "||date()"."
  1772.  
  1773. RetCode = SysPutEA(File, '.HISTORY','FDFF'x||D2C(LENGTH(Message))||'00'x||Message)
  1774. return RetCode
  1775.  
  1776. putlong: procedure
  1777. parse arg FileName, LongName
  1778.  
  1779. if FileName = '' | LongName= '' then DO
  1780.    return 0
  1781.    end  /* Do */
  1782.  
  1783. Return SysPutEA(FileName, '.LONGNAME','FDFF'x||D2C(LENGTH(LongName))||'00'x||LongName)
  1784.  
  1785. visinit: procedure expose origdir
  1786.  
  1787. if RxFuncQuery("VInit") then
  1788.    do
  1789.    rc = RxFuncAdd("VInit","VREXX","VINIT")
  1790.    if rc\=0 then
  1791.       do
  1792.       say "Error loading the VRexx/2 package.  VRexx/2 is an extension to REXX"
  1793.       say "that allows it to create PM list boxes and dialogs.  It is necessary"
  1794.       say "to use MaxiFTP's VISUAL mode.  You can obtain VRexx/2 via anonymous"
  1795.       say "FTP from software.watson.ibm.com or ftp-os2.cdrom.com."
  1796.       say
  1797.       say "Unable to switch to Visual mode."
  1798.       visual=0
  1799.       return 0
  1800.       end
  1801.    end
  1802.  
  1803. initcode = Vinit()
  1804. if initcode = 'ERROR' then 
  1805.    do
  1806.    say "Unable to switch to Visual mode."
  1807.    visual=0
  1808.    return 0
  1809.    end
  1810.  
  1811. signal on halt name CLEANUP
  1812. signal on failure name CLEANUP
  1813. signal on syntax name CLEANUP
  1814.  
  1815. call VdialogPos 50,50
  1816.  
  1817. return 1
  1818.  
  1819. visftp:
  1820.  
  1821. say "MaxiFTP is entering Visual mode."
  1822.  
  1823. needdir=1
  1824. do forever
  1825.    if connect()=0 then leave
  1826.    host=""
  1827.    user=""
  1828.    pass=""
  1829. end
  1830.  
  1831. do queued()
  1832.    parse pull cmd cmdargs
  1833.    call processcmd cmd, cmdargs
  1834. end
  1835.  
  1836. request=""
  1837. do forever                                    
  1838.    request=visdir()
  1839.    if request="**CANCEL**" then 
  1840.       do
  1841.       if vmsg("Leave MaxiFTP?","Do you wish to leave MaxiFTP? ",6)=="YES" then signal cleanup
  1842.       iterate
  1843.       end
  1844.    if left(request,1)='<' then
  1845.       do
  1846.       cmd=word(request,1)
  1847.       select
  1848.          when cmd="<MODE>" then call toggle 'MODE'
  1849.          when cmd="<DIR>" then call dir
  1850.          when cmd="<HOST>" then
  1851.             do
  1852.                oldhost=host
  1853.                olduser=user
  1854.                oldpass=pass
  1855.                host=""
  1856.                user=""
  1857.                pass=""
  1858.                if connect()<>0 then
  1859.                   do
  1860.                      host=oldhost
  1861.                      user=olduser
  1862.                      pass=oldpass
  1863.                      do forever
  1864.                         if connect()=0 then leave
  1865.                         host=""
  1866.                         user=""
  1867.                         pass=""
  1868.                      end
  1869.                   end
  1870.                do queued()
  1871.                   parse pull cmd cmdargs
  1872.                   call processcmd cmd, cmdargs
  1873.                end
  1874.             end
  1875.          when cmd="<LCD>" then
  1876.             do
  1877.             prompt.0=1
  1878.             prompt.1="Enter the new local directory "
  1879.             prompt.vstring=directory()
  1880.             button=VInputBox("Change Local Directory",'prompt',60,3)
  1881.             if button<>"CANCEL" then call directory prompt.vstring
  1882.             end
  1883.          when cmd="<PUT>" then
  1884.             do
  1885.             filespec=directory()
  1886.             if right(filespec,1)="\" then filespec=filespec||"*.*"
  1887.             else filespec=filespec||"\*.*"
  1888.             button=VFileBox("Choose the file to send.",filespec,'file')
  1889.             if button="OK" then put(file.vstring)
  1890.             end
  1891.          when cmd="<CMD>" then
  1892.             do
  1893.             prompt.0=2
  1894.             prompt.1="Enter a MaxiFTP command          "
  1895.             prompt.2="(Output will go the window where MaxiFTP started.)          "
  1896.             prompt.vstring="dir"
  1897.             button=VInputBox("MaxiFTP Command Line",'prompt',75,3)
  1898.             if button<>"CANCEL" then 
  1899.                do
  1900.                parse var prompt.vstring cmd cmdargs
  1901.                call processcmd cmd, cmdargs
  1902.                end
  1903.             say "MaxiFTP is in Visual mode."
  1904.             end
  1905.          otherwise say "Unimplemented: "cmd
  1906.       end
  1907.       end
  1908.    else do
  1909.       if pos(right(request,1),'/@*')<>0 then request=left(request,length(request)-1)
  1910.       err = FtpChDir(request)
  1911.       if err<>0 then call ProcessCMD VisCMD, request
  1912.       else needdir=1
  1913.       if err<>0 then
  1914.          if word(request,1)<>request then 
  1915.             do
  1916.             err=FtpChDir(word(request,1))
  1917.             if err<>0 then err=Get(word(request,1))
  1918.             end
  1919.       end
  1920. end
  1921.  
  1922. signal cleanup
  1923.  
  1924. visdir:
  1925. if needdir then
  1926.    do
  1927.    err=dir('LS','-F','>nul')
  1928.    if err<>0 then err=dir('ls','.','>nul')
  1929.    if err<>0 then 
  1930.       do
  1931.       stem.0=1
  1932.       stem.1="<NO FILES AVAILABLE>"
  1933.       end
  1934.    list.0=6
  1935.    list.1="<HOST> "||user||"@"||host
  1936.    list.2="<LCD> Current local dir: "directory()
  1937.    list.3="<CMD> Issue a MaxiFTP command"
  1938.    list.4="<DIR> Show long information about this listing in the text window"
  1939.    list.5="<PUT> Transfer a file TO "host
  1940.    list.6=".."
  1941.    do i=1 to stem.0
  1942.       j=list.0+1
  1943.       list.j=stem.i
  1944.       list.0=j
  1945.    end
  1946.    needdir=0
  1947.    end
  1948. err = FtpPwd('dir')
  1949. if pos('"',dir)<>0 then parse var dir '"'dirname'"'.
  1950. else dirname=dir
  1951. button=VlistBox('Directory Listing: 'dirname,list,80,8,3)
  1952. if button="CANCEL" then return "**CANCEL**"
  1953. return list.vstring
  1954.  
  1955. GetHost: procedure expose host user pass netrcfile hostnetrcline
  1956. p.0=3
  1957. p.1="Remote host: "
  1958. p.2="Username: "
  1959. p.3="Password: "
  1960. w.0=3
  1961. w.1=40
  1962. w.2=40
  1963. w.3=40
  1964. h.0=3
  1965. h.1=0
  1966. h.2=0
  1967. h.3=1
  1968. r.=""
  1969. r.0=3
  1970. if host<>"" then r.1=host
  1971. if user<>"" then r.2=user
  1972. else r.2="anonymous"
  1973. if pass<>"" then r.3=pass
  1974. do until host<>""
  1975. button=VMultBox('Specify a host',p,w,h,r,3)
  1976. if button="CANCEL" then 
  1977.    do
  1978.    if vmsg("Leave MaxiFTP?","Do you wish to leave MaxiFTP? ",6)=="YES" then signal cleanup
  1979.    host=""
  1980.    user=""
  1981.    pass=""
  1982.    end
  1983. else
  1984.    do
  1985.    host=r.1
  1986.    user=r.2
  1987.    pass=r.3
  1988.    end
  1989. if host<>"" then
  1990.    if (vmsg("Update NETRC file","Add this entry to the end of the NETRC file? ",6)=="YES") then
  1991.    do
  1992.    p.0=1
  1993.    p.1="Alias: "
  1994.    w.0=1
  1995.    w.1=50
  1996.    h.0=1
  1997.    h.1=0
  1998.    r.=""
  1999.    r.0=1
  2000.    alias=""
  2001.    button=VMultBox('Alias for host 'host,p,w,h,r,3)
  2002.    if button<>"CANCEL" then alias="#alias "r.1
  2003.    say "Updating "netrcfile
  2004.    call lineout netrcfile, "##Following entry added by MaxiFTP on "date()
  2005.    call lineout netrcfile, "machine "host alias
  2006.    if user<>"" then call lineout netrcfile, "     login "user
  2007.    if pass<>"" then call lineout netrcfile, "     password "pass
  2008.    call lineout netrcfile
  2009.    end
  2010. if host="" then host=VListNETRC()
  2011. end
  2012. return button
  2013.  
  2014. vmsg: procedure expose origdir
  2015.  
  2016. n=0
  2017. do i=2 to arg()-1
  2018.    n=n+1
  2019.    prompt.n=arg(i)
  2020. end
  2021. prompt.0=n
  2022.  
  2023. return VMsgBox(arg(1),'prompt',arg(arg()))
  2024.  
  2025. VListNETRC: procedure expose visual origdir netrcfile hostnetrcline hostlist.
  2026.  
  2027. say "Presenting a visual list of hosts..."
  2028.  
  2029. Call SysFileSearch 'machine', netrcfile,'hits.','N'
  2030.  
  2031. hostnetrcline=""
  2032.  
  2033. n=1
  2034. do i=1 to hostlist.0
  2035.    n=n+1
  2036.    hosts.0=n
  2037.    if words(hostlist.i)=1 then hosts.n=hostlist.i
  2038.    else hosts.n=left(subword(hostlist.i,2),100," ")||"@"||word(hostlist.i,1)
  2039. end
  2040.  
  2041. do i=1 to hits.0
  2042.    if left(word(hits.i,2),1)="#" then iterate
  2043.    n=n+1
  2044.    hosts.0=n
  2045.    parse var hits.i "#alias "alias
  2046.    if alias<>"" then
  2047.       hosts.n=left(alias,100," ")||"@"||word(hits.i,1+wordpos('MACHINE',translate(hits.i)))||" <"||word(hits.i,1)||">"
  2048.    else hosts.n=left(word(hits.i,1+wordpos('MACHINE',translate(hits.i))),100," ")||"<"||word(hits.i,1)||">"
  2049. end
  2050. if n=1 then return ""
  2051.  
  2052. hosts.1="<Enter a different host>"
  2053.  
  2054. button=VlistBox('Host Selection: ','hosts',45,8,3)
  2055. if button="CANCEL" | hosts.vstring="<Enter a different host>" then return ""
  2056. parse var hosts.vstring host "<"hostnetrcline">"
  2057. if pos("@",host)<>0 then parse var host with " @"host
  2058. return strip(host)
  2059.  
  2060. addslash: procedure
  2061.  
  2062. parse arg path
  2063. if right(path,1)="\" then return path
  2064. else return path||"\"
  2065.  
  2066. CLEANUP:          
  2067.    call VExit
  2068. signal done
  2069.