-- file: ChollaBBoard.mesa
-- edited by Barth, August 11, 1981 4:34 PM
-- edited by Brotz, March 3, 1983 5:12 PM
-- edited by Crowther, January 13, 1982 10:36 AM

DIRECTORY
Ascii,
ccD: FROM "ChollaCmdDefs",
dsD: FROM "DisplayDefs",
exD: FROM "ExceptionDefs",
inD: FROM "InteractorDefs",
intCommon,
lmD: FROM "LaurelMenuDefs",
MessageParse,
opD: FROM "OperationsDefs",
prD: FROM "ProtectionDefs",
Storage,
String,
tsD: FROM "TOCSelectionDefs",
vmD: FROM "VirtualMgrDefs";

ChollaBBoard: PROGRAM
IMPORTS ccD, dsD, exD, inD, intC: intCommon, lmD, MessageParse, Storage, String, tsD,
vmD
EXPORTS ccD =
BEGIN


bbTopHp, bbMiddleHp, bbLowerHp: inD.HousePtr;

-- the following variables save state from the time of a modify to the time of a deliver
bbAction: ccD.Action ← none;
savedUniqueId: STRING ← [24];
savedThisId: STRING ← [24];
savedIndex: vmD.TOCIndex ← 0;


InstallBB: PUBLIC PROCEDURE =
BEGIN
tnp: inD.TOCTextNbrPtr = intC.tocTextNbr;
oldToc: vmD.TOCHandle;
bbtoc: vmD.TOCHandle;
key: CARDINAL;
inD.StopBlinkingCaret[];
intC.userBracketsHouse.nextHouse ← bbTopHp;
bbTopHp.nextHouse.text.length ← 0;
lmD.ChangeEditorMenu[singleLine];
inD.ChangeCommandMenu
[cnp: intC.mailCommandNbr, region: intC.mailCommandRegion, linesToKeep: 2];
intC.tocCommandNbr.houses ← bbMiddleHp;
inD.ChangeCommandMenu
[cnp: intC.tocCommandNbr, region: intC.TOCCommandRegion, linesToKeep: 0];
intC.cmCommandNbr.houses ← bbLowerHp;
inD.ChangeCommandMenu
[cnp: intC.cmCommandNbr, region: intC.CMCommandRegion, linesToKeep: 0];
[bbtoc, key] ← ccD.GetTOCForFile["ChollaBulletinBoard"L, bb];
vmD.UnlockTOC[bbtoc, key];
oldToc ← tnp.toc;
key ← vmD.WaitForLock[oldToc];
tnp.toc ← bbtoc;
tnp.haveToc ← TRUE;
vmD.UnlockTOC[oldToc, key];
key ← vmD.WaitForLock[bbtoc];
dsD.ClearRectangle[inD.leftMargin, inD.rightMargin, tnp.topY, tnp.bottomY];
inD.TOCTextPainter[tnp, key];
vmD.UnlockTOC[bbtoc, key];
IF inD.CaretIsBlinking[] THEN inD.SetCaretBlinking[intC.target.point, intC.target.mnp];
END; -- of InstallBB --


BBLaurel: inD.CommandProcedure = {ccD.RestoreLaurel[]};


BBSpecs: inD.CommandProcedure =
BEGIN
IF ~ccD.IsAuthorized[onlooker, hp] THEN RETURN;
ccD.InstallSpecs[];
END; -- of BBSpecs --


BBDisplay: inD.CommandProcedure =
BEGIN
IF ~ccD.IsAuthorized[onlooker, hp] THEN RETURN;
inD.DisplayMessageCommand[hp, TRUE];
END; -- of BBDisplay --


BBDeliver: inD.CommandProcedure =
BEGIN
cm: vmD.ComposedMessagePtr = vmD.ComposedMessage[intC.cmTextNbr.message];
toc: vmD.TOCHandle;
key: CARDINAL;
index: vmD.TOCIndex;
ok: BOOLEAN;
IF ~ccD.IsAuthorized[technician, hp] THEN RETURN;
IF bbAction = none THEN
{exD.DisplayExceptionString["Nothing to Deliver!"L]; RETURN};
[toc, key] ← ccD.GetTOCForFile["ChollaBulletinBoard"L, bb];
[index, ok] ← GetSingleSelectedEntry[toc, key, bbAction = insert];
IF bbAction = insert THEN index ← index + 1;
SELECT TRUE FROM
(bbAction = replace AND index # savedIndex) =>
exD.DisplayExceptionString["Invalid Selection"L];
ok =>
BEGIN
fieldList: MessageParse.FieldList ← MessageParse.MakeFieldList[cm];
IF bbAction = replace THEN
BEGIN
MessageParse.ReplaceOrAppendField[cm, @fieldList, "UniqueId"L, savedUniqueId];
MessageParse.ReplaceOrAppendField[cm, @fieldList, "ThisId"L, savedThisId];
END;
IF ~ccD.SendChollaMail[bbAction, bb, toc, key, index, cm, @fieldList] THEN
exD.DisplayExceptionString["Faulty update message!"L];
MessageParse.FreeFieldList[fieldList];
END;
ENDCASE;
vmD.UnlockTOC[toc, key];
bbAction ← none;
END; -- of BBDeliver --


BBDelete: inD.CommandProcedure =
BEGIN
cm: vmD.ComposedMessagePtr ← vmD.AllocateComposedMessageObject[];
toc: vmD.TOCHandle;
key: CARDINAL;
index: vmD.TOCIndex;
run: STRING ← [ccD.maxRunNameLength];
ok: BOOLEAN;
IF ~ccD.IsAuthorized[maven, hp] THEN RETURN;
ccD.StartMultiTOCOperation[];
[toc, key] ← ccD.GetTOCForFile["ChollaBulletinBoard"L, bb];
[index, ok] ← GetSingleSelectedEntry[toc, key];
IF ok THEN
BEGIN
IF confirmed OR inD.Confirm[1] THEN
BEGIN -- he wants to delete.
fieldList: MessageParse.FieldList;
ccD.LoadComposedMessage[toc, key, index, cm];
fieldList ← MessageParse.MakeFieldList[cm];
IF ObtainRunName[cm, fieldList, run] THEN
BEGIN
exD.DisplayExceptionString
["Are you sure that you wish to delete all traces of this run?"L];
IF inD.Confirm[2] THEN
IF ~ccD.SendChollaMail[delete, bb, toc, key, index, cm, @fieldList] THEN
exD.DisplayExceptionString["Cannot perform run deletion!"L];
END
ELSE IF ~ccD.SendChollaMail[delete, bb, toc, key, index, cm, @fieldList] THEN
exD.DisplayExceptionString["Cannot delete entry!"L];
MessageParse.FreeFieldList[fieldList];
END;
END;
vmD.UnlockTOC[toc, key];
ccD.FinishMultiTOCOperation[];
vmD.FreeVirtualMessageObject[cm];
bbAction ← none;
END; -- of BBDelete --


BBNewForm: inD.CommandProcedure=
BEGIN
mnp: inD.MessageTextNbrPtr = intC.cmTextNbr;
cm: vmD.ComposedMessagePtr ← vmD.ComposedMessage[mnp.message];
IF ~ccD.IsAuthorized[technician, hp] THEN RETURN;
bbAction ← insert;
vmD.InitComposedMessage[cm,
"Subject: Ťopic¿

M̌essage¿

"L
];
ccD.ResetTheEditor[];
END; -- of BBNewForm --


BBModify: inD.CommandProcedure=
BEGIN
mnp: inD.MessageTextNbrPtr = intC.cmTextNbr;
cm: vmD.ComposedMessagePtr = vmD.ComposedMessage[mnp.message];
bbSelection: vmD.TOCIndex;
toc: vmD.TOCHandle;
key: CARDINAL;
ok: BOOLEAN;
IF ~ccD.IsAuthorized[technician, hp] THEN RETURN;
IF ~confirmed AND intC.composedMessageEdited
AND vmD.GetMessageSize[cm] # 0
AND ~inD.AskUserToConfirm[exD.willReplaceMessage]
THEN RETURN;
[toc, key] ← ccD.GetTOCForFile["ChollaBulletinBoard"L, bb];
[bbSelection, ok] ← GetSingleSelectedEntry[toc, key];
IF ok THEN BEGIN
dm: vmD.DisplayMessagePtr ← vmD.AllocateDisplayMessageObject[];
fieldList: MessageParse.FieldList;
runName: STRING ← [20];
vmD.LoadDisplayMessage[toc, key, bbSelection, dm];
fieldList ← MessageParse.MakeFieldList[dm];
IF ObtainRunName[dm, fieldList, runName] THEN
exD.DisplayExceptionString["Can’t modify a run-in-progress entry!"L]
ELSE BEGIN
MessageParse.GetWholeField[dm, fieldList, "UniqueID"L, savedUniqueId];
MessageParse.GetWholeField[dm, fieldList, "ThisID"L, savedThisId];
ccD.WriteMessageIntoComposeWindow[dm, @fieldList];
MessageParse.DeleteField[cm, @fieldList, "Date"L];
MessageParse.DeleteField[cm, @fieldList, "From"L];
ccD.ResetTheEditor[];
bbAction ← replace;
savedIndex ← bbSelection;
END;
vmD.FlushDisplayMessage[dm, key];
vmD.FreeVirtualMessageObject[dm];
MessageParse.FreeFieldList[fieldList];
END;
vmD.UnlockTOC[toc, key];
END; -- of BBModify --


BBStepList: inD.CommandProcedure =
BEGIN
selectedEntry: vmD.TOCIndex;
toc: vmD.TOCHandle;
key: CARDINAL;
IF ~ccD.IsAuthorized[onlooker, hp] THEN RETURN;
[toc, key] ← ccD.GetTOCForFile["ChollaBulletinBoard"L, bb];
selectedEntry ← tsD.FirstSelectedEntry[toc, key];
IF selectedEntry # 0 AND selectedEntry = tsD.LastSelectedEntry[toc, key] THEN
BEGIN
dm: vmD.DisplayMessagePtr ← vmD.AllocateDisplayMessageObject[];
runName: STRING ← [ccD.maxRunNameLength];
fieldList: MessageParse.FieldList;
vmD.LoadDisplayMessage[toc, key, selectedEntry, dm];
fieldList ← MessageParse.MakeFieldList[dm];
IF ObtainRunName[dm, fieldList, runName] THEN
{hp.nextHouse.text.length ← 0; String.AppendString[hp.nextHouse.text, runName]};
MessageParse.FreeFieldList[fieldList];
vmD.FlushDisplayMessage[dm, key];
vmD.FreeVirtualMessageObject[dm];
END;
vmD.UnlockTOC[toc, key];
hp.nextHouse.houseRefresher[hp.nextHouse];
SELECT TRUE FROM
~(confirmed OR inD.ConfirmBrackets[hp: hp.nextHouse, fileExtension: "StepList.chml."L]) =>
inD.IndicateCommandFinished[hp];
hp.nextHouse.text.length = 0 =>
{exD.DisplayExceptionString["Must name a run."L]; inD.IndicateCommandFinished[hp]};
hp.nextHouse.text.length > 20 =>
BEGIN
exD.DisplayExceptionString["Run name is too long!"L];
inD.IndicateCommandFinished[hp];
END;
ENDCASE =>
BEGIN
ccD.CleanupDisplayMessage[];
[toc, key] ← ccD.GetTOCForFile["ChollaBulletinBoard"L, bb];
tsD.ResetTOCSelection[toc, key];
vmD.UnlockTOC[toc, key];
IF ~ccD.InstallStepList[hp.nextHouse.text] THEN inD.IndicateCommandFinished[hp];
END;
IF inD.CaretIsBlinking[] THEN inD.SetCaretBlinking[intC.target.point, intC.target.mnp];
END; -- of BBStepList --


BBTalk: inD.CommandProcedure =
BEGIN
worked: BOOLEAN ← FALSE;
IF ~ccD.IsAuthorized[technician, hp] THEN RETURN;
IF confirmed OR inD.ConfirmBrackets[hp: hp.nextHouse, fileExtension: "Talk.bcd."L] THEN
BEGIN
lmD.ChangeEditorMenu[singleLine];
worked ← ccD.MachineTalker[hp.nextHouse.text];
END;
inD.IndicateCommandFinished[hp];
END; -- of BBTalk --


BBFilter: inD.CommandProcedure =
BEGIN
exD.DisplayExceptionString["Not yet implemented."L];
END; -- of BBFilter --


ObtainRunName: PUBLIC PROCEDURE
[vm: vmD.VirtualMessagePtr, fieldList: MessageParse.FieldList, runName: STRING]
RETURNS [isRun: BOOLEAN] =
BEGIN
string: STRING ← [10];
MessageParse.GetStringFromField[vm, fieldList, "BBEntryType"L, string];
-- no field returns zero length string.
IF (isRun ← String.EquivalentString[string, "Run"L]) THEN
MessageParse.GetStringFromField[vm, fieldList, "Subject"L, runName];
END; -- of ObtainRunName --


GetSingleSelectedEntry:
PROCEDURE [toc: vmD.TOCHandle, key: CARDINAL, zeroOk: BOOLEAN ← FALSE]
RETURNS [entry: vmD.TOCIndex, ok: BOOLEAN] =
BEGIN
ok ← FALSE;
SELECT (entry ← tsD.FirstSelectedEntry[toc, key]) FROM
0 => IF ~(ok ← zeroOk) THEN exD.DisplayExceptionString["An entry must be selected"L];
tsD.LastSelectedEntry[toc, key] => ok ← TRUE;
ENDCASE => exD.DisplayExceptionString["Only a single entry may be selected"L];
END; -- of GetSingleSelectedEntry --


-- Startup code for BBoard --


Init: PROCEDURE =
BEGIN
bbTopMenu: ARRAY [0 .. 3) OF lmD.HouseDescriptor ←
[[text: "Step list"L, type: brackets, bracketsText: ""L, command: BBStepList,
indicDone: FALSE],
[text: "Specs"L, command: BBSpecs, indicDone: FALSE],
[text: "Laurel"L, rightFlush: TRUE, command: BBLaurel, indicDone: FALSE]];
-- [text: "Filter"L, type: brackets, bracketsText: ""L, command: BBFilter]];
bbMiddleMenu: ARRAY [0 .. 2) OF lmD.HouseDescriptor ←
[[text: "Display"L, command: BBDisplay],
[text: "Delete"L, command: BBDelete]];
bbLowerMenu: ARRAY [0 .. 5) OF lmD.HouseDescriptor ←
[[text: "New entry"L, command: BBNewForm],
[text: "Modify"L, command: BBModify],
[text: "Get"L, command: inD.GetCommand],
[text: "Talk"L, type: brackets, bracketsText: ""L, command: BBTalk, indicDone: FALSE],
[text: "Post"L, endOfLine: TRUE, rightFlush: TRUE, command: BBDeliver]];
specsHp, laurelHp: inD.HousePtr;

bbTopHp ← lmD.CreateCommandHouses
[DESCRIPTOR[bbTopMenu], Storage.Node, Storage.String, 2,
intC.newMailCommandHouse.leftX];
specsHp ← lmD.MapHouseTextToHousePtr[bbTopHp, "Specs"L];
laurelHp ← lmD.MapHouseTextToHousePtr[specsHp, "Laurel"L];
specsHp.leftX ← specsHp.leftX + (laurelHp.leftX - specsHp.rightX - 25);
specsHp.rightX ← specsHp.rightX + (laurelHp.leftX - specsHp.rightX - 25);
bbMiddleHp ← lmD.CreateCommandHouses
[DESCRIPTOR[bbMiddleMenu], Storage.Node, Storage.String];
bbLowerHp ← lmD.CreateCommandHouses
[DESCRIPTOR[bbLowerMenu], Storage.Node, Storage.String];
END; -- of Init --


Init[];


END. -- of ChollaBBoard --