DIRECTORY CIFS: TYPE USING[Close, create, GetFC, Open, OpenFile, replace, write], ConvertUnsafe: TYPE USING[ToRope], CWF: TYPE USING [SWF1, SWF4, WF0, WF1, WF2, WFCR], DCSFileTypes: TYPE USING [tLeaderPage], Directory: TYPE USING [CreateFile, DeleteFile, Error, Handle, ignore, Lookup, Rename], Environment: TYPE USING [bytesPerPage], File: TYPE USING [Capability, nullCapability, Permissions, read, SetSize], FileStream: TYPE USING [Create, GetLength, SetLeaderPropertiesForCapability], FQ: TYPE USING[FileQuery, Result], Heap: TYPE USING[systemZone], Inline: TYPE USING [BITNOT, LowHalf], IO: TYPE USING[card, PutF, string, UserAbort], LongString: TYPE USING [AppendChar, EquivalentString], Process: TYPE USING [Pause, SecondsToTicks], Space: TYPE USING [Create, Delete, Handle, LongPointer, Map, nullHandle, virtualMemory], UnsafeSTP: TYPE USING [Connect, Create, CreateRemoteStream, DesiredProperties, Destroy, Error, ErrorCode, FileInfo, GetFileInfo, Handle, Login, NextFileName, Open, SetDesiredProperties, Type], UnsafeSTPOps: TYPE USING [FindFileType, Handle, SetPListItem], STPSubr: TYPE USING [RetrieveProcType, StpState], Stream: TYPE USING [Delete, EndOfStream, GetBlock, Handle, PutBlock], Subr: TYPE USING [AbortMyself, AllocateString, Any, CopyString, CursorInWindow, EndsIn, errorflg, FileError, FreeString, GetCreateDate, GetNameandPassword, LongZone, NewStream, Prefix, Read, SetRemoteFilenameProp, strcpy, SubStrCopy, TTYProcs, Write], UserCredentialsUnsafe: TYPE USING[GetUserCredentials], UserTerminal: TYPE USING [cursor, CursorArray, GetCursorPattern, SetCursorPattern]; STPSubrImpl: PROGRAM IMPORTS CIFS, ConvertUnsafe, CWF, Directory, File, FileStream, FQ, Heap, Inline, IO, LongString, Process, Space, STP: UnsafeSTP, STPOps: UnsafeSTPOps, Stream, Subr, UserCredentialsUnsafe, UserTerminal EXPORTS STPSubr SHARES File = { useCIFS: BOOL _ TRUE; connseq: LONG POINTER TO ConnSeqRecord _ NIL; maxNumberOfTries: CARDINAL _ 10; -- # tries to get connected if rejecting MAXCONNS: CARDINAL = 8; ConnSeqRecord: TYPE = RECORD[ size: CARDINAL _ 0, -- # of connections body: SEQUENCE maxsize: CARDINAL OF ConnTable ]; ConnTable: TYPE = RECORD[ stphandle: STP.Handle _ NIL, host: LONG STRING _ NIL ]; SetUseOfCIFS: PUBLIC PROC[shouldUseCIFS: BOOL] = { useCIFS _ shouldUseCIFS; -- in a procedure to make sure the module is started }; EnumerateForRetrieve: PUBLIC PROC[host, filePattern: LONG STRING, enumProc: STPSubr.RetrieveProcType, h: Subr.TTYProcs, onlyOne: BOOL] ={ stp: STP.Handle; remoteStream: Stream.Handle _ NIL; remoteName: LONG STRING _ NIL; skipRest, tryAgain: BOOL; desiredProperties: STP.DesiredProperties _ ALL[FALSE]; shortFilePattern: LONG STRING _ Subr.AllocateString[100]; Cleanup: PROC = { IF remoteName ~= NIL THEN Heap.systemZone.FREE[@remoteName]; IF remoteStream ~= NIL THEN Stream.Delete[remoteStream]; remoteStream _ NIL; }; TryIt: PROC = { skipRest _ FALSE; remoteName _ NIL; remoteStream _ STP.CreateRemoteStream[stp, shortFilePattern, read ! STP.Error => IF HandleSTPError[stp, code, error, h] THEN RETRY ]; DO ENABLE UNWIND => Cleanup[]; IF remoteName ~= NIL THEN Heap.systemZone.FREE[@remoteName]; remoteName _ STP.NextFileName[remoteStream]; IF remoteName = NIL THEN EXIT; IF skipRest THEN LOOP; skipRest _ enumProc[remoteName, stp, remoteStream]; ENDLOOP; Cleanup[]; }; {ENABLE UNWIND => Subr.FreeString[shortFilePattern]; Subr.strcpy[shortFilePattern, filePattern]; desiredProperties[directory] _ TRUE; desiredProperties[nameBody] _ TRUE; desiredProperties[version] _ TRUE; desiredProperties[createDate] _ TRUE; desiredProperties[size] _ TRUE; DO tryAgain _ FALSE; stp _ Connect[host: host, h: h, onlyOne: onlyOne]; STP.SetDesiredProperties[stp, desiredProperties]; TryIt[ ! STP.Error => IF HandleSTPError[stp, code, error, h] THEN { tryAgain _ TRUE; CONTINUE; } ELSE IF code = connectionClosed THEN { CWF.WF1["Connection to %s timed out.\n"L, host]; tryAgain _ TRUE; CONTINUE; }; ]; IF NOT tryAgain THEN EXIT; stp _ ForceClosed[stp]; IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; ENDLOOP; }; -- of ENABLE UNWIND Subr.FreeString[shortFilePattern]; }; GeneralOpen: PUBLIC PROC[filename: LONG STRING, h: Subr.TTYProcs, access: File.Permissions, fileType: STP.Type, -- FileType -- createtime: LONG CARDINAL] RETURNS[sh: Stream.Handle, stphandle: STP.Handle] = { tryAgain: BOOL; desiredProperties: STP.DesiredProperties _ ALL[FALSE]; host, sfn: LONG STRING _ NIL; sh _ NIL; IF filename[0] ~= '[ AND filename[0] ~= '< THEN { sh _ Subr.NewStream[filename, access]; RETURN[sh, NIL]; }; host _ Subr.AllocateString[40]; sfn _ Subr.AllocateString[100]; {ENABLE UNWIND => {Subr.FreeString[host]; Subr.FreeString[sfn]}; Subr.strcpy[sfn, filename]; StripHost[host, sfn]; StartSTP[]; DO tryAgain _ FALSE; stphandle _ Connect[host, h, FALSE]; desiredProperties[directory] _ TRUE; desiredProperties[nameBody] _ TRUE; desiredProperties[version] _ TRUE; desiredProperties[createDate] _ TRUE; desiredProperties[size] _ TRUE; STP.SetDesiredProperties[stphandle, desiredProperties]; sh _ STP.CreateRemoteStream[stp: stphandle, file: sfn, access: IF access = Subr.Read THEN read ELSE write, fileType: IF access = Subr.Read THEN unknown ELSE (IF fileType = unknown THEN GetFileType[sfn] ELSE fileType), creation: LOOPHOLE[createtime] ! STP.Error => IF code = noSuchFile THEN { CWF.WF2["Error - %s: %s.\n\n"L, filename, error]; ERROR Subr.FileError[notFound]; } ELSE IF code = connectionClosed THEN { CWF.WF1["Connection to %s timed out.\n"L, host]; tryAgain _ TRUE; CONTINUE; } ELSE IF HandleSTPError[stphandle,code,error,h] THEN RETRY]; IF NOT tryAgain THEN EXIT; stphandle _ ForceClosed[stphandle]; IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; ENDLOOP; }; -- of ENABLE UNWIND Subr.FreeString[host]; Subr.FreeString[sfn]; }; PatternGeneralOpen: PUBLIC PROC [filepattern: LONG STRING, proc: STPSubr.RetrieveProcType, h: Subr.TTYProcs] = { host, sfn: LONG STRING _ NIL; IF filepattern[0] ~= '[ AND filepattern[0] ~= '< THEN { sh: Stream.Handle; sh _ Subr.NewStream[filepattern, Subr.Read ! Subr.FileError => GOTO err]; [] _ proc[filepattern, NIL, sh]; Stream.Delete[sh]; RETURN; EXITS err => Subr.errorflg _ TRUE; }; host _ Subr.AllocateString[40]; sfn _ Subr.AllocateString[100]; {ENABLE UNWIND => {Subr.FreeString[host]; Subr.FreeString[sfn]}; Subr.strcpy[sfn, filepattern]; StripHost[host, sfn]; EnumerateForRetrieve[host, sfn, proc, h, TRUE ! STP.Error => IF code = noSuchFile THEN { CWF.WF2["Error - %s: %s.\n\n"L, filepattern, error]; GOTO err; } ]; EXITS err => Subr.errorflg _ TRUE}; -- of ENABLE UNWIND Subr.FreeString[host]; Subr.FreeString[sfn]; }; CachedOpen: PUBLIC PROC[host, directory, shortname: LONG STRING, version: CARDINAL, wantcreatetime: LONG CARDINAL, h: Subr.TTYProcs, stpState: STPSubr.StpState, wantExplicitVersion, onlyOne, tryDollars: BOOL] RETURNS[sh: Stream.Handle, cap: File.Capability] = { cap _ CachedRetrieve[host, directory, shortname, version, wantcreatetime, h, stpState, wantExplicitVersion, onlyOne, tryDollars]; sh _ NIL; IF cap ~= File.nullCapability THEN sh _ FileStream.Create[[cap.fID, File.read]] ELSE sh _ Subr.NewStream[shortname, Subr.Read]; RETURN[sh, cap]; }; CachedRetrieve: PUBLIC PROC[host, directory, shortname: LONG STRING, version: CARDINAL, wantcreatetime: LONG CARDINAL, h: Subr.TTYProcs, stpState: STPSubr.StpState, wantExplicitVersion, onlyOne, tryDollars: BOOL] RETURNS[cap: File.Capability _ File.nullCapability] = { localOnly: BOOL _ host = NIL OR host.length = 0; localcreatetime: LONG CARDINAL _ 0; fileNotRetrieved: BOOL _ FALSE; { cap _ Directory.Lookup[fileName: shortname, permissions: Directory.ignore ! Directory.Error => GOTO notonlocal]; localcreatetime _ Subr.GetCreateDate[cap]; IF localcreatetime = wantcreatetime OR (wantcreatetime = 0 AND localOnly) THEN RETURN; EXITS notonlocal => NULL; }; IF tryDollars THEN { sDollar: LONG STRING _ Subr.AllocateString[100]; checkLocalDate: BOOL _ TRUE; {ENABLE UNWIND => Subr.FreeString[sDollar]; CWF.SWF1[sDollar, "%s$$"L, shortname]; cap _ Directory.Lookup[fileName: sDollar, permissions: Directory.ignore ! Directory.Error => {checkLocalDate _ FALSE; CONTINUE}]; }; Subr.FreeString[sDollar]; IF checkLocalDate THEN { localcreatetime _ Subr.GetCreateDate[cap]; IF localcreatetime = wantcreatetime THEN RETURN; }; }; IF NOT localOnly THEN { targetFileName: LONG STRING _ Subr.AllocateString[125]; localname: LONG STRING _ Subr.AllocateString[100]; dollar: LONG STRING _ Subr.AllocateString[100]; sfn: LONG STRING _ Subr.AllocateString[100]; remoteVersion: CARDINAL; remoteCreateTime: LONG CARDINAL; OneFile: STPSubr.RetrieveProcType = { info: STP.FileInfo _ STP.GetFileInfo[stp]; skipRest _ TRUE; IF tryDollars AND localcreatetime ~= 0 THEN CWF.SWF1[localname, "%s$$"L, shortname] ELSE { IF stpState.checkForOverwrite AND localcreatetime ~= 0 THEN SELECT CheckForOverwrite[shortname, localcreatetime, targetFileName, remoteCreateTime, h] FROM no => { fileNotRetrieved _ TRUE; RETURN; }; substitute => { cap _ Directory.Lookup[fileName: shortname, permissions: Directory.ignore ! Directory.Error => CONTINUE]; RETURN; }; yes => NULL; all => stpState.checkForOverwrite _ FALSE; ENDCASE => ERROR; Subr.strcpy[localname, shortname]; }; CWF.WF1["Retrieving %s "L, targetFileName]; IF tryDollars AND localcreatetime ~= 0 THEN CWF.WF1["(as %s)"L, localname] ELSE IF remoteCreateTime < localcreatetime THEN { CWF.SWF1[dollar, "%s$$"L, shortname]; Directory.DeleteFile[dollar ! Directory.Error => CONTINUE]; Directory.Rename[oldName: shortname, newName: dollar]; CWF.WF1["(local version renamed to %s)"L, dollar]; }; CWF.WF0[" ... "L]; [cap,] _ WriteStreamToDisk[remoteStream, localname, info.size, h]; Subr.SetRemoteFilenameProp[cap, targetFileName]; FileStream.SetLeaderPropertiesForCapability[cap: cap, create: LOOPHOLE[remoteCreateTime]]; CWF.WF1["%lu bytes.\n"L, @info.size]; RETURN; }; {ENABLE UNWIND => { Subr.FreeString[targetFileName]; Subr.FreeString[localname]; Subr.FreeString[dollar]; Subr.FreeString[sfn]; }; fres: FQ.Result; [fres: fres, remoteVersion: remoteVersion, remoteCreateTime: remoteCreateTime] _ FQ.FileQuery[host, directory, shortname, version, wantcreatetime, wantExplicitVersion, h, targetFileName]; SELECT fres FROM foundCorrectVersion => { vstring: STRING; IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; IF localcreatetime = remoteCreateTime THEN GO TO return; -- already on disk vstring _ IF Subr.Prefix[host, "maxc"L] THEN ";"L ELSE "!"L; CWF.SWF4[sfn, "<%s>%s%s%u"L, directory, shortname, vstring, @remoteVersion]; EnumerateForRetrieve[host, sfn, OneFile, h, onlyOne]; IF fileNotRetrieved THEN cap _ File.nullCapability; }; foundWrongVersion => ERROR Subr.FileError[wrongVersion]; notFound => ERROR Subr.FileError[notFound]; ENDCASE => ERROR; EXITS return => {}}; -- of ENABLE UNWIND Subr.FreeString[targetFileName]; Subr.FreeString[localname]; Subr.FreeString[dollar]; Subr.FreeString[sfn]; }; -- of IF NOT localOnly }; CheckForOverwrite: PROC [localname: LONG STRING, localcreate: LONG CARDINAL, remotename: LONG STRING, remotecreate: LONG CARDINAL, h: Subr.TTYProcs] RETURNS[answer: {all, yes, no, substitute}] = { h.out.PutF["Ok to retrieve %s, dated %t,\n\tand overwrite %s of %t ", IO.string[remotename], IO.card[remotecreate], IO.string[localname], IO.card[localcreate]]; SELECT h.Confirm[h.in, h.out, h.data, "", 'y] FROM 'q => SIGNAL Subr.AbortMyself; 'y => answer _ yes; 'l => answer _ substitute; 'a => answer _ all; ENDCASE => answer _ no; }; StartSTP: PROC = { longzone: UNCOUNTED ZONE; IF connseq ~= NIL THEN RETURN; longzone _ Subr.LongZone[]; connseq _ longzone.NEW[ConnSeqRecord[MAXCONNS]]; }; StopSTP: PUBLIC PROC = { ENABLE UNWIND => connseq _ NIL; longzone: UNCOUNTED ZONE; IF connseq = NIL THEN RETURN; longzone _ Subr.LongZone[]; FOR i: CARDINAL IN [0..connseq.size) DO IF connseq[i].stphandle ~= NIL THEN CloseAndFree[i]; ENDLOOP; longzone.FREE[@connseq]; }; Connect: PUBLIC PROC[host: LONG STRING, h: Subr.TTYProcs, onlyOne: BOOL] RETURNS[stphandle: STP.Handle] = { free: CARDINAL; StartSTP[]; IF onlyOne THEN { IF connseq.size > 0 AND connseq[0].host ~= NIL AND NOT LongString.EquivalentString[host, connseq[0].host] THEN { CloseAndFree[0]; IF connseq.size = 1 THEN connseq.size _ 0; }; }; free _ connseq.size; { FOR i: CARDINAL IN [0..connseq.size) DO IF connseq[i].host ~= NIL AND connseq[i].stphandle ~= NIL AND LongString.EquivalentString[host,connseq[i].host] AND LOOPHOLE[connseq[i].stphandle, STPOps.Handle].remoteStream = NIL THEN { free _ i; GOTO leave; }; IF connseq[i].host = NIL THEN free _ i; ENDLOOP; IF free = connseq.size THEN { IF connseq.size >= connseq.maxsize THEN { CWF.WF0["Error - to many conns\n"L]; RETURN[NIL]; }; connseq.size _ connseq.size + 1; }; connseq[free] _ [NIL, NIL]; -- in case MakeSTPHandle signals connseq[free].stphandle _ MakeSTPHandle[host, h]; connseq[free].host _ Subr.CopyString[host]; EXITS leave => NULL; }; STP.SetDesiredProperties[connseq[free].stphandle, ALL[FALSE]]; RETURN[connseq[free].stphandle]; }; ForceClosed: PUBLIC PROC[stphandle: STP.Handle] RETURNS[STP.Handle] = { FOR i: CARDINAL IN [0 .. connseq.size) DO IF stphandle = connseq[i].stphandle THEN CloseAndFree[i]; ENDLOOP; RETURN[NIL]; }; CloseAndFree: PROC[i: CARDINAL] = { CWF.WF1["Closing connection to %s ... "L, connseq[i].host]; connseq[i].stphandle _ STP.Destroy[connseq[i].stphandle ! STP.Error => CONTINUE]; CWF.WF0["closed.\n"L]; Subr.FreeString[connseq[i].host]; connseq[i].host _ NIL; }; CheckStarted: PROC = { IF connseq = NIL THEN ERROR; }; NPAGEBUFFER: CARDINAL = 6; WriteStreamToDisk: PUBLIC PROC[remotesh: Stream.Handle, localfilename: LONG STRING, byteLengthHint: LONG CARDINAL, h: Subr.TTYProcs] RETURNS[cap: File.Capability, nbytes: LONG CARDINAL] = { nxfer, npages: CARDINAL; stopit, flip: BOOL _ FALSE; space: Space.Handle _ Space.nullHandle; localsh: Stream.Handle _ NIL; buffer: LONG POINTER _ NIL; ca: UserTerminal.CursorArray _ ALL[0]; cursorX, cursorY: INTEGER; openFile: CIFS.OpenFile; ftp: UserTerminal.CursorArray _ [ 177400B, 177400B, 177400B, 177400B, 177400B, 177400B, 177400B, 177400B, 000377B, 000377B, 000377B, 000377B, 000377B, 000377B, 000377B, 000377B]; Cleanup: PROC = { IF space ~= Space.nullHandle THEN Space.Delete[space]; space _ Space.nullHandle; IF localsh ~= NIL THEN Stream.Delete[localsh]; localsh _ NIL; IF flip THEN UserTerminal.SetCursorPattern[ca]; IF useCIFS AND openFile ~= NIL THEN CIFS.Close[openFile]; openFile _ NIL; }; npages _ Inline.LowHalf[byteLengthHint/Environment.bytesPerPage] + 2; nbytes _ 0; cap _ File.nullCapability; IF useCIFS THEN { openFile _ CIFS.Open[ConvertUnsafe.ToRope[localfilename], CIFS.replace+CIFS.create+CIFS.write]; cap _ CIFS.GetFC[openFile]; } ELSE { cap _ Directory.CreateFile[localfilename, DCSFileTypes.tLeaderPage, npages ! Directory.Error => { IF type = fileAlreadyExists THEN { cap _ Directory.Lookup[fileName: localfilename, permissions: Directory.ignore]; IF npages > 2 THEN File.SetSize[cap, npages]; } ELSE ERROR Subr.FileError[notFound]; CONTINUE }]; }; localsh _ FileStream.Create[[cap.fID, Subr.Write]]; space _ Space.Create[NPAGEBUFFER, Space.virtualMemory]; Space.Map[space]; buffer _ Space.LongPointer[space]; IF Subr.CursorInWindow[h] THEN { [cursorX, cursorY] _ UserTerminal.cursor^; ca _ UserTerminal.GetCursorPattern[]; UserTerminal.SetCursorPattern[ftp]; flip _ TRUE; }; WHILE NOT stopit DO ENABLE UNWIND => Cleanup[]; [bytesTransferred: nxfer] _ Stream.GetBlock[remotesh, [buffer, 0, NPAGEBUFFER*Environment.bytesPerPage] ! STP.Error => IF code = noSuchFile THEN { CWF.WF1["\n\tError - %s not found.\n"L, localfilename]; EXIT; }; Stream.EndOfStream => { stopit _ TRUE; nxfer _ nextIndex; CONTINUE } ]; IF nxfer = 0 THEN EXIT; Stream.PutBlock[localsh, [buffer, 0, nxfer]]; nbytes _ nbytes + nxfer; IF flip AND cursorX = UserTerminal.cursor^.x AND cursorY = UserTerminal.cursor^.y THEN { bits: UserTerminal.CursorArray _ UserTerminal.GetCursorPattern[]; FOR i: CARDINAL IN [0..16) DO bits[i] _ Inline.BITNOT[bits[i]]; ENDLOOP; UserTerminal.SetCursorPattern[bits]; }; ENDLOOP; Cleanup[]; }; Store: PUBLIC PROC [stphandle: STP.Handle, remoteName: LONG STRING, localCap: File.Capability, createDate: LONG CARDINAL, h: Subr.TTYProcs] RETURNS[nbytes: LONG CARDINAL] = { ft: STP.Type; localStream, remoteStream: Stream.Handle _ NIL; len: LONG CARDINAL; lstr: LONG STRING _ Subr.AllocateString[40]; remName: LONG STRING _ Subr.AllocateString[100]; Cleanup: PROC = { IF localStream ~= NIL THEN Stream.Delete[localStream]; localStream _ NIL; IF remoteStream ~= NIL THEN Stream.Delete[remoteStream]; remoteStream _ NIL; Subr.FreeString[lstr]; Subr.FreeString[remName] }; {ENABLE UNWIND => Cleanup[]; desiredProperties: STP.DesiredProperties _ ALL[FALSE]; nbytes _ 0; Subr.strcpy[remName, remoteName]; ft _ GetFileType[remoteName]; localStream _ FileStream.Create[[localCap.fID, Subr.Read]]; IF ft = unknown THEN ft _ STPOps.FindFileType[localStream]; desiredProperties[directory] _ TRUE; desiredProperties[nameBody] _ TRUE; desiredProperties[version] _ TRUE; STP.SetDesiredProperties[stphandle, desiredProperties]; remoteStream _ STP.CreateRemoteStream[stp: stphandle, file: remName, access: write, fileType: ft, creation: LOOPHOLE[createDate] ! STP.Error => IF HandleSTPError[stphandle, code, error, h] THEN RETRY]; len _ FileStream.GetLength[localStream]; CWF.SWF1[lstr, "%lu"L, @len]; STPOps.SetPListItem[LOOPHOLE[stphandle, STPOps.Handle].plist, "Size"L, lstr]; nbytes _ WriteDiskToStream[localStream, remoteStream, h]; }; -- of ENABLE UNWIND Cleanup[]; }; WriteDiskToStream: PROC [localsh, remotesh: Stream.Handle, h: Subr.TTYProcs] RETURNS[nbytes: LONG CARDINAL] = { nxfer: CARDINAL; stopit, flip: BOOL _ FALSE; space: Space.Handle _ Space.nullHandle; buffer: LONG POINTER _ NIL; cursorX, cursorY: INTEGER; ca: UserTerminal.CursorArray _ ALL[0]; ftp: UserTerminal.CursorArray _ [ 177400B, 177400B, 177400B, 177400B, 177400B, 177400B, 177400B, 177400B, 000377B, 000377B, 000377B, 000377B, 000377B, 000377B, 000377B, 000377B]; Cleanup: PROC = { IF space ~= Space.nullHandle THEN Space.Delete[space]; space _ Space.nullHandle; IF flip THEN UserTerminal.SetCursorPattern[ca]; }; nbytes _ 0; space _ Space.Create[NPAGEBUFFER, Space.virtualMemory]; Space.Map[space]; buffer _ Space.LongPointer[space]; IF Subr.CursorInWindow[h] THEN { [cursorX, cursorY] _ UserTerminal.cursor^; ca _ UserTerminal.GetCursorPattern[]; UserTerminal.SetCursorPattern[ftp]; flip _ TRUE; }; WHILE NOT stopit DO ENABLE UNWIND => Cleanup[]; [bytesTransferred: nxfer] _ Stream.GetBlock[localsh, [buffer, 0, NPAGEBUFFER*Environment.bytesPerPage] ! Stream.EndOfStream => { stopit _ TRUE; nxfer _ nextIndex; CONTINUE } ]; IF nxfer = 0 THEN EXIT; Stream.PutBlock[remotesh, [buffer, 0, nxfer]]; nbytes _ nbytes + nxfer; IF flip AND cursorX = UserTerminal.cursor^.x AND cursorY = UserTerminal.cursor^.y THEN { bits: UserTerminal.CursorArray _ UserTerminal.GetCursorPattern[]; FOR i: CARDINAL IN [0..16) DO bits[i] _ Inline.BITNOT[bits[i]]; ENDLOOP; UserTerminal.SetCursorPattern[bits]; }; ENDLOOP; Cleanup[]; }; StripHost: PROC[host, sfn: LONG STRING] = { IF sfn[0] ~= '[ THEN { Subr.strcpy[host, "Ivy"L]; RETURN; }; host.length _ 0; FOR i: CARDINAL IN [1..sfn.length) DO IF sfn[i] = '] THEN { FOR j: CARDINAL IN [1 .. i-1] DO LongString.AppendChar[host, sfn[j]]; ENDLOOP; Subr.SubStrCopy[sfn, sfn, i+1]; RETURN; }; ENDLOOP; CWF.WF1["Error - %s is not a valid remote file name.\n"L, sfn]; }; NSECPAUSE: CARDINAL = 10; -- # seconds to wait SetNumberOfConnectTries: PUBLIC PROC[nTries: CARDINAL] = { maxNumberOfTries _ nTries; }; MakeSTPHandle: PUBLIC PROC [host: LONG STRING, h: Subr.TTYProcs] RETURNS[stphandle: STP.Handle] = { herald, shorthost: LONG STRING _ NIL; ntries: CARDINAL _ 0; IF host = NIL OR host.length = 0 THEN { CWF.WF0["Error: remote host has not been specified.\n"L]; RETURN[NIL]; }; shorthost _ Subr.AllocateString[40]; {ENABLE UNWIND => Subr.FreeString[shorthost]; stphandle _ STP.Create[]; CWF.WF1["Opening connection to %s.\n"L, host]; Subr.strcpy[shorthost, host]; herald _ STP.Open[stphandle, shorthost ! STP.Error => IF code = connectionRejected THEN { CWF.WF1["Connection rejected by %s.\n"L, host]; ntries _ ntries + 1; IF ntries < maxNumberOfTries THEN { CWF.WF0["Will pause and try again. (Type control-DEL to abort.)\n"L]; IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; Process.Pause[Process.SecondsToTicks[NSECPAUSE]]; IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; RETRY; } ELSE CWF.WF0["Connection rejected too many times.\n"L]; }]; CWF.WF1["%s\n"L,herald]; Heap.systemZone.FREE[@herald]; STPLogin[stphandle]; }; -- of ENABLE UNWIND Subr.FreeString[shorthost]; }; STPLogin: PROC[stphandle: STP.Handle] = { n: LONG STRING _ Subr.AllocateString[50]; p: LONG STRING _ Subr.AllocateString[50]; {ENABLE UNWIND => {Subr.FreeString[n]; Subr.FreeString[p]}; UserCredentialsUnsafe.GetUserCredentials[name: n, password: p]; STP.Login[stphandle, n, p]; }; -- of ENABLE UNWIND Subr.FreeString[n]; Subr.FreeString[p]; }; HandleSTPError: PUBLIC PROC [stphandle: STP.Handle, stpError: STP.ErrorCode, message: LONG STRING, h: Subr.TTYProcs] RETURNS [retryit: BOOL] ={ SELECT stpError FROM illegalUserPassword, illegalUserName, illegalUserAccount, credentailsMissing => SetPass[stphandle, h, message]; illegalConnectName, illegalConnectPassword, accessDenied => SetOtherPass[stphandle, h, message]; ENDCASE => RETURN [FALSE]; RETURN[TRUE]; }; SetPass: PROC[stphandle: STP.Handle, h: Subr.TTYProcs, error: LONG STRING] = { IF error ~= NIL THEN CWF.WF1["Error - %s\n"L,error]; CWF.WF0["Enter "L]; Subr.GetNameandPassword[login, NIL, NIL, h]; CWF.WFCR[]; IF stphandle ~= NIL THEN STPLogin[stphandle]; }; SetOtherPass: PROC[stphandle: STP.Handle, h: Subr.TTYProcs, error: LONG STRING] = { user2: LONG STRING _ Subr.AllocateString[40]; -- must remain short for STP, dammitt! password2: LONG STRING _ Subr.AllocateString[40]; -- must remain short for STP, dammitt! {ENABLE UNWIND => {Subr.FreeString[user2]; Subr.FreeString[password2]}; IF error ~= NIL THEN CWF.WF1["Error - %s\n"L,error]; CWF.WF0["Enter Connect "L]; Subr.GetNameandPassword[connect, user2, password2, h]; IF stphandle ~= NIL AND user2.length > 0 THEN STP.Connect[stphandle, user2, IF password2.length = 0 THEN NIL ELSE password2]; IF user2.length = 0 AND password2.length = 0 THEN { IF h.Confirm[h.in, h.out, h.data, "\nType y to retry with different login name, n to abort ", 'n] = 'n THEN SIGNAL Subr.AbortMyself; CWF.WF0["Enter "L]; Subr.GetNameandPassword[login, NIL, NIL, h]; CWF.WFCR[]; STPLogin[stphandle]; }; }; -- of ENABLE UNWIND Subr.FreeString[user2]; Subr.FreeString[password2]; }; AddUserName: PUBLIC PROC[sto: LONG STRING, spat: LONG STRING, h: Subr.TTYProcs] = { u: LONG STRING _ Subr.AllocateString[40]; -- must remain short for STP, dammitt! p: LONG STRING _ Subr.AllocateString[40]; -- must remain short for STP, dammitt! lengthzero: BOOL; {ENABLE UNWIND => {Subr.FreeString[u]; Subr.FreeString[p]}; UserCredentialsUnsafe.GetUserCredentials[name: NIL, password: p]; lengthzero _ p = NIL OR p.length = 0; DO UserCredentialsUnsafe.GetUserCredentials[name: u, password: NIL]; IF u = NIL OR u.length = 0 OR Subr.Any[u,' ] OR Subr.Prefix[u, "CedarUser"L] OR lengthzero THEN { lengthzero _ FALSE; CWF.WF0["Enter "L]; Subr.GetNameandPassword[login, NIL, NIL, h]; CWF.WFCR[]; } ELSE EXIT; ENDLOOP; IF sto ~= NIL THEN CWF.SWF1[sto,spat,u]; }; -- of ENABLE UNWIND Subr.FreeString[u]; Subr.FreeString[p]; }; GetFileType: PROC[filename: LONG STRING] RETURNS[filetype: STP.Type] = { old: CARDINAL _ filename.length; FOR i: CARDINAL IN [0..old) DO IF filename[i] = '! OR filename[i] = '; THEN { filename.length _ i; EXIT; }; ENDLOOP; filetype _ unknown; IF Subr.EndsIn[filename,".mesa"L] OR Subr.EndsIn[filename,".bravo"L] OR Subr.EndsIn[filename,".config"L] OR Subr.EndsIn[filename,".cm"L] OR Subr.EndsIn[filename, ".mail"L] OR Subr.EndsIn[filename, ".df"L] THEN filetype _ text; IF Subr.EndsIn[filename,".bcd"L] OR Subr.EndsIn[filename,".press"L] OR Subr.EndsIn[filename,".run"L] THEN filetype _ binary; filename.length _ old; }; }. p STPSubrImpl.Mesa last edit March 8, 1983 12:37 pm last edit May 23, 1983 5:59 pm, Russ Atkinson reduced use of STRING in favor of LONG STRING MDS USAGE !!! endof MDS USAGE !!! connection table we use the username and password from Profile.userName, userPassword nested procedure needed to handle retrys of entire enumerates may generate STP.Error! if not found, raises Subr.FileError, for both remote and local files filename looks like [host]