DIRECTORY Buttons, Containers, Commander, Encrypt, FS, IO, Menus, MessageWindow, PutGet, Rope, TEditDocument, TiogaExtraOps, TiogaOps, ViewerClasses, ViewerOps, ViewerTools; EncryptTool: CEDAR PROGRAM IMPORTS Buttons, Commander, Containers, Encrypt, FS, IO, Menus, MessageWindow, PutGet, Rope, TiogaExtraOps, TiogaOps, ViewerOps, ViewerTools = BEGIN EncryptHandle: TYPE = REF EncryptToolRec; EncryptToolRec: TYPE = RECORD [ outer: Containers.Container _ NIL, key: Rope.ROPE _ NIL, keyViewer: ViewerClasses.Viewer _ NIL, files: ViewerClasses.Viewer _ NIL ]; EncryptedText: TYPE = Rope.ROPE; SelectKey: Buttons.ButtonProc = BEGIN handle: EncryptHandle = NARROW[clientData]; ViewerTools.SetContents[handle.keyViewer, handle.key]; ViewerTools.SetSelection[handle.keyViewer]; handle.keyViewer.newVersion _ TRUE; -- forces stars to return on button op END; SelectFiles: Buttons.ButtonProc = BEGIN handle: EncryptHandle = NARROW[clientData]; ViewerTools.SetSelection[handle.files]; END; GetKey: PROC [handle: EncryptHandle] RETURNS [Rope.ROPE] = BEGIN IF handle.keyViewer.newVersion THEN BEGIN handle.key _ ViewerTools.GetContents[handle.keyViewer]; ViewerTools.SetContents[handle.keyViewer, "*****"]; handle.keyViewer.newVersion _ FALSE; END; RETURN[handle.key]; END; EncryptFiles: Buttons.ButtonProc = BEGIN handle: EncryptHandle = NARROW[clientData]; key: Rope.ROPE = GetKey[handle]; inputs: IO.STREAM = IO.RIS[ViewerTools.GetContents[handle.files]]; sourceFile: Rope.ROPE; sourceFile _ inputs.GetTokenRope[IO.IDProc ! IO.EndOfStream => {sourceFile _ NIL; CONTINUE}].token; IF Rope.Length[key]=0 THEN BEGIN MessageWindow.Append["Please enter an encryption key", TRUE]; MessageWindow.Blink[]; END ELSE WHILE sourceFile#NIL DO destFile: Rope.ROPE = Rope.Concat[sourceFile, ".des"]; Encrypt.EncryptFile[plain: sourceFile, cipher: destFile, key: key ! FS.Error => BEGIN MessageWindow.Append[IO.PutFR["Trouble encrypting file ""%g"" because %g. Aborting encryption.", IO.rope[sourceFile], IO.rope[error.explanation]], TRUE]; MessageWindow.Blink[]; EXIT; END; ]; sourceFile _ inputs.GetTokenRope[IO.IDProc ! IO.EndOfStream => {sourceFile _ NIL; CONTINUE}].token; ENDLOOP; END; DecryptFiles: Buttons.ButtonProc = BEGIN handle: EncryptHandle = NARROW[clientData]; key: Rope.ROPE = GetKey[handle]; outputs: IO.STREAM = IO.RIS[ViewerTools.GetContents[handle.files]]; destFile: Rope.ROPE; destFile _ outputs.GetTokenRope[IO.IDProc ! IO.EndOfStream => {destFile _ NIL; CONTINUE}].token; IF Rope.Length[key]=0 THEN BEGIN MessageWindow.Append["Please enter an encryption key", TRUE]; MessageWindow.Blink[]; END ELSE WHILE destFile#NIL DO sourceFile: Rope.ROPE = Rope.Concat[destFile, ".des"]; Encrypt.DecryptFile[plain: destFile, cipher: sourceFile, key: key ! FS.Error => BEGIN MessageWindow.Append[IO.PutFR["Trouble encrypting file ""%g"" because %g. Aborting encryption.", IO.rope[sourceFile], IO.rope[error.explanation]], TRUE]; MessageWindow.Blink[]; EXIT; END; Encrypt.BadEncryption => BEGIN MessageWindow.Append[IO.PutFR["File ""%g"" isn't properly encrypted or you gave me the wrong key.", IO.rope[destFile]], TRUE]; MessageWindow.Blink[]; EXIT; END; ]; destFile _ outputs.GetTokenRope[IO.IDProc ! IO.EndOfStream => {destFile _ NIL; CONTINUE}].token; ENDLOOP; END; EncryptSelection: Buttons.ButtonProc = BEGIN OPEN TiogaOps; DoEncrypt: PROC [root: TiogaOps.Ref] = BEGIN [start: start, end: end, viewer: viewer] _ GetSelection[]; ProcessSelection[root, start.node, end.node, EncryptBranch, key, viewer]; END; EncryptBranch: PROC [node: TiogaOps.Ref, key: Rope.ROPE] = BEGIN IF GetProp[node, $EncryptedChars]=NIL THEN TRUSTED BEGIN doNext: BOOL; cipher: Rope.ROPE; TiogaOps.SetSelection[viewer, [node, 0], [node, 0], point, TRUE, TRUE]; doNext _ Rope.Size[TiogaOps.GetRope[TiogaOps.GetCaret[].node]] # 0; TiogaOps.Break[]; -- insert a fake root node in front of the branch node _ TiogaOps.GetCaret[].node; IF doNext THEN node _ TiogaOps.Next[node]; TiogaOps.SelectBranches[viewer, node, node, node, TRUE, TRUE]; -- select the branch TiogaOps.Nest[]; -- nest it under the extra node node _ TiogaOps.Parent[TiogaOps.GetCaret[].node]; -- get the extra node again cipher _ Encrypt.EncryptRope[plain: PutGet.ToRope[LOOPHOLE[node]].output, key: key]; TiogaOps.SelectBranches[viewer, node, node, node, TRUE, TRUE]; TiogaOps.SetLooks["is", caret]; TiogaOps.InsertRope["...encrypted..."]; PutProp[n: TiogaOps.GetCaret[].node, name: $EncryptedChars, value: cipher]; END ELSE BEGIN OPEN MessageWindow; Append["Node already encrypted", TRUE]; Blink[]; END; END; start, end: Location; viewer: ViewerClasses.Viewer; handle: EncryptHandle = NARROW[clientData]; key: Rope.ROPE = GetKey[handle]; IF Rope.Length[key]=0 THEN BEGIN MessageWindow.Append["Please enter an encryption key", TRUE]; MessageWindow.Blink[]; END ELSE DoTiogaOpsCallWithLocks[DoEncrypt ! TiogaOps.NoSelection => BEGIN MessageWindow.Append["Please make a text selection", TRUE]; MessageWindow.Blink[]; CONTINUE; END; ]; END; DecryptSelection: Buttons.ButtonProc = BEGIN OPEN TiogaOps; Decrypt: PROC [root: TiogaOps.Ref] = BEGIN [start: start, end: end, viewer: viewer] _ GetSelection[]; ProcessSelection[root, start.node, end.node, DecryptBranch, key, viewer]; END; DecryptBranch: PROC [node: TiogaOps.Ref, key: Rope.ROPE] = BEGIN chars: REF = GetProp[node, $EncryptedChars]; IF chars#NIL THEN TRUSTED BEGIN new: TiogaOps.Ref; encryptedText: EncryptedText = NARROW[chars]; plain: Rope.ROPE = Encrypt.DecryptRope[cipher: encryptedText, key: key]; TiogaExtraOps.RemProp[node, $EncryptedChars]; TiogaOps.SelectNodes[viewer, node, node, node]; new _ LOOPHOLE[PutGet.FromRope[plain]]; TiogaOps.SaveSpanForPaste[[new, 0], TiogaOps.LastLocWithin[new], node]; TiogaOps.Paste[]; new _ TiogaOps.GetSelection[].start.node; TiogaOps.SelectBranches[viewer, TiogaOps.FirstChild[new], TiogaOps.FirstChild[new], node, TRUE, TRUE]; TiogaOps.UnNest[]; TiogaOps.SelectNodes[viewer, new, new, node]; -- select the fake root node TiogaOps.Delete[]; -- get rid of it TiogaOps.SelectNodes[viewer, node, node, node]; -- select the "encrypted" node TiogaOps.Delete[]; -- get rid of it END ELSE BEGIN OPEN MessageWindow; Append["Node already unencrypted", TRUE]; Blink[]; END; END; start, end: Location; viewer: ViewerClasses.Viewer; handle: EncryptHandle = NARROW[clientData]; key: Rope.ROPE = GetKey[handle]; IF Rope.Length[key]=0 THEN BEGIN MessageWindow.Append["Please enter an encryption key", TRUE]; MessageWindow.Blink[]; RETURN; END ELSE DoTiogaOpsCallWithLocks[Decrypt ! TiogaOps.NoSelection => BEGIN MessageWindow.Append["Please make a text selection", TRUE]; MessageWindow.Blink[]; CONTINUE; END; Encrypt.BadEncryption => BEGIN MessageWindow.Append["It seems you gave me an incorrect key.", TRUE]; MessageWindow.Blink[]; CONTINUE; END; ]; END; DoTiogaOpsCallWithLocks: PROC [proc: PROC [root: TiogaOps.Ref], root: TiogaOps.Ref _ NIL] = BEGIN IF TiogaOps.SelectionRoot[]=NIL THEN ERROR TiogaOps.NoSelection; TiogaOps.CallWithLocks[proc: proc, root: root]; END; Level: PROC [node: TiogaOps.Ref] RETURNS [level: INTEGER] = BEGIN level _ 0; UNTIL (node _ TiogaOps.Parent[node])=NIL DO level _ level+1; ENDLOOP; END; ProcessSelection: PROC [ root: TiogaOps.Ref, start, end: TiogaOps.Ref, proc: PROC [node: TiogaOps.Ref, key: Rope.ROPE], key: Rope.ROPE, viewer: ViewerClasses.Viewer] = BEGIN node, next, selectAfter, selectUntil: TiogaOps.Ref; readOnly: BOOL _ FALSE; tdd: TEditDocument.TEditDocumentData _ NARROW[viewer.data]; startLevel, endLevel: INTEGER; startLevel _ Level[start]; endLevel _ Level[end]; IF endLevelJšœ%™%—Jšœ˜JšœΠisœ˜'J˜KJšž˜—šž˜Jšžœžœ˜Jšœ!žœ˜'J˜Jšžœ˜—Jšžœ˜J˜—J˜Jšœ˜Jšœžœ ˜+Jšœ žœ˜ šžœžœž˜ Jšœ7žœ˜=J˜Jšž˜—šžœ"˜&šœž˜Jšœ5žœ˜;J˜Jšžœ˜ Jšžœ˜—Jšœ˜—Jšžœ˜J˜—šœ&˜&Jšžœžœ ˜J˜š œžœ˜$Jšž˜Jšœ:˜:JšœI˜IJšžœ˜J˜—š  œžœ žœ˜:Jšž˜Jšœžœ"˜,šžœžœž˜Jšžœž˜ J˜Jšœžœ˜-Jšœ žœ8˜HJ˜-Jšœ/˜/Jšœžœ˜'JšœG˜GJšœ˜J˜)JšœZžœžœ˜fJšœ˜Jšœ.Ÿ˜JJšœŸ˜#Jšœ0Ÿ˜NJšœŸ˜#Jšž˜—šž˜Jšžœžœ˜Jšœ#žœ˜)J˜Jšžœ˜—Jšžœ˜J˜—J˜Jšœ˜Jšœžœ ˜+Jšœ žœ˜ šžœžœž˜ Jšœ7žœ˜=J˜Jšžœ˜Jšž˜—šžœ ˜$šœž˜Jšœ5žœ˜;J˜Jšžœ˜ Jšžœ˜—šœž˜Jšœ?žœ˜EJ˜Jšžœ˜ Jšžœ˜—Jšœ˜—Jšžœ˜J˜—š œžœžœ,žœ˜[Jšž˜šžœžœžœžœ˜@Jšœ1™1—Jšœ/˜/Jšžœ˜J˜—š  œžœžœ žœž˜AJšœ ˜ Jšžœ žœžœžœ˜EJšžœ˜—J˜š œžœ˜šœ-˜-Jšœžœ žœ žœ˜@Jšœ˜—Jšž˜Jšœ3˜3Jšœ žœžœ˜Jšœ'žœ˜;Jšœžœ˜Jšœ˜Jšœ˜šžœžœž˜!Jšœ/žœ˜5J˜Jšžœ˜Jšžœ˜—šžœž˜!Jšœ˜Jšžœ˜—šžœ-žœž˜9Jšœ/žœ˜5J˜Jšžœ˜Jšžœ˜—šžœžœž˜Jšœ žœ˜Jšœ$˜$Jšžœ˜—Jšœ ˜ Jšœ+˜+Jšœ!˜!šž˜Jšœ˜Jšœ˜Jšžœ žœžœ˜Jšœ ˜ Jšžœ˜—šžœ žœž˜Jšœ%˜%Jšœžœ˜Jšœ'˜'Jšžœ˜—Jšœ*˜*Jšœ ˜ Jšžœ žœžœ˜JJšœ3Ÿ˜PJšžœ˜J˜—šœ'˜'Jšž˜Jšœžœ˜1J˜-J˜&˜J˜˜JšœŸ˜0JšœŸ˜8J˜J˜—J˜—˜J˜˜JšœŸ˜0JšœŸ˜8J˜J˜—J˜—˜J˜˜JšœŸ˜-JšœŸ˜5J˜J˜—J˜—˜J˜˜JšœŸ˜-JšœŸ˜5J˜J˜—J˜—šœ'Ÿ ˜GJšœŸ ˜9JšœžœŸ4˜EJšœŸ ˜2JšœŸ˜2Jšœ žœŸ'˜