-- Yodel: Signal Handler

-- YodelSignals.mesa
-- Last Edited by: Hagmann, April 4, 1984 4:26:49 pm PST


DIRECTORY
AlpineEnvironment
   USING[ NeededAccess, OperationFailure, Principal,
    UnknownType],
AlpineInterimDirectory
     USING[ DirectoryInconsistent,
      Error, ErrorType],
AlpInstance  USING[ AccessFailed, Create, Handle, LockFailed, Failed,
      OperationFailed, PossiblyDamaged, StaticallyInvalid, Unknown],
AlpTransaction USING[ Create, Finish, Handle, OperationFailed, Outcome],
AMTypes  USING[ IndexToName, Type],
FS    USING[ Error],
IO,
PrincOpsUtils USING[ IsBound ],
Rope,
RPC    USING[ CallFailed, CallFailure, EncryptionKey, MakeKey],
UserCredentials USING[ Get ],
YodelData;

YodelSignals: CEDAR PROGRAM
IMPORTS AlpineInterimDirectory, AlpInstance, AlpTransaction, AMTypes, FS, IO, PrincOpsUtils, Rope, RPC, UserCredentials

EXPORTS YodelData

=

BEGIN OPEN YodelData;





ROPE: TYPE = Rope.ROPE;

   -- This procedure checks to be sure Alpine is bound, and then calls the PerformProc.
   -- Most signals from Alpine are caught, and appropiate lists of ropes are returned.
PerformOp: PUBLIC PROC[ performProc: PerformProc, server: ROPE,
user: ROPENIL, password: ROPENIL]
RETURNS [LIST OF REF ANY] = {
failureName: ROPE ← "" ;
userName, userPassword, keyRope: ROPE;
caller: AlpineEnvironment.Principal ;
key: RPC.EncryptionKey;
inst: AlpInstance.Handle ← NIL;
trans: AlpTransaction.Handle ← NIL ;
outcome: AlpTransaction.Outcome ← unknown;
result: LIST OF REF ANYNIL ;
{

ENABLE BEGIN
RPC.CallFailed => {
type: AMTypes.Type ← CODE[RPC.CallFailure];
failure: RPC.CallFailure;
count: CARDINAL ← 1 ;
failureName ← "*unknown*";
FOR failure IN RPC.CallFailure DO
IF why = failure THEN {
failureName ← AMTypes.IndexToName[type: type, index: count];
};
count ← count + 1 ;
ENDLOOP;
GOTO RPCFailed;
};
AlpInstance.StaticallyInvalid => GOTO statInvalid ;
AlpInstance.Unknown =>{
type: AMTypes.Type ← CODE[AlpineEnvironment.UnknownType];
failure: AlpineEnvironment.UnknownType;
count: CARDINAL ← 1 ;
failureName ← "*unknown*";
IF what = AlpineEnvironment.UnknownType.owner THEN GOTO badOwner;
FOR failure IN AlpineEnvironment.UnknownType DO
IF what = failure THEN {
failureName ← AMTypes.IndexToName[type: type, index: count];
};
count ← count + 1 ;
ENDLOOP;
GOTO alpUnknown;
};
AlpInstance.AccessFailed =>{
type: AMTypes.Type ← CODE[AlpineEnvironment.NeededAccess];
failure: AlpineEnvironment.NeededAccess;
count: CARDINAL ← 1 ;
failureName ← "*unknown*";
FOR failure IN AlpineEnvironment.NeededAccess DO
IF missingAccess = failure THEN {
failureName ← AMTypes.IndexToName[type: type, index: count];
};
count ← count + 1 ;
ENDLOOP;
GOTO accFail;
};
AlpInstance.OperationFailed => {
type: AMTypes.Type ← CODE[AlpineEnvironment.OperationFailure];
failure: AlpineEnvironment.OperationFailure;
count: CARDINAL ← 1 ;
failureName ← "*unknown*";
FOR failure IN AlpineEnvironment.OperationFailure DO
IF why = failure THEN {
failureName ← AMTypes.IndexToName[type: type, index: count];
};
count ← count + 1 ;
ENDLOOP;
GOTO opFail;
};
AlpineInterimDirectory.DirectoryInconsistent => GOTO dirInconsistent;
AlpineInterimDirectory.Error => {
type: AMTypes.Type ← CODE[AlpineInterimDirectory.ErrorType];
failure: AlpineInterimDirectory.ErrorType;
count: CARDINAL ← 1 ;
failureName ← "*unknown*";
FOR failure IN AlpineInterimDirectory.ErrorType DO
IF why = failure THEN {
failureName ← AMTypes.IndexToName[type: type, index: count];
};
count ← count + 1 ;
ENDLOOP;
GOTO dirError;
};
AlpInstance.LockFailed => GOTO lockFail;
AlpInstance.PossiblyDamaged => GOTO possDamaged;
AlpTransaction.OperationFailed => GOTO alpineBusy;
AlpInstance.Failed => {
SELECT why FROM
alpineDownOrCommunications => {
 failureName ← " alpine or communications are down";
GOTO alpineError ;
 };
alpineDown => {
 failureName ← " alpine server is down";
GOTO alpineError ;
 };
authenticateFailed => {
 failureName ← " of authentication error- suspect bad user name or password";
GOTO alpineError ;
 };
badCallee => {
 failureName ← " of bad server name";
GOTO alpineError ;
 };
grapevineDownOrCommunications => {
 failureName ← " communications or server are down";
GOTO alpineError ;
 };
mismatch => {
 failureName ← " mismatch (for example, version incompatibility)";
GOTO alpineError ;
 };
ENDCASE ;
};
FS.Error => {
failureName ← error.explanation ;
GOTO FSError ;
};

IO.Error => {
SELECT ec FROM
SyntaxError => {
 failureName ← "Syntax Error";
GOTO syntaxError ;} ;
ENDCASE ;

};


END;



TRUSTED BEGIN
IF NOT PrincOpsUtils.IsBound[link: LOOPHOLE[AlpInstance.Create]] THEN GOTO notBound ;
END;

[userName, userPassword] ← UserCredentials.Get[];
IF (Rope.Equal[user,""] OR Rope.Equal[user,NIL]) THEN caller ← userName
ELSE caller ← user ;
IF (Rope.Equal[password,""] OR Rope.Equal[password,NIL]) THEN keyRope ← userPassword
ELSE keyRope ← password ;
TRUSTED BEGIN key ← RPC.MakeKey[keyRope]; END;

IF Rope.Match[pattern: "*.alpine", object: server, case: FALSE] THEN {
 inst ← AlpInstance.Create[fileStore: server, caller: caller, key: key];
 trans ← AlpTransaction.Create[inst];
 };

result ← performProc[trans: trans, caller: caller, key: key];

IF trans # NIL THEN {
 outcome ← AlpTransaction.Finish[trans, commit];
 };

RETURN[result];

EXITS
RPCFailed => {
IF trans # NIL THEN outcome ← AlpTransaction.Finish[trans, abort
  ! RPC.CallFailed => CONTINUE;];
RETURN[CONS[IO.PutFR["RPC failure: %g", IO.rope[failureName]],NIL]];
 };
alpineBusy => {
IF trans # NIL THEN outcome ← AlpTransaction.Finish[trans, abort];
RETURN[CONS[
NARROW["Alpine server is busy - please try again later",ROPE]
 ,NIL]];
};
dirInconsistent => {
IF trans # NIL THEN outcome ← AlpTransaction.Finish[trans, abort];
RETURN[CONS[NARROW[
"Alpine Interim Directory: directory is inconsistent",ROPE],NIL]];
};
dirError => {
IF trans # NIL THEN outcome ← AlpTransaction.Finish[trans, abort];
RETURN[CONS[IO.PutFR["Alpine Interim Directory Error: %g",
IO.rope[failureName]],NIL]];
   };
accFail => {
IF trans # NIL THEN outcome ← AlpTransaction.Finish[trans, abort];
RETURN[CONS[IO.PutFR[
"Alpine denied access because client is not in the %g access control list",
IO.rope[failureName]],NIL]];
   };
lockFail => {
IF trans # NIL THEN outcome ← AlpTransaction.Finish[trans, abort];
RETURN[CONS[
NARROW[
  "Alpine server has a conflict or timed out a lock - please try again later",ROPE]
  ,NIL]];
   };
opFail => {
IF trans # NIL THEN outcome ← AlpTransaction.Finish[trans, abort];
RETURN[CONS[IO.PutFR["Alpine Instance Operation Failed: %g",
IO.rope[failureName]],NIL]];
   };
possDamaged => {
IF trans # NIL THEN outcome ← AlpTransaction.Finish[trans, abort];
RETURN[CONS[
NARROW["Alpine server reports possible damage",ROPE]
,NIL]];
   };
alpUnknown => {
IF trans # NIL THEN outcome ← AlpTransaction.Finish[trans, abort];
RETURN[CONS[IO.PutFR["Alpine Instance Unknown Type: %g",
IO.rope[failureName]],NIL]];
   };
badOwner => {
IF trans # NIL THEN outcome ← AlpTransaction.Finish[trans, abort];
RETURN[CONS[
NARROW[
"Alpine Unknown Type: owner -- suspect bad directory, owner or access list name",
ROPE]
,NIL]];
   };
statInvalid => {
IF trans # NIL THEN outcome ← AlpTransaction.Finish[trans, abort];
RETURN[CONS[
NARROW[
"Alpine Statically Invalid error - suspect unreasonable property value or Yodel bug"
,ROPE]
,NIL]];
   };
notBound => {
IF trans # NIL THEN outcome ← AlpTransaction.Finish[trans, abort
  ! RPC.CallFailed => CONTINUE;];
RETURN[CONS[NARROW[
"unbound error- suspect AlpineUserImpls has not been run",ROPE],NIL]];
   };
alpineError => {
IF trans # NIL THEN outcome ← AlpTransaction.Finish[trans, abort];
RETURN[CONS[IO.PutFR[
"Alpine error because %g",IO.rope[failureName]],NIL]];
   };
FSError => {
IF trans # NIL THEN outcome ← AlpTransaction.Finish[trans, abort];
RETURN[CONS[IO.PutFR[
"FS could not perform operation because %g",IO.rope[failureName]],NIL]];
   };
syntaxError => {
IF trans # NIL THEN outcome ← AlpTransaction.Finish[trans, abort];
RETURN[CONS[IO.PutFR["Syntax error in input: %g",
IO.rope[failureName]],NIL]];
   };
};

};




END.