// IfsTelnetGroup.bcpl -- Commands dealing with group membership
// Copyright Xerox Corporation 1979, 1981

// Last modified November 18, 1981  12:02 PM by Taft

get "IfsFiles.decl"
get "IfsDirs.decl"
get "Streams.d"
get "IfsRS.decl"
get "CmdScan.decl"

external
[
// outgoing procedures
ExecChangeGroup; ExecShowGroup

// incoming procedures
CreateKeywordTable; InsertKeyword; DestroyKeywordTable
GetString; GetGroup; AbortCmd; PrintSubFilename
TelnetCommandLoop; TelnetSubcommandPrompt; TelnetAborting; Plural
LookupIFSFile; NextFD; DestroyFD
OpenIFSStream; KsBufferAddress; CloseIFSStream
GetDIF; UpdateCachedDIF; WheelCall
SysFree; FreePointer; GetBit; SetBit
Gets; Errors; Wss; Ws; PutTemplate; IFSPrintError

// incoming statics
CtxRunning; dsp; enableGrapevineGroup
]

//----------------------------------------------------------------------------
let ExecChangeGroup(cs) be
//----------------------------------------------------------------------------
// Change Group-membership <group> <subcommands>
// Subcommands are:
// Add <user>
// Remove <user>
[
Wss(cs, " (of group) ")
let group = GetGroup(cs)
if CtxRunning>>RSCtx.userInfo>>UserInfo.capabilities.wheel eq 0 then
   [
   let dif = GetDIF(0, true)  // read my DIF from file system
   if dif eq 0 then Errors(cs, 0)
   let own = GetBit(lv dif>>DIF.ownedGroups, group)
   SysFree(dif)
   unless own do
      AbortCmd(cs, "*nYou do not have access to manipulate that group.")
   ]

if enableGrapevineGroup then
   [
   Ws("*n[Caution: Grapevine group-membership checking is enabled.")
   Ws("*n Changes involving Grapevine R-Names will not be permanent.]")
   ]

let kt = CreateKeywordTable(2)
InsertKeyword(kt, "Add")!0 = true
InsertKeyword(kt, "Remove")!0 = false
TelnetCommandLoop(kt, TelnetSubcommandPrompt(), true, group, 0, 0, SetGroup)
DestroyKeywordTable(kt)
]

//----------------------------------------------------------------------------
and SetGroup(cs, entry, group) be
//----------------------------------------------------------------------------
// Add|Remove <user>
[
Wss(cs, " (user) ")
let name = GetString(cs, 0, Wss, "directory name")

let dif = GetDIF(name, true)  // accept only real DIFs
if dif eq 0 then [ SysFree(name); Errors(cs, 0) ]

SetBit(lv dif>>DIF.userGroups, group, entry!0)

UpdateCachedDIF(name, dif)
FreePointer(lv name, lv dif) 
]

//----------------------------------------------------------------------------
and ExecShowGroup(cs) be
//----------------------------------------------------------------------------
// Show Group-membership <group>
[
Wss(cs, " (of group) ")
let group = GetGroup(cs)

if enableGrapevineGroup then
   [
   Ws("*n[Caution: Grapevine group-membership checking is enabled.")
   Ws("*n Information about Grapevine R-Names may not be up-to-date.]")
   ]

let numUsers = 0

let fd = LookupIFSFile("<**>!1", lcVExplicit+lcMultiple)
if fd ne 0 then
   [
      [ // repeat
      if TelnetAborting() break
      if fd>>FD.dr>>DR.type ne drTypeDIF then loop
      let stream = WheelCall(OpenIFSStream, fd, 0, modeRead, wordItem)
      if stream ne 0 then
         [  // DIF is in the stream buffer now
         if GetBit(lv KsBufferAddress(stream)>>DIF.userGroups, group) then
            [
            Ws((numUsers rem 5 eq 0? "*n", ", "))
            PrintSubFilename(dsp, fd, 2, fd>>FD.lenDirString-1)
            numUsers = numUsers+1
            ]
         CloseIFSStream(stream)
         ]
      ] repeatwhile NextFD(fd)

   DestroyFD(fd)
   ]

PutTemplate(dsp, "*n$D user$S in group $D.",
 numUsers, Plural(numUsers), group)
]