(**************************************************************************)
(*                                                                        *)
(*  Setup for Weasel mail server                                          *)
(*  Copyright (C) 2024   Peter Moylan                                     *)
(*                                                                        *)
(*  This program is free software: you can redistribute it and/or modify  *)
(*  it under the terms of the GNU General Public License as published by  *)
(*  the Free Software Foundation, either version 3 of the License, or     *)
(*  (at your option) any later version.                                   *)
(*                                                                        *)
(*  This program is distributed in the hope that it will be useful,       *)
(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *)
(*  GNU General Public License for more details.                          *)
(*                                                                        *)
(*  You should have received a copy of the GNU General Public License     *)
(*  along with this program.  If not, see <http://www.gnu.org/licenses/>. *)
(*                                                                        *)
(*  To contact author:   http://www.pmoylan.org   peter@pmoylan.org       *)
(*                                                                        *)
(**************************************************************************)

IMPLEMENTATION MODULE DKIM;

        (****************************************************************)
        (*                                                              *)
        (*                      PM Setup for Weasel                     *)
        (*                   DKIM page of the notebook                  *)
        (*                                                              *)
        (*        Started:        8 May 2023                            *)
        (*        Last edited:    11 May 2024                           *)
        (*        Status:         OK                                    *)
        (*                                                              *)
        (****************************************************************)


(*IMPORT Debug;*)

FROM SYSTEM IMPORT CARD8, BOOL32, ADDRESS, CAST, ADR;

IMPORT OS2, OS2RTL, DID, CommonSettings, SUDomains, Strings;

FROM Languages IMPORT
    (* type *)  LangHandle,
    (* proc *)  StrToBuffer;

FROM WSUINI IMPORT
    (* proc *)  SetDomain, OpenINIforDomain, CloseINIFile;

FROM RINIData IMPORT
    (* proc *)  INIPut, INIFetch, INIGetCard,
                INIGetString, INIPutString;

FROM PMInit IMPORT
    (* proc *)  OurHab;

FROM Names IMPORT
    (* type *)  DomainName;

FROM LowLevel IMPORT
    (* proc *)  Copy;

FROM Storage IMPORT
    (* proc *)  ALLOCATE, DEALLOCATE;

(************************************************************************)

(*VAR err: CARDINAL;*)

CONST Nul = CHR(0);
      DisableChecking = TRUE;

TYPE GlobalVars =   RECORD
                        OurPageHandle, notebookhandle: OS2.HWND;
                        OurPageID: CARDINAL;
                        CurrentDomain: DomainName;
                    END (*RECORD*);

    GlobalVarPtr = POINTER TO GlobalVars;

VAR
    ourlang: LangHandle;
    ChangeInProgress: BOOLEAN;

    (* These global variables create a reentrancy problem, because the  *)
    (* values when editing a domain can overwrite those in the "DKIM    *)
    (* default" instance.  The language is not a problem since it       *)
    (* can't be changed while editing a domain, and ChangeInProgress is *)
    (* a short-term flag for which there isn't a conflict.  The         *)
    (* following variables, however, must be saved and restored.        *)

    gv: GlobalVars;

(************************************************************************)
(*                SAVING AND RESTORING GLOBAL VARIABLES                 *)
(************************************************************************)

PROCEDURE SaveGlobals(): GlobalVarPtr;

    (* Saves a copy of some critical variables, returns a pointer   *)
    (* to the copy.                                                 *)

    VAR p: GlobalVarPtr;

    BEGIN
        NEW (p);
        p^ := gv;
        RETURN p;
    END SaveGlobals;

(************************************************************************)

PROCEDURE RestoreGlobals (VAR (*INOUT*) p: GlobalVarPtr);

    (* Restores the data saved by SaveGlobals.  *)

    BEGIN
        gv := p^;
        DISPOSE (p);
    END RestoreGlobals;

(************************************************************************)
(*                    OPERATIONS ON DIALOGUE LABELS                     *)
(************************************************************************)

PROCEDURE SetLanguage (lang: LangHandle);

    (* Relabels this page in the new language. *)

    VAR stringval: ARRAY [0..511] OF CHAR;

    BEGIN
        ourlang := lang;
        StrToBuffer (lang, "DKIM.tab", stringval);
        OS2.WinSendMsg (gv.notebookhandle, OS2.BKM_SETTABTEXT,
                        CAST(ADDRESS,gv.OurPageID), ADR(stringval));
        StrToBuffer (lang, "DKIM.CheckEnable", stringval);
        OS2.WinSetDlgItemText (gv.OurPageHandle, DID.DKIMCheckEnable, stringval);
        StrToBuffer (lang, "DKIM.Enable", stringval);
        OS2.WinSetDlgItemText (gv.OurPageHandle, DID.DKIMSignEnable, stringval);
        OS2.WinSetDlgItemText (gv.OurPageHandle, DID.DKIMsha1, "rsa-sha1");
        OS2.WinSetDlgItemText (gv.OurPageHandle, DID.DKIMsha256, "rsa-sha256");
        StrToBuffer (lang, "DKIM.SigningDomain", stringval);
        OS2.WinSetDlgItemText (gv.OurPageHandle, DID.SigningLabel, stringval);
        StrToBuffer (lang, "DKIM.Selector", stringval);
        OS2.WinSetDlgItemText (gv.OurPageHandle, DID.DKIMSelectorLabel, stringval);
        StrToBuffer (lang, "DKIM.DNSTXT", stringval);
        OS2.WinSetDlgItemText (gv.OurPageHandle, DID.DKIMDNSTXTlocLabel, stringval);
        (**)
        StrToBuffer (lang, "DKIM.copy", stringval);
        OS2.WinSetDlgItemText (gv.OurPageHandle, DID.DKIMcopy, stringval);
        (**)
        StrToBuffer (lang, "DKIM.PrivKeyFile", stringval);
        OS2.WinSetDlgItemText (gv.OurPageHandle, DID.DKIMPrivKeyFileLabel, stringval);
        StrToBuffer (lang, "DKIM.Headers", stringval);
        OS2.WinSetDlgItemText (gv.OurPageHandle, DID.DKIMHeadersLabel, stringval);
        StrToBuffer (lang, "DKIM.Canonic", stringval);
        OS2.WinSetDlgItemText (gv.OurPageHandle, DID.DKIMcanonic, stringval);
        StrToBuffer (lang, "DKIM.header", stringval);
        OS2.WinSetDlgItemText (gv.OurPageHandle, DID.DKIMh, stringval);
        StrToBuffer (lang, "DKIM.body", stringval);
        OS2.WinSetDlgItemText (gv.OurPageHandle, DID.DKIMb, stringval);
        StrToBuffer (lang, "DKIM.simple", stringval);
        OS2.WinSetDlgItemText (gv.OurPageHandle, DID.hsimple, stringval);
        OS2.WinSetDlgItemText (gv.OurPageHandle, DID.bsimple, stringval);
        StrToBuffer (lang, "DKIM.relaxed", stringval);
        OS2.WinSetDlgItemText (gv.OurPageHandle, DID.hrelaxed, stringval);
        OS2.WinSetDlgItemText (gv.OurPageHandle, DID.brelaxed, stringval);
    END SetLanguage;

(************************************************************************)

PROCEDURE DefaultStyle (default: BOOLEAN);

    (* Switches between two display formats.  Set default to TRUE if    *)
    (* this page is a page of default parameters rather than the        *)
    (* DKIM parameters for a specific domain.                           *)

    VAR stringval: ARRAY [0..511] OF CHAR;

    BEGIN
        IF default THEN
            StrToBuffer (ourlang, "DKIM.DefaultText", stringval);
            OS2.WinSetDlgItemText (gv.OurPageHandle, DID.DKIMDefaultText, stringval);
            stringval := "DKIM defaults";
        ELSE
            StrToBuffer (ourlang, "DKIM.tab", stringval);
        END (*IF*);
        OS2.WinSendMsg (gv.notebookhandle, OS2.BKM_SETTABTEXT,
                        CAST(ADDRESS,gv.OurPageID), ADR(stringval));
        OS2.WinShowWindow (OS2.WinWindowFromID (
                            gv.OurPageHandle, DID.DKIMDefaultText),
                             CAST(BOOL32, default));
    END DefaultStyle;

(************************************************************************)
(*                 SHOW/HIDE SOME DIALOGUE ELEMENTS                     *)
(************************************************************************)

PROCEDURE ShowHide (hwnd: OS2.HWND;  signenable: BOOLEAN);

    (* Alters some dialogue elements.  *)

    (********************************************************************)

    PROCEDURE DoIt (ID: CARDINAL);

        BEGIN
            IF signenable THEN
                OS2.WinShowWindow (OS2.WinWindowFromID (hwnd, ID), TRUE);
            ELSE
                OS2.WinShowWindow (OS2.WinWindowFromID (hwnd, ID), FALSE);
            END (*IF*);
        END DoIt;

    (********************************************************************)

    BEGIN
        DoIt (DID.DKIMsha1);
        DoIt (DID.DKIMsha256);
        DoIt (DID.SigningLabel);
        DoIt (DID.DKIMSigning);
        DoIt (DID.DKIMSelectorLabel);
        DoIt (DID.DKIMSelector);
        DoIt (DID.DKIMDNSTXTlocLabel);
        DoIt (DID.DKIMDNSTXTloc);
        (*DoIt (DID.DKIMcopy);*)
        DoIt (DID.DKIMPrivKeyFileLabel);
        DoIt (DID.DKIMPrivKeyFile);
        DoIt (DID.DKIMHeadersLabel);
        DoIt (DID.DKIMHeaders);
        DoIt (DID.DKIMcanonic);
        DoIt (DID.DKIMh);
        DoIt (DID.DKIMb);
        DoIt (DID.hsimple);
        DoIt (DID.hrelaxed);
        DoIt (DID.bsimple);
        DoIt (DID.brelaxed);
    END ShowHide;

(************************************************************************)

PROCEDURE SetTxtLoc (hwnd: OS2.HWND);

    (* Works out the subdomain where the public key will be published. *)

    VAR domain, result: ARRAY [0..511] OF CHAR;

    BEGIN
        OS2.WinQueryDlgItemText (gv.OurPageHandle, DID.DKIMSelector, 512, result);
        Strings.Append ("._domainkey.", result);
        OS2.WinQueryDlgItemText (gv.OurPageHandle, DID.DKIMSigning, 512, domain);
        Strings.Append (domain, result);
        Strings.Append ('.', result);
        OS2.WinSetDlgItemText (hwnd, DID.DKIMDNSTXTloc, result);
    END SetTxtLoc;

(************************************************************************)
(*                   LOADING AND STORING INI DATA                       *)
(************************************************************************)

PROCEDURE LoadValues (hwnd: OS2.HWND);

    (* Fills the dialogue elements on page 1 with data from the INI file, *)
    (* or loads default values if they're not in the INI file.            *)

    CONST L = 512;

    VAR Selector, Signing: DomainName;
        text: ARRAY [0..L-1] OF CHAR;
        DKIMsr: CARD8;  bool, firsttime: BOOLEAN;
        DKIMCheckEnable, DKIMSignEnable: BOOLEAN;

    BEGIN
        firsttime := FALSE;
        IF DisableChecking THEN
            OS2.WinEnableWindow (OS2.WinWindowFromID(hwnd, DID.DKIMCheckEnable), FALSE);
        END (*IF*);

        OpenINIforDomain (gv.CurrentDomain);

        (* Special case check: the DKIMSignEnable will be missing if this   *)
        (* is the first time we've accessed this page.  In that case, load  *)
        (* the values for the default domain.                               *)

        IF NOT INIFetch ("$SYS", "DKIMSignEnable", DKIMSignEnable) THEN
            firsttime := TRUE;
            CloseINIFile;
            OpenINIforDomain ("");
        END (*IF*);

        (* Enable DKIM checking. *)

        IF DisableChecking OR NOT INIFetch ("$SYS", "DKIMCheckEnable", DKIMCheckEnable) THEN
            DKIMCheckEnable := FALSE;
        END (*IF*);
        OS2.WinSendDlgItemMsg (hwnd, DID.DKIMCheckEnable, OS2.BM_SETCHECK,
                         OS2.MPFROMSHORT(ORD(DKIMCheckEnable)), NIL);

        (* Enable DKIM signing. *)

        IF NOT INIFetch ("$SYS", "DKIMSignEnable", DKIMSignEnable) THEN
            DKIMSignEnable := FALSE;
        END (*IF*);
        OS2.WinSendDlgItemMsg (hwnd, DID.DKIMSignEnable, OS2.BM_SETCHECK,
                         OS2.MPFROMSHORT(ORD(DKIMSignEnable)), NIL);

        (* Algorithm. *)

        IF NOT INIFetch ("$SYS", "DKIMsha1", bool) THEN
            bool := FALSE;
        END (*IF*);
        IF bool THEN
            OS2.WinSendDlgItemMsg (hwnd, DID.DKIMsha1, OS2.BM_SETCHECK,
                             OS2.MPFROMSHORT(1), NIL);
        ELSE
            OS2.WinSendDlgItemMsg (hwnd, DID.DKIMsha256, OS2.BM_SETCHECK,
                             OS2.MPFROMSHORT(1), NIL);
        END (*IF*);

        (* Signing domain. *)

        IF firsttime THEN Signing := gv.CurrentDomain;
        ELSIF (NOT INIGetString ("$SYS", "DKIMSigning", Signing))
                    OR (Signing[0] = Nul) THEN
            IF gv.CurrentDomain[0] = Nul THEN
                SUDomains.GetOriginalDomainName (Signing);
            ELSE
                Signing := gv.CurrentDomain;
            END (*IF*);
        END (*IF*);
        OS2.WinSetDlgItemText (hwnd, DID.DKIMSigning, Signing);

        (* Selector *)

        IF NOT INIGetString ("$SYS", "DKIMSelector", Selector) THEN
            Selector := "default";
        END (*IF*);
        OS2.WinSetDlgItemText (hwnd, DID.DKIMSelector, Selector);

        (* Initial value of DNS/txt location. *)

        OS2.WinSetDlgItemText (hwnd, DID.DKIMDNSTXTloc, "");

        (* Private key file *)

        IF NOT INIGetString ("$SYS", "DKIMPrivKeyFile", text) THEN
            text := "keys\priv.key";
        END (*IF*);
        OS2.WinSetDlgItemText (hwnd, DID.DKIMPrivKeyFile, text);

        (* Headers *)

        IF NOT INIGetString ("$SYS", "DKIMHeaders", text) THEN
            text := "From:To:Subject:Date:Message-ID";
        END (*IF*);
        OS2.WinSetDlgItemText (hwnd, DID.DKIMHeaders, text);

        (* The simple/relaxed choice. *)

        IF NOT INIFetch ("$SYS", "DKIMsr", DKIMsr) THEN
            DKIMsr := 3;
        END (*IF*);
        (*    00 = s/s     01 = s/r    10 = r/s    11 = r/r  *)
        IF ODD(DKIMsr) THEN
            OS2.WinSendDlgItemMsg (hwnd, DID.brelaxed, OS2.BM_SETCHECK,
                         OS2.MPFROMSHORT(1), NIL);
        ELSE
            OS2.WinSendDlgItemMsg (hwnd, DID.bsimple, OS2.BM_SETCHECK,
                         OS2.MPFROMSHORT(1), NIL);
        END (*IF*);
        IF ODD(DKIMsr DIV 2) THEN
            OS2.WinSendDlgItemMsg (hwnd, DID.hrelaxed, OS2.BM_SETCHECK,
                         OS2.MPFROMSHORT(1), NIL);
        ELSE
            OS2.WinSendDlgItemMsg (hwnd, DID.hsimple, OS2.BM_SETCHECK,
                         OS2.MPFROMSHORT(1), NIL);
        END (*IF*);

        CloseINIFile;
        SetDomain (gv.CurrentDomain);
        ShowHide(hwnd, DKIMSignEnable);

    END LoadValues;

(************************************************************************)

PROCEDURE StoreData;

    (* Stores the values on this page back into the INI file. *)

    CONST L = 512;

    VAR Signing, Selector, text: ARRAY [0..L-1] OF CHAR;
        DKIMsr: CARD8;  bool, DKIMCheckEnable, DKIMSignEnable: BOOLEAN;

    BEGIN
        OpenINIforDomain (gv.CurrentDomain);

        (* Enable DKIM checking. *)

        DKIMCheckEnable := OS2.LONGFROMMR (OS2.WinSendDlgItemMsg (gv.OurPageHandle,
                                    DID.DKIMCheckEnable, OS2.BM_QUERYCHECK, NIL, NIL)) <> 0;
        INIPut ('$SYS', 'DKIMCheckEnable', DKIMCheckEnable);

        (* Enable DKIM signing. *)

        DKIMSignEnable := OS2.LONGFROMMR (OS2.WinSendDlgItemMsg (gv.OurPageHandle,
                                    DID.DKIMSignEnable, OS2.BM_QUERYCHECK, NIL, NIL)) <> 0;
        INIPut ('$SYS', 'DKIMSignEnable', DKIMSignEnable);

        (* Algorithm. *)

        bool := OS2.LONGFROMMR (OS2.WinSendDlgItemMsg (gv.OurPageHandle, DID.DKIMsha1,
                                    OS2.BM_QUERYCHECK, NIL, NIL)) <> 0;
        INIPut ('$SYS', 'DKIMsha1', bool);

        (* Signing domain. *)

        OS2.WinQueryDlgItemText (gv.OurPageHandle, DID.DKIMSigning, L, Signing);
        INIPutString ("$SYS", "DKIMSigning", Signing);

        (* Selector *)

        OS2.WinQueryDlgItemText (gv.OurPageHandle, DID.DKIMSelector, L, Selector);
        INIPutString ("$SYS", "DKIMSelector", Selector);

        (* Private key file *)

        OS2.WinQueryDlgItemText (gv.OurPageHandle, DID.DKIMPrivKeyFile, L, text);
        INIPutString ("$SYS", "DKIMPrivKeyFile", text);

        (* Headers *)

        OS2.WinQueryDlgItemText (gv.OurPageHandle, DID.DKIMHeaders, L, text);
        INIPutString ("$SYS", "DKIMHeaders", text);

        (* The simple/relaxed choice. *)

        IF OS2.LONGFROMMR (OS2.WinSendDlgItemMsg (gv.OurPageHandle, DID.hrelaxed,
                                    OS2.BM_QUERYCHECK, NIL, NIL)) > 0 THEN
           DKIMsr := 2;
        ELSE
           DKIMsr := 0;
        END (*IF*);
        IF OS2.LONGFROMMR (OS2.WinSendDlgItemMsg (gv.OurPageHandle, DID.brelaxed,
                                    OS2.BM_QUERYCHECK, NIL, NIL)) > 0 THEN
           INC (DKIMsr);
        END (*IF*);

        INIPut ("$SYS", "DKIMsr", DKIMsr);

        CloseINIFile;

    END StoreData;

(************************************************************************)

PROCEDURE Close (notebook, hwnd: OS2.HWND);

    (* Shuts down this window and removes it from the notebook. *)

    BEGIN
        StoreData;
        OS2.WinSendMsg (notebook, OS2.BKM_DELETEPAGE,
                        CAST(ADDRESS, gv.OurPageID),
                        OS2.MPFROMLONG (OS2.BKA_SINGLE));
        OS2.WinSendMsg (hwnd, OS2.WM_CLOSE, NIL, NIL);
    END Close;

(**********************************************************************)

(*
PROCEDURE CopyField (hwnd: OS2.HWND);

    (* Copies the DID.DKIMDNSTXTloc value to the clipboard.  *)
    (* Not working, because of invalid parameter in DosAllocSharedMem.  *)
    (* I think the problem is that I need to pass a NIL as the "name"   *)
    (* parameter to indicate unnamed shared memory, and the XDS OS2.DEF *)
    (* does not provide a way to do this.                               *)

    CONST MemName = "\SHAREMEM\WEASEL\DKIM";

    VAR name, text: ARRAY [0..511] OF CHAR;
        loc, p: ADDRESS;
        hab: OS2.HAB;
        rc: CARDINAL;

    BEGIN
        (*p := ADR(loc);*)
        name := "";
        rc := OS2.DosAllocSharedMem (loc, name, 512, OS2.OBJ_GIVEABLE+OS2.PAG_COMMIT+OS2.PAG_READ+OS2.PAG_WRITE);
        IF rc <> 0 THEN
            err := rc;
        END (*IF*);
        Debug.DebugText ("After DosAllocSharedMem, rc = ");
        Debug.DebugCard (rc);  Debug.DebugEOL;
        Debug.DebugText ("Shared memory address is ");
        Debug.DebugHex (CAST(CARDINAL,loc));  Debug.DebugEOL;
        OS2.WinQueryDlgItemText (hwnd, DID.DKIMDNSTXTloc, 512, text);
        Copy (ADR(text), loc, 512);
        hab := OurHab();
        IF NOT OS2.WinOpenClipbrd (hab) THEN
            Debug.DebugText ("Failed to open clipboard");
        END (*IF*);
        OS2.WinEmptyClipbrd (hab);
        OS2.WinSetClipbrdData (hab, CAST(CARDINAL,loc), OS2.CF_TEXT, OS2.CFI_POINTER);
        OS2.WinCloseClipbrd (hab);
        OS2.DosFreeMem (loc);
    END CopyField;
*)

(************************************************************************)

PROCEDURE ["SysCall"] DialogueProc(hwnd     : OS2.HWND
                     ;msg      : OS2.ULONG
                     ;mp1, mp2 : OS2.MPARAM): OS2.MRESULT;

    VAR NotificationCode, ItemID: CARDINAL;
        DKIMSignEnable: BOOLEAN;

    BEGIN
        IF msg = OS2.WM_INITDLG THEN
            OS2.WinSetWindowPos (hwnd, 0, 0, 0, 0, 0, OS2.SWP_MOVE);
            LoadValues (hwnd);
            RETURN NIL;
        ELSIF msg = OS2.WM_PRESPARAMCHANGED THEN

            IF ChangeInProgress THEN
                RETURN OS2.WinDefDlgProc(hwnd, msg, mp1, mp2);
            ELSE
                ChangeInProgress := TRUE;
                CommonSettings.UpdateFontFrom (hwnd, CommonSettings.MainNotebook);
                ChangeInProgress := FALSE;
                RETURN NIL;
            END (*IF*);
        ELSIF msg = OS2.WM_COMMAND THEN
            (* "Copy" is the only button command we should receive. *)
            (*CopyField (hwnd);*)
            RETURN NIL;
        ELSIF msg = OS2.WM_CONTROL THEN
            NotificationCode := OS2.ULONGFROMMP(mp1);
            ItemID := NotificationCode MOD 65536;
            NotificationCode := NotificationCode DIV 65536;
            IF (ItemID = DID.DKIMSelector) OR (ItemID = DID.DKIMSigning) THEN
                IF NotificationCode = OS2.EN_CHANGE THEN
                    SetTxtLoc (hwnd);
                    RETURN NIL;
                ELSE
                    RETURN OS2.WinDefDlgProc(hwnd, msg, mp1, mp2);
                END (*IF*)
            ELSIF ItemID = DID.DKIMSignEnable THEN
                DKIMSignEnable := OS2.LONGFROMMR (OS2.WinSendDlgItemMsg (gv.OurPageHandle,
                                    DID.DKIMSignEnable, OS2.BM_QUERYCHECK, NIL, NIL)) <> 0;
                ShowHide(hwnd, DKIMSignEnable);
            END (*IF*);
            RETURN OS2.WinDefDlgProc(hwnd, msg, mp1, mp2);
        ELSE
            RETURN OS2.WinDefDlgProc(hwnd, msg, mp1, mp2);
        END (*CASE*);
    END DialogueProc;

(************************************************************************)

PROCEDURE CreatePage (notebook: OS2.HWND;  domainname: DomainName;
                                after: CARDINAL;
                                VAR (*OUT*) PageID: CARDINAL);

    (* Creates DKIM page and adds it to the notebook after the page *)
    (* whose ID is "after".                                         *)

    BEGIN
        gv.CurrentDomain := domainname;
        gv.notebookhandle := notebook;
        gv.OurPageHandle := OS2.WinLoadDlg(notebook, notebook,
                       DialogueProc,        (* dialogue procedure *)
                       0,                   (* use resources in EXE *)
                       DID.DKIM,            (* dialogue ID *)
                       NIL);                (* creation parameters *)
        PageID := OS2.ULONGFROMMR (OS2.WinSendMsg (notebook, OS2.BKM_INSERTPAGE,
                         CAST(ADDRESS, after),
                          OS2.MPFROM2SHORT (OS2.BKA_MAJOR+OS2.BKA_AUTOPAGESIZE, OS2.BKA_NEXT)));
        gv.OurPageID := PageID;
        OS2.WinSendMsg (notebook, OS2.BKM_SETPAGEWINDOWHWND,
                        CAST(ADDRESS,PageID), CAST(ADDRESS,gv.OurPageHandle));
        SetTxtLoc (gv.OurPageHandle);
    END CreatePage;

(************************************************************************)

PROCEDURE SetFont (VAR (*IN*) name: CommonSettings.FontName);

    (* Sets the font of the text on this page. *)

    CONST bufsize = CommonSettings.FontNameSize;

    BEGIN
        OS2.WinSetPresParam (gv.OurPageHandle, OS2.PP_FONTNAMESIZE, bufsize, name);
    END SetFont;

(************************************************************************)

BEGIN
    ChangeInProgress := FALSE;
    gv.OurPageHandle := OS2.NULLHANDLE;
END DKIM.

