//License Agreement: // The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the License at // http://www.skyhunter.com/marcs/securit-Edesk-license.html // Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF // ANY KIND, either express or implied. See the License for the specific language governing rights and // limitations under the License. //The Original Code is The Securit-Edesk Program. //The Initial Developer of the Original Code is Marc Stiegler. Portions created by // Marc Stiegler are Copyright (C) Marc Stiegler. All Rights Reserved. //********** # set up tracing; stub out all the printing for operational version define traceln(str) { println(str) } traceln("started") define versionNumber := "0.57" def makeErr(errorDescription) {^import:java.lang.Exception new(errorDescription)} define io(className) {^(import:java.io.* )[className]} define byte := import:java.lang.Byte TYPE //uiSet define uiSet { to labelPad() {^8} to fontMetrics(component) {^component getFontMetrics(component getFont)} to swing(className) {^ (import:javax.swing.* )[className] } to awt(className) {^ (import:java.awt.* )[className] } to baseWidth(component) { def goodHeight := uiSet fontMetrics(component) getHeight + uiSet labelPad() component.preferredSize := uiSet awt("Dimension") new (150,goodHeight) component.maximumSize := uiSet awt("Dimension") new(2000,goodHeight) component.alignmentX := 0.5 } to varyWidth(comp) { uiSet baseWidth(comp) def goodWidth := (uiSet fontMetrics(comp) stringWidth(comp getLabel)) + uiSet labelPad() def goodHeight := uiSet fontMetrics(comp) getHeight + uiSet labelPad() comp.preferredSize := uiSet awt("Dimension") new (goodWidth, goodHeight) comp.maximumSize := uiSet awt("Dimension") new (2000, goodHeight) } to fixWidth (comp) { uiSet baseWidth(comp) def widthPad := (uiSet fontMetrics(comp) stringWidth(" ")) def goodWidth := (uiSet fontMetrics(comp) stringWidth(comp getLabel toString)) + widthPad traceln("rigid width" +goodWidth + " on " + comp.label toString) def goodHeight := uiSet fontMetrics(comp) getHeight + uiSet labelPad() comp.maximumSize := uiSet awt("Dimension") new (goodWidth,goodHeight) comp.preferredSize := uiSet awt("Dimension") new (goodWidth,goodHeight) } to attachAction(component,target,verb) { define listener { to actionPerformed(event) { E call(target, verb, []) } } component addActionListener(listener) } to newButton(labelText, verb, target) { define button := E call(uiSet swing("JButton"), "new(String)", [labelText]) uiSet varyWidth(button) button.background := (uiSet awt("SystemColor") control); uiSet attachAction(button,target,verb) ^button } to addComponents(container, componentList) { for each in componentList { E call(container, "add(Component)", [each]); } } to addMenuItem(menu,labelText, verb, target) { define item := E call(uiSet swing("JMenuItem"), "new(String)", [labelText]) uiSet attachAction(item, target, verb) E call(menu, "add(JMenuItem)", [item]) } } // eDialog: make textFieldDefaultValue null to not show a textfield // If window closed with close box, not button, getClickedButton and // getEnteredText both return null // returns a promise for a dialog that has been answered define eDialogPromiser new(title, label, textFieldDefaultValue, buttonNames) { define myClickedButton := null define [finishedDialogPromise, resolver] := PromiseMaker() def eDialog := { def myWin := uiSet swing("JFrame") new(title) define windowListener { to windowClosing(event) { //farDialogListener <- dialogAnswered(eDialog) resolver resolve(eDialog) } to windowClosed(event) { myWin dispose } match _ {} } traceln("about to add window listener") myWin addWindowListener(windowListener) traceln("added window listener") def mainPane := myWin.contentPane mainPane.preferredSize := uiSet awt("Dimension") new (400,200) def labelPane := E call(uiSet swing("JTextArea"), "new(String)",["\n" +label]) labelPane setEditable(false) labelPane.background := (uiSet awt("SystemColor") control); def labelScrollPane := uiSet swing("JScrollPane") new(labelPane) mainPane add(labelScrollPane, "North") def myTextField := null if (textFieldDefaultValue != null) { myTextField := uiSet swing("JTextField") new(textFieldDefaultValue) uiSet baseWidth(myTextField) mainPane add(myTextField, "Center") } def buttonRow := uiSet swing("JPanel") new() buttonRow setLayout(uiSet awt("GridLayout") new(1,buttonNames size)) mainPane add(buttonRow, "South") traceln("about to build dialog buttons") for index in 0..(buttonNames size - 1) { def nextButton := uiSet newButton(buttonNames[index], "button" + index, eDialog) uiSet addComponents(buttonRow,[nextButton]) } traceln("made buttons") def clickedButton(index) { myClickedButton := buttonNames[index] //farDialogListener <- dialogAnswered(eDialog) resolver resolve(eDialog) myWin dispose } myWin pack myWin show ^ def eDialog { to getEnteredText() { def answer := null if (myClickedButton != null && textFieldDefaultValue != null) { answer := myTextField.text} ^answer } to getClickedButton() {^myClickedButton} to button0 { clickedButton(0)} to button1 { clickedButton(1)} to button2 { clickedButton(2)} to button3 { clickedButton(3)} } } ^finishedDialogPromise } //finisher def promiseAllDone(thePromiseList) { //resolves after all in list resolved, returns true if all promises fulfilled def [resolutionPromise,resolver] := PromiseMaker() def promiseCount := thePromiseList size define breakMessages := "" if (promiseCount == 0) {resolver resolve(true)} for each in thePromiseList { each <- whenResolved(def obs(result) { if (E isBroken(result)) {breakMessages := breakMessages + " :" +result} promiseCount -= 1 if (promiseCount == 0) { if (breakMessages size == 0) { resolver resolve(true) } else { resolver smash(makeErr (breakMessages)) } } }) } ^resolutionPromise } def vowsMonitorMaker new() { def [bundlePromise,resolver] := PromiseMaker() def bundle := [] diverge ^def vowsMonitor { to add (thePromise) {bundle push(thePromise)} to finishAll {resolver resolve(promiseAllDone(bundle))} to promiseFinish {^bundlePromise} } } # Ensure the user knows if he's using a clear, unencrypted connection traceln(introducer negotiable[0]) if (introducer negotiable != ["3DES_SDH_M"]) { try { uiSet swing("JOptionPane") showMessageDialog(null, "You are using DaffE, so you'll be chatting in the clear. To be secure, use E instead.", "Unencrypted DaffE Session", uiSet swing("JOptionPane") WARNING_MESSAGE) } catch e {} println("Connection may be insecure.") } # return the object represented by the URI define getObjectFromURI(uri) { ^introducer sturdyFromURI(uri) liveRef } define makeURIFromObject(obj) { ^introducer sturdyToURI(sturdyRef(obj)) } define connectionWarning(description) { uiSet swing("JOptionPane") showMessageDialog(null, description, "Connection apparently lost", uiSet swing("JOptionPane") WARNING_MESSAGE) } define checkLink(thePromise) { thePromise <- whenResolved(def obs(o) { if (E isBroken(o)) { connectionWarning("Error:\n" + o) } }) } def forwarderMaker new(target) { ^def forwarder { match [verb,args] {^E send(target,verb,args)} } } def makeWriteFile { to run(fileName) {^ file: fileName} to label() {^""} } def makeReadFile { to run(fileName) {^ (file: fileName) transReadOnly} to label() {^"(Read Only)"} } def fileHash(file, numBytesToHash) { def MDMaker := import:java.security.MessageDigest def blockSize := 100000 def hashedBytes := 0 def openFile(file) { ^E call(io("FileInputStream"), "new(File)", [file]) } def sha := MDMaker.instance("SHA") def inStream := openFile(file) def result := [] if (numBytesToHash <= file length) { while (hashedBytes < numBytesToHash) { if (numBytesToHash - hashedBytes < blockSize) {blockSize := numBytesToHash - hashedBytes} def buf := byte[blockSize] def count := inStream read(buf) sha update(buf, 0, count) hashedBytes := hashedBytes + blockSize } result := sha digest } inStream close traceln("hashed: " + result) ^result } def readOnlyToFileCopierMaker new(myFile) { ^def fileCopier { to copyEventually(a,farProgressObserver,c,d) { farProgressObserver <- copyFailed def [dead,resolver] := PromiseMaker() resolver smash(makeErr("readOnlyFile")) ^dead } match _ {^null} } } def writeableToFileCopierMaker new(myFile) { define myOutputStream := null define myTempFile := null define myRemoteProgressObserver := null define [copyPromise,resolver] := PromiseMaker() ^define fileCopier { to copyEventually(farFile, farProgressObserver, farLastResortForwarderToSelf, farLastResortForwarderToFarFile) { traceln("into copy eventually" + farProgressObserver) myTempFile := file: ((myFile getAbsolutePath) + ".tmp") traceln("did temp file creation") def sendBytesRequest(fromCopier,toCopier) { def fileVow := null if (myTempFile exists) { traceln("temp file exists") def hash := fileHash(myTempFile, myTempFile length) fileVow := fromCopier <- sendToPartialFile(toCopier, myTempFile length, hash) } else if (myFile exists) { traceln("about to hash in file copier") def hash := fileHash(myFile, myFile length) fileVow := fromCopier <- sendToExistingFile(toCopier, myFile length, hash) } else { fileVow := fromCopier <- sendByteBlocks(toCopier) } ^fileVow } def fp := sendBytesRequest(farFile, fileCopier) fp <- whenResolved(def obs(connection) { if (E isBroken(connection)) { sendBytesRequest (farLastResortForwarderToFarFile, farLastResortForwarderToSelf) traceln("using forwarders to copy file") farLastResortForwarderToFarFile <- whenBroken(def o2(p2) { resolver smash(makeErr ("lost forwarded file copy connection" + p2)) farProgressObserver copyFailed }) } else { farFile <- whenBroken(def o3(p3) { resolver smash(makeErr ("lost file copy connection")) farProgressObserver copyFailed }) } }) myRemoteProgressObserver := farProgressObserver ^copyPromise } to amountBeingSent(amount) {myRemoteProgressObserver <-setFileSize(amount)} to receiveByteBlock(count,bytes) { if (myOutputStream == null) {myOutputStream := E call(io("FileOutputStream"), "new(String)", [(myTempFile getAbsolutePath)]); traceln("receiveBytes made stream")} traceln("receiving bytes") myOutputStream write(bytes,0,count) try {myOutputStream flush()} catch e{} myRemoteProgressObserver <- updateCount(count) } to existingFileIsFine { myRemoteProgressObserver <- completed resolver resolve(true) } to partialFileIsFine { traceln("in partialIsFine") myOutputStream := E call(io("RandomAccessFile"), "new(File, String)",[myTempFile,"rw"]) myOutputStream skipBytes(myTempFile length) traceln("should have skipped by now") } to allBytesSent() { myOutputStream close() if (myFile exists) {myFile delete} myTempFile renameTo(myFile) myRemoteProgressObserver <- completed resolver resolve(true) } } } def toFileCopierMaker := writeableToFileCopierMaker def fromFileCopierMaker new(myFile) { ^define fileCopier { to sendByteBlocks(farRecipient, startIndex) { traceln("send bytes recipient:" + farRecipient) farRecipient <- amountBeingSent(myFile length - startIndex) def inStream := E call(io("FileInputStream"), "new(String)", [(myFile getAbsolutePath)]) inStream skip (startIndex) def blockSize := 50000 def sendRemainingBlocks() { def bytesAvailable := inStream available() if (bytesAvailable > 0) { if (bytesAvailable < blockSize) { blockSize := bytesAvailable } def bytes := byte[blockSize] def count := inStream read(bytes) traceln("about to send receiveByteBlock for" + (myFile getAbsolutePath)) def sentPromise := farRecipient <- receiveByteBlock(count,bytes) sentPromise <- whenResolved (def obs(sent) { if (E isBroken(sent)) { traceln("lost connection transferrring file: " + sent) } else { sendRemainingBlocks() } }) } else { inStream close() farRecipient <- allBytesSent() } } sendRemainingBlocks () } to sendByteBlocks(farRecipient) {fileCopier sendByteBlocks(farRecipient, 0)} to sendToExistingFile(farRecipient, farSize, farHash) { if (myFile length == farSize && fileHash(myFile, myFile length) == farHash ) { traceln("copy file is duplicate") farRecipient <- existingFileIsFine } else { traceln("copy file is not duplicate") fileCopier sendByteBlocks(farRecipient) } } to sendToPartialFile(farRecipient, farSize, farHash) { if (myFile length >= farSize && fileHash(myFile, farSize) == farHash ) { traceln("partial file is good:" + farSize + "my size" +myFile length) farRecipient <- partialFileIsFine fileCopier sendByteBlocks(farRecipient, farSize) } else { traceln("partial file is not duplicate") fileCopier sendByteBlocks(farRecipient) } } } } //FileModel define fileModelMaker new(myFile) { ^define fileModel { to getFromCopier { ^ fromFileCopierMaker new(myFile) } to getToCopier{^toFileCopierMaker new(myFile)} delegate {^myFile} } } define buildFilePopup(invokingComponent, invokingNavWindow) { def popup := uiSet swing("JPopupMenu") new("File Ops") uiSet addMenuItem(popup,"New File", "newFile", invokingNavWindow) uiSet addMenuItem(popup,"Edit","editFile", invokingNavWindow) uiSet addMenuItem(popup,"Open Edesk", "openEdesk", invokingNavWindow) uiSet addMenuItem(popup,"Copy","copy",invokingNavWindow) uiSet addMenuItem(popup,"Paste", "paste", invokingNavWindow) uiSet addMenuItem(popup, "Delete", "delete", invokingNavWindow) uiSet addMenuItem(popup, "Rename", "rename", invokingNavWindow) uiSet addMenuItem(popup,"Properties", "properties", invokingNavWindow) popup show(invokingComponent, 5, 5) } def buildDirPopup(invokingComponent, invokingNavWindow) { def popup := uiSet swing("JPopupMenu") new("Dir Ops") uiSet addMenuItem(popup,"New Folder", "makeDir", invokingNavWindow) uiSet addMenuItem(popup,"Copy","copyDir",invokingNavWindow) uiSet addMenuItem(popup,"Paste", "paste", invokingNavWindow) uiSet addMenuItem(popup, "Delete", "deleteDir", invokingNavWindow) uiSet addMenuItem(popup, "Rename", "renameDir", invokingNavWindow) traceln("added menuitm") popup show(invokingComponent, 5, 5) } //creating an empty set, working around bad initial capacity bug for empty startups //close whole app when windowset returns to zero size define windowSet := [] asKeys diverge define standardWindow (title, windowClosingHandler) { define mainFrame := uiSet swing("JFrame") new(title) define mainPane := mainFrame.contentPane define border := uiSet swing("BoxLayout") new(mainPane,1) mainPane.layout := border; windowSet[mainFrame] := mainFrame define windowListener { to windowClosing(event) { windowClosingHandler windowClosing() } to windowClosed(event) { windowSet removeKey(mainFrame) if (windowSet size == 0) { interp continueAtTop } } match _ {} } mainFrame addWindowListener(windowListener) ^mainFrame } define progressWindowMaker new(title) { def fileSize := 1000000000 ^define progressWindow := { define myFrame := standardWindow(title,progressWindow) //define myProgressPane := E call(uiSet swing("JProgressBar"), "new(String)",[" "]) def myProgressPane := uiSet swing("JProgressBar") new() myProgressPane setStringPainted(true) uiSet addComponents(myFrame.contentPane,[myProgressPane]) myFrame pack() myFrame show() ^define progressWindow { to setProgress(amountCopied) { def percent := (amountCopied *100) _/ fileSize myProgressPane.value := (percent) myProgressPane.string := percent toString + "%" } to setFileSize(size) { fileSize := size } to windowClosing() {} to closeWindow() {myFrame dispose()} } } } define fileProgressObserverMaker new(title, farFile) { define myWindow := progressWindowMaker new(title) define bytesSent := 0 def localFailed() {myWindow closeWindow} farFile <- whenBroken(def o(p) { localFailed() }) ^define fileProgressObserver { to completed() { traceln("completed file transfer!") myWindow closeWindow() } to setFileSize(theSize) {myWindow.fileSize := theSize} to updateCount(countIncrement) { bytesSent := bytesSent + countIncrement myWindow.progress := bytesSent } to copyFailed() { localFailed() } } } def fileProgressObserverStub { match _ {} } def popAboutBox() { def text := "For Help with Securit-Edesk, see http://www.skyhunter.com/marcs/securit-Edesk-help.html Copyright 1999 Marc Stiegler. All rights reserved. This software covered by the Mozilla license. For details see http://www.skyhunter.com/marcs/securit-Edesk-license.html" eDialogPromiser new("About Securit-Edesk", text, null, ["OK"]) } //QuickEdit define quickEditMaker new(myFilePromise) { ^define quickEdit := { def myText := myFilePromise <- getText() def canWrite := myFilePromise <- canWrite() def myFileName := myFilePromise <- getName() def closingInProcess := false define mainFrame := standardWindow("",quickEdit) define mainPane := mainFrame.contentPane mainFrame setDefaultCloseOperation(uiSet swing("WindowConstants") DO_NOTHING_ON_CLOSE) define border := uiSet awt("BorderLayout") new() mainPane.layout := border def saveButton := uiSet newButton ("Save","save",quickEdit) def textPane := uiSet swing("JTextArea") new() textPane.lineWrap := true textPane.tabSize := 4 def scrollingTextPane := uiSet swing("JScrollPane") new(uiSet swing("ScrollPaneConstants") VERTICAL_SCROLLBAR_ALWAYS, uiSet swing("ScrollPaneConstants") HORIZONTAL_SCROLLBAR_NEVER) uiSet addComponents(scrollingTextPane getViewport, [textPane]) mainPane add(saveButton,"North") mainPane add(scrollingTextPane, "Center") myFileName <- whenResolved( def obs(o) { if (!(E isBroken(o))) { mainFrame setTitle("Eedit - " + myFileName) saveButton setEnabled(canWrite) textPane setText(myText) mainFrame pack() mainFrame setSize(600,400) mainFrame show() } }) ^define quickEdit { to save() { myText := textPane getText def setPromised := myFilePromise <- setText(myText) setPromised <- whenResolved(def obs(o) { if(E isBroken(o)) { connectionWarning("Save may have failed for: " + myFileName) } }) } to windowClosing() { if (!closingInProcess) { closingInProcess := true def finalText:= textPane getText if (finalText == myText) { mainFrame dispose() } else { def saveDecision := eDialogPromiser new("Modified File " + myFileName, "Save Before Exiting?", null, ["Save", "Exit", "Cancel"]) (saveDecision <- getClickedButton) <- whenResolved (def o(answer) { closingInProcess := false if (answer == null) { answer := "Cancel" } if (answer =="Save") { traceln("into save") quickEdit save mainFrame dispose } else if (answer == "Exit") { myText := finalText mainFrame dispose } }) } } } } } } //NavigatorWindow define navigatorWindowMaker new(myFtController, myDiskNavigator) { ^define navigatorWindow := { def myStorageName := myDiskNavigator <- getStorageName define navFrame := standardWindow("", navigatorWindow) myStorageName <- whenResolved(def obs(o) { navFrame.title := myStorageName }) define mainPane := navFrame.contentPane define border := uiSet awt("BorderLayout") new() mainPane.layout := border traceln("about to make listpane") define noScrollDirPane := uiSet swing("JList") new() define dirPane := uiSet swing("JScrollPane") new(noScrollDirPane); def dirPaneListener{ to mouseClicked(theEvent) { if (theEvent getClickCount() > 1) { navigatorWindow openDir() } } match _ {} } noScrollDirPane addMouseListener(dirPaneListener) define noScrollFilePane := uiSet swing("JList") new() define filePane := uiSet swing("JScrollPane") new(noScrollFilePane) def popButton := uiSet newButton("File Ops", "popupFileMenu",navigatorWindow) def openRemoteButton := uiSet newButton("Remote Edesk","openRemote", navigatorWindow) def gotoButton := uiSet newButton("Goto", "gotoFieldName", navigatorWindow) uiSet fixWidth(gotoButton) def dupWinButton := uiSet newButton("New Window", "dupWindow", navigatorWindow) def refreshButton := uiSet newButton("Refresh", "refresh", navigatorWindow) def aboutButton := uiSet newButton("About/Help", "aboutBox", navigatorWindow) def upButton := uiSet newButton("Up","goUp", navigatorWindow) def homeButton := uiSet newButton("Home","goHome", navigatorWindow) def popDirButton := uiSet newButton("Folder Ops", "popupDirMenu", navigatorWindow) def statusPanel := uiSet swing("JLabel") new() uiSet baseWidth(statusPanel) traceln("made buttons") def fullPathTextField := uiSet swing("JTextField") new() def enterKeyListener{ to keyPressed(theEvent) { if (theEvent getKeyCode == import:java.awt.event.KeyEvent VK_ENTER) { navigatorWindow gotoFieldName() } } match _ {} } fullPathTextField addKeyListener(enterKeyListener) uiSet baseWidth(fullPathTextField) traceln("about to build refreshLocal") def setStatus(status) {statusPanel setText(status)} def refreshLocal() { traceln("about to refreshLocal" + myDiskNavigator) setStatus("Refreshing Window...") def currentPath := myDiskNavigator <- getCurrentPath() def dirsPromise := myDiskNavigator <- listCurrentSubdirectoriesAndFiles() dirsPromise <- whenResolved(define observer(dirsFilesTuple) { if (E isBroken(dirsFilesTuple)) { connectionWarning("Screen Refresh Failed\n" + dirsFilesTuple) } else { E call(noScrollDirPane, "setListData(Object[])", [dirsFilesTuple[0]]); E call(noScrollFilePane,"setListData(Object[])", [dirsFilesTuple[1]]); fullPathTextField.text := currentPath navFrame repaint() } setStatus("Refresh done.") }) } def propertiesList(theList) { if (theList != null) { setStatus("Showing files properties...") for each in theList { def farFile := myDiskNavigator <- getFileNamed(each) def path := farFile <- getPath def canonical := farFile <- getCanonicalPath def fileSize := farFile <- length def lastModified := farFile <- lastModified lastModified <- whenResolved(def o(p) { if (E isBroken(p)) { connectionWarning(p) } else { def display := "Full Path:\n " + path + "\n" + "Canonical Path: \n " + canonical + "\n" + "Size: \n " + fileSize + " bytes\n" + "Last Modified Designation: \n " + lastModified eDialogPromiser new("Properties For " + each, display, null, ["OK"]) } }) } setStatus("") } } def renameList(theList) { if (theList != null && theList size > 0) { setStatus("Renaming files...") for each in theList { def newName := uiSet swing("JOptionPane") showInputDialog (null, "New Name for: " + each , "Rename" , uiSet swing("JOptionPane") QUESTION_MESSAGE, null, null, each) if (newName != null && newName size >0) { myDiskNavigator <- rename(each, newName) } } navigatorWindow refresh } } def deleteList(theList){ if (theList != null && theList size > 0) { setStatus("Deleting files...") for each in theList { myDiskNavigator <- deleteFileObject(each) } navigatorWindow refresh } } def copyList(theList) { if (theList != null && theList size > 0) { def localNavigator := myDiskNavigator <- dupNavigator() def files := [] traceln("copyfile: " + theList) for each in theList { files := files + [localNavigator <-getFileNamed (each)] } myFtController copyFrom (files, localNavigator) } } def bottomLeftColumn := uiSet swing("JPanel") new() bottomLeftColumn.layout := uiSet awt("BorderLayout") new() def bottomLeftColumnButtonsColumn := uiSet swing("Box") new(1) def bottomRightColumn := uiSet swing("JPanel") new() bottomRightColumn.layout := uiSet awt("BorderLayout") new() def row1Panel := uiSet swing("Box") new(0) def row2Panel := uiSet swing("Box") new(0) def northPanel := uiSet swing("Box") new(1) uiSet addComponents(northPanel ,[row1Panel, row2Panel]) def navButtonPanel := uiSet swing("Box") new(0) def listsRowPanel := uiSet swing("JPanel") new() define listsborder := uiSet awt("GridLayout") new(1,2) listsRowPanel.layout := listsborder traceln("starting add components") uiSet addComponents(row1Panel,[refreshButton, dupWinButton, openRemoteButton, aboutButton]) uiSet addComponents(row2Panel,[gotoButton,fullPathTextField]) uiSet addComponents(listsRowPanel, [bottomLeftColumn, bottomRightColumn]) uiSet addComponents(navButtonPanel,[upButton, homeButton]) uiSet addComponents(bottomLeftColumnButtonsColumn, [popDirButton, navButtonPanel]) bottomLeftColumn add(bottomLeftColumnButtonsColumn, "North") bottomLeftColumn add(dirPane,"Center") //uiSet addComponents(bottomRightColumn, [popButton, filePane]) bottomRightColumn add(popButton,"North") bottomRightColumn add(filePane,"Center") mainPane add(northPanel,"North") mainPane add(listsRowPanel,"Center") mainPane add(statusPanel,"South") //uiSet addComponents(mainPane, [row1Panel , row2Panel, listsRowPanel, statusPanel]) traceln("about to call refreshLocal") refreshLocal() navFrame pack() navFrame show() ^define navigatorWindow { to getDiskNavigator(){^myDiskNavigator} to dupWindow() { def diskNavigator := myDiskNavigator <- dupNavigator() diskNavigator <- whenResolved (def obs(o) { if (E isBroken(o)) { connectionWarning(o) } else { navigatorWindowMaker new(myFtController, diskNavigator) } }) } to aboutBox() {popAboutBox()} to popupFileMenu { buildFilePopup(popButton, navigatorWindow) } to popupDirMenu { buildDirPopup(popDirButton, navigatorWindow) } to gotoFieldName() { myDiskNavigator <-changeToDirectory(fullPathTextField getText) navigatorWindow refresh() } to makeDir() { def newName := uiSet swing("JOptionPane") showInputDialog(navFrame, "Name for New Folder: ", "New Folder", uiSet swing("JOptionPane") QUESTION_MESSAGE) traceln("Dir Name: " + newName) if (newName != null && newName size >0) { myDiskNavigator <- makeDir(newName) } navigatorWindow refresh } to copy () { def copyFileNames := noScrollFilePane getSelectedValues() copyList(copyFileNames) } to copyDir() { def names := noScrollDirPane getSelectedValues() copyList(names) } to paste() { setStatus("Paste/Copying files...") myFtController paste(navigatorWindow) } to getStorageName() {^myStorageName} to refresh() {refreshLocal()} to windowClosing() {navFrame dispose()} to newFile() { def newName := uiSet swing("JOptionPane") showInputDialog(navFrame, "Name for New File: ", "New File", uiSet swing("JOptionPane") QUESTION_MESSAGE) if (newName != null && newName size >0) { myDiskNavigator <- newFile( newName) } navigatorWindow refresh } to editFile() { traceln("into editFile") def fileNames := noScrollFilePane getSelectedValues() if (fileNames != null && fileNames size > 0) { for each in fileNames { quickEditMaker new(myDiskNavigator<-getFileNamed(each)) } } } to rename() { def fileNames := noScrollFilePane getSelectedValues() renameList(fileNames) } to renameDir() { def names := noScrollDirPane getSelectedValues() renameList(names) } to properties() { def fileNames := noScrollFilePane getSelectedValues() propertiesList(fileNames) } to delete() { def fileNames := noScrollFilePane getSelectedValues() deleteList(fileNames) } to deleteDir() { def names := noScrollDirPane getSelectedValues() deleteList(names) } to openDir() { def newDir := noScrollDirPane getSelectedValue() if (newDir != null && newDir size > 0) { noScrollDirPane clearSelection() myDiskNavigator <- changeToSubdirectory(newDir) navigatorWindow refresh } } to goUp() { myDiskNavigator <- goUp() navigatorWindow refresh } to goHome() { myDiskNavigator <- gotoHome() navigatorWindow refresh } to openRemote() {myFtController openRemote()} to openEdesk() { def fileNames := noScrollFilePane getSelectedValues() if (fileNames != null && fileNames size >0) { for each in fileNames { myFtController openEdesk(myDiskNavigator <- getFileNamed(each)) } } } } } } //DiskNavigator define diskNavigatorMaker new(myHomeDirectoryPath, myStorageName,myRootDirPath, makeFileFunction) { traceln("into making disk navigator") def myCurrentDir := makeFileFunction(myHomeDirectoryPath) //file: myHomeDirectoryPath define dirPathString (path) { //makes sure a dir separator is at end def sep := import:java.io.File separator def answerPath := path if (path(path size - 1, path size) == sep) { answerPath :=path } else { answerPath :=path + sep } ^answerPath } def dirPath (theDir) {^ dirPathString(theDir getPath)} define isInRootTree(theDir) { def answer := true if (myRootDirPath != null) { answer := dirPathString(theDir getCanonicalPath) startsWith(myRootDirPath) } ^answer } define setCurrentDir(theDir) { if (theDir exists && isInRootTree(theDir)) {myCurrentDir := theDir} } if (myRootDirPath != null) { myRootDirPath := dirPathString((makeFileFunction(myRootDirPath)) getCanonicalPath) if (isInRootTree(myCurrentDir)) { traceln("home is part of the root tree") } else { println("Home path not part of root tree! Changing...") myCurrentDir := makeFileFunction( myRootDirPath) myHomeDirectoryPath := myRootDirPath } } traceln("making navigator") ^define diskNavigator { //offers MakeAnotherNavigator(homeDirname) returns the navigator uri to dupNavigator() { traceln("into dupnavigator") def newNav := diskNavigatorMaker new(myHomeDirectoryPath, myStorageName, myRootDirPath, makeFileFunction) newNav changeToDirectory (myCurrentDir getAbsolutePath) ^newNav } to getStorageName() {^myStorageName + makeFileFunction label()} to versionNumber() {^versionNumber} to getCurrentPath () { if (! (myCurrentDir exists)) {diskNavigator gotoHome()} ^myCurrentDir getAbsolutePath } to getParentPath() {^myCurrentDir getParent} to newFile(name) { def theFile := makeFileFunction( (dirPath(myCurrentDir) + name)) if (! (theFile exists)) { theFile setText("") } null } to makeDir(dirName) { def fullName := dirPath(myCurrentDir) + dirName (makeFileFunction( fullName)) mkdir() } to gotoHome() { myCurrentDir := makeFileFunction( myHomeDirectoryPath) } to changeToDirectory(fullPathName) {setCurrentDir(makeFileFunction( fullPathName))} to changeToSubdirectory(name) { setCurrentDir(makeFileFunction( (dirPath(myCurrentDir) + name))) traceln(dirPath(myCurrentDir)) } to goUp() {setCurrentDir(makeFileFunction( (myCurrentDir getParent)))} to listCurrentSubdirectoriesAndFiles() { if (! (myCurrentDir exists)) {diskNavigator gotoHome()} def fileobjNames := myCurrentDir list def dirTuple := [] diverge def fileTuple := [] diverge traceln("into list subs, count:" + fileobjNames size) for next in fileobjNames { if ((makeFileFunction( (dirPath(myCurrentDir) + next))) isDirectory) { dirTuple push(next) } else { fileTuple push(next) } } ^[dirTuple sort snapshot, fileTuple sort snapshot] } to getFileNamed(name) { ^fileModelMaker new(makeFileFunction( (dirPath(myCurrentDir) + name))) } to rename(fileName,newName) { (makeFileFunction (dirPath(myCurrentDir) + fileName)) renameTo(makeFileFunction (dirPath(myCurrentDir) + newName)) } to deleteFileObject(fileName) { def fileObj := diskNavigator getFileNamed(fileName) try {fileObj delete} catch e1 {} if (fileObj exists && fileObj isDirectory) { traceln("found undeleted dir") for each in fileObj { if (each isFile) { try {each delete} catch e2{traceln("no file delete" + e2)} } else { def subNavigator := diskNavigator dupNavigator traceln("got sub navigator for delete") subNavigator changeToSubdirectory (fileName) traceln("about to del dir "+ each getName) subNavigator deleteFileObject(each getName) } } try {fileObj delete} catch e3 { traceln("delete folder try 2 failed" + e3)} } } } } def revokableConnectionMaker new(myFtController) { ^def revokableConnection { to getANavigator() { ^myFtController getANavigator() } to versionNumber() {^versionNumber} } } // farOverwriteAnswerer uses state pattern // with different functions for different behaviors // it select the right function with lazy evaluation: // if there's never a preexisting file to consider overwriting, // no overwriting policy request ever goes to the user def overwriteAnswererMaker new() { def alwaysOverwrite(fileName) {^true} def neverOverwrite(fileName) {^false} def askOverwrite(fileName) { def [answerPromise, resolver] := PromiseMaker() def answerDialog := eDialogPromiser new("Overwrite?", "Overwrite file " + fileName + "?", null, ["Yes","No"]) answerDialog <- whenResolved (def obs(o) { resolver resolve (answerDialog.clickedButton == "Yes") }) ^answerPromise } def answerFunctionSelectionAlreadyStarted := false def [answerFunction,functionResolver] := PromiseMaker() def determineOverwritePlan() { answerFunctionSelectionAlreadyStarted := true def planDialog := eDialogPromiser new("OverwritePolicy", "When should files be overwritten?", null, ["Always","Never","After Confirmation"]) planDialog <- whenResolved(def obs(o) { def button := planDialog.clickedButton if (button == "Always") { functionResolver resolve(alwaysOverwrite) }else if (button == "Never") { functionResolver resolve(neverOverwrite) }else {functionResolver resolve(askOverwrite)} }) } def overwriteAnswerer { to promiseOverwriteAnswer(fileName) { if (!answerFunctionSelectionAlreadyStarted) {determineOverwritePlan()} ^answerFunction <- run(fileName) } } ^overwriteAnswerer } def copyFiles(fromNavigator, toNavigator, overwriteAnswerer) { traceln("into copyFiles" + fromNavigator+toNavigator + overwriteAnswerer) def copyVows := vowsMonitorMaker new() def copyBase(farFromFile, farToFile, fileName) { copyVows add(farToFile <- getToCopier <- copyEventually(farFromFile <- getFromCopier, fileProgressObserverMaker new("Copying " + fileName, farToFile), forwarderMaker new(farToFile), forwarderMaker new(farFromFile))) } def filesDirs := fromNavigator <- listCurrentSubdirectoriesAndFiles filesDirs <- whenResolved( def obs(o) { def fileNames := filesDirs[1] for each in fileNames { def nextFromFile := fromNavigator <- getFileNamed(each) def nextToFile := toNavigator <- getFileNamed(each) (nextToFile <- exists) <- whenResolved (def obs(doesExist) { if (!(E isBroken(doesExist)) && doesExist) { def shouldCopy := overwriteAnswerer promiseOverwriteAnswer(each) shouldCopy <- whenResolved(def obs2(o2) { if (shouldCopy) { copyBase(nextFromFile, nextToFile, each) } }) } else if (!(E isBroken(doesExist))) { copyBase(nextFromFile, nextToFile, each) } }) } copyVows finishAll }) ^ copyVows promiseFinish } def marshalledDirPromiser new (farOuterNavigator, farDir) { traceln("make marshall" + farOuterNavigator + farDir) def [marshalledDirPromise, resolver] := PromiseMaker() def farDirNavigator := null def dirExists := farDir <- exists def dirName := farDir <- getName def dirCanonicalPath := farDir <- getCanonicalPath def dirPath := farDir <- getPath def fillWhenDirExists() { farDirNavigator := farOuterNavigator <- dupNavigator farDirNavigator <- changeToSubdirectory (dirName) dirExists := true } def marshalledDir := { dirPath <- whenResolved (def obs(o) { if (!(E isBroken(o))) { if (dirExists) {fillWhenDirExists()} resolver resolve(marshalledDir) traceln("dir paths: " + dirCanonicalPath + " :" + dirPath) } else { resolver smash(makeErr ("dead dir: "+ o)) } }) ^def marshalledDir { to getDir {^farDir} to getOuterNavigator{^farOuterNavigator} to getDirNavigator{^farDirNavigator} to exists {^dirExists} to getName { ^dirName} to promiseMarshalledSubDir(subName) { def farSubdir := farDirNavigator <- getFileNamed(subName) ^ marshalledDirPromiser new(farDirNavigator,farSubdir) } to makeSelf { def makePromise := null if (!dirExists) { makePromise := farDir <-mkdir fillWhenDirExists() } ^makePromise } to isProperSubDir {^dirCanonicalPath toLowerCase == dirPath toLowerCase} to getCanonicalPath{^dirCanonicalPath} to getPath{^dirPath} } } ^ marshalledDirPromise } def paster { to paste(farFromFiles, fromDiskNavigator, toNavigatorWindow) { traceln("into paster paste:" + farFromFiles + fromDiskNavigator + toNavigatorWindow) def toDiskNavigator := toNavigatorWindow getDiskNavigator <- dupNavigator def allDone := vowsMonitorMaker new() def myOverwriter := overwriteAnswererMaker new() for each in farFromFiles { traceln("got each file" + each) def isDir := each <- isDirectory() def [nextCopyPromise, nextResolver] := PromiseMaker() allDone add(nextCopyPromise) isDir <- whenResolved( def obs (o) { if (! (E isBroken(o))) { if (isDir) { def nextPromise := paster copyDirBegin(each, fromDiskNavigator, toDiskNavigator, myOverwriter) nextResolver resolve(nextPromise) }else{ def nextPromise := paster pasteFile(each, toDiskNavigator, toNavigatorWindow) nextResolver resolve(nextPromise) } } }) } allDone finishAll allDone promiseFinish <- whenResolved (def o(p) { traceln("about to refresh after pasting files") toNavigatorWindow refresh if (E isBroken(p)) { connectionWarning("Some files may not have been copy/pasted.\n" + p) } }) } to pasteFile(fromFilePromise, toDiskNavigator, toNavigatorWindow) { traceln("into pasteFile") def [finishPromise,resolver] := PromiseMaker() def startCopyTo(target,fromName) { traceln("about to copy in pastefile") def finalPromise := (target <- getToCopier) <- copyEventually(fromFilePromise <- getFromCopier, fileProgressObserverMaker new("Copying " + fromName, target), forwarderMaker new(target), forwarderMaker new(fromFilePromise)) traceln("about to start resolver in pastefile") finalPromise <- whenResolved(def o(p) { traceln("about to resolve in pastefile") resolver resolve(p) }) } def fromName := fromFilePromise <- getName() fromName <- whenResolved(def obs(o) { if (E isBroken(o)) { connectionWarning(o) } else { traceln("paste is getting target" + o) def target := toDiskNavigator <- getFileNamed(fromName) (target <- exists())<- whenResolved(def obs2(fileExists) { if (fileExists) { traceln("file exists: " + fromName) def result := uiSet swing("JOptionPane") showInputDialog (null, "Confirm or change name, or cancel", "File " + fromName + " already exists", uiSet swing("JOptionPane") QUESTION_MESSAGE, null, null, fromName + "") if (result != null) { if (result != fromName) { target := toDiskNavigator <- getFileNamed(result) } startCopyTo(target,fromName) } else { resolver resolve("user canceled") } } else { traceln("about to copyeventually") startCopyTo(target,fromName) } }) } }) ^finishPromise } to copyDirCautiously(marshalledFromDir, marshalledToDir, createdDirPaths, overwriteAnswerer) { traceln("in copyDirCautiously" + marshalledFromDir + " :" +marshalledToDir) //only continue copying if the fromDir is not something we just // created as a todir(indicating we are copying a dir into its own subdir) //and if the fromdir is not a symlink running off to someplace odd) traceln("is proper subdir " + (marshalledFromDir isProperSubDir) toString) def copyVows := vowsMonitorMaker new() if ((! (createdDirPaths contains(marshalledFromDir getCanonicalPath))) && marshalledFromDir isProperSubDir) { traceln("continuing copying in cautiously") if (! (marshalledToDir exists)) { marshalledToDir makeSelf traceln("made dir") createdDirPaths push(marshalledToDir getCanonicalPath) } copyVows add(copyFiles(marshalledFromDir getDirNavigator, marshalledToDir getDirNavigator,overwriteAnswerer)) def filesDirs := marshalledFromDir getDirNavigator <- listCurrentSubdirectoriesAndFiles filesDirs <- whenResolved(def o(p) { def dirs := filesDirs[0] for each in dirs { traceln("copying dir: " + each) def [subDirPromise,subDirResolver] := PromiseMaker() copyVows add(subDirPromise) def fromSubNavigator := marshalledFromDir getDirNavigator def marshalledFromSubDir := marshalledDirPromiser new(fromSubNavigator, fromSubNavigator <- getFileNamed(each)) def toSubNavigator := marshalledToDir getDirNavigator def marshalledToSubDir := marshalledDirPromiser new(toSubNavigator, toSubNavigator <- getFileNamed(each)) def dirsReadyVow := promiseAllDone([marshalledToSubDir, marshalledFromSubDir]) when (dirsReadyVow) -> done(dirsReady) { subDirResolver resolve(paster copyDirCautiously (marshalledFromSubDir, marshalledToSubDir, createdDirPaths, overwriteAnswerer)) } catch e { connectionWarning(e) subDirResolver smash(makeErr ("Couldn't connect to directory: " + e)) } } copyVows finishAll }) } else {copyVows finishAll} ^copyVows promiseFinish } to copyDirBegin(farFromDir, farFromDisk, toDiskNavigator, overwriteAnswerer) { def farToDisk := toDiskNavigator <- dupNavigator def fromDir := marshalledDirPromiser new(farFromDisk,farFromDir) def createdDirPaths := [] diverge def [dirCopyCompletePromise, dirCopyCompleteResolver] := PromiseMaker() fromDir <- whenResolved( def obs(o) { def farToDir := farToDisk <- getFileNamed(fromDir getName) def toDir := marshalledDirPromiser new(farToDisk, farToDir) toDir <- whenResolved (def obs2(o2) { if (!(E isBroken(o2))) { def copyPromise := paster copyDirCautiously (fromDir, toDir, createdDirPaths, overwriteAnswerer) dirCopyCompleteResolver resolve(copyPromise) } else { dirCopyCompleteResolver smash(makeErr ("Lost connection: " +o2)) connectionWarning(o2) } }) }) ^dirCopyCompletePromise } } //ftController define ftControllerMaker new() { ^define ftController := { def copyBuffer := null def copyBufferDiskNavigator := null define commandArgs := interp getArgs traceln("command arguments" + commandArgs) define myStorageName := commandArgs[0] define myIsGui := commandArgs[1] == "gui" define myHomeDirectoryPath := commandArgs[2] def myCapabilityFilePath := null if (commandArgs size > 3) {myCapabilityFilePath := commandArgs[3]} def myRootDirPath := null if (commandArgs size >4) {myRootDirPath := commandArgs[4]} def myMakeFileFunction := makeWriteFile if (commandArgs size > 5 && commandArgs[5] != "write") { traceln("Read Only File System") myMakeFileFunction := makeReadFile toFileCopierMaker := readOnlyToFileCopierMaker } define myHomeNavigator := diskNavigatorMaker new(myHomeDirectoryPath, myStorageName, myRootDirPath, myMakeFileFunction) if (!myIsGui) { def capFile := file: myCapabilityFilePath capFile.text := makeURIFromObject(revokableConnectionMaker new(ftController)) println("Disk Navigator Operational") } else { navigatorWindowMaker new(ftController, myHomeNavigator) } def getRemoteConnectionURI() { def uri := null def blah := uiSet swing("JFrame") new() define dialog := uiSet awt("FileDialog") new(blah, "Select an Edesk erights file") dialog show define path := dialog.file if (path != null) { path := dialog.directory + path uri := (file: path).text traceln("connection is:" + uri) } ^uri } def buildNavWindow(uri) { traceln("in buildnavwin, uri:" + uri) def connector:= getObjectFromURI(uri) traceln("connector is" + connector) def navigator := connector <- getANavigator() def versionPromise := (connector <-versionNumber()) versionPromise <- whenResolved(define observer(version) { traceln("ha! resolved promiste") if(E isBroken(version)) { connectionWarning("Remote Navigator Not Acquired\n" + version) traceln("connection failure" + version) } else { if (version == versionNumber) { navigatorWindowMaker new(ftController, navigator) } else { connectionWarning("Wrong Version") } } }) } ^define ftController { to copyFrom(fromFilePromises,fromDiskNavigator) { copyBuffer := fromFilePromises copyBufferDiskNavigator := fromDiskNavigator <- dupNavigator } to paste(navigatorWindow) { paster paste(copyBuffer, copyBufferDiskNavigator, navigatorWindow) } to getANavigator() { ^diskNavigatorMaker new(myHomeDirectoryPath, myStorageName, myRootDirPath, myMakeFileFunction) } to openRemote() { def uri := getRemoteConnectionURI() if (uri != null) { buildNavWindow(uri) } } to openEdesk(filePromise) { def uri := filePromise <- getText uri <- whenResolved(def obs (o) { traceln("remote Edesk:" + uri) if (E isBroken(o)) { connectionWarning("No Edesk server") }else{ buildNavWindow(uri) } }) } } } } introducer onTheAir traceln("about to make controller") define baseController := ftControllerMaker new() interp blockAtTop