*	open an FTP connection (text only) for CSNOBOL4
*	Phil Budne <phil@ultimate.com>
*	Sept 26, 1997
*	$Id: ftp.sno,v 1.6 2004-08-19 06:55:31 phil Exp $

-include "tcp.sno"

*	whatever needs to be appended to line to make a CRLF
	FTP.EOL = CHAR(13)

****************
*	FTP.GETRES()
*	Get FTP result
*
*	for internal use only

	FTP.DIGIT = ANY('0123456789')

	DEFINE("FTP.GETRES(FTP.NAME)FTP.RES")		:(FTP.GETRES.END)
FTP.GETRES
	FTP.RES = $FTP.NAME				:F(FRETURN)
*	OUTPUT = '< ' FTP.RES
	FTP.RES POS(0) FTP.DIGIT FTP.DIGIT FTP.DIGIT '-' :S(FTP.GETRES)
	FTP.RES POS(0) '5'				:S(FRETURN)
							:(RETURN)
FTP.GETRES.END

****************
*	FTP.OPEN()
*	Open FTP command connection
*
*	args;
*	Name to associate for I/O
*	Internet hostname
*	Username
*	Password
*	TCP port (or null)

	DEFINE("FTP.OPEN(FTP.NAME,FTP.HOST,FTP.USER,FTP.PASS,FTP.PORT)FTP.RES")
							:(FTP.OPEN.END)

FTP.OPEN
*	Open command connection, read banner
	FTP.PORT = IDENT(FTP.PORT) "21" 
*	OUTPUT = FTP.HOST '/' FTP.PORT
	TCP.OPEN(FTP.NAME,FTP.HOST,FTP.PORT)		:F(FRETURN)
	FTP.GETRES(FTP.NAME)				:F(FTP.ERR)

*	Log in
	FTP.COMMAND(FTP.NAME, "USER " FTP.USER)		:F(FTP.ERR)
	FTP.COMMAND(FTP.NAME, "PASS " FTP.PASS)		:F(FTP.ERR)
							:(RETURN)

FTP.ERR	TCP.CLOSE(.FTP.CCON)				:(FRETURN)
FTP.OPEN.END

****************
*	FTP.COMMAND()
*		send an FTP command, no data connection
*
*	args;
*	I/O var for data, if any
*	command

	DEFINE("FTP.COMMAND(FTP.NAME,FTP.CMD)FTP.RES")	:(FTP.COMMAND.END)

FTP.COMMAND
*	OUTPUT = '> ' FTP.CMD
	$FTP.NAME = FTP.CMD FTP.EOL			:F(FRETURN)
	FTP.GETRES(FTP.NAME)				:F(FRETURN)
							:(RETURN)
FTP.COMMAND.END

****************
*	FTP.DATA.COMMAND()
*		send an FTP command, make data connection
*
*	args;
*	I/O var for control connection (from FTP.OPEN)
*	command
*	I/O var for data connection
*	I/O mode for data connection

	DEFINE("FTP.DATA.COMMAND(FTP.NAME,FTP.CMD,FTP.DATA,FTP.DATA.MODE)"
+		"FTP.RES,FTP.HOST,FTP.PORT.HI,FTP.PORT.LO")
							:(FTP.DATA.COMMAND.END)
FTP.DATA.COMMAND
*	OUTPUT = '> PASV'
	$FTP.NAME = "PASV" FTP.EOL			:F(FRETURN)
	FTP.RES = $FTP.NAME				:F(FRETURN)
*	OUTPUT = '< ' FTP.RES
	FTP.RES POS(0) '2' BREAKX('(') '('
+		(BREAK(',') ',' BREAK(',') ',' BREAK(',') ',' BREAK(','))
+			. FTP.HOST ',' BREAK(',') . FTP.PORT.HI ','
+			BREAK(')') . FTP.PORT.LO ')'	:F(FRETURN)

*	OUTPUT = REPLACE(FTP.HOST,',','.')
*	OUTPUT = FTP.PORT.HI * 256 + FTP.PORT.LO

	TCP.OPEN(FTP.DATA,
+		REPLACE(FTP.HOST, ',', '.'),
+		FTP.PORT.HI * 256 + FTP.PORT.LO,
+		FTP.DATA.MODE)				:F(FRETURN)

	$FTP.NAME = FTP.CMD FTP.EOL			:F(FRETURN)
	FTP.GETRES(FTP.NAME)				:F(FRETURN)

* 	XXX SAVE DATA CONN VAR NAME (indexed by command conn name)
							:(RETURN)

FTP.DATA.COMMAND.END

****************
*	FTP.DATA.CLOSE()
*		close an FTP data connection
*
*	args;
*	I/O var for data connection

	DEFINE("FTP.DATA.CLOSE(FTP.DATA)")		:(FTP.DATA.CLOSE.END)
FTP.DATA.CLOSE
	TCP.CLOSE(FTP.DATA)				:F(FRETURN)S(RETURN)
FTP.DATA.CLOSE.END

****************
*	FTP.CLOSE
*		close command connection
*
*	args;
*	I/O var

	DEFINE("FTP.CLOSE(FTP.NAME)FTP.RES")		:(FTP.CLOSE.END)
FTP.CLOSE
	$FTP.NAME = "QUIT"				:F(FTP.CLOSE2)
	FTP.RES = $FTP.NAME				:F(FTP.CLOSE2)

FTP.CLOSE2
*	XXX close current data connection too?
	TCP.CLOSE(FTP.NAME)				:(RETURN)
FTP.CLOSE.END

****************
*	FTP.OPEN.ANON()
*	Open Anonymous FTP command connection
*
*	args;
*	Name to associate for I/O
*	Internet hostname
*	TCP port (or null)

	FTP.ANON.USER = '-' (HOST(4,"LOGNAME"), HOST(4,"USER"), "idunno") '@'

	DEFINE("FTP.OPEN.ANON(FTP.NAME,FTP.HOST,FTP.PORT)")
							:(FTP.OPEN.ANON.END)
FTP.OPEN.ANON
	FTP.OPEN(FTP.NAME, FTP.HOST, 'anonymous', FTP.ANON.USER, FTP.PORT)
+							:F(FRETURN)S(RETURN)
FTP.OPEN.ANON.END

****************

*	example 1; retrieve a file using anonymous ftp

*	FTP.OPEN.ANON(.X, 'hostname')			:F(END)
*	FTP.DATA.COMMAND(.X, "RETR README", .Y)		:F(END)
*LOOP	OUTPUT = Y					:S(LOOP)
*	FTP.DATA.CLOSE(.Y)
*	FTP.CLOSE(.X)

*	example 2; store a file

*	FTP.OPEN(.X, 'hostname', 'user', 'password')	:F(END)
*	FTP.DATA.COMMAND(.X, "STOR FOO", .Y)		:F(END)
*	Y = "STUFF"
*	....
*	FTP.DATA.CLOSE(.Y)
*	FTP.CLOSE(.X)
