// FtpUtilb.bcpl - Routines common to User and Server modules
// Copyright Xerox Corporation 1979, 1980, 1981, 1982
// Last modified May 13, 1982  1:22 PM by Boggs

get "Pup.decl"
get "FtpProt.decl"

external
[
// outgoing procedures
FTPM; GetCommand
LsPuts; DlsPuts; DblsPuts

// incoming procedures
DefaultArgs; ExtractSubstring; Free
Gets; Puts; Wss; PutTemplate
BSPPutMark; BSPGetMark

// incoming statics
CtxRunning; sysZone
mt
]

//-----------------------------------------------------------------------------------------
let FTPM(markType,code,string,eoc,par0,par1,par2,par3,par4; numargs na) be
//-----------------------------------------------------------------------------------------
[
DefaultArgs(lv na, -1, 0, 0, false)
let bspSoc = CtxRunning>>FtpCtx.bspSoc
BSPPutMark(bspSoc, markType, -1, markType eq markEndOfCommand)
PutTemplate(CtxRunning>>FtpCtx.dls, "*N$C: [$S]", (CtxRunning>>FtpCtx.serverFlag? $S, $U),
 mt>>MT.string↑markType)
if mt>>MT.sc↑markType then
   [
   Puts(CtxRunning>>FtpCtx.bspStream, code)
   PutTemplate(CtxRunning>>FtpCtx.dls, " <$O> ", code)
   ]
if string then PutTemplate(CtxRunning>>FtpCtx.dbls, string, par0, par1, par2, par3, par4)
if eoc then FTPM(markEndOfCommand)
]

//-----------------------------------------------------------------------------------------
and GetCommand(timeout; numargs na) = valof
//-----------------------------------------------------------------------------------------
// Returns subcode,,mark, string in FtpCtx.getCmdString
// Returns 0 if timeout or connection closed
// Eats up comments
// 'timeout' defaults to infinity
[
let bspStream = CtxRunning>>FtpCtx.bspStream
let bspSoc = CtxRunning>>FtpCtx.bspSoc
   [  //discard bytes up to next mark
   let char = Gets(bspStream, (na eq 0? -1, timeout))
   if char eq -1 break  //mark|timeout|stream end
   Puts(CtxRunning>>FtpCtx.dls, char)
   ] repeat
unless bspSoc>>BSPSoc.markPending resultis 0  //timeout|stream end
let mark, subCode = BSPGetMark(bspSoc), 0
if mark le 0 % mark gr numMarks % mt>>MT.code↑mark eq 0 then
   [  //assumes mark space is dense
   FTPM(markNo, 1, "Unknown mark: $O", false, mark)
   PutTemplate(CtxRunning>>FtpCtx.dls, "*NUnknown mark: $O", mark)
   loop
   ]
PutTemplate(CtxRunning>>FtpCtx.dls, "*N$C: [$S]",
 (CtxRunning>>FtpCtx.serverFlag? $U, $S), mt>>MT.string↑mark)
if mt>>MT.sc↑mark then
   [
   subCode = Gets(bspStream)
   PutTemplate(CtxRunning>>FtpCtx.dls, " <$O> ", subCode)
   ]
unless mt>>MT.nf↑mark do
   [
   let getCmdString, length = vec 128, 0
      [
      let char = Gets(bspStream); if char eq -1 break
      if length ls 255 then length = length +1
      getCmdString>>String.char↑length = char
      ] repeat
   if length ne 0 then
      [
      getCmdString>>String.length = length
      if CtxRunning>>FtpCtx.getCmdString ne 0 then
         Free(sysZone, CtxRunning>>FtpCtx.getCmdString)
      CtxRunning>>FtpCtx.getCmdString = ExtractSubstring(getCmdString)
      if mt>>MT.ptx↑mark then Wss(CtxRunning>>FtpCtx.lst, "*N< ")
      Wss((mt>>MT.ptx↑mark? CtxRunning>>FtpCtx.lst, CtxRunning>>FtpCtx.dls), getCmdString)
      ]
   ]
unless mark eq markComment resultis (subCode lshift 8) + mark
] repeat


//-----------------------------------------------------------------------------------------
and LsPuts(st, char) be Puts(CtxRunning>>FtpCtx.dspStream, char)
//-----------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------
and DlsPuts(st, char) be
//-----------------------------------------------------------------------------------------
   if CtxRunning>>FtpCtx.debugFlag then
      Puts(CtxRunning>>FtpCtx.dspStream, char)

//-----------------------------------------------------------------------------------------
and DblsPuts(st, char) be
//-----------------------------------------------------------------------------------------
[
Puts(CtxRunning>>FtpCtx.bspStream, char)
Puts(CtxRunning>>FtpCtx.dls, char)
]