// IfsMiscSwap.bcpl - Miscellaneous & Echo - SWAPPABLE
// Copyright Xerox Corporation 1979, 1980, 1981, 1982
// Last modified July 12, 1982  2:05 PM by Taft

get "Pup0.decl"
get "Pup1.decl"
get "IfsRs.decl"
get "IfsMisc.decl"

external
[
// outgoing procedures
MiscellaneousCtx; HandleMiscellaneousPup
HandleEchoPup

// incoming procedures
TimeServ; NameServ; BootServ; MailMiscServ

CreateJob; DestroyJob; Dequeue; Enqueue
CompletePup; ExchangePorts; ReleasePBI
TimerHasExpired; Block; SetTimer
MoveBlock; DoubleIncrement

// incoming statics
entFlag; system; CtxRunning
socMiscellaneous; ctxMiscellaneousCtx
socEcho; echoStats
]

//---------------------------------------------------------------------------
let HandleMiscellaneousPup(pbi) be
//---------------------------------------------------------------------------
//Called from MiscellaneousEvent when the MiscellaneousCtx doesn't exist, to
// deal with pups directed to the Miscellaneous socket.  Simple requests are
// handled by this procedure.  More complex requests (particularly those
// requiring access to files) are left for the MiscellaneousCtx if it can be
// created.  If it can't be created the requests are discarded.
// Note that the pbi we are passed has NOT been dequeued.
[
if entFlag switchon pbi>>PBI.pup.type into
   [
   case typeUserAuthenticate:
   case typeLaurelMailCheck:
   case typeMsgMailCheck:
   case typeValidateRecipient:
   case ptBootDirReply:
      [  // These requests require us to be running as MiscellaneousCtx
      ctxMiscellaneousCtx = CreateJob(MiscellaneousCtx, jobTypeMiscellaneous)
      if ctxMiscellaneousCtx ne 0 return  // MiscellaneousCtx will handle it
      endcase
      ]
   default:
      [  // All other requests can be answered from within the event
      MiscellaneousPup(Dequeue(lv socMiscellaneous>>PupSoc.iQ))
      return
      ]
   ]

// Discard pbi if not entFlag % it's complex & can't create CtxMiscellaneous
ReleasePBI(Dequeue(lv socMiscellaneous>>PupSoc.iQ))
]

//---------------------------------------------------------------------------
and MiscellaneousCtx(ctx) be
//---------------------------------------------------------------------------
[
let timer = nil  //(bum: no need to initialize timer since we're checking iQ)

   [  // repeat
   ctx>>RSCtx.userInfo = system
   if socMiscellaneous>>PupSoc.iQ.head ne 0 then
      [
      SetTimer(lv timer, 200)  //dally 2 seconds to handle retransmissions
      MiscellaneousPup(Dequeue(lv socMiscellaneous>>PupSoc.iQ))
      ]
   Block()
   ] repeatuntil TimerHasExpired(lv timer)

ctxMiscellaneousCtx = 0
DestroyJob()  // commit suicide
]

//---------------------------------------------------------------------------
and MiscellaneousPup(pbi) be
//---------------------------------------------------------------------------
// Called either from HandleMiscellaneousPup or from MiscellaneousCtx.
// If the request is complex, this must be called from MiscellaneousCtx.
// Note that the pbi HAS been dequeued.
[
switchon pbi>>PBI.pup.type into
   [
   case typeWhereUserRequest:
      // Always answer by saying user not logged in
      ExchangePorts(pbi)
      CompletePup(pbi, typeWhereUserReply, pupOvBytes)
      endcase
   case typeUserAuthenticate:
   case typeLaurelMailCheck:
   case typeMsgMailCheck:
   case typeValidateRecipient:
      MailMiscServ(pbi); endcase
   case ptLockTimeRequest:
   case ptResetTimeRequest:
   case ptAltoTimeRequest:
   case ptTimeStatsRequest:
      TimeServ(pbi); endcase
   case ptNetDirLockRequest:
   case ptNetDirUnlockRequest:
   case ptNameLookup:
   case ptAddressLookup:
   case ptSendNetDir:
   case ptNetDirVersion:
   case ptNetDirStatsRequest:
      NameServ(pbi); endcase
   case ptBootLockRequest:
   case ptBootUnlockRequest:
   case ptBootFileRequest:
   case ptBootMicrocodeRequest:
   case ptBootNamedFileRequest:
   case ptBootDirRequest:
   case ptBootDirReply:
   case ptBootStatsRequest:
      BootServ(pbi); endcase
   default:
      ReleasePBI(pbi)
   ]
]

//---------------------------------------------------------------------------
and HandleEchoPup() be
//---------------------------------------------------------------------------
// Called from MiscellaneousEvent
[
let pbi = Dequeue(lv socEcho>>PupSoc.iQ); if pbi eq 0 return
ExchangePorts(pbi)
switchon pbi>>PBI.pup.type into
   [
   case typeEchoMe:
      [
      DoubleIncrement(lv echoStats>>EchoStats.packetsEchoed)
      CompletePup(pbi, typeImAnEcho)
      endcase
      ]
   case typeStatsRequest:
      [
      MoveBlock(lv pbi>>PBI.pup.words, echoStats, lenEchoStats)
      CompletePup(pbi, typeStatsReply, pupOvBytes+lenEchoStats*2)
      endcase
      ]
   default: ReleasePBI(pbi)
   ]
] repeat