-- WFileInterface.mesa -- last edit: Maxwell, July 14, 1982 10:35 am (search for "JTM") -- last edit: Stewart, March 28, 1983 5:33 pm -- last edit: McGregor, 20-Apr-82 14:45:11 -- last edit: MBrown, 29-Mar-82 15:10:31 -- last edit: Paul Rovner, October 28, 1982 5:51 pm -- last edit: Russ Atkinson, April 7, 1983 12:03 am DIRECTORY Buttons USING [Button, ButtonProc, Create, SetDisplayStyle], Commander USING [CommandProc, Register], Containers USING [ChildXBound, ChildYBound], Graphics USING[SetCP], GraphicsOps USING[BitmapRep, DrawBitmap], IO USING[Close, CreateOutputStreamToRope, Flush, GetOutputStreamRope, Handle, PutF, PutFR, rope, SetEcho, time], Labels USING[Create, Set], -- List USING [Remove], Process USING [Detach, Pause, SecondsToTicks], Rope USING [Cat, Equal, Fetch, Find, Index, Length, ROPE, SkipTo, Substr, Translate, TranslatorType], Rules USING [Create], Runtime USING [GetBcdTime], STP USING [Destroy], TypeScript USING [-- CharProc, -- Create -- GetLine, PutChar --], VFTOps USING [BuildOuter, CloseCommand, ConfirmAbort, FreeTask, FTPCommand, Functions, GetTheFile, GiveCommand, GiveConfirm, Handle, LeftSmallMap, RGDestroy, RightSmallMap, SmallMap, StopFTP, VFTObject], ViewerClasses USING [DestroyProc, PaintProc, Viewer, ViewerClass, ViewerClassRec], ViewerOps USING [AddProp, -- CloseViewer, -- CreateViewer, FetchProp, FetchViewerClass, PaintViewer, RegisterViewerClass], ViewerIO USING [CreateViewerStreams], ViewerTools USING [GetContents, SetContents, SetSelection]; WFileInterface: MONITOR LOCKS self.LOCK USING self: VFTOps.Handle IMPORTS Buttons, Commander, Containers, Graphics, GraphicsOps, IO, Labels, Process, Rope, Rules, Runtime, STP, TypeScript, VFTOps, ViewerOps, ViewerIO, ViewerTools EXPORTS VFTOps = BEGIN -- CommentRope: Rope.ROPE _ "FileTool Notes:\n Control-DEL doesn't work, use 'Stop!' instead.\n User name and password acquired from UserExec.\n Entry of connect password must end with CR, DEL or Space.\n 'Directory:' will accept either\n [Indigo]Top>\n /Indigo/Cedar/Top/\n 'Directory:' must start with a '/ or '[.\n Except for Delete operations, the file name specification, e.g. *.mesa, may be in either of the fields 'FileName(s):,' or 'Local:.'\n DF File operations always use 'FileName(s):' for individual file names. Last component of df file name must be in 'DF File:' field. Use Control-Del in UserExec vuewer to abort DF operations. ExportsOnly is like bringover /p switch.\n Remote-Delete requires a name in 'FileName(s):.'\n Local-Delete requires a name in 'Local:.'\n Verify requests user approval of each file operation. DF operations are like Bringover /a if Verify is off.\n Update > transfers if the source file is newer than the destination file.\n Update a> transfers if the source file is newer or if the destination file does not exist.\n"; -- vftlist: LIST OF REF ANY _ NIL; fileToolClass: ViewerClasses.ViewerClass _ NEW[ViewerClasses.ViewerClassRec _ ViewerOps.FetchViewerClass[$Container]^]; -- deltas from Container class stored in Init Proc elsewhere in this module bitmapClass: ViewerClasses.ViewerClass _ NEW[ViewerClasses.ViewerClassRec _ [ paint: BitmapPaint ]]; BaselineFix: INTEGER = 3; TWidth: INTEGER = 500; THT: INTEGER = 300; MsgHT: INTEGER = 16; SWHeight: INTEGER = 40; CHT: INTEGER = 16; PCol0: INTEGER = 0; PCol1: INTEGER = 230; PCol2: INTEGER = 400; CCol0: INTEGER = 0; CCol1: INTEGER = 78; CCol2: INTEGER = 182; CCol3: INTEGER = 290; CCol4: INTEGER = 370; -- Parameter support procedures UpdateButtonProc: Buttons.ButtonProc = TRUSTED { vft: VFTOps.Handle _ NARROW[clientData]; viewer: Buttons.Button _ NARROW[parent]; SELECT viewer FROM vft.updateButton => vft.update _ BoolButton[b: viewer, p: vft.update]; vft.updateAlwaysButton => vft.updateAlways _ BoolButton[b: viewer, p: vft.updateAlways]; vft.verifyButton => vft.verify _ BoolButton[b: viewer, p: vft.verify]; vft.exportsOnlyButton => vft.publiconly _ BoolButton[b: viewer, p: vft.publiconly]; ENDCASE => ERROR; }; OptionsButtonProc: Buttons.ButtonProc = TRUSTED { vft: VFTOps.Handle _ NARROW[clientData]; viewer: Buttons.Button _ NARROW[parent]; SELECT viewer FROM vft.typeOption => vft.newOptions[type] _ BoolButton[viewer, vft.newOptions[type]]; vft.bytesOption => vft.newOptions[bytes] _ BoolButton[viewer, vft.newOptions[bytes]]; vft.pagesOption => vft.newOptions[pages] _ BoolButton[viewer, vft.newOptions[pages]]; vft.authorOption => vft.newOptions[author] _ BoolButton[viewer, vft.newOptions[author]]; vft.createOption => vft.newOptions[create] _ BoolButton[viewer, vft.newOptions[create]]; vft.writeOption => vft.newOptions[write] _ BoolButton[viewer, vft.newOptions[write]]; vft.readOption => vft.newOptions[read] _ BoolButton[viewer, vft.newOptions[read]]; vft.abortOption => { vft.newOptions _ vft.options; DelayChangeCommandSubwindow[vft, commands]; }; vft.applyOption => { vft.options _ vft.newOptions; DelayChangeCommandSubwindow[vft, commands]; }; ENDCASE => ERROR; }; BoolButton: PROC [b: Buttons.Button, p: BOOL] RETURNS [BOOL] = { p _ NOT p; SetBoolButton[b, p]; RETURN[p]; }; SetBoolButton: PROC [b: Buttons.Button, p: BOOL] = { IF p THEN Buttons.SetDisplayStyle[b, $WhiteOnBlack] ELSE Buttons.SetDisplayStyle[b, $BlackOnWhite]; }; CommandButtonProc: Buttons.ButtonProc = TRUSTED { vft: VFTOps.Handle _ NARROW[clientData]; viewer: Buttons.Button _ NARROW[parent]; SELECT viewer FROM vft.retrieveButton => Command[vft, retrieve, TRUE]; vft.storeButton => Command[vft, store, TRUE]; vft.localListButton => Command[vft, localList, FALSE]; vft.remoteListButton => Command[vft, remoteList, TRUE]; vft.listOptionsButton => { DelayChangeCommandSubwindow[vft, options]; SetBoolButton[vft.typeOption, vft.newOptions[type]]; SetBoolButton[vft.bytesOption, vft.newOptions[bytes]]; SetBoolButton[vft.authorOption, vft.newOptions[author]]; SetBoolButton[vft.createOption, vft.newOptions[create]]; SetBoolButton[vft.writeOption, vft.newOptions[write]]; SetBoolButton[vft.readOption, vft.newOptions[read]]; SetBoolButton[vft.pagesOption, vft.newOptions[pages]]; }; vft.closeButton => { -- meed interlock with dataTransferring? Labels.Set[vft.msg, " "]; VFTOps.CloseCommand[vft]; }; vft.dfGetButton => Command[vft, dfGet, FALSE]; vft.dfGetBothButton => Command[vft, dfGetBoth, FALSE]; vft.localDeleteButton => Command[vft, localDelete, TRUE]; vft.remoteDeleteButton => Command[vft, remoteDelete, TRUE]; ENDCASE => ERROR; }; LocalRemoteGet: PROC [self: VFTOps.Handle, cmd: VFTOps.FTPCommand] = { VFTOps.GetTheFile[self, cmd=dfGetBoth]; NeedCommand[self]; }; StrButtonProc: Buttons.ButtonProc = TRUSTED { vft: VFTOps.Handle _ NARROW[clientData]; viewer: Buttons.Button _ NARROW[parent]; SELECT viewer FROM vft.stringFileNames => StartOther[vft.fileNamesBox]; vft.stringLocal => StartOther[vft.localBox]; vft.stringDFFile => StartOther[vft.dfFileBox]; vft.stringConnect => StartOther[vft.connectBox]; vft.stringDirectory => StartOther[vft.directoryBox]; ENDCASE => ERROR; }; StrCPasswordButtonProc: Buttons.ButtonProc = TRUSTED { vft: VFTOps.Handle _ NARROW[clientData]; -- PCharProc: TypeScript.CharProc = { -- SELECT char FROM -- ' , '\l, '\n, '\177 => RETURN[process: FALSE, activate: TRUE]; -- '\b => RETURN[process: TRUE, activate: FALSE]; -- ENDCASE => { -- TypeScript.PutChar[ts, '*]; -- RETURN[process: FALSE, activate: FALSE]; -- }; -- }; --IF vft.cPasswordActive THEN RETURN; --vft.cPasswordActive _ TRUE; --Buttons.SetDisplayStyle[button: vft.stringCPassword, style: $BlackOnGrey]; ViewerTools.SetContents[vft.cpasswordBox, "Doesn't Work!"]; --ViewerTools.SetSelection[vft.cpasswordBox, NIL]; -- vft.cPasswordRope _ TypeScript.GetLine[ts: vft.cpasswordBox, charProc: PCharProc]; --Buttons.SetDisplayStyle[button: vft.stringCPassword, style: $BlackOnWhite]; --vft.cPasswordActive _ FALSE; }; StartOther: PROC [v: ViewerClasses.Viewer] = { IF v#NIL THEN ViewerTools.SetSelection[v, NIL]; }; ConfirmButtonProc: Buttons.ButtonProc = TRUSTED { vft: VFTOps.Handle _ NARROW[clientData]; viewer: Buttons.Button _ NARROW[parent]; ca: VFTOps.ConfirmAbort _ SELECT viewer FROM vft.confirmButton => confirm, vft.denyButton => skip, vft.stopButton => stop ENDCASE => ERROR; ChangeCommandSubwindow[vft, empty]; VFTOps.GiveConfirm[vft, ca]; }; -- Display routines PostComment: PUBLIC PROC [self: VFTOps.Handle, s: Rope.ROPE] = { Labels.Set[self.msg, s]; self.log.PutF["%s\n", IO.rope[s]]; }; InvertIndicator: PUBLIC PROC [self: VFTOps.Handle]= { SELECT self.data.indicator FROM left => self.data.indicator _ right; off => self.data.indicator _ left; right => self.data.indicator _ left; ENDCASE => ERROR; ViewerOps.PaintViewer[self.transferBox, client, FALSE]; }; DelayChangeCommandSubwindow: PROC [self: VFTOps.Handle, function: VFTOps.Functions] = { IF function # self.data.function THEN { SELECT function FROM empty => self.commandSW.child _ self.transferChildren; commands => self.commandSW.child _ self.commandChildren; confirms => self.commandSW.child _ self.confirmChildren; options => self.commandSW.child _ self.optionsChildren; ENDCASE => ERROR; self.data.function _ function; self.data.indicator _ off; Process.Detach[FORK DelayPaintViewer[viewer: self.commandSW]]; }; }; DelayPaintViewer: PROC [viewer: ViewerClasses.Viewer] = { Process.Pause[Process.SecondsToTicks[1]]; ViewerOps.PaintViewer[viewer: viewer, hint: all]; }; ChangeCommandSubwindow: PROC [self: VFTOps.Handle, function: VFTOps.Functions] = { IF function # self.data.function THEN { SELECT function FROM empty => self.commandSW.child _ self.transferChildren; commands => self.commandSW.child _ self.commandChildren; confirms => self.commandSW.child _ self.confirmChildren; options => self.commandSW.child _ self.optionsChildren; ENDCASE => ERROR; self.data.function _ function; self.data.indicator _ off; ViewerOps.PaintViewer[viewer: self.commandSW, hint: all]; }; }; SlashToRightAngle: Rope.TranslatorType = TRUSTED { new _ IF old = '/ THEN '> ELSE old; }; Command: PROC [self: VFTOps.Handle, cmd: VFTOps.FTPCommand, useSTP: BOOL] = { -- stop future button pushes! ChangeCommandSubwindow[self, empty]; -- command underway; self.connectNameRope _ ViewerTools.GetContents[self.connectBox]; self.localRope _ Rope.Translate[base: ViewerTools.GetContents[self.localBox], translator: SlashToRightAngle]; self.fileNamesRope _ Rope.Translate[base: ViewerTools.GetContents[self.fileNamesBox], translator: SlashToRightAngle]; IF self.directoryBox.newVersion THEN { lastCharOK: BOOL; newHostRope: Rope.ROPE; c: CHAR; dirDelimIndex: INT; path: Rope.ROPE _ ViewerTools.GetContents[self.directoryBox]; pathLength: INT _ path.Length[]; IF pathLength=0 THEN { -- why?? self.hostRope _ ""; self.directoryRope _ ""; GOTO FinParsing; }; -- The last character must be the end of a legal host name or the end of a legal directory name. c _ path.Fetch[pathLength-1]; -- last char of path lastCharOK _ c='> OR c='/ OR c=']; -- '] if only host e.g. Alto, with filename in Remote: -- The first character of the Directory string must be a '[ or a '/ c _ path.Fetch[0]; IF c#'[ AND c#'/ THEN GOTO FNError; -- Directory is assumed to be a directory, but may not have a terminator already IF ~lastCharOK THEN { -- ONLY a host name IF c='[ AND Rope.Find[s1: path, s2: ">"] = -1 THEN path _ Rope.Cat[path, "]"] ELSE path _ Rope.Cat[path, IF c='[ THEN ">" ELSE "/"]; pathLength _ pathLength+1; lastCharOK _ TRUE; }; -- At this point, the remote name is in fileNames and the rest is in path dirDelimIndex _ Rope.Index[s1: path, pos1: 1, s2: IF c='[ THEN "]" ELSE "/"]; IF dirDelimIndex = pathLength THEN GOTO FNError; -- no trailing directory character ! newHostRope _ Rope.Substr[base: path, start: 1, len: dirDelimIndex-1]; IF (dirDelimIndex + 1) = pathLength THEN self.directoryRope _ NIL ELSE { IF c='[ THEN { -- old syntax IF path.Fetch[dirDelimIndex+1] # '< THEN GOTO FNError; self.directoryRope _ Rope.Substr[base: path, start: dirDelimIndex + 2, len: path.Length[] - dirDelimIndex - 3]; } ELSE { -- New syntax self.directoryRope _ Rope.Translate[base: Rope.Substr[base: path, start: dirDelimIndex + 1, len: pathLength - dirDelimIndex - 2], translator: SlashToRightAngle]; }; }; IF NOT Rope.Equal[s1: newHostRope, s2: self.hostRope, case: FALSE] THEN { -- Close connection, forcing a re-open with the new host self.hostRope _ newHostRope; }; EXITS FinParsing => NULL; }; -- there remains to determine what is a source and what is a destination for various cases... SELECT cmd FROM remoteDelete => { self.sourceRope _ self.fileNamesRope; self.destRope _ NIL; }; localDelete => { self.sourceRope _ self.localRope; self.destRope _ NIL; }; remoteList => { self.sourceRope _ IF self.fileNamesRope.Length[]>0 THEN self.fileNamesRope ELSE self.localRope; self.destRope _ NIL; }; localList => { self.sourceRope _ IF self.localRope.Length[]>0 THEN self.localRope ELSE self.fileNamesRope; self.destRope _ NIL; }; store => IF self.localRope.Length[]>0 THEN { self.sourceRope _ self.localRope; self.destRope _ self.fileNamesRope; } ELSE { self.sourceRope _ self.fileNamesRope; self.destRope _ NIL; }; retrieve, dfGet, dfGetBoth => IF self.fileNamesRope.Length[]>0 THEN { self.sourceRope _ self.fileNamesRope; self.destRope _ self.localRope; } ELSE { self.sourceRope _ self.localRope; self.destRope _ NIL; }; ENDCASE => ERROR; IF (cmd = store OR cmd = retrieve) AND self.sourceRope.Length[] > 0 AND self.destRope.Length[] > 0 THEN { -- Check for multiple rename IF (Rope.SkipTo[s: self.sourceRope, skip: " #*@"] # self.sourceRope.Length[]) OR (Rope.SkipTo[s: self.destRope, skip: " #*@"] # self.destRope.Length[]) THEN { PostComment[self, "Multiple rename not implemented"]; self.log.PutF["The FileTool does not understand what you want to happen when both the FileNames and Local fields contain something and at least one of them contains either more than one filename, a command file (@) or a pattern.\r"]; NeedCommand[self]; RETURN; }; }; Labels.Set[self.msg, " "]; IF useSTP THEN self.data.transferring _ TRUE; IF cmd = dfGet OR cmd = dfGetBoth THEN LocalRemoteGet[self, cmd] ELSE [] _ VFTOps.GiveCommand[self, cmd]; EXITS FNError => { PostComment[self, "Illegal Directory or Filename!"]; NeedCommand[self]; }; }; NeedCommand: PUBLIC PROC [self: VFTOps.Handle] = { ChangeCommandSubwindow[self, commands]; self.data.transferring _ FALSE; }; NeedConfirm: PUBLIC PROC [self: VFTOps.Handle] = { ChangeCommandSubwindow[self, confirms]; }; -- create world CreateVFT: Commander.CommandProc = TRUSTED { CR0, CR1, top: INTEGER; vft: VFTOps.Handle _ NEW[VFTOps.VFTObject]; -- NO FORK! MakeButton: PROC [name: Rope.ROPE, proc: Buttons.ButtonProc, x, y: INTEGER, fork: BOOL _ FALSE, doc: Rope.ROPE] RETURNS [Buttons.Button] = { top _ y; RETURN[Buttons.Create[ info: [ name: name, wx: x, wy: y, wh: CHT, parent: vft.win, border: FALSE], proc: proc, clientData: vft, fork: fork, paint: FALSE, documentation: doc]]; }; MakeText: PROC [x, y, w: INTEGER] RETURNS [ViewerClasses.Viewer] = { top _ y; RETURN[ViewerOps.CreateViewer[flavor: $Text, info: [ parent: vft.win, wx: x, wy: y, ww: w, wh: CHT, border: FALSE], paint: FALSE]]; }; -- FORK MakeSubButton: PROC [name: Rope.ROPE, proc: Buttons.ButtonProc, x, y: INTEGER, guarded: BOOL _ FALSE, doc: Rope.ROPE] RETURNS [Buttons.Button] = { top _ y; RETURN[Buttons.Create[ info: [ name: name, wx: x, wy: y, wh: CHT, parent: vft.commandSW, border: FALSE], proc: proc, clientData: vft, paint: FALSE, guarded: guarded, documentation: doc]]; }; vft.bits[off] _ NEW[GraphicsOps.BitmapRep _ [NEW[VFTOps.SmallMap _ ALL[0]], 1, 16, 16]]; vft.bits[left] _ NEW[GraphicsOps.BitmapRep _ [NEW[VFTOps.SmallMap _ VFTOps.LeftSmallMap], 1, 16, 16]]; vft.bits[right] _ NEW[GraphicsOps.BitmapRep _ [NEW[VFTOps.SmallMap _ VFTOps.RightSmallMap], 1, 16, 16]]; vft.win _ ViewerOps.CreateViewer[flavor: $FileTool, info: [name: "File Tool", iconic: TRUE, scrollable: FALSE], paint: TRUE ]; ViewerOps.AddProp[vft.win, $FileToolData, vft]; vft.stop _ Buttons.Create[info: [ name: "Stop! ", wx: 0, wy: 0, wh: MsgHT, parent: vft.win, border: FALSE], proc: MyStop, clientData: vft, fork: TRUE, paint: FALSE, guarded: FALSE, documentation: "Abort transfer"]; vft.msg _ Labels.Create[info: [ name: IO.PutFR["VFT of %t", IO.time[Runtime.GetBcdTime[]]], parent: vft.win, wx: vft.stop.ww, wy: 0, ww: TWidth-vft.stop.ww, wh: MsgHT, border: FALSE], paint: FALSE ]; vft.bottomMsgRule _ Rules.Create[info: [parent: vft.win, wx: 0, wy: vft.msg.wy+vft.msg.wh+4, ww: TWidth, wh: 1], paint: FALSE]; vft.stringDirectory _ MakeButton[name: "Directory: ", proc: StrButtonProc, x: PCol0, y: vft.bottomMsgRule.wy+vft.bottomMsgRule.wh+4, doc: "Full remote directory name"]; vft.stringFileNames _ MakeButton[name: "FileName(s): ", proc: StrButtonProc, x: PCol0, y: top+CHT, doc: "Remote file name here"]; vft.stringLocal _ MakeButton[name: "Local: ", proc: StrButtonProc, x: PCol0, y: top+CHT, doc: "Local file name if different from remote name"]; vft.stringDFFile _ MakeButton[name: "DF File: ", proc: StrButtonProc, x: PCol0, y: top+CHT, doc: "DF file name for use by DFGet and DFGetBoth"]; vft.stringConnect _ MakeButton[name: "Connect: ", proc: StrButtonProc, x: PCol0, y: top+CHT, doc: "Connect name, if needed"]; vft.stringCPassword _ MakeButton[name: "Password: ", proc: StrCPasswordButtonProc, x: PCol1, y: vft.stringConnect.wy, fork: TRUE, doc: "Connect password, end with CR"]; vft.directoryBox _ MakeText[ x: vft.stringDirectory.wx+vft.stringDirectory.ww, y: vft.stringDirectory.wy+BaselineFix, w: TWidth-(vft.stringDirectory.wx+vft.stringDirectory.ww) ]; vft.fileNamesBox _ MakeText[ x: vft.stringFileNames.wx+vft.stringFileNames.ww, y: vft.stringFileNames.wy+BaselineFix, w: PCol2-(vft.stringFileNames.wx+vft.stringFileNames.ww) ]; vft.updateAlwaysButton _ MakeButton[name: "Update a>", proc: UpdateButtonProc, x: PCol2, y: vft.stringFileNames.wy, doc: "Store or retrieve if the file does not exist or if the source file is newer than the destination file"]; vft.localBox _ MakeText[ x: vft.stringLocal.wx+vft.stringLocal.ww, y: vft.stringLocal.wy+BaselineFix, w: PCol2-(vft.stringLocal.wx+vft.stringLocal.ww) ]; vft.updateButton _ MakeButton[name: "Update >", proc: UpdateButtonProc, x: PCol2, y: vft.stringLocal.wy, doc: "Store or retrieve only if the destination file already exists, but is older than the source file"]; vft.dfFileBox _ MakeText[ x: vft.stringDFFile.wx+vft.stringDFFile.ww, y: vft.stringDFFile.wy+BaselineFix, w: PCol2-(vft.stringDFFile.wx+vft.stringDFFile.ww) ]; vft.exportsOnlyButton _ MakeButton[name: "ExportsOnly", proc: UpdateButtonProc, x: PCol2, y: vft.stringDFFile.wy, doc: "Retrieve only Exported files from DF file"]; vft.connectBox _ MakeText[ x: vft.stringConnect.wx+vft.stringConnect.ww, y: vft.stringConnect.wy+BaselineFix, w: PCol1-(vft.stringConnect.wx+vft.stringConnect.ww) ]; vft.cpasswordBox _ TypeScript.Create[info: [ parent: vft.win, wx: vft.stringCPassword.wx+vft.stringCPassword.ww, wy: vft.stringCPassword.wy+BaselineFix, ww: PCol2-(vft.stringCPassword.wx+vft.stringCPassword.ww), wh: CHT, border: FALSE], paint: FALSE]; vft.verifyButton _ MakeButton[name: "Verify", proc: UpdateButtonProc, x: PCol2, y: vft.stringConnect.wy, doc: "FileTool will ask for confirmation for each file transferred"]; vft.bottomParamRule _ Rules.Create[info: [parent: vft.win, wx: 0, wy: vft.stringConnect.wy+vft.stringConnect.wh+4, ww: TWidth, wh: 1], paint: FALSE]; vft.commandSW _ ViewerOps.CreateViewer[ flavor: $Container, info: [ parent: vft.win, wx: 0, wy: vft.bottomParamRule.wy+4, ww: TWidth, wh: SWHeight, scrollable: FALSE, border: FALSE], paint: FALSE ]; vft.bottomCommandRule _ Rules.Create[info: [parent: vft.win, wx: 0, wy: vft.commandSW.wy+vft.commandSW.wh+4, ww: TWidth, wh: 1], paint: FALSE]; CR0 _ 4; CR1 _ CR0+CHT; vft.confirmButton _ MakeSubButton[name: "Confirm!", proc: ConfirmButtonProc, x: CCol0, y: CR0, guarded: FALSE, doc: "Approve transfer"]; vft.denyButton _ MakeSubButton[name: "Deny!", proc: ConfirmButtonProc, x: CCol1, y: CR0, guarded: FALSE, doc: "Reject transfer of this file, but continue"]; vft.stopButton _ MakeSubButton[name: "Stop!", proc: ConfirmButtonProc, x: CCol2, y: CR0, guarded: FALSE, doc: "Reject transfer and stop"]; vft.confirmChildren _ vft.commandSW.child; vft.commandSW.child _ NIL; vft.transferBox _ ViewerOps.CreateViewer[ flavor: $Bitmap, info: [ parent: vft.commandSW, wx: 10, wy: 10, ww: 16, wh: 16, data: vft, scrollable: FALSE, border: FALSE]]; vft.transferChildren _ vft.commandSW.child; vft.commandSW.child _ NIL; vft.typeOption _ MakeSubButton[name: "Type!", proc: OptionsButtonProc, x: CCol0, y: CR0, doc: "Show file type (text or binary) if known"]; vft.bytesOption _ MakeSubButton[name: "Bytes!", proc: OptionsButtonProc, x: CCol1, y: CR0, doc: "Show file length in bytes"]; vft.authorOption _ MakeSubButton[name: "Author!", proc: OptionsButtonProc, x: CCol2, y: CR0, doc: "Show last writer of file"]; vft.applyOption _ MakeSubButton[name: "Apply!", proc: OptionsButtonProc, x: CCol4, y: CR0, doc: "Activate current options"]; vft.pagesOption _ MakeSubButton[name: "Pages!", proc: OptionsButtonProc, x: CCol3, y: CR0, doc: "Size of file in Disk pages, local files only"]; vft.createOption _ MakeSubButton[name: "Create!", proc: OptionsButtonProc, x: CCol0, y: CR1, doc: "Show create date"]; vft.writeOption _ MakeSubButton[name: "Write!", proc: OptionsButtonProc, x: CCol1, y: CR1, doc: "Show write date"]; vft.readOption _ MakeSubButton[name: "Read!", proc: OptionsButtonProc, x: CCol2, y: CR1, doc: "Show read date"]; vft.abortOption _ MakeSubButton[name: "Abort!", proc: OptionsButtonProc, x: CCol4, y: CR1, doc: "Restore previous options"]; vft.optionsChildren _ vft.commandSW.child; vft.commandSW.child _ NIL; vft.retrieveButton _ MakeSubButton[name: "Retrieve!", proc: CommandButtonProc, x: CCol0, y: CR0, doc: "Retrieve remote file(s) to local disk"]; vft.storeButton _ MakeSubButton[name: "Store!", proc: CommandButtonProc, x: CCol0, y: CR1, doc: "Store local file(s) to remote server"]; vft.localListButton _ MakeSubButton[name: "Local-List!", proc: CommandButtonProc, x: CCol1, y: CR0, doc: "List local files matching pattern"]; vft.remoteListButton _ MakeSubButton[name: "Remote-List!", proc: CommandButtonProc, x: CCol1, y: CR1, doc: "List remote files matching pattern"]; vft.closeButton _ MakeSubButton[name: "Close!", proc: CommandButtonProc, x: CCol2, y: CR1, doc: "Close current Ethernet connection"]; vft.listOptionsButton _ MakeSubButton[name: "List-Options!", proc: CommandButtonProc, x: CCol2, y: CR0, doc: "Display option menu for file listings"]; vft.dfGetButton _ MakeSubButton[name: "DFGet!", proc: CommandButtonProc, x: CCol3, y: CR0, doc: "Get named files from DF file"]; vft.dfGetBothButton _ MakeSubButton[name: "DFGetBoth!", proc: CommandButtonProc, x: CCol3, y: CR1, doc: "Get named .mesa and .bcd files from DF file"]; vft.localDeleteButton _ MakeSubButton[name: "Local-Delete!", proc: CommandButtonProc, x: CCol4, y: CR0, guarded: TRUE, doc: "Delete local file(s), requires confirmation, file names must be in Local field"]; vft.remoteDeleteButton _ MakeSubButton[name: "Remote-Delete!", proc: CommandButtonProc, x: CCol4, y: CR1, guarded: TRUE, doc: "Delete remote file(s), requires confirmation, file names must be in Path or Remote fields"]; vft.commandChildren _ vft.commandSW.child; top _ vft.bottomCommandRule.wy+4; vft.ts _ TypeScript.Create[info: [parent: vft.win, wx: 0, wy: top, ww: TWidth, wh: 800 -- _ McGregor did this--, border: FALSE], paint: FALSE]; Containers.ChildXBound[vft.win, vft.bottomMsgRule]; Containers.ChildXBound[vft.win, vft.bottomParamRule]; Containers.ChildXBound[vft.win, vft.bottomCommandRule]; Containers.ChildXBound[vft.win, vft.ts]; Containers.ChildYBound[vft.win, vft.ts]; [in: vft.logIn, out: vft.log] _ ViewerIO.CreateViewerStreams[name: "FileTool.log", viewer: vft.ts, editedStream: FALSE]; [] _ vft.logIn.SetEcho[NIL]; --ViewerOps.CloseViewer[viewer: vft.win]; vft.cPasswordRope _ ""; ViewerTools.SetContents[vft.cpasswordBox, ""]; SetBoolButton[vft.updateButton, vft.update]; SetBoolButton[vft.updateAlwaysButton, vft.updateAlways]; SetBoolButton[vft.exportsOnlyButton, vft.publiconly]; SetBoolButton[vft.verifyButton, vft.verify]; VFTOps.BuildOuter[vft]; -- create Remote Get stuff -- TypeScript.PutRope[vft.ts, CommentRope]; -- vftlist _ CONS[vft, vftlist]; }; -- Destroy and Cleanup routines -- The filetool needs to use something like Event to clean up in the event of a world swap! -- Remember to apply the cleanup procedure to each active filetool. FileToolDestroy: ViewerClasses.DestroyProc = TRUSTED { vft: VFTOps.Handle _ NARROW[ViewerOps.FetchProp[self, $FileToolData]]; vft.task _ VFTOps.FreeTask[vft.task]; -- vftlist _ List.Remove[vft, vftlist]; Process.Detach[FORK MyDestroyInternal[vft]]; -- next line is a crock to avoid signal in TypeScripts, see McGregor Process.Pause[Process.SecondsToTicks[1]]; }; MyDestroyInternal: PROC [self: VFTOps.Handle] = { -- vft.log.Close[]; VFTOps.StopFTP[self]; IF self.user # NIL THEN self.user _ STP.Destroy[self.user]; VFTOps.RGDestroy[self]; -- remote get stuff self.log.Flush[]; }; MyStop: Buttons.ButtonProc = TRUSTED { vft: VFTOps.Handle _ NARROW[clientData]; IF vft=NIL THEN RETURN; VFTOps.StopFTP[vft]; }; Init: PROC = { fileToolClass.destroy _ FileToolDestroy; fileToolClass.icon _ fileCabinet; ViewerOps.RegisterViewerClass[$FileTool, fileToolClass]; ViewerOps.RegisterViewerClass[$Bitmap, bitmapClass]; Commander.Register[ key: "FileTool", proc: CreateVFT, doc: "Tool for manipulating local and remote files"]; [] _ CreateVFT[NIL]; }; BitmapPaint: ViewerClasses.PaintProc = TRUSTED { vft: VFTOps.Handle _ NARROW[self.data]; Graphics.SetCP[context, 0, 16]; GraphicsOps.DrawBitmap[context, vft.bits[vft.data.indicator], 16, 16]; }; -- MAINLINE CODE Init[]; END. -- Phil Karlton; 16-Mar-81 12:26:37 -- Mark; 12-Mar-81 19:53:13 16-Jan-82 15:59:28, Stewart, created from FileInterface.mesa 25-Jan-82 23:39:50, Stewart, objects March 27, 1982 8:18 pm, Stewart, Cedar 3.0 cleanup & bug fixing April 24, 1982 4:44 pm, Stewart, Cedar 3.0 June 7, 1982 7:13 pm, Stewart, Cedar 3.2, Menus July 3, 1982 7:53 pm, Stewart, Cedar 3.2 bug fixes before release September 16, 1982 10:33 am, Stewart, Cedar 3.4 March 28, 1983 3:18 pm, Stewart, Commander, remove vftList FileTool notes Ideas for improvements: VTables style sets of filenames Menus for list options and commands instead of subwindow Check for multiple rename Incorporate official Cedar pattern matcher and use CIFS Provide programmer's interface (Filetool should just be a forms-fill-out user interface for the file moving and listing machinery.)