DIRECTORY AlpFile USING[ FileID, GetSize, Handle, LockOption, Open, ReadProperties, ReadPages, SetSize, WritePages, WriteProperties], AlpineEnvironment USING[ AccessList, ByteCount, bytesPerPage, NeededAccess, Outcome, OwnerName, PageCount, Principal, Property, PropertyValuePair, RName, UniversalFile, wordsPerPage], AlpineFile USING [ allProperties, PropertySet], AlpineInterimDirectory USING[ CreateOptions, DeleteUnderTrans, EnumerateDirectoryUnderTrans, OpenUnderTrans], AlpInstance USING[ AccessFailed, Create, Handle, LockFailed ], AlpTransaction USING[ AssertAlpineWheel, Create, Finish, Handle, Outcome], BasicTime USING[ GMT], Basics USING[ Comparison], Buttons USING[ Button, ButtonProc, SetDisplayStyle ], FS USING[ Close, ComponentPositions, Copy, Create, Delete, EnumerateForInfo, Error, ExpandName, GetInfo, GetName, InfoProc, Open, OpenFile, Read, SetByteCountAndCreatedTime, Write], IO USING[ int, PutF, PutFR, PutRope, rope, STREAM, text, time ], List USING[ Sort, Car, Cdr], Menus USING[ MouseButton], RefText USING[ TrustTextAsRope], Rope, RPC, UserCredentials USING[ Get ], ViewerClasses USING[ Viewer ], ViewerTools USING[ GetContents], VM USING[ AddressForPageNumber, Allocate, Free, Interval], YodelData; YodelUser: CEDAR PROGRAM IMPORTS AlpineInterimDirectory, AlpFile, AlpInstance, AlpTransaction, Buttons, FS, IO, List, RefText, Rope, RPC, UserCredentials, ViewerTools, VM, YodelData EXPORTS YodelData = BEGIN OPEN AE: AlpineEnvironment, YodelData; ByteCount: TYPE = AE.ByteCount; bytesPerPage: INT = AE.bytesPerPage; PageCount: TYPE = AE.PageCount; PropertyValuePair: TYPE = AE.PropertyValuePair; UniversalFile: TYPE = AE.UniversalFile; wordsPerPage: INT = AE.wordsPerPage; PagesForBytes: PROC [byteLength: ByteCount] RETURNS [pageCount: PageCount] = { RETURN [(byteLength+bytesPerPage-1)/bytesPerPage]; }; BytesForPages: PROC [pageCount: PageCount] RETURNS [byteLength: ByteCount] = { RETURN [pageCount * bytesPerPage]; }; ROPE: TYPE = Rope.ROPE; hasPattern: PUBLIC SAFE PROC [pattern: ROPE] RETURNS [BOOL] = { RETURN [-1 # Rope.Find[s1: pattern, s2: "*"]]; }; CompareProc: SAFE PROC [ref1, ref2: REF ANY] RETURNS [Basics.Comparison] = CHECKED { RETURN [Rope.Compare[NARROW[ref1], NARROW[ref2], FALSE]]; }; makeSlashAWedge: Rope.TranslatorType = { IF old = '/ THEN RETURN['>] ELSE RETURN[old]; }; ParseSArgs: PUBLIC PROC [ d: MyData] RETURNS [user, password, srcServer, srcDir, srcFile: ROPE] = { srcFileTemp: ROPE ; srcServer _ ViewerTools.GetContents[d.srcServer]; -- srcFile _ ViewerTools.GetContents[d.srcFile]; srcFileTemp _ ViewerTools.GetContents[d.srcFile] ; IF (NOT srcFileTemp.IsEmpty[]) AND srcFileTemp.Fetch[0] = '/ THEN srcFileTemp _ Rope.Concat["<" , srcFileTemp.Substr[start: 1, len: srcFileTemp.InlineLength[]-1]]; srcFile _ Rope.Translate[base: srcFileTemp, translator: makeSlashAWedge ]; user _ ViewerTools.GetContents[d.user]; IF (Rope.Equal[user,""] OR Rope.Equal[user,NIL]) THEN [user] _ UserCredentials.Get[]; password _ ViewerTools.GetContents[d.password]; [srcDir] _ DecomposePattern[server: srcServer, pattern: srcFile, user: user]; }; ParseDArgs: PROC [user: ROPE, d: MyData] RETURNS [destServer, destDir, destFile: ROPE] = { destFileTemp: ROPE ; destServer _ ViewerTools.GetContents[d.destServer]; destFileTemp _ ViewerTools.GetContents[d.destFile]; IF (NOT destFileTemp.IsEmpty[]) AND destFileTemp.Fetch[0] = '/ THEN destFileTemp _ Rope.Concat["<" , destFileTemp.Substr[start: 1, len: destFileTemp.InlineLength[]-1]]; destFile _ Rope.Translate[base: destFileTemp, translator: makeSlashAWedge ]; [destDir] _ DecomposePattern[server: destServer, pattern: destFile, user: user]; }; listFiles: PROC [trans: AlpTransaction.Handle, server: ROPE, pattern: ROPE, user: ROPE _ NIL, password: ROPE _ NIL , displayProperties: AlpineFile.PropertySet _ AlpineFile.allProperties, d: MyData] RETURNS [LIST OF REF ANY] = { directory, restOfPattern: ROPE; resultList: LIST OF REF ANY _ NIL; AlpineEnumProc: PROC [fileName: REF TEXT, universalFile: AlpineEnvironment.UniversalFile] RETURNS [quit: BOOL] = { intendReadLockOption: AlpFile.LockOption = [intendRead , IF d.breakLocks THEN wait ELSE fail]; readLockOption: AlpFile.LockOption = [read, IF d.breakLocks THEN wait ELSE fail]; IF d.stopFlag THEN { resultList _ CONS[first: NARROW[" ** List aborted **", ROPE], rest: NIL]; RETURN [quit: TRUE]; }; IF Rope.Match[pattern: restOfPattern, object: RefText.TrustTextAsRope[fileName], case: FALSE] THEN { file: AlpFile.Handle; fileID: AlpFile.FileID; properties: LIST OF AlpineEnvironment.PropertyValuePair; byteLength: INT; resultRope: ROPE ; [file, fileID] _ AlpFile.Open[transHandle: trans, universalFile: universalFile, lock: intendReadLockOption ! AlpInstance.LockFailed => GOTO lockError; AlpInstance.AccessFailed => IF missingAccess = AlpineEnvironment.NeededAccess.fileRead THEN GOTO skipFile ELSE REJECT; ]; properties _ AlpFile.ReadProperties[handle: file, lock: readLockOption ! AlpInstance.LockFailed => GOTO lockError; AlpInstance.AccessFailed => IF missingAccess = AlpineEnvironment.NeededAccess.fileRead THEN GOTO skipFile ELSE REJECT; ]; byteLength _ NARROW[properties.first, AlpineEnvironment.PropertyValuePair.byteLength].byteLength; resultRope _ IO.PutFR["%g\t", IO.text[fileName]]; UNTIL properties = NIL DO property: AlpineEnvironment.PropertyValuePair _ properties.first ; properties _ properties.rest; IF displayProperties[property.property] THEN BEGIN SELECT property.property FROM byteLength => { byteLength: INT _ NARROW[property, AlpineEnvironment.PropertyValuePair.byteLength].byteLength; resultRope _ Rope.Concat[resultRope, IO.PutFR["%g bytes ", IO.int[byteLength]]]; }; createTime => { createTime: BasicTime.GMT _ NARROW[property, AlpineEnvironment.PropertyValuePair.createTime].createTime; resultRope _ Rope.Concat[resultRope, IO.PutFR["%g ", IO.time[createTime]]]; }; highWaterMark => { highWaterMark: AlpineEnvironment.PageCount _ NARROW[property, AlpineEnvironment.PropertyValuePair.highWaterMark].highWaterMark; resultRope _ Rope.Concat[resultRope, IO.PutFR["HWM: %g ", IO.int[highWaterMark]]]; }; modifyAccess => { modifyAccess: AlpineEnvironment.AccessList _ NARROW[property, AlpineEnvironment.PropertyValuePair.modifyAccess].modifyAccess; resultRope _ Rope.Concat[resultRope,"modify access: ("]; IF modifyAccess = NIL THEN resultRope _ Rope.Concat[resultRope,"*none*"] ELSE BEGIN UNTIL modifyAccess = NIL DO accessItem: AlpineEnvironment.RName _ modifyAccess.first; resultRope _ Rope.Concat[resultRope,accessItem]; modifyAccess _ modifyAccess.rest; IF modifyAccess # NIL THEN resultRope _ Rope.Concat[resultRope,", "]; ENDLOOP; END ; resultRope _ Rope.Concat[resultRope,") "]; }; owner => { owner: AlpineEnvironment.OwnerName _ NARROW[property, AlpineEnvironment.PropertyValuePair.owner].owner; resultRope _ Rope.Concat[resultRope, IO.PutFR["owner: %g ", IO.rope[owner]]]; }; readAccess => { readAccess: AlpineEnvironment.AccessList _ NARROW[property, AlpineEnvironment.PropertyValuePair.readAccess].readAccess; resultRope _ Rope.Concat[resultRope,"read access: ("]; IF readAccess = NIL THEN resultRope _ Rope.Concat[resultRope,"*none*"] ELSE BEGIN UNTIL readAccess = NIL DO accessItem: AlpineEnvironment.RName _ readAccess.first; resultRope _ Rope.Concat[resultRope,accessItem]; readAccess _ readAccess.rest; IF readAccess # NIL THEN resultRope _ Rope.Concat[resultRope,", "]; ENDLOOP; END ; resultRope _ Rope.Concat[resultRope,") "]; }; stringName => { stringName: ROPE _ NARROW[property, AlpineEnvironment.PropertyValuePair.stringName].stringName; resultRope _ Rope.Concat[resultRope, IO.PutFR["stringName: %g ", IO.rope[stringName]]]; }; version => { version: LONG INTEGER _ NARROW[property, AlpineEnvironment.PropertyValuePair.version].version; resultRope _ Rope.Concat[resultRope, IO.PutFR["version: %g ", IO.int[version]]]; }; ENDCASE; END; ENDLOOP; resultList _ CONS[first: resultRope, rest: resultList]; EXITS lockError => { resultRope _ IO.PutFR["%g has lock set", IO.text[fileName]]; resultList _ CONS[first: resultRope, rest: resultList]; }; skipFile => {}; }; RETURN [quit: FALSE]; }; FSEnumProc: FS.InfoProc = { -- PROC [fullFName, attachedTo: ROPE, created: BasicTime.GMT, bytes: INT, -- keep: CARDINAL] RETURNS [continue: BOOLEAN]; resultRope: ROPE ; fName: ROPE ; componentPositions: FS.ComponentPositions ; IF d.stopFlag THEN { resultList _ CONS[first: NARROW[" ** List aborted **", ROPE], rest: NIL]; RETURN [continue: FALSE]; }; [fullFName: fName, cp: componentPositions] _ FS.ExpandName[name: fullFName]; resultRope _ IO.PutFR["%g\t", IO.rope[fName]]; resultRope _ Rope.Concat[resultRope, IO.PutFR["%g bytes ", IO.int[bytes]]]; resultRope _ Rope.Concat[resultRope, IO.PutFR["\t%g ", IO.time[created]]]; resultList _ CONS[first: resultRope, rest: resultList]; RETURN [continue: TRUE]; }; resultRope: ROPE _ NIL; outcome: AlpTransaction.Outcome; failureName: ROPE _ "" ; { [directory, restOfPattern] _ DecomposePattern[server, pattern, user]; IF trans # NIL THEN { bangPos: INT ; IF d.assertWheel THEN trans.AssertAlpineWheel[TRUE]; IF (bangPos _ Rope.Find[restOfPattern,"!"]) >= 0 THEN { IF bangPos = 0 THEN restOfPattern _ "*" ELSE restOfPattern _ Rope.Substr[base: restOfPattern, len: bangPos]; }; AlpineInterimDirectory.EnumerateDirectoryUnderTrans[ transHandle: trans, directoryName: Rope.Concat["[",Rope.Concat[server,Rope.Concat["]",directory]]], enumProc: AlpineEnumProc]; outcome _ AlpTransaction.Finish[trans, commit]; } ELSE { pattern: ROPE; pattern _ Rope.Concat[Rope.Concat[Rope.Concat[Rope.Concat ["[", server], "]"], directory], restOfPattern]; FS.EnumerateForInfo[pattern: pattern, proc: FSEnumProc ]; }; }; resultList _ List.Sort[resultList, CompareProc]; RETURN [resultList]; }; DecomposePattern: PUBLIC PROC [server: ROPE, pattern: ROPE, user: ROPE] RETURNS [directory, restOfPattern: ROPE] = { rightAngleBracket: INT; dir: ROPE ; isAlpine: BOOL ; IF Rope.Match[pattern: "*.alpine", object: server, case: FALSE] THEN { isAlpine _ TRUE; dir _ user; } ELSE { isAlpine _ FALSE; IF server.IsEmpty[] THEN dir _ NIL ELSE { IF Rope.Match[pattern: "*.*", object: user, case: FALSE] THEN dir _ user.Substr[start: 0, len: user.SkipTo[1, "."]] ELSE dir _ user; }; }; IF NOT Rope.Match[pattern: "<*>*", object: pattern, case: FALSE] THEN BEGIN directory _ Rope.Concat["<", dir] ; directory _ Rope.Concat[directory,">"]; restOfPattern _ pattern ; IF restOfPattern.IsEmpty[] THEN restOfPattern _ "*"; END ELSE BEGIN rightAngleBracket _ pattern.SkipTo[1, ">"]; IF rightAngleBracket > 1 THEN directory _ pattern.Substr[start: 0, len: rightAngleBracket+1] ELSE directory _ Rope.Concat["<>", dir] ; restOfPattern _ pattern.Substr[start: rightAngleBracket+1]; IF restOfPattern.IsEmpty[] THEN restOfPattern _ "*"; END }; ListFilesProc: PUBLIC Buttons.ButtonProc= BEGIN resultList: LIST OF REF ANY _ NIL; d: MyData = NARROW[clientData]; server, user, file, password: ROPE; directory, restOfPattern: ROPE; printedSomething: BOOL _ FALSE; callList: YodelData.PerformProc = { RETURN[listFiles[trans, server, file, user, password, d.displayProperties, d]]; }; d.stopFlag _ FALSE; [user, password, server, directory, file] _ ParseSArgs[d]; [directory, restOfPattern] _ DecomposePattern[server: server, pattern: file, user: user]; d.out.PutF["\nList of [%g]%g%g\n", IO.rope[server], IO.rope[directory], IO.rope[restOfPattern]]; resultList _ PerformOp[performProc: callList, server: server, user: user, password: password]; DO nowRope: ROPE _ NARROW[List.Car[resultList]]; IF resultList = NIL THEN EXIT; resultList _ List.Cdr[resultList]; d.out.PutF[" %g\n", IO.rope[nowRope]]; printedSomething _ TRUE ; ENDLOOP; IF NOT printedSomething THEN d.out.PutRope[" ** no files match the pattern **\n"]; END; fileDelete: PROC [trans: AlpTransaction.Handle, server: ROPE, file: ROPE, user: ROPE _ NIL, password: ROPE _ NIL, d: MyData] RETURNS[resultList:LIST OF REF ANY _ NIL] = { directory, restOfPattern, directoryName: ROPE; AlpineDeleteEnumProc: PROC [fileName: REF TEXT, universalFile: AlpineEnvironment.UniversalFile] RETURNS [quit: BOOL] = { IF d.stopFlag THEN { resultList _ CONS[first: NARROW[" ** Delete aborted **", ROPE], rest: NIL]; RETURN [quit: TRUE]; }; IF Rope.Match[pattern: restOfPattern, object: RefText.TrustTextAsRope[fileName], case: FALSE] THEN { fileN: ROPE; fileN _ Rope.Concat[directoryName,Rope.FromRefText[fileName]]; AlpineInterimDirectory.DeleteUnderTrans[transHandle: trans, fileName: fileN]; resultRope _ IO.PutFR["%g deleted", IO.text[fileName]]; resultList _ CONS[first: resultRope, rest: resultList]; }; RETURN [quit: FALSE]; }; FSDeleteEnumProc: FS.InfoProc = { -- PROC [fullFName, attachedTo: ROPE, created: BasicTime.GMT, bytes: INT, -- keep: CARDINAL] RETURNS [continue: BOOLEAN]; IF d.stopFlag THEN { resultList _ CONS[first: NARROW[">> ** Delete aborted **", ROPE], rest: NIL]; RETURN [continue: FALSE]; }; FS.Delete[ name: fullFName, wantedCreatedTime: created]; resultRope _ IO.PutFR["%g deleted", IO.rope[fullFName]]; resultList _ CONS[first: resultRope, rest: resultList]; RETURN [continue: TRUE]; }; resultRope: ROPE _ NIL; outcome: AlpTransaction.Outcome; failureName: ROPE _ "" ; { [directory, restOfPattern] _ DecomposePattern[server, file, user]; IF trans # NIL THEN { -- alpine files to delete bangPos: INT ; IF d.assertWheel THEN trans.AssertAlpineWheel[TRUE]; IF (bangPos _ Rope.Find[restOfPattern,"!"]) >= 0 THEN { IF bangPos = 0 THEN restOfPattern _ "*" ELSE restOfPattern _ Rope.Substr[base: restOfPattern, len: bangPos]; }; directoryName _ Rope.Concat["[",Rope.Concat[server,Rope.Concat["]",directory]]]; AlpineInterimDirectory.EnumerateDirectoryUnderTrans[ transHandle: trans, directoryName: directoryName, enumProc: AlpineDeleteEnumProc]; outcome _ AlpTransaction.Finish[trans, commit]; IF outcome # commit THEN { resultList _ CONS[ first: Rope.Concat["Alpine transaction aborted -- deletes NOT done", IF resultList = NIL THEN NIL ELSE "; log before abort is:"], rest: resultList]; }; } ELSE { -- FS or IFS files to delete pattern: ROPE; pattern _ Rope.Concat[Rope.Concat[Rope.Concat[Rope.Concat ["[", server], "]"], directory], restOfPattern]; IF pattern.Find["!"] < 0 THEN pattern _ Rope.Concat[pattern, "!l"]; FS.EnumerateForInfo[pattern: pattern, proc: FSDeleteEnumProc ]; }; }; resultList _ List.Sort[resultList, CompareProc]; RETURN [resultList]; }; DeleteFilesProc: PUBLIC Buttons.ButtonProc= BEGIN d: MyData = NARROW[clientData]; resultList: LIST OF REF ANY _ NIL; srcServer, srcFile, srcDir: ROPE; user, password: ROPE; directory, restOfPattern: ROPE; printedSomething: BOOL _ FALSE; callDelete: YodelData.PerformProc = { RETURN[fileDelete[trans: trans, server: srcServer, file: srcFile, user: user, password: password, d: d]]; }; d.stopFlag _ FALSE; [user, password, srcServer, srcDir, srcFile] _ ParseSArgs[d]; [directory, restOfPattern] _ DecomposePattern[server: srcServer, pattern: srcFile, user: user]; IF Rope.IsEmpty[srcFile] THEN { d.out.PutF["\nDelete of [%g]%g%g NOT done -- MUST have explicit pattern\n", IO.rope[srcServer], IO.rope[srcDir], IO.rope[restOfPattern]]; RETURN; }; d.out.PutF["\nDelete of [%g]%g%g\n", IO.rope[srcServer], IO.rope[srcDir], IO.rope[restOfPattern]]; resultList _ PerformOp[performProc: callDelete, server: srcServer, user: user, password: password]; DO nowRope: ROPE _ NARROW[List.Car[resultList]]; IF resultList = NIL THEN EXIT; resultList _ List.Cdr[resultList]; d.out.PutF[" %g\n", IO.rope[nowRope]]; printedSomething _ TRUE ; ENDLOOP; IF NOT printedSomething THEN d.out.PutRope[" ** no files match the pattern **\n"]; END; -- excessBytes is only used if expunging = TRUE. fileCopy: PROC [trans: AlpTransaction.Handle, to: ROPE, from: ROPE, fullCopy: BOOL, user: ROPE _ NIL, password: ROPE _ NIL , expunging: BOOLEAN _ FALSE, excessBytes: AlpineEnvironment.ByteCount _ 0, caller: AlpineEnvironment.Principal, key: RPC.EncryptionKey, d: MyData] RETURNS [copyResult: LIST OF REF ANY _ NIL] = { FileStateObject: TYPE = RECORD [ SELECT type: {alpine, fs} FROM alpine => [fileHandle: AlpFile.Handle], fs => [openFile: FS.OpenFile], ENDCASE]; AlpineFileStateObject: TYPE = FileStateObject.alpine; FSFileStateObject: TYPE = FileStateObject.fs; FileState: TYPE = REF FileStateObject; AlpineFileState: TYPE = REF AlpineFileStateObject; FSFileState: TYPE = REF FSFileStateObject; CreateFileState: PROC [file: ROPE, createOptions: AlpineInterimDirectory.CreateOptions, createLength: INT _ 0, trans: AlpTransaction.Handle _ transHandle] RETURNS [FileState] = { -- test for alpine files IF Rope.Match[pattern: "[*.alpine]*", object: file, case: FALSE] THEN { universalFile: UniversalFile; createdFile: BOOLEAN; alpineFileState: AlpineFileState; rightSquareBracket: INT _ file.Find["]", 1]; IF rightSquareBracket IN [-1..1] THEN BEGIN IF expunging THEN ERROR ELSE ERROR ; END; [universalFile, createdFile] _ AlpineInterimDirectory.OpenUnderTrans[ trans, file, createOptions, createLength]; alpineFileState _ NEW[AlpineFileStateObject _ [alpine[fileHandle: AlpFile.Open[trans, universalFile, IF createOptions = oldOnly THEN readOnly ELSE readWrite, [IF createOptions = oldOnly THEN read ELSE write, wait], log, sequential].handle]]]; IF createOptions # oldOnly -- this is the "to" file. THEN BEGIN IF ((expunging) AND (NOT createdFile)) THEN BEGIN alpineFileState.fileHandle.WriteProperties[LIST[[highWaterMark[0]]]]; IF (trans.Finish[requestedOutcome: commit, continue: TRUE] # commit) THEN ERROR; END; alpineFileState.fileHandle.SetSize[PagesForBytes[createLength + (IF expunging THEN excessBytes ELSE 0)]]; END; RETURN [alpineFileState]; } ELSE { openFile: FS.OpenFile; fsFileState: FSFileState; IF createOptions = oldOnly THEN { openFile _ FS.Open[file]; } ELSE { openFile _ FS.Create[ name: file, setPages: TRUE, pages: PagesForBytes[createLength]]; }; fsFileState _ NEW[FSFileStateObject _ [fs[openFile: openFile]]]; RETURN [fsFileState]; }; }; CleanupFileState: PROC [fileState: FileState] = { WITH fileState SELECT FROM alpineFileState: AlpineFileState => { }; fsFileState: FSFileState => { fsFileState.openFile.Close[]; }; ENDCASE => ERROR; }; GetFileProperties: PROC [fileState: FileState] RETURNS [ byteLength: AlpineEnvironment.ByteCount, createTime: BasicTime.GMT, mutableAlpineProperites: LIST OF AlpineEnvironment.PropertyValuePair _ NIL, highWaterMark: AlpineEnvironment.PageCount _ 0, alpineSize: INT _ 0] = { WITH fileState SELECT FROM alpineFileState: AlpineFileState => { properties: LIST OF PropertyValuePair ; alpineSize _ alpineFileState.fileHandle.GetSize[]; properties _ alpineFileState.fileHandle.ReadProperties[]; WHILE properties # NIL DO property: AlpineEnvironment.PropertyValuePair _ properties.first ; properties _ properties.rest; SELECT property.property FROM byteLength => { byteLength _ NARROW[property, AlpineEnvironment.PropertyValuePair.byteLength].byteLength; mutableAlpineProperites _ CONS[[byteLength[byteLength]], mutableAlpineProperites]; }; createTime => { createTime _ NARROW[property, AlpineEnvironment.PropertyValuePair.createTime].createTime; mutableAlpineProperites _ CONS[[createTime[createTime]], mutableAlpineProperites]; }; highWaterMark => { highWaterMark _ NARROW[property, AlpineEnvironment.PropertyValuePair.highWaterMark].highWaterMark; mutableAlpineProperites _ CONS[[highWaterMark[highWaterMark]], mutableAlpineProperites]; }; modifyAccess => { modifyAccess: AlpineEnvironment.AccessList _ NARROW[property, AlpineEnvironment.PropertyValuePair.modifyAccess].modifyAccess; mutableAlpineProperites _ CONS[[modifyAccess[modifyAccess]], mutableAlpineProperites]; }; readAccess => { readAccess: AlpineEnvironment.AccessList _ NARROW[property, AlpineEnvironment.PropertyValuePair.readAccess].readAccess; mutableAlpineProperites _ CONS[[readAccess[readAccess]], mutableAlpineProperites]; }; ENDCASE; ENDLOOP; }; fsFileState: FSFileState => { [bytes: byteLength, created: createTime] _ fsFileState.openFile.GetInfo[]; }; ENDCASE => ERROR; }; SetFileProperties: PROC [fileState: FileState, byteLength: AlpineEnvironment.ByteCount, createTime: BasicTime.GMT, alpineProperties: LIST OF AlpineEnvironment.PropertyValuePair _ NIL] = { WITH fileState SELECT FROM alpineFileState: AlpineFileState => { IF fullCopy THEN alpineFileState.fileHandle.WriteProperties[alpineProperties] ELSE alpineFileState.fileHandle.WriteProperties[LIST[[byteLength[byteLength]], [createTime[createTime]]]]; }; fsFileState: FSFileState => { fsFileState.openFile.SetByteCountAndCreatedTime[bytes: byteLength, created: createTime]; }; ENDCASE => ERROR; }; FillBuffer: PROC [fromFile: FileState, pagesToMove: CARDINAL] = { WITH fromFile SELECT FROM alpineFileState: AlpineFileState => { TRUSTED BEGIN alpineFileState.fileHandle.ReadPages[ pageRun: [firstPage: pagesCopied, count: pagesToMove], pageBuffer: DESCRIPTOR [ bufferPtr, pagesToMove*wordsPerPage]]; END; }; fsFileState: FSFileState => { TRUSTED BEGIN fsFileState.openFile.Read[from: pagesCopied, nPages: pagesToMove, to: bufferPtr]; END; }; ENDCASE => ERROR; }; EmptyBuffer: PROC [toFile: FileState, pagesToMove: CARDINAL] = { WITH toFile SELECT FROM alpineFileState: AlpineFileState => { TRUSTED BEGIN alpineFileState.fileHandle.WritePages[ pageRun: [firstPage: pagesCopied, count: pagesToMove], pageBuffer: DESCRIPTOR [ bufferPtr, pagesToMove*wordsPerPage]]; END; }; fsFileState: FSFileState => { TRUSTED BEGIN fsFileState.openFile.Write[to: pagesCopied, nPages: pagesToMove, from: bufferPtr]; END; }; ENDCASE => ERROR; }; moveTheBits: PROC [] RETURNS [aborted: BOOL _ FALSE]= { pagesCopied _ 0; UNTIL pagesCopied = pageCount DO pagesLeft: CARDINAL _ pageCount-pagesCopied; pagesToMove: CARDINAL _ MIN [bufferLen, pagesLeft]; IF d.stopFlag THEN { WITH toFile SELECT FROM alpineFileState: AlpineFileState => { [] _ transHandle.Finish[requestedOutcome: abort, continue: FALSE] ; IF secondTransHandle # NIL THEN [] _ secondTransHandle.Finish[requestedOutcome: abort, continue: FALSE] ; }; fsFileState: FSFileState => { fullF: ROPE; created: BasicTime.GMT ; [fullFName: fullF] _ fsFileState.openFile.GetName[]; [created: created] _ fsFileState.openFile.GetInfo[]; fsFileState.openFile.Close[]; FS.Delete[name: fullF, wantedCreatedTime: created]; }; ENDCASE => ERROR; RETURN[TRUE]; }; FillBuffer[fromFile, pagesToMove]; EmptyBuffer[toFile, pagesToMove]; pagesCopied _ pagesCopied + pagesToMove; ENDLOOP; }; transHandle: AlpTransaction.Handle _ trans; secondInst: AlpInstance.Handle _ NIL; secondTransHandle: AlpTransaction.Handle _ NIL; toFile, fromFile: FileState; byteLength: AlpineEnvironment.ByteCount; createTime: BasicTime.GMT; bufferLen: CARDINAL = 12; pageCount: PageCount ; bufferInterval: VM.Interval _ TRASH; bufferAllocated: BOOL _ FALSE ; bufferPtr: LONG POINTER; pagesCopied: INT; cp: FS.ComponentPositions; toServer, fromServer: ROPE ; fullN: ROPE ; IFSResult: BOOL ; alpineSource: BOOL ; alpineResult: BOOL ; alpineSourceAndResult: BOOL; twoDifferentAlpine: BOOL _ FALSE; alpineProperties: LIST OF AlpineEnvironment.PropertyValuePair _ NIL; highWaterMark: AlpineEnvironment.PageCount _ 0; createLength: AlpineEnvironment.ByteCount; alpineSize: INT; { ENABLE UNWIND => { IF transHandle # NIL THEN [] _ AlpTransaction.Finish[transHandle, abort ! RPC.CallFailed => CONTINUE]; IF secondTransHandle # NIL THEN [] _ AlpTransaction.Finish[secondTransHandle, abort ! RPC.CallFailed => CONTINUE]; IF bufferAllocated THEN TRUSTED {VM.Free[bufferInterval]}; bufferAllocated _ FALSE; IF fromFile # NIL THEN CleanupFileState[fromFile ! FS.Error => CONTINUE]; IF toFile # NIL THEN CleanupFileState[toFile ! FS.Error => CONTINUE]; }; IF transHandle # NIL AND d.assertWheel THEN transHandle.AssertAlpineWheel[TRUE]; fromFile _ CreateFileState[file: from, createOptions: oldOnly]; [byteLength, createTime, alpineProperties, highWaterMark, alpineSize] _ GetFileProperties[fromFile]; [fullFName: fullN, cp: cp] _ FS.ExpandName[name: to]; toServer _ Rope.Substr[fullN,cp.server.start, cp.server.length]; alpineResult _ Rope.Match[pattern: "*.alpine", object: toServer, case: FALSE] ; [fullFName: fullN, cp: cp] _ FS.ExpandName[name: from]; fromServer _ Rope.Substr[fullN,cp.server.start, cp.server.length]; alpineSource _ Rope.Match[pattern: "*.alpine", object: fromServer, case: FALSE] ; alpineSourceAndResult _ alpineResult AND alpineSource ; IF byteLength < 0 AND (~alpineSourceAndResult OR ~fullCopy) THEN RETURN[CONS[ NARROW["The source file has negative length. Copy aborted.",ROPE] ,NIL]]; IF alpineSourceAndResult AND fullCopy THEN { createLength _ MAX[byteLength, BytesForPages[highWaterMark], alpineSize]; } ELSE createLength _ byteLength; IF Rope.IsEmpty[toServer] OR alpineResult THEN { IFSResult _ FALSE; IF alpineSourceAndResult AND ~Rope.Equal[ s1: fromServer, s2: toServer, case: FALSE] THEN { twoDifferentAlpine _ TRUE; secondInst _ AlpInstance.Create[fileStore: toServer, caller: caller, key: key]; secondTransHandle _ AlpTransaction.Create[secondInst]; IF d.assertWheel THEN secondTransHandle.AssertAlpineWheel[TRUE]; toFile _ CreateFileState[file: to, createOptions: none, createLength: createLength, trans: secondTransHandle]; } ELSE toFile _ CreateFileState[file: to, createOptions: none, createLength: createLength]; } ELSE { IFSResult _ TRUE; toFile _ CreateFileState[file: "///temp/qqqscratch.yodel", createOptions: none, createLength: createLength]; }; -- toFile _ CreateFileState[file: to, createOptions: none, createLength: byteLength]; pageCount _ PagesForBytes[createLength]; TRUSTED BEGIN bufferInterval _ VM.Allocate[count: bufferLen]; bufferAllocated _ TRUE ; bufferPtr _ VM.AddressForPageNumber[bufferInterval.page]; END; IF moveTheBits[] THEN RETURN[CONS[ NARROW["Copy aborted ",ROPE] ,NIL]]; SetFileProperties[toFile, byteLength, createTime, alpineProperties]; CleanupFileState[fromFile]; CleanupFileState[toFile]; IF twoDifferentAlpine THEN { IF (secondTransHandle.Finish[requestedOutcome: commit, continue: FALSE] # commit) THEN RETURN[CONS[ NARROW[ "Transaction on destination server failed to commit - validity of copy is in question", ROPE] ,NIL]]; }; TRUSTED BEGIN VM.Free[bufferInterval]; bufferAllocated _ FALSE ; END; IF IFSResult THEN { FS.Copy[from: "///temp/qqqscratch.yodel", to: to ]; FS.Delete[name: "///temp/qqqscratch.yodel"]; }; IF transHandle # NIL AND (transHandle.Finish[requestedOutcome: commit, continue: FALSE] # commit) THEN RETURN[CONS[ NARROW["Transaction on source server failed to commit - validity of copy is in question",ROPE] ,NIL]]; }; }; CopyFilesProc: PUBLIC Buttons.ButtonProc = { InnerCopyFilesProc[FALSE, parent, clientData, mouseButton, shift, control]; }; FullCopyFilesProc: PUBLIC Buttons.ButtonProc = { InnerCopyFilesProc[TRUE, parent, clientData, mouseButton, shift, control]; }; InnerCopyFilesProc: PROC [fullCopy: BOOL, parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift, control: BOOL _ FALSE]= BEGIN d: MyData = NARROW[clientData]; resultList: LIST OF REF ANY _ NIL; result: ROPE; server, srcServer, srcFile, srcDir, destServer, destFile, destDir: ROPE; user, password: ROPE; directory, sRestOfPattern, dRestOfPattern: ROPE; toFile, fromFile: ROPE; callCopy: YodelData.PerformProc = { RETURN[fileCopy[trans: trans, to: toFile, from: fromFile, fullCopy: fullCopy, user: user, password: password, caller: caller, key: key, d: d ]]; }; d.stopFlag _ FALSE; [user, password, srcServer, srcDir, srcFile] _ ParseSArgs[d]; [destServer, destDir, destFile] _ ParseDArgs[user, d]; [directory, sRestOfPattern] _ DecomposePattern[server: srcServer, pattern: srcFile, user: user]; IF (Rope.Equal[srcServer,""] OR Rope.Equal[srcServer,NIL]) THEN BEGIN IF srcFile.InlineLength[]>0 AND srcFile.InlineFetch[0] = '< THEN fromFile _ Rope.Concat["[]", srcFile] ELSE fromFile _ srcFile; END ELSE BEGIN fromFile _ Rope.Concat["[",Rope.Concat[srcServer,Rope.Concat["]", Rope.Concat[directory,sRestOfPattern]]]]; END; [directory, dRestOfPattern] _ DecomposePattern[server: destServer, pattern: destFile, user: user]; IF (Rope.Equal[destServer,""] OR Rope.Equal[destServer,NIL]) THEN BEGIN IF destFile.InlineLength[]>0 AND destFile.InlineFetch[0] = '< THEN toFile _ Rope.Concat["[]", destFile] ELSE toFile _ destFile; END ELSE BEGIN toFile _ Rope.Concat["[",Rope.Concat[destServer,Rope.Concat["]", Rope.Concat[directory,dRestOfPattern]]]]; END; IF hasPattern[sRestOfPattern] OR hasPattern[dRestOfPattern] THEN BEGIN d.out.PutF["\nCopy only works on a single file to a single file\n"]; END ELSE BEGIN d.out.PutF["\nCopy of %g to %g\n", IO.rope[fromFile], IO.rope[toFile]]; IF Rope.Match[pattern: "*.alpine", object: srcServer, case: FALSE] THEN server _ srcServer ELSE server _ destServer ; resultList _ PerformOp[performProc: callCopy, server: server, user: user, password: password]; IF resultList = NIL THEN BEGIN d.out.PutF[" Copy seems OK.\n"]; END ELSE BEGIN result _ NARROW[resultList.first]; d.out.PutF[" %g\n", IO.rope[result]]; END; END; END; OptionsProc: PUBLIC Buttons.ButtonProc= BEGIN d: MyData = NARROW[clientData]; p: ViewerClasses.Viewer = NARROW[parent]; d.displayOptions _ NOT d.displayOptions ; CreateButtons[d, p.parent.parent]; END; ChangeOptionsProc: PUBLIC Buttons.ButtonProc = BEGIN d: MyData = NARROW[clientData]; p: ViewerClasses.Viewer = NARROW[parent]; count: INT ; option: AlpineEnvironment.Property; FOR count IN [0..NumberOfAlpineProperties) DO propertyName: ROPE ; [option, propertyName] _ PropertySetToRopeArray[count]; IF Rope.Equal[propertyName, p.name] THEN BEGIN d.displayProperties[option] _ NOT d.displayProperties[option] ; IF d.displayProperties[option] THEN Buttons.SetDisplayStyle[p, $WhiteOnBlack] ELSE Buttons.SetDisplayStyle[p, $BlackOnWhite]; EXIT; END; ENDLOOP; END; END. ฆYodel: User commands YodelUser.mesa Last Edited by: Hagmann, January 23, 1985 5:22:33 pm PST Rhagmann, January 24, 1985 9:39:30 am PST loop through properties and print those enabled byteLength createTime highWaterMark modifyAccess owner readAccess stringName version alpine files to list FS or IFS files to list loop through all the properties and find the one selected comparison is by Rope equivalent to option! สs˜Jšœ™Jšœ™šœ8™8J™)—Jšœ˜Jšฯk ˜ Jšœ œG˜VJšœ,˜,Jšœ˜Jšœ œ'˜7Jšœ0˜0JšœH˜HJšœ+˜+Jšœ œ˜0Jšœ˜Jšœœ#˜-Jšœ4˜4Jšœ œ-˜?Jšœœ6˜JJšœ œœ˜Jšœ œ˜Jšœ œ(˜7Jšœœ2˜>JšœF˜FJšœ?˜?Jšœœ$œ˜EJšœœ˜Jšœœ˜Jšœ œ˜"Jšœ˜Jšœ˜Jšœœ˜Jšœœ ˜Jšœ œ˜!Jšœœ2˜=Jšœ ˜ J˜Jšฯb œœ˜J˜JšœHœœ:œ ˜œJ˜Jšœ ˜Jšœ˜Jšœ˜J˜Jšœœœ˜,Jšœ˜Jšœ œœ ˜Jšœœœ˜$Jšœ œœ ˜Jšœœœ˜/Jšœœœ˜'Jšœœœ˜$J˜J˜šฯn œœœ˜NJšœ,˜2Jšœ˜—J˜šŸ œœœ˜NJšœ˜"Jšœ˜—J˜J˜Jšœ˜Jšœœœ˜J˜šž œœœœ œœœ˜?Jšœ(˜.Jšœ˜—JšUœ Ÿ œœœœœœœ œœœœžœœ œœœœŸ œœœœ.œœAฯc2œ?œœœœ๚œœœœถŸ œœœœ!œœ{œœœœฌ˜า š&ž œœ(œ œœœ œœiœœœœœ$œœœœœœ˜ะš Ÿœœ œœ2œœ˜rJšœ9œœœ˜^Jšœ,œœœ˜Qšœ œ˜Jš œ œœœ œ˜JJšœœ˜Jšœ˜—JšœUœœ˜dJšœ˜Jšœ˜Jšœ œœ%˜8Jšœ œ˜Jšœ œ˜Jš œ‡œ(œ:œœ œœ˜Jšœ˜J˜JšœF˜FJšœ%œ ˜4Jšœ&˜&Jšœ œ9œœ ˜ZJšœ œœ˜Jšœ ˜ Jšœœ˜-JšœE˜EJšœœœ˜9Jšœ/™/Jšœœœ˜!JšœL˜LJšœ'˜'Jšœ œ&œ˜œ3œœFœœFœœ(œ8œ œ˜่—J˜Jšœ˜Jšœœœ˜Jšœ$˜$Jšœœ˜šœ ˜ JšœE˜Ešœ œœ˜Jšœ™Jšœ œ˜Jšœœœ˜4šœ/œ˜7Jšœ œœ@˜lJšœ˜—Jšœณ˜ณJšœ/˜/Jšœ˜—Jšœœ˜šœ™Jšœ œ˜Jšœj˜jJšœ7˜9Jšœ˜—Jšœ˜J˜Jšœ0˜0Jšœ˜Jšœ˜—Jš œŸœœœ œ œœ˜HJšƒœœœœ œœœ7œœœœœœœœœ œ0œœFœ"œœ4œœœƒœœœœœ=œ œIœnœœœž œœœœœœœœœ2œ"œœœ=œwœไœœœ‡œœœœœœœFœ*œœœœœ:œž œœ(œœ œœ œœœ œœœœœ1œŸœœ œœ7œœ œ œœœœ œ œœœ_œœœมœœ(œ:œœžœœ Kœ 1œœ œœœœ œ œ œ œFœœ'œ.œ œ"œœ2œRœ œœ  œœ œœœ œ/œ œ œœ‹œœœZœœœœœTœ  œœƒœœ.œ™œžœœœœœœœœœ"œœ œœœ;œ—œธœœ\œœœœ<œœœ…œœœœœœœFœ*œœœœœ=œ˜™5Jšวœ +ะck Ÿžœœ$œœœœœ œœœœ\œœœœœœœ#œœ œœJœœ%œ2œ&œœ'œœ)œœŸœœœJœ8œ œœ8œœ>œHœœœœœœ'œœœœœŸœdœœ œœœœ>œ œ œœœœœœœIœ0œ3œ(œœœPœœ œœ œ$œœ5œœœ"œœ8œYœBœ.Ÿœœ!œ œœžœœ˜ศšœŸœœ˜/šœBœœœ'œ œ-œ ˜โšœ œ˜šœ%˜%Jšœ œœ˜'Jšœ2˜2Jšœ9˜9šœœ˜JšœB˜BJšœ˜šœ˜šœ˜šœ œ ˜Jšœ;˜;—Jšœœ4˜RJšœ˜—šœ˜Jšœ œ ˜Jšœ;˜;Jšœœ4˜RJšœ˜—šœ˜šœœ ˜ JšœA˜A—Jšœœ:˜XJ˜—šœ˜šœ-œ ˜=Jšœ?˜?—Jšœœ8˜VJ˜—šœ˜šœ+œ ˜;Jšœ;˜;—Jšœœ4˜RJ˜—J˜Jšœ˜—Jšœ˜—Jšœ˜—šœ˜JšœJ˜JJšœ˜—Jšœœ˜—šœ˜J˜———Jš๙œŸœœ] œœœ$œ œ œœรœ๘œœŸ œœ$œ œ œœ9œœ‚ œ8œ?œœiœœœŸ œœ"œ œœœ9œœƒ œ8œ?œœjœœœž œœœ œœ"œœœ/œœ!œ œ œœœxœœœœPœMœ œทœJœœ œœœcœ1œjœœ6œ œœœœœœ œ/œœœœœ<œœœœ'œˆœœ œœœ:œะksœ œœœ@œขœœœœœ1œ œ œœœ œ œ œœœ œœœœœœย˜%JšEœ)œงœ'œฑœ/œœœœ œœœ œ7œ œœœ œœHœ*œœœœ œœ<œœ!œคœœ%œœiœœ‘˜๔ šWœ XœCœœœ6œœ2œœœœœœœœ—œœ œ?œœœœœtœœœœœ,œœœ œ œ9œ;œœœ@œœœœ œSœœ˜ˆ šž œœ˜,Jšœœ3˜KJšœ˜J˜—šžœœ˜0Jšœœ3˜JJ˜—J˜šะbnœœ œ œœœœœ˜UJš•œ6œœœœœœœœœœIœœ1œœ9œพœ์œœœœœœœ)œ2œœœœ~œrœœœœœœœ+œ1œœœœ}œ œœœœXœœœ3œœœ:œ œœ‰œœœœ1œœœœ1œœœ œž œœœœ,œ!œ=œ˜Ž——šžœœ˜4Jšœ œ ˜Jšœœ ˜)Jšœœ˜ šœ#˜#Jšœ9™9Jšœ+™+—šœœ˜-Jšœœ˜Jšœ7˜7šœ"œ˜.Jšœœ˜?Jšœœ+œ+˜}Jšœ˜Jšœ˜—Jšœ˜—Jšœ˜—Jšœ˜Jšœ˜Jšœœ˜J˜—…—‰ชกร