// IfsFtpRetrieve.bcpl -- IFS Ftp Retrieve command
// Copyright Xerox Corporation 1979, 1980, 1981
// Last modified May 11, 1982  11:33 AM by Taft

get "IfsDirs.decl"
get "IfsFiles.decl"
get "IfsFtpProt.decl"

external
[
// outgoing procedures
FtpSRetrieve; FtpSRetrieveFile

// incoming procedures from other Ftp files
FtpSMakeSFIL; FtpSSendMark
FtpSCheckAccess; FtpSFillPLFromLD
MtpSAnonymousAccess; FtpSCheckConnection
DiskToNet; FileType; FreePList

// incoming procedures from IFS Dirs
NextFD; DestroyFD
LookupIFSFile; OpenIFSStream; CloseIFSStream

// incoming procedures - miscellaneous
IFSPrintError

// incoming statics
CtxRunning
]

//---------------------------------------------------------------------------
let FtpSRetrieve(remotePL, localPL) = valof
//---------------------------------------------------------------------------
[ // repeat
localPL = FreePList(localPL)
unless FtpSCheckConnection() resultis false
let ec = nil
test CtxRunning>>FtpCtx.fd eq 0
   ifso
      [  // first time for this Retrieve request
      FtpSMakeSFIL(remotePL)
      test CtxRunning>>FtpCtx.type eq jobTypeFTP
         ifso unless FtpSCheckAccess(remotePL) resultis false
         ifnot unless MtpSAnonymousAccess(remotePL) resultis false
      CtxRunning>>FtpCtx.fd = LookupIFSFile(remotePL>>PL.SFIL,
       lcMultiple+lcVHighest, lv ec, 0, remotePL>>PL.DIRE)
      if CtxRunning>>FtpCtx.fd eq 0 resultis FtpSSendMark(markNo, ec)
      ]
   ifnot unless NextFD(CtxRunning>>FtpCtx.fd, false) do
      [  // failed - no more files
      CtxRunning>>FtpCtx.fd = DestroyFD(CtxRunning>>FtpCtx.fd)
      resultis false
      ]
let fd = CtxRunning>>FtpCtx.fd

// Set up outgoing property list
localPL = FtpSFillPLFromLD(remotePL, true)
if localPL eq 0 then loop  // file went away?

// If we encounter problems with the pList, respond with either
//  markNo or markComment depending on whether the retrieve request
//  specified multiple files (serverFilename contained a wildcard char).
let markFail = fd>>FD.template eq 0? markNo, markComment

if localPL>>PL.TYPE eq Unspecified then
   [  // do it the hard way
   let diskStream = OpenIFSStream(fd, lv ec)
   test diskStream ne 0
      ifso
         [
         localPL>>PL.TYPE = FileType(diskStream)? Text, Binary
         CloseIFSStream(diskStream)
         ]
      ifnot localPL>>PL.TYPE = remotePL>>PL.TYPE ne 0?
       remotePL>>PL.TYPE, Binary
   ]

if remotePL>>PL.TYPE ne 0 &
 localPL>>PL.TYPE ne remotePL>>PL.TYPE then
   test localPL>>PL.TYPE eq Binary
      ifso
         [
         FtpSSendMark(markFail, ecNotRetrieved, lv fd>>FD.dr>>DR.pathName,
          IFSPrintError, ecBinaryNotText)
         loop
         ]
      ifnot
         [
         FtpSSendMark(markComment, ecMayBeText, lv fd>>FD.dr>>DR.pathName)
         localPL>>PL.TYPE = Binary
         ]

// FtpSRetrieve (cont'd)

test localPL>>PL.TYPE eq Text
   ifso
      [
      localPL>>PL.EOLC = CR
      if remotePL>>PL.EOLC eq CRLF then
         [
         FtpSSendMark(markFail, ecNotRetrieved, lv fd>>FD.dr>>DR.pathName,
          IFSPrintError, ecCRLFConversion)
         loop
         ]
      ]
   ifnot test remotePL>>PL.BYTE eq 0
      ifso if localPL>>PL.BYTE eq 0 then localPL>>PL.BYTE = 8
      ifnot test localPL>>PL.BYTE eq 0
         ifso localPL>>PL.BYTE = remotePL>>PL.BYTE
         ifnot if localPL>>PL.BYTE ne remotePL>>PL.BYTE then
            [
            FtpSSendMark(markFail, ecNotRetrieved, lv fd>>FD.dr>>DR.pathName,
             IFSPrintError, ecByteSize)
            loop
            ]

resultis localPL
] repeat

//---------------------------------------------------------------------------
and FtpSRetrieveFile(pList) = valof
//---------------------------------------------------------------------------
[
let ec = nil
let diskStream = OpenIFSStream(CtxRunning>>FtpCtx.fd, lv ec, modeRead)
if diskStream ne 0 then
   [
   ec = DiskToNet(CtxRunning>>FtpCtx.bspStream, diskStream)
   CloseIFSStream(diskStream)
   ]
resultis ec eq 0? true, FtpSSendMark(markNo, ec)
]