FTPUser.mesa
Last edited by:
Taft, October 17, 1983 4:11 pm
DIRECTORY
;
FTPUser: CEDAR PROGRAM
IMPORTS
EXPORTS FTP, FTPInternal =
BEGIN OPEN FTP, FTPInternal;
FTP.
Object: PUBLIC TYPE = FTPInternal.Object;
CreateFromName: PUBLIC PROCEDURE [hostName: ROPE, localHerald: ROPENIL] RETURNS [h: Handle, remoteHerald: ROPE] =
BEGIN
hostAddress: PupStream.PupAddress = PupStream.GetPupAddress[PupTypes.ftpSoc, hostName !
PupStream.PupNameTrouble => h.GenerateFailed[MapNameLookupError[code], e]];
[h, remoteHerald] ← CreateFromAddress[hostAddress, localHerald];
END;
CreateFromAddress: PUBLIC PROCEDURE [hostAddress: PupStream.PupAddress, localHerald: ROPENIL] RETURNS [h: Handle, remoteHerald: ROPE] =
BEGIN
mark: Mark;
code: FailureCode;
h ← NEW[Object ← []];
h.byteStream ← PupStream.PupByteStreamCreate[hostAddress, PupStream.veryLongWait];
h.PutCommand[mark: version, code: LOOPHOLE[ftpVersion], text: localHerald, sendEOC: TRUE];
[mark, code] ← h.GetCommand[];
IF mark#version THEN h.GenerateFailed[protocolError];
IF code#ftpVersion THEN h.GenerateFailed[protocolError, "Incompatible protocol version"];
remoteHerald ← h.GetText[gobbleEOC: TRUE];
END;
Delete: PUBLIC PROCEDURE [h: Handle, confirm: ConfirmProc ← NIL] =
BEGIN
h.PutCommandAndPList[mark: delete, pList: h.pList[local], sendEOC: TRUE];
FOR firstTime: BOOLEANTRUE, FALSE DO
mark: Mark;
code: ReplyCode;
[mark, code] ← h.GetCommand[];
SELECT mark FROM
hereIsPList =>
BEGIN
h.pList[remote] ← h.GetPList[gobbleEOC: TRUE];
IF confirm#NIL AND confirm[h] THEN
BEGIN
h.PutCommand[mark: yes, text: "Delete it!", sendEOC: TRUE];
[] ← h.GetYesNo[resumable: TRUE];
END
ELSE h.PutCommand[mark: no, code: skipThisFile, sendEOC: FALSE];
END;
no =>
IF firstTime THEN h.GenerateFailed[code, h.GetText[gobbleEOC: TRUE], resumable: TRUE] ELSE h.GenerateFailed[protocolError];
endOfCommand =>
EXIT;
ENDCASE =>
h.GenerateFailed[protocolError];
ENDLOOP;
END;
Enumerate: PUBLIC PROCEDURE [h: Handle, noteFile: PROCEDURE [h: Handle]] =
BEGIN
NewEnumerate: PROCEDURE RETURNS [tryOld: BOOLEANFALSE] =
BEGIN
mark: Mark;
code: ReplyCode;
h.PutCommandAndPList[mark: newEnumerate, pList: h.pList[local], sendEOC: TRUE];
[mark, code] ← h.GetCommand[];
SELECT mark FROM
hereIsPList =>
DO -- process all property lists in (single) response to newEnumerate command
h.pList[remote] ← h.GetPList[endOfPropertiesOK: TRUE];
IF h.pList[remote]=NIL THEN EXIT;
noteFile[h];
ENDLOOP;
no =>
IF code=badCommand THEN RETURN [TRUE] -- newEnumerate unimplemented
ELSE h.GenerateFailed[code, h.GetText[gobbleEOC: TRUE]];
ENDCASE =>
h.GenerateFailed[protocolError];
END; -- NewEnumerate
OldEnumerate: PROCEDURE =
BEGIN
h.PutCommandAndPList[mark: enumerate, pList: h.pList[local], sendEOC: TRUE];
FOR firstTime: BOOLEANTRUE, FALSE DO
mark: Mark;
code: ReplyCode;
[mark, code] ← h.GetCommand[];
SELECT mark FROM
hereIsPList =>
BEGIN
h.pList[remote] ← h.GetPList[];
noteFile[h];
END;
no =>
IF firstTime THEN h.GenerateFailed[code, h.GetText[gobbleEOC: TRUE]] ELSE h.GenerateFailed[protocolError];
endOfCommand =>
IF firstTime THEN h.GenerateFailed[protocolError] ELSE EXIT;
ENDCASE =>
h.GenerateFailed[protocolError];
ENDLOOP;
END; -- OldEnumerate
IF ~NewEnumerate[] THEN OldEnumerate[];
END;
Rename: PUBLIC PROCEDURE [h: Handle, changeName: PROCEDURE [h: Handle]] =
BEGIN
oldPList: PList ← h.pList[local];
h.pList[local] ← NIL;
changeName[h];
h.PutCommandAndPList[mark: rename, pList: oldPList];
h.PutPList[pList: h.pList[local], sendEOC: TRUE];
[] ← h.GetYesNo[gobbleEOC: TRUE];
END;
Retrieve: PUBLIC PROCEDURE [h: Handle, confirm: ConfirmProc ← NIL, transfer: TransferProc, complete: CompleteProc ← NIL] =
BEGIN
h.PutCommandAndPList[mark: retrieve, pList: h.pList[local], sendEOC: TRUE];
FOR firstTime: BOOLEANTRUE, FALSE DO
mark: Mark;
code: ReplyCode;
[mark, code] ← h.GetCommand[];
SELECT mark FROM
hereIsPList =>
BEGIN
h.pList[remote] ← h.GetPList[gobbleEOC: TRUE];
IF confirm#NIL AND confirm[h] THEN
BEGIN
h.PutCommand[mark: yes, text: "Yes, please", sendEOC: TRUE];
[mark, code] ← h.GetCommand[];
SELECT mark FROM
hereIsData =>
BEGIN
ok: BOOLEANFALSE;
tranfer[h, h.byteStream];
ok ← h.GetYesNo[resumable: TRUE];
IF complete#NIL THEN complete[h, ok];
END;
no =>
h.GenerateFailed[code, h.GetText[gobbleEOC: TRUE], resumable: TRUE];
ENDCASE =>
h.GenerateFailed[protocolError];
END
ELSE h.PutCommand[mark: no, code: skipThisFile, sendEOC: FALSE];
END;
no =>
IF firstTime THEN h.GenerateFailed[code, h.GetText[gobbleEOC: TRUE], resumable: TRUE] ELSE h.GenerateFailed[protocolError];
endOfCommand =>
EXIT;
ENDCASE =>
h.GenerateFailed[protocolError];
ENDLOOP;
END;
Store: PUBLIC PROCEDURE [h: Handle, confirm: ConfirmProc ← NIL, transfer: TransferProc, complete: CompleteProc ← NIL] =
BEGIN
mark: Mark;
code: ReplyCode;
FOR protocol: {new, old} IN [new..old] DO
h.PutCommandAndPList[mark: IF protocol=new THEN newStore ELSE store, pList: h.pList[local], sendEOC: TRUE];
[mark, code] ← h.GetCommand[];
SELECT mark FROM
yes, hereIsPList =>
BEGIN
IF mark=hereIsPList THEN h.pList[remote] ← h.GetPList[gobbleEOC: TRUE];
IF confirm[h] THEN
BEGIN
ok: BOOLEANFALSE;
h.PutCommand[mark: hereIsFile];
tranfer[h, h.byteStream];
h.PutCommand[mark: yes, text: "Sent ok", sendEOC: TRUE];
ok ← h.GetYesNo[resumable: TRUE];
IF complete#NIL THEN complete[h, ok];
EXIT;
END
ELSE h.PutCommand[mark: no, code: skipThisFile, sendEOC: FALSE];
END;
no =>
BEGIN
text: ROPE = h.GetText[gobbleEOC: TRUE];
IF protocol=new AND code=badCommand THEN NULL -- try again with old protocol
ELSE h.GenerateFailed[code, text];
END;
ENDCASE =>
h.GenerateFailed[protocolError];
ENDLOOP;
END;
Procedures for doing FTP protocol operations
SmashClosed: PUBLIC PROCEDURE [stp: STPOps.Handle] =
BEGIN
IF stp = NIL OR stp.byteStream = NIL THEN RETURN;
First smash connection so it will not give us any grief, THEN close it
PupStream.PupByteStreamAbort[stp.byteStream, "Unwinding..."];
STP.Close[stp ! STP.Error => IF code = noConnection THEN CONTINUE];
END;
Error generation routines
END.