-- Grapevine:  program to check database for export controls

-- DBExport.mesa

-- Andrew Birrell  11-Feb-82  9:41:35

DIRECTORY
Ascii		USING[ CR ],
BodyDefs	USING[ maxRNameLength, RName ],
IODefs		USING[ WriteChar, WriteString ],
LaurelExecDefs	USING[ MakeMenuCommandCallable ],
NameInfoDefs	USING[ Close, Enumerate, Expand, ExpandInfo, GetMembers,
		       MemberInfo ],
Runtime		USING[ IsBound ],
Storage		USING[ Free, Node, String ],
String		USING[ AppendChar, AppendString ];

DBExport: PROGRAM
IMPORTS IODefs, LaurelExecDefs, NameInfoDefs, Runtime, Storage, String =

BEGIN

OPEN IODefs, BodyDefs, NameInfoDefs;

LowerCase: PROC[c: CHARACTER] RETURNS[ CHARACTER ] = INLINE
  { RETURN[ IF c IN ['A..'Z] THEN 'a + (c-'A) ELSE c] };

EndsWith: PROC[a, b: STRING] RETURNS[ BOOLEAN ] = INLINE
  BEGIN
  j: CARDINAL ← a.length;
  -- Assumes b is all lower case --
  IF a.length < b.length THEN RETURN[FALSE];
  FOR i: CARDINAL DECREASING IN [0..b.length)
  DO j ← j-1;
     IF LowerCase[a[j]] # LowerCase[b[i]] THEN RETURN[FALSE];
  ENDLOOP;
  RETURN[TRUE]
  END;

targets: DESCRIPTOR FOR ARRAY OF STRING ← DESCRIPTOR[NIL,0];

GetTargets: PROC =
  BEGIN
  info: NameInfoDefs.MemberInfo =
    NameInfoDefs.GetMembers["OtherRegistries↑.internet"L];
  WITH info SELECT FROM
    allDown =>
      WriteString["Can't get OtherRegistries↑.internet - all down"L];
    notFound, individual =>
      WriteString["Can't get OtherRegistries↑.internet - not a group"L];
    group =>
      BEGIN
      count: CARDINAL ← 0;
      GetCount: PROC[entry: RName] RETURNS[done: BOOLEAN] =
        { count ← count+1; done ← FALSE };
      GetReg: PROC[entry: RName] RETURNS[done: BOOLEAN] =
        BEGIN
        FOR i: CARDINAL DECREASING IN [0..entry.length)
        DO IF entry[i] = '.
           THEN BEGIN
                targets[count] ← Storage.String[entry.length-i];
                FOR j: CARDINAL IN [i..entry.length)
                DO String.AppendChar[targets[count], entry[j]] ENDLOOP;
                count ← count+1;
                WriteString[SELECT count FROM
                              1 => """"L,
                              LENGTH[targets] => " and """L,
                            ENDCASE => ", """L];
                WriteString[targets[count-1]];
                WriteChar['"];
                EXIT
                END;
        ENDLOOP;
        done ← FALSE;
        END;
      WriteString["Looking for members and forwardees in: "L];
      NameInfoDefs.Enumerate[members,GetCount];
      targets ← DESCRIPTOR[Storage.Node[count*SIZE[STRING]],count];
      count ← 0;
      NameInfoDefs.Enumerate[members,GetReg];
      NameInfoDefs.Close[members];
      END;
  ENDCASE => ERROR;
  END;

FreeTargets: PROC =
  BEGIN
  tBase: POINTER ← BASE[targets];
  FOR i: CARDINAL IN [0..LENGTH[targets])
  DO Storage.Free[@targets[i]] ENDLOOP;
  Storage.Free[@tBase];
  END;

lookType: { group, individual };

Look: PROC[entry: RName] RETURNS[done: BOOLEAN] =
   BEGIN
   first: BOOLEAN ← TRUE;
   Check: PROC[n: RName] RETURNS[done: BOOLEAN] =
      BEGIN
      FOR i: CARDINAL IN [0..LENGTH[targets])
      DO IF EndsWith[n, targets[i]]
         THEN BEGIN
              IF first
              THEN BEGIN
                   WriteChar[Ascii.CR]; WriteChar[Ascii.CR];
                   WriteString[entry];
                   WriteString[IF lookType = group
                               THEN " contains "
                               ELSE " is forwarded to "];
                   first ← FALSE;
                   END
              ELSE WriteString[", "];
              WriteString[n];
              EXIT
              END;
      ENDLOOP;
      done ← FALSE;
      END;
   memberInfo: NameInfoDefs.ExpandInfo = NameInfoDefs.Expand[entry];
   WITH memberInfo SELECT FROM
     group =>
       BEGIN ENABLE UNWIND => NameInfoDefs.Close[members];
       NameInfoDefs.Enumerate[members, Check];
       NameInfoDefs.Close[members];
       done ← FALSE
       END;
     allDown => { done ← TRUE; WriteString["all R-Servers down!"L] };
     individual => { done ← FALSE; NameInfoDefs.Close[sites] };
     notFound => done ← FALSE;
   ENDCASE => ERROR;
   END;


LookEnum: PROC[enumName: RName,
               work: PROC[RName]RETURNS[done: BOOLEAN] ] =
   -- argument is "groups.reg", "individuals.reg", or "dead.reg" --
   BEGIN
   memberInfo: NameInfoDefs.MemberInfo;
   memberInfo ← NameInfoDefs.GetMembers[enumName];
   WITH memberInfo SELECT FROM
     group => BEGIN ENABLE UNWIND => NameInfoDefs.Close[members];
       NameInfoDefs.Enumerate[members, work];
       NameInfoDefs.Close[members];
       END;
     allDown =>
       { WriteString[enumName]; WriteString[": all R-Servers down!"L] };
     notFound =>
       { WriteString[enumName]; WriteString[": not found!"L] };
   ENDCASE => ERROR;
   END;

LookAtRegistry: PROC[regGroup: RName] RETURNS[done: BOOLEAN] =
   BEGIN
   wanted: RName = [maxRNameLength];
   FOR i: CARDINAL DECREASING IN [0..regGroup.length)
   DO regGroup.length ← regGroup.length-1;
      IF regGroup[i] = '. THEN EXIT;
   ENDLOOP;
   String.AppendString[wanted, "Groups."L];
   String.AppendString[wanted, regGroup];
   -- Don't look inside target registries --
   FOR i: CARDINAL IN [0..LENGTH[targets])
   DO IF EndsWith[wanted, targets[i]] THEN RETURN[FALSE]; ENDLOOP;
   WriteChar[Ascii.CR]; WriteChar[Ascii.CR];
   WriteString["Registry "L]; WriteString[regGroup];
   lookType ← group; LookEnum[wanted, Look];
   wanted.length ← 0;
   String.AppendString[wanted, "Individuals."L];
   String.AppendString[wanted, regGroup];
   lookType ← individual; LookEnum[wanted, Look];
   done ← FALSE;
   END;

LookAtAll: PROC =
   { LookEnum["Groups.gv"L, LookAtRegistry] };


IF Runtime.IsBound[LaurelExecDefs.MakeMenuCommandCallable]
THEN BEGIN
     LaurelExecDefs.MakeMenuCommandCallable[user];
     LaurelExecDefs.MakeMenuCommandCallable[newMail];
     LaurelExecDefs.MakeMenuCommandCallable[mailFile];
     LaurelExecDefs.MakeMenuCommandCallable[display];
     LaurelExecDefs.MakeMenuCommandCallable[delete];
     LaurelExecDefs.MakeMenuCommandCallable[undelete];
     LaurelExecDefs.MakeMenuCommandCallable[moveTo];
     LaurelExecDefs.MakeMenuCommandCallable[copy];
     END;

GetTargets[];
IF LENGTH[targets] # 0 THEN LookAtAll[];
IF BASE[targets] # NIL THEN FreeTargets[];

END.