DIRECTORY Buttons, Containers, Commander, Encrypt, FS, IO, Menus, MessageWindow, PutGet, Rope, TEditDocument, TiogaExtraOps, TiogaOps, VFonts, ViewerClasses, ViewerOps, ViewerTools; EncryptTool: CEDAR PROGRAM IMPORTS Buttons, Commander, Containers, Encrypt, FS, IO, Menus, MessageWindow, PutGet, Rope, TiogaExtraOps, TiogaOps, VFonts, 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šœ œž'˜