MODULE DLprefs;

IMPORT c  := Conversions,
       d  := Dos,
       DLs:= DLstrings,
       DLr:= DLrequester,
       e  := Exec,
       fs := FileSystem,
       hot:= HotKey,
       I  := Intuition,
       ol := OberonLib,
       s  := Strings,
       sys:= SYSTEM,
       u  := Utility,
       WB := WBReadArgs,
       w  := Workbench;


(*-------------------------------------------------------------------------*)

CONST
  identLength	  = 20;  (*  * drivenum * 2 *)
  passkeyLength   = 30;  (*  * drivenum    *)
  pubLength	  = 60;  (*  * 1  *)
  lockLength	  = 30;  (*  * 2  *)

  lckallHot    -= -1;
  opencloseHot -= -2;
  gotofrontHot -= -3;
  normallHot   -= -4;

  template = "SETTINGS/K,PS=PUBSCREEN/K,NOWARNINGS/S,TOOLPRI/N/K,"
	     "CX_PRIORITY/N/K,CX_POPUP/K,CX_POPKEY/K";

  LPkeep   -= 0;
  LPlock   -= 1;
  LPunlock -= -1;


(*-------------------------------------------------------------------------*)

TYPE
  LPOINTER = UNTRACED POINTER TO LONGINT;

  ARGV = STRUCT
	   settings  : e.LSTRPTR;
	   pubscr    : e.LSTRPTR;
	   noWarnings: LONGINT;
	   toolpri   : LPOINTER;
	   pri	    -: LPOINTER;
	   popup     : e.LSTRPTR;
	   popkey    : e.LSTRPTR;
	 END;  

  driveT * = RECORD
	     GadPtr	    *: I.GadgetPtr;
	     PrintName	    *: ARRAY identLength OF CHAR;
	     DeviceName     *: ARRAY identLength OF CHAR;	   
	     PassKey	    *: ARRAY passkeyLength OF CHAR;
	     disabled	    *: BOOLEAN;
	     locked	    *: BOOLEAN;
	     lockprefs	    -: SHORTINT; 
	     disabledchanged*: BOOLEAN;
	   END;
  driveP * = POINTER TO ARRAY OF driveT;

  PrefsT = RECORD
	     LeftEdge	    -: INTEGER;
	     TopEdge	    -: INTEGER;
	     SizeOnlyZoom   -: BOOLEAN;
	     LeftEdgeZoomed -: INTEGER;
	     TopEdgeZoomed  -: INTEGER;
	     OpenWindow     -: BOOLEAN;
	     OpenZoomed     -: BOOLEAN;
	     CheckTime	    -: INTEGER;

  (* do not store HotKeyDescriptions, only add them and then forget them
     (for now!)
	     KeyLock	    -: ARRAY OF CHAR;
	     KeyWindow	    -: ARRAY OF CHAR;
	     KeyFront	    -: ARRAY OF CHAR; *)
 
	     PubScreen	    -: ARRAY pubLength	OF CHAR;
	     LockString     -: ARRAY lockLength OF CHAR;
	     UnlockString   -: ARRAY lockLength OF CHAR;
	     NotifyDL	    -: BOOLEAN;   (* not implemented *)
	     UnlockBeep     -: BOOLEAN;
	     LockAllBeep    -: BOOLEAN;
	     NormAllBeep    -: BOOLEAN;
	     RemPosition    -: BOOLEAN;   (* not implemented *)
	     DriveNum	    -: INTEGER;
	   END;


(*-------------------------------------------------------------------------*)

VAR
  OSrelease3	 -: BOOLEAN;

 
  Buffer1      *: ARRAY 256 OF CHAR;
  Buffer2	: ARRAY 256 OF CHAR;

  drive        *: driveP;
  Prefs        *: PrefsT;

  Argv	       -: ARGV;
  Arguments	: d.RDArgsPtr;
  wbargs	: WB.Arguments;
  wbm		: w.WBStartupPtr;

(*-------------------------------------------------------------------------*)

CONST
  PrefsConst = PrefsT(0,0,FALSE,-10,-10,TRUE,FALSE,5,"",
		      "lock %s on %s","lock %s off %s",FALSE,TRUE,FALSE,FALSE,FALSE,0);
  prgName  = "DeviceLock";



(*------ Read Prefs in DeviceLock.prefs from "", ENV: or PROGDIR: --------*)

PROCEDURE ReadPrefs*();
VAR
    wrongCV : BOOLEAN;
    conf    : fs.File;
    opwin   : BOOLEAN;
    length  : INTEGER;

  (*---- Tries to Open settings and checks Version and returns TRUE
	 if there is a valid settings file			      -----*)

  PROCEDURE SearchPrefs(path: ARRAY OF CHAR):BOOLEAN;  (* $CopyArrays- *)
  BEGIN
    COPY(path,Buffer2);
    IF ~ (fs.Open(conf,Buffer2,FALSE) AND fs.ReadString(conf,Buffer1)) THEN RETURN(FALSE) END;
    s.Cut(Buffer1,s.Occurs(Buffer1,"VER")+5,16,Buffer2);
    IF u.Strnicmp("DeviceLock.Prefs",Buffer2,17)#0 THEN
      wrongCV := TRUE;
      IF conf.handle # NIL THEN IF fs.Close(conf) THEN END END;
      RETURN(FALSE);
    ELSE
      RETURN(TRUE)
    END;
  END SearchPrefs;

  (*---- Read Line from input, skipping lines beginning with ; ------------*)

  PROCEDURE GetNewLine():BOOLEAN;
  VAR i     : INTEGER;
      ret   : BOOLEAN;
      equpos: INTEGER;
  BEGIN
    REPEAT
      ret := fs.ReadString(conf,Buffer1);
    UNTIL ((Buffer1[0]#";") & (Buffer1[0]#" ") & (Buffer1[0]#0X)) OR (ret=FALSE);
    IF ret THEN
       length := SHORT(s.Length(Buffer1));
       i := 0;
       WHILE ((i < length) & (Buffer1[i]#";")) DO
	 INC(i);
       END; (* WHILE *)
       IF Buffer1[i]=";" THEN Buffer1[i] := 0X END;
       i := SHORT(s.Length(Buffer1))-1;
       WHILE (i > 0) & ((Buffer1[i]=" ") OR (Buffer1[i]=09X)) DO
	 DEC(i);
       END;
       Buffer1[i+1]:=0X;
       length := SHORT(s.Length(Buffer1));
       i := 0;
       WHILE ((i < length) & (Buffer1[i]#"=")) DO
	 INC(i);
       END; (* WHILE *)
       IF Buffer1[i]="=" THEN equpos := i ELSE equpos := -1 END;
       IF (equpos = -1) OR (equpos+1 = length) THEN
	 Buffer2 := "INVALID";
       ELSE
	 s.Cut(Buffer1,equpos+1,length-equpos-1,Buffer2);
	 Buffer1[equpos]:="\o";
	 length := SHORT(s.Length(Buffer2));
       END;
    END;
    RETURN ret;
  END GetNewLine;

  (*---- Convert Number, complain if not possible -------------------------*)

  PROCEDURE ConvNumber():INTEGER;
  VAR number  : LONGINT;
  BEGIN
    IF c.StringToInt(Buffer2,number) & (number <= MAX(INTEGER)) THEN
      RETURN(SHORT(number))
    ELSE
      DLr.RequestWarning(DLs.GetString(DLs.WarnCorruptNumber),sys.ADR(Buffer2));
      RETURN (0);
    END;
  END ConvNumber;

  (*---- Convert Boolean, complain if not possible ------------------------*)

  PROCEDURE ConvBool():BOOLEAN;
  BEGIN
    IF CAP(Buffer2[0]) = "N" THEN RETURN FALSE
    ELSIF CAP(Buffer2[0]) = "Y" THEN RETURN TRUE
    ELSE
      DLr.RequestWarning(DLs.GetString(DLs.WarnCorruptBoolean),sys.ADR(Buffer2));
      RETURN(FALSE);
    END;
  END ConvBool;

  (*---- Copy String and check if orginal length --------------------------*)

  PROCEDURE CopyTo(VAR str: ARRAY OF CHAR);
  BEGIN
    COPY(Buffer2,str);
    str[LEN(str)-1] := "\o"; (* Our strings end with \o ! *)
    IF (s.Length(str) # s.Length(Buffer2)) THEN
      DLr.RequestWarning(DLs.GetString(DLs.WarnStringTooLong),sys.ADR(str));
    END;
  END CopyTo;

  (*---- Tries to add Hotkey and warns on failure -------------------------*)
  PROCEDURE AddKey (ID: INTEGER);
  BEGIN
    IF ~hot.AddKey (Buffer2,ID) THEN
      IF hot.badDescription IN hot.ErrorSet THEN
	 DLr.RequestWarning(DLs.GetString(DLs.WarnNotValidKeyCode),sys.ADR(Buffer2));
      ELSE
       DLr.RequestWarning(DLs.GetString(DLs.WarnCannotAddKeyCode),sys.ADR(Buffer2));
      END;
    END;
  END AddKey;

  (*---- Tries to determine number of drives ------------------------------*)
  PROCEDURE GetNumberOfDrives():INTEGER;
  VAR num: INTEGER;
      ret: BOOLEAN;
  BEGIN
    num := 0;
    REPEAT
      ret := fs.ReadString(conf,Buffer1);
      IF ret & (Buffer1[0]#";") & (Buffer1[0]#" ") & (Buffer1[0]#0X) THEN
	IF u.Strnicmp("DeviceName=",Buffer1,11)=0 THEN INC(num) END;
      END;
    UNTIL ret=FALSE;
    IF fs.Move(conf,0) THEN END;
    RETURN(num);
  END GetNumberOfDrives;


BEGIN
wrongCV := FALSE;
opwin := FALSE;
IF Argv.settings # NIL THEN
  IF ~ SearchPrefs(Argv.settings^) THEN
    IF wrongCV THEN
      DLr.BailOut(DLs.GetString(DLs.ErrGivenSettingsNotValid)^);
    ELSE
      DLr.BailOut(DLs.GetString(DLs.ErrCantOpenOrReadGivenSettings)^);
    END;
  END;
ELSE
  IF ~ SearchPrefs("DeviceLock.Prefs") THEN
    IF ~ SearchPrefs("ENV:DeviceLock.Prefs") THEN
      IF ~ SearchPrefs("PROGDIR:DeviceLock.Prefs") THEN
	IF wrongCV THEN
	  DLr.BailOut(DLs.GetString(DLs.ErrWrongPrefs)^);
	ELSE
	  DLr.BailOut(DLs.GetString(DLs.ErrCantFindAnyPrefs)^);
	END;
      END;
    END;
  END;
END;

Prefs.DriveNum := GetNumberOfDrives();
IF Prefs.DriveNum >= MAX(INTEGER) THEN Prefs.DriveNum := MAX(INTEGER)-1 END;
IF Prefs.DriveNum = 0 THEN DLr.BailOut(DLs.GetString(DLs.ErrZeroDrives)^) END;
NEW(drive,Prefs.DriveNum);

Prefs.DriveNum := -1;
WHILE GetNewLine() DO
  IF	u.Stricmp(Buffer2,"INVALID")       = 0 THEN 
    DLr.RequestWarning(DLs.GetString(DLs.WarnCommentIsNoComment),sys.ADR(Buffer1));
  ELSIF u.Stricmp(Buffer1,"LeftEdge")      = 0 THEN Prefs.LeftEdge       := ConvNumber()
  ELSIF u.Stricmp(Buffer1,"TopEdge")       = 0 THEN Prefs.TopEdge        := ConvNumber()
  ELSIF u.Stricmp(Buffer1,"LeftEdgeZoomed")= 0 THEN Prefs.LeftEdgeZoomed := ConvNumber()
  ELSIF u.Stricmp(Buffer1,"TopEdgeZoomed") = 0 THEN Prefs.TopEdgeZoomed  := ConvNumber()
  ELSIF u.Stricmp(Buffer1,"CheckTime")     = 0 THEN Prefs.CheckTime      := ConvNumber()
  ELSIF u.Stricmp(Buffer1,"OpenWindow")    = 0 THEN Prefs.OpenWindow     := ConvBool()
  ELSIF u.Stricmp(Buffer1,"OpenZoomed")    = 0 THEN Prefs.OpenZoomed     := ConvBool()
  ELSIF u.Stricmp(Buffer1,"SizeOnlyZoom")  = 0 THEN Prefs.SizeOnlyZoom   := ConvBool()
  ELSIF u.Stricmp(Buffer1,"UnlockBeep")    = 0 THEN Prefs.UnlockBeep     := ConvBool()
  ELSIF u.Stricmp(Buffer1,"LockAllBeep")   = 0 THEN Prefs.LockAllBeep    := ConvBool()
  ELSIF u.Stricmp(Buffer1,"NormAllBeep")   = 0 THEN Prefs.NormAllBeep    := ConvBool()
  ELSIF u.Stricmp(Buffer1,"RemPosition")   = 0 THEN Prefs.RemPosition    := ConvBool()
  ELSIF u.Stricmp(Buffer1,"NotifyDL")      = 0 THEN Prefs.NotifyDL       := ConvBool()
  ELSIF u.Stricmp(Buffer1,"KeyLock")       = 0 THEN AddKey(lckallHot)
  ELSIF u.Stricmp(Buffer1,"KeyNorm")       = 0 THEN AddKey(normallHot)
  ELSIF u.Stricmp(Buffer1,"KeyWindow")     = 0 THEN
    IF Argv.popkey # NIL THEN COPY(Argv.popkey^,Buffer2) END;
    AddKey(opencloseHot);
  ELSIF u.Stricmp(Buffer1,"KeyFront")      = 0 THEN AddKey(gotofrontHot)
  ELSIF u.Stricmp(Buffer1,"PubScreen")     = 0 THEN CopyTo(Prefs.PubScreen)
  ELSIF u.Stricmp(Buffer1,"LockString")    = 0 THEN CopyTo(Prefs.LockString)
  ELSIF u.Stricmp(Buffer1,"UnlockString")  = 0 THEN CopyTo(Prefs.UnlockString)
  ELSIF u.Stricmp(Buffer1,"DeviceName")    = 0 THEN
    INC(Prefs.DriveNum);
    CopyTo(drive[Prefs.DriveNum].DeviceName);
    COPY(drive[Prefs.DriveNum].DeviceName, drive[Prefs.DriveNum].PrintName);
    drive[Prefs.DriveNum].lockprefs := LPlock;
  ELSIF u.Stricmp(Buffer1,"PrintName")     = 0 THEN
    IF (Prefs.DriveNum >= 0) THEN CopyTo(drive[Prefs.DriveNum].PrintName) END
  ELSIF u.Stricmp(Buffer1,"PassKey")       = 0 THEN
    IF (Prefs.DriveNum >= 0) THEN CopyTo(drive[Prefs.DriveNum].PassKey) END
  ELSIF u.Stricmp(Buffer1,"Lock")          = 0 THEN
    IF (Prefs.DriveNum >= 0) THEN
      IF Buffer2[0] = "*" THEN drive[Prefs.DriveNum].lockprefs := LPkeep
      ELSIF Buffer2[0] = "-" THEN drive[Prefs.DriveNum].lockprefs := LPunlock
      ELSIF Buffer2[0] = "+" THEN drive[Prefs.DriveNum].lockprefs := LPlock
      ELSIF CAP(Buffer2[0]) = "N" THEN drive[Prefs.DriveNum].lockprefs := LPkeep
      ELSIF CAP(Buffer2[0]) = "Y" THEN drive[Prefs.DriveNum].lockprefs := LPlock
      ELSE
	DLr.RequestWarning(DLs.GetString(DLs.WarnCorruptLockValue),sys.ADR(Buffer2));
	drive[Prefs.DriveNum].lockprefs := LPlock;
      END;
    END;
  ELSIF u.Stricmp(Buffer1,"HotKey")        = 0 THEN
    IF (Prefs.DriveNum >= 0) THEN AddKey(Prefs.DriveNum+1) END
  ELSE DLr.RequestWarning(DLs.GetString(DLs.WarnUnknownOption),sys.ADR(Buffer1)) 
  END; (* IF *)
END; (* WHILE *)

INC(Prefs.DriveNum);
IF (Prefs.SizeOnlyZoom & OSrelease3) THEN
  Prefs.LeftEdgeZoomed := -1;
  Prefs.TopEdgeZoomed := -1;
ELSE
  IF (Prefs.LeftEdgeZoomed = -10) THEN Prefs.LeftEdgeZoomed := Prefs.LeftEdge END;
  IF (Prefs.TopEdgeZoomed  = -10) THEN Prefs.TopEdgeZoomed  := Prefs.TopEdge END;
END;

IF Argv.popup  # NIL THEN
  COPY(Argv.popup^,Buffer2);
  Prefs.OpenWindow := ConvBool();
END; (* IF *)
IF Argv.pubscr # NIL THEN
  COPY(Argv.pubscr^,Buffer2);
  CopyTo(Prefs.PubScreen);
END; (* IF *)

IF conf.handle#NIL THEN IF fs.Close(conf) THEN END END;

END ReadPrefs;

(*------ Read CLI or Workbench arguments ---------------------------------*)

PROCEDURE ReadArgs*();
BEGIN
  NEW(Argv.pri); NEW(Argv.toolpri);
  Argv.pri^ := 0; Argv.toolpri^ := 1;
  
  IF ol.wbStarted THEN
    wbm := ol.wbenchMsg;
    IF ~ WB.ReadArgs(wbm.argList[0],template,Argv,wbargs) THEN
      DLr.BailOut(DLs.GetString(DLs.ErrWBReadArgs)^);
    END;
  ELSE
  Arguments := d.OldReadArgs(template,Argv,NIL);
  IF Arguments = NIL THEN
    IF d.PrintFault(d.IoErr(),prgName) THEN END;
    HALT(20);
  END;
  END;

  IF Argv.noWarnings = d.DOSTRUE THEN DLr.noWarnings := TRUE END;
  sys.SETREG(0,e.SetTaskPri(DLr.NoDosRequester(),Argv.toolpri^));
END ReadArgs;

(*------ Free CLI or Workbench arguments ---------------------------------*)

PROCEDURE FreeArgs*();
BEGIN
  (* Save to call with NIL ! *)
  d.FreeArgs(Arguments); Arguments := NIL;
  WB.FreeArgs(wbargs);
END FreeArgs;

(***************************************************************************
	 M A I N
 ***************************************************************************)

BEGIN
  OSrelease3 := I.int.libNode.version > 38;
  Prefs := PrefsConst;
  IF OSrelease3 THEN Prefs.SizeOnlyZoom := TRUE END;

CLOSE
    (* Save to call with NIL ! *)
    d.FreeArgs(Arguments);
    WB.FreeArgs(wbargs);

END DLprefs.
