// IfsLeafRare.bcpl - Leaf Rare - SWAPPABLE
// Copyright Xerox Corporation 1979, 1980, 1981

// Last modified November 25, 1981  6:33 PM by Taft

get ecBuddingLeaf, ecBrokenLeaf, ecIllegalLeafTruncate from
 "IfsLeafErrors.decl";
get "IfsLeaf.decl";
get "IfsSequin.decl";

external
[
//outgoing procedures
BuddingLeaf; DeleteLeaf; DoNothingLeaf; LeafError;
ParamsLeaf; ResetLeaf; TruncateLeaf;

//incoming procedures
AnswerSetOp; CallersFrame; CheckHandle; SetModeLength;
CloseFH; DeleteFileFromFD; DoubleDifference; Free; Umin;
FreeLeafVMem; FreePointer; LeafLogin; MoveBlock;
NextLockedSequin; ReturnFrom; SequinDestroy; SequinReset; StringCompare; Zero;

//incoming statics
CtxRunning; leafOpLim; lenPup; system;
]

manifest portOffset = offset Sequin.port/16;


//----------------------------------------------------------------------------
let BuddingLeaf(sequin, answerPBI, op) =
   LeafError(answerPBI, op, ecBuddingLeaf)
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
and DoNothingLeaf(requestSequin, answerPBI, op) = valof
//----------------------------------------------------------------------------
[
AnswerSetOp(answerPBI, op, 2*lenLeafAnswer);
resultis leafOpComplete;
]

//----------------------------------------------------------------------------
and ResetLeaf(requestSequin, answerPBI, op) = valof
//----------------------------------------------------------------------------
[
// All opCodes to 'broken leaf' sequins get passed here....filter them.
let leafstring = lv op>>ResetRequest.strings; let ui = vec lenUserInfo;
let ec = (op>>Op.code ne opReset? ecBrokenLeaf, LeafLogin(lv leafstring, ui));
CtxRunning>>RSCtx.userInfo = system;
if ec ne 0 then resultis LeafError(answerPBI, op, ec);

// Note that no resetOps work unless login is successful.
let unam = ui>>UserInfo.userName;
FreePointer(lv requestSequin>>Sequin.unam, lv ui>>UserInfo.connName);
requestSequin>>Sequin.unam = unam;

let allHosts = false;
switchon op>>ResetRequest.resetOp into
   [
   case resetAllHosts:
      allHosts = true;
   default:
      [
      let sequin = 0;
         [ // Loop through sequin queue.
         sequin = NextLockedSequin(sequin); if sequin eq 0 then break;
         let samePort = requestSequin!portOffset eq sequin!portOffset;
         unless samePort % allHosts do loop;
         unless StringCompare(unam, sequin>>Sequin.unam) eq 0 do
            [ if samePort then SequinReset(sequin); loop; ]
         // Close all files on this sequin.
         // The only reason that this is done here is that "reset"
         // might be used to close handles on an open connection.
            [
            let fh = sequin>>Sequin.fhQ.head; if fh eq 0 break;
            CloseFH(sequin, fh);
            ] repeat
         if sequin ne requestSequin then SequinDestroy(sequin);
         ] repeat
      ]
   // fall through
   case resetBrokenLeaf:
      requestSequin>>Sequin.brokenLeaf = false; endcase;
   ]
AnswerSetOp(answerPBI, op, 2*lenLeafAnswer);
resultis leafOpComplete;
]

//----------------------------------------------------------------------------
and ParamsLeaf(sequin, answerPBI, op) = valof
//----------------------------------------------------------------------------
[
switchon op>>Op.length/2 into
   [
   case 4:
      if op>>ParamsRequest.connTimeout ne 0 then
         sequin>>Sequin.connTimeout = op>>ParamsRequest.connTimeout;
   case 3:
      if op>>ParamsRequest.lockTimeout ne 0 then
         sequin>>Sequin.lockTimeout =
            Umin(op>>ParamsRequest.lockTimeout, defaultLockTimeout);
   case 2:
      [
      if op>>ParamsRequest.pupDataBytes ne 0 then
         sequin>>Sequin.pupDataBytes =
            Umin(op>>ParamsRequest.pupDataBytes, 2*lenPup-pupOvBytes);
      ]
   default: endcase;
   ]
AnswerSetOp(answerPBI, op, 2*lenLeafAnswer);
resultis leafOpComplete;
]

//----------------------------------------------------------------------------
and DeleteLeaf(sequin, answerPBI, op) = valof
//----------------------------------------------------------------------------
[
let fh = CheckHandle(sequin, answerPBI, op);
let ec = DoTruncate(fh, 0);
if ec eq 0 then
   [
   let fd = fh>>FH.fd;
   FreeLeafVMem(fd, fh>>FH.lvmd); fh>>FH.lvmd = 0;
   CtxRunning>>RSCtx.userInfo = lv fh>>FH.ui; ec = DeleteFileFromFD(fd);
   CtxRunning>>RSCtx.userInfo = system; CloseFH(sequin, fh);
   ]
if ec ne 0 resultis LeafError(answerPBI, op, ec);
AnswerSetOp(answerPBI, op, 2*lenLeafAnswer);
resultis leafOpComplete;
]

//----------------------------------------------------------------------------
and TruncateLeaf(sequin, answerPBI, op) = valof
//----------------------------------------------------------------------------
[
let fh = CheckHandle(sequin, answerPBI, op);
let ec = DoTruncate(fh, lv op>>FileRequest.address);
if ec ne 0 then resultis LeafError(answerPBI, op, ec);
AnswerSetOp(answerPBI, op, 2*lenLeafAnswer);
resultis leafOpComplete;
]

//----------------------------------------------------------------------------
and DoTruncate(fh, address) = valof
//----------------------------------------------------------------------------
[
let op = vec writeRequestOv/2; Zero(op, writeRequestOv/2);
if address ne 0 then
 MoveBlock(lv op>>FileRequest.address, address, size LeafAddress/16);
op>>FileRequest.address.newEOF = true;
op>>FileRequest.address.mode = checkExtend;
resultis (SetModeLength(op, fh, true)? 0,ecIllegalLeafTruncate);
]

//----------------------------------------------------------------------------
and LeafError(answerPBI, op, ec) = valof
//----------------------------------------------------------------------------
[
let answer = AnswerSetOp(answerPBI, op, 2*lenErrorAnswer);
answer>>ErrorAnswer.op.code = opError;
answer>>ErrorAnswer.error = ec;
answer>>ErrorAnswer.errorOp = @op;
answer>>ErrorAnswer.handle = @(op+1);
resultis leafOpError;
]