// IfsTelnetList.bcpl -- IFS server telnet List command
// Copyright Xerox Corporation 1979, 1981, 1982

// Last modified May 15, 1982  11:04 AM by Taft

get "Ifs.decl"
get "IfsFiles.decl"
get "IfsDirs.decl"
get "IfsRs.decl"
get "IfsTelnet.decl"

external
[
// outgoing procedures
ExecList; ListProtection; ListOneProt

// incoming procedures
CollectListSubcommands; ListHeaders
CollectFilenames; NextFile; DestroyFGD; Subcommands
WhatChanged; PrintSubFilename; GetGroupName
TelnetAborting; LockTransferLeaderPage; GetBufferForFD; DestroyFD
UNPACKDT; MONTHNAME; ExtractSubstring; Mul; Div32x16
SysAllocateZero; SysFree; FreePointer; Zero; MoveBlock; DoubleAdd
Puts; Ws; Wss; Wns; PutTemplate; GetBit

// incoming statics
dsp
]

//---------------------------------------------------------------------------
let ExecList(cs, fs) be
//---------------------------------------------------------------------------
// List <file-designators> [, <subcommands> ]
// Note: fs = 0 when called as top-level List command (by virtue of the
// top-level TelnetCommandLoop being called with arg = 0).
// fs = an auxiliary file system when called as Backup List command.
[
Wss(cs, " (files) ")
let fgd = CollectFilenames(cs, lcVAll+lcMultiple, 0, true, fs)

let options = (Subcommands(fgd)? CollectListSubcommands(), 0)
if options ne 0 then ListHeaders(options)

let lastFD = SysAllocateZero(lenFD)
let buf = 0
let files = 0
let pages = vec 1
Zero(pages, 2)

until TelnetAborting() do
   [
   let fd = NextFile(fgd)
   if fd eq 0 break
   if options ne 0 then
      [
      buf = GetBufferForFD(fd)
      unless LockTransferLeaderPage(fd, buf) eq 0 do
         [ SysFree(buf); loop ]
      ]
   files = files+1

// ExecList (cont'd)

   switchon WhatChanged(fd, lastFD) into
      [
      case 0:  //directory changed
         Puts(dsp, $*n); PrintSubFilename(dsp, fd, 1, fd>>FD.lenSubDirString)
      case 1:  //name body changed
         [
         Ws("*n  ")
         let length = fd>>FD.dr>>DR.pathName.length
         PrintSubFilename(dsp, fd, fd>>FD.lenSubDirString+1)
         if options ne 0 then
            [
            for i = length-fd>>FD.lenSubDirString to 20 do Puts(dsp, $*s)
            if (options&listType) ne 0 then
               PutTemplate(dsp, selecton buf>>ILD.type into
                  [
                  case ftText: " Text "
                  case ftBinary: " B($2D)"
                  default: " ??   "
                  ],
                buf>>ILD.byteSize)
            if (options&listLength) ne 0 then
               [
               let fileLength = vec 1
               test buf>>ILD.hintLastPageFa.pageNumber eq 0
                  ifso Zero(fileLength, 2)
                  ifnot
                     [
                     Mul(buf>>ILD.hintLastPageFa.charPos,
                      buf>>ILD.hintLastPageFa.pageNumber-1,
                      2*fd>>FD.fs>>IFS.pageLength, fileLength)
                     if buf>>ILD.byteSize gr 0 then
                        Div32x16(fileLength, (buf>>ILD.byteSize+7) rshift 3)
                     ]
               PutTemplate(dsp, " $7ED", fileLength)
               ]
            let p = vec 1
            p!0, p!1 = 0, buf>>ILD.hintLastPageFa.pageNumber+1
            DoubleAdd(pages, p)
            if (options&listSize) ne 0 then
               PutTemplate(dsp, " $3ED", p)
            if (options&listCreation) ne 0 then
               ListDate(lv buf>>ILD.created, options)
            if (options&listWrite) ne 0 then
               ListDate(lv buf>>ILD.written, options)
            if (options&listRead) ne 0 then
               ListDate(lv buf>>ILD.read, options)
            if (options&listBackup) ne 0 then
               test buf>>ILD.noBackup
                  ifso Ws((options&listTimes) eq 0?
                      " No Backup", " No Backup      ")
                  ifnot ListDate(lv buf>>ILD.backedUp, options)
            if (options&listAuthor) ne 0 then
               PutTemplate(dsp, " $S", lv buf>>ILD.author)
            if (options&listProtection) ne 0 then
               ListProtection(lv buf>>ILD.fileProt)
            if buf>>ILD.damaged then Ws(" ****** Damaged ******")
            ]
         endcase
         ]
      case 2:  //version changed
         if options ne 0 then docase 1
         PutTemplate(dsp, ", $UD", fd>>FD.version)
         endcase
      ]
   FreePointer(lv buf)
   ]

// ExecList (cont'd)

DestroyFD(lastFD)
DestroyFGD(fgd)
test options eq 0
   ifso if files ge 10 then
      PutTemplate(dsp, "*nTotal of $D files.", files)
   ifnot if files ge 2 then
      PutTemplate(dsp, "*nTotal of $ED pages in $D files.", pages, files)
]

//---------------------------------------------------------------------------
and ListDate(date, options) be
//---------------------------------------------------------------------------
[
test date!0 eq 0 & date!1 eq 0
   ifnot
      [
      let uv = vec 6
      UNPACKDT(date, uv)
      let month = vec 1
      MoveBlock(month, MONTHNAME(uv!1), 2)
      month>>String.length = 3
      PutTemplate(dsp, " $2D-$S-$2F0D", uv!2, month, uv!0 rem 100)
      if (options&listTimes) ne 0 then
         PutTemplate(dsp, " $2F0D:$2F0D", uv!3, uv!4)
      ]
   ifso
      [
      Ws("    ---   ")
      if (options&listTimes) ne 0 then Ws("      ")
      ]
]

//---------------------------------------------------------------------------
and ListProtection(fileProt) be
//---------------------------------------------------------------------------
[
Ws(" R:")
ListOneProt(lv fileProt>>FileProt.readProt)
Ws("; W:")
ListOneProt(lv fileProt>>FileProt.writeProt)
Ws("; A:")
ListOneProt(lv fileProt>>FileProt.appendProt)
]

//---------------------------------------------------------------------------
and ListOneProt(prot) be
//---------------------------------------------------------------------------
[
for i = 0 to lenProtection-1 do if prot!i ne 0 then
   [
   for group = 0 to size Protection-1 do
      if GetBit(prot, group) then
         [
         Puts(dsp, $*s)
         let name = GetGroupName(group)
         test name eq 0
            ifso Wns(dsp, group)
            ifnot [ Ws(name); SysFree(name) ]
         ]
   return
   ]
Ws(" None")
]