NEW
  AUTO 3,1
				.LIST OFF
				.OP	65C02
				.OR	$2000
				.TF bin/httpget
*--------------------------------------
				.INB inc/macros.i
				.INB inc/a2osx.i
				.INB inc/mli.i
				.INB inc/mli.e.i
				.INB inc/eth.i
				.INB inc/libtcpip.i
				.INB inc/net.tcpip.i
				.INB inc/net.http.i
*--------------------------------------
TIMEOUT.MAX		.EQ 250					25 sec.
*--------------------------------------
				.DUMMY
				.OR ZPBIN
ZS.START
ZPIPCfgPtr		.BS 2
ZPHostPtr		.BS 2
ZPPtr			.BS 2
ArgIndex		.BS 1
hSocket			.BS 1

hReqBuf			.BS 1
ZPReqBufPtr		.BS 2
ZPReqBufLen		.BS 2
bHeader			.BS 1
TimeOut			.BS 1

hEncodedBuf		.BS 1
ZPEncodedBufPtr	.BS 2
ZPEncodedBufLen	.BS 2
hSendBuf		.BS 1
ZPSendBufPtr	.BS 2

hRespBuf		.BS 1
ZPRespBufPtr	.BS 2
ZPRespBufLen	.BS 2
hFile			.BS 1
ZPFileName		.BS 2

ZS.END			.ED
*--------------------------------------
*			File Header (16 Bytes)
*--------------------------------------
CS.START		cld
				jmp (.1,x)
				.DA #$61				6502,Level 1 (65c02)
				.DA #1					BIN Layout Version 1
				.DA #S.PS.F.EVENT		S.PS.F
				.DA #0
				.DA CS.END-CS.START		Code Length To Relocate
				.DA DS.END-DS.START		Data Segment to Allocate
				.DA #64					SS
				.DA #ZS.END-ZS.START	Zero Page Size
				.DA 0
*--------------------------------------
.1				.DA CS.INIT
				.DA CS.RUN
				.DA CS.DOEVENT
				.DA	CS.QUIT
L.LIBTCPIP		.DA LIBTCPIP
L.SA.LOCAL		.DA SA.LOCAL
L.SA.REMOTE		.DA SA.REMOTE
L.SA.REMOTE.AD	.DA SA.REMOTE+S.SOCKADDR.ADDR
L.MSG.IPKO		.DA MSG.IPKO
L.MSG.USAGE		.DA MSG.USAGE
L.MSG.CRLF		.DA MSG.CRLF
L.MSG.NULL		.DA MSG.NULL
L.MSG.UNKNOWN	.DA MSG.UNKNOWN
L.MSG.CONNECT	.DA MSG.CONNECT
L.MSG.SKTKO		.DA MSG.SKTKO
L.MSG.CONNECTED	.DA MSG.CONNECTED
L.MSG.SKTERR	.DA MSG.SKTERR
L.MSG.IOERR		.DA MSG.IOERR
L.MSG.FileLength	.DA MSG.FileLength
L.MSG.Progress	.DA MSG.Progress
L.HTTP.GET		.DA HTTP.GET
				.DA 0
*--------------------------------------
CS.INIT			>LDYA L.LIBTCPIP
				>SYSCALL LoadLib
				bcs .9
				sta hLIBTCPIP

.9				rts
*--------------------------------------
CS.RUN			>LIBCALL hLIBTCPIP,LIBTCPIP.GETCFG	is TCPIP loaded ?
				>STYA ZPIPCfgPtr
				lda (ZPIPCfgPtr)		Configured ?
				bmi CS.RUN.IPOK

				>LDYA L.MSG.IPKO
				>SYSCALL PutS
				lda #E.SYN
				sec
				rts

CS.RUN.IPOK		ldy #S.IPCFG.IP+3
				ldx #3

.1				lda (ZPIPCfgPtr),y
				sta SA.LOCAL+S.SOCKADDR.ADDR,x
				dey
				dex
				bpl .1

				jsr CS.RUN.GETNEXTARG
				bcs .9

				>STYA ZPHostPtr
				jsr Init.TimeOut

.2				>PUSHW L.SA.REMOTE.AD
				>PUSHW ZPHostPtr
				>LIBCALL hLIBTCPIP,LIBTCPIP.HST.GetByName
				bcc CS.RUN.HOSTOK
				>SLEEP

				lda TimeOut
				bne .2

				>PUSHW L.MSG.UNKNOWN
				>PUSHW ZPHostPtr
				>PUSHBI 2
				>SYSCALL PrintF
				bra CS.RUN.ESYN

.9				>PUSHW L.MSG.USAGE
				>PUSHBI 0
				>SYSCALL PrintF

CS.RUN.ESYN		lda #E.SYN
				sec
CS.RUN.RTS		rts
*--------------------------------------
CS.RUN.HOSTOK	jsr CS.RUN.GETNEXTARG
				bcc .10

.8				jmp CS.RUN.ARGSOK

.10				>STYA ZPPtr
				lda (ZPPtr)

				cmp #'-'
				beq .1

				>LDYA ZPPtr
				>SYSCALL AToI
				bcs CS.RUN.RTS

				>STYA SA.REMOTE+S.SOCKADDR.PORT

				jsr CS.RUN.GETNEXTARG
				bcs .8

				>STYA ZPPtr
				lda (ZPPtr)
				cmp #'-'
				bne CS.RUN.ESYN

.1				ldy #1
				lda (ZPPtr),y
				cmp #'a'
				bcc .11

				cmp #'z'+1
				bcs .11

				eor #$20

.11				cmp #'U'
				bne .2

				lda ZPReqBufPtr+1
				bne CS.RUN.ESYN

				jsr CS.RUN.GETNEXTARG

.9				bcs CS.RUN.ESYN

				>STYA ZPReqBufPtr
				>SYSCALL StrLen
				>STYA ZPReqBufLen
				bra CS.RUN.HOSTOK

.2				cmp #'F'
				bne .3

				lda ZPReqBufPtr+1
				bne CS.RUN.ESYN

				jsr CS.RUN.GETNEXTARG
				bcs CS.RUN.ESYN2

				>SYSCALL LoadTxtFile
				bcs CS.RUN.RTS

				>STYA ZPReqBufLen
				stx hReqBuf
				>SYSCALL GetMemPtr
				>STYA ZPReqBufPtr

				jmp CS.RUN.HOSTOK

.3 				cmp #'O'
				bne CS.RUN.ESYN2
				
				lda ZPFileName+1
				bne CS.RUN.ESYN2

				jsr CS.RUN.GETNEXTARG
				bcs CS.RUN.ESYN2

				>STYA ZPFileName
				jmp CS.RUN.HOSTOK
*--------------------------------------
CS.RUN.ESYN2	lda #E.SYN
				sec
				rts
*--------------------------------------
CS.RUN.ARGSOK	>PUSHW L.MSG.CONNECT
				ldx #0

.1				>PUSHB SA.REMOTE+S.SOCKADDR.ADDR,x
				inx
				cpx #4
				bne .1

				>PUSHW SA.REMOTE+S.SOCKADDR.PORT
				>PUSHW ZPHostPtr

				>PUSHBI 8
				>SYSCALL PrintF

CS.RUN.OPENSKT	>PUSHBI S.SOCKET.T.SEQPKT
				>PUSHBI 0				no protocol
				>LIBCALL hLIBTCPIP,LIBTCPIP.Socket
				bcs .9

				sta hSocket

				>PUSHB hSocket
				>PUSHW L.SA.LOCAL
				>LIBCALL hLIBTCPIP,LIBTCPIP.Bind
				bcc .1

.9				pha
				>LDYA L.MSG.SKTKO
				>SYSCALL PutS
				pla
				sec
.99				rts

.1				jsr Init.TimeOut

.2				>SLEEP

				>PUSHB hSocket
				>PUSHW L.SA.REMOTE
				>LIBCALL hLIBTCPIP,LIBTCPIP.Connect
				bcc .3

				cmp #ERR.SKT.NOCONN
				bne .9

				lda TimeOut
				bne .2

				lda #ERR.SKT.NOCONN
				bra .9

.3				>SLEEP

				lda hSocket
				>LIBCALL hLIBTCPIP,LIBTCPIP.Recv
				bcc .7

				cmp #E.NODATA
				beq .8

				ldx TimeOut
				bne .3
				
				lda #ERR.SKT.NOCONN
				bra .9
				
.7				>SYSCALL Freemem				
				
.8				>LDYA L.MSG.CONNECTED
				>SYSCALL PutS

				>SLEEP

CS.RUN.GET		jsr CS.RUN.ENCODE
				bcs .99

				jsr CS.RUN.REQUEST
				bcs .99

				>LDYA ZPFileName
				beq .1

				>PUSHYA
				>PUSHBI	O.CREATE+O.WRONLY+O.TRUNC
				>PUSHBI 0				TYPE
				>PUSHWZ					AUXTYPE
				>SYSCALL FOpen
				bcs .99

				sta hFile

.1				jsr CS.RUN.RESPONSE
				bcs .99

.9				lda #0
				sec
.99				rts
*--------------------------------------
CS.RUN.SKTERR	pha
				>PUSHW L.MSG.SKTERR
				bra CS.RUN.ERR
*--------------------------------------
CS.RUN.IOERR	pha
				>PUSHW L.MSG.IOERR
CS.RUN.ERR		pla
				pha
				>PUSHA
				>PUSHBI 1
				>SYSCALL PrintF
				pla
				sec
				rts
*--------------------------------------
CS.RUN.GETNEXTARG
				inc ArgIndex
				lda ArgIndex
				>SYSCALL ArgV
				rts
*--------------------------------------
CS.RUN.ENCODE	ldy ZPReqBufPtr
				lda ZPReqBufPtr+1
				bne .10
				
				>LDYA L.MSG.NULL
				>STYA ZPReqBufPtr
				
.10				>STYA ZPPtr

				inc ZPEncodedBufLen		for ending \0

.1				lda (ZPPtr)
				beq .4

	            inc ZPPtr
				bne .2

				inc ZPPtr+1

.2				jsr CS.RUN.TOENCODE		if CS 3 bytes, if CC 1 byte

				lda #1
				bcc .3

				inc

.3				adc ZPEncodedBufLen
				sta ZPEncodedBufLen
				bcc .1

				inc ZPEncodedBufLen+1
				bra .1
*--------------------------------------
.4				>LDYA ZPEncodedBufLen
				>SYSCALL GetMem
				bcs .9

				>STYA ZPEncodedBufPtr
				>STYA ZPPtr
				stx hEncodedBuf

.5				lda (ZPReqBufPtr)
				beq .8

				inc ZPReqBufPtr
				bne .6

				inc ZPReqBufPtr+1

.6				jsr CS.RUN.TOENCODE
				bcc .7

				jsr CS.RUN.ADDBYTETOBUF
				bra .5

.7				jsr CS.RUN.ADDTOBUF
				bra .5

.8				sta (ZPPtr)				ending \0

				clc
.9				rts
*--------------------------------------
CS.RUN.TOENCODE	ldx #URI.ToEncode.Cnt-1

.1				cmp URI.ToEncode,x
				beq .9					CS

				dex
				bpl .1

				clc
.9				rts
*--------------------------------------
CS.RUN.ADDBYTETOBUF
				pha
				lda #'%'
				jsr CS.RUN.ADDTOBUF
				pla
				pha
				lsr
				lsr
				lsr
				lsr
				ora #$30
				cmp #$3A
				bcc .1

				adc #6

.1				jsr CS.RUN.ADDTOBUF
				pla
				and #$0F
				ora #$30
				cmp #$3A
				bcc CS.RUN.ADDTOBUF

				adc #6

*--------------------------------------
CS.RUN.ADDTOBUF	sta (ZPPtr)
				inc ZPPtr
				bne .8
				inc ZPPtr+1
.8				rts
*--------------------------------------
CS.RUN.REQUEST	jsr Init.TimeOut

				>LDYAI 1024
				>SYSCALL GetMem
				bcs .9

				>STYA ZPSendBufPtr
				stx hSendBuf

				>PUSHYA
				>PUSHW L.HTTP.GET
				>PUSHW ZPEncodedBufPtr
				>PUSHW ZPHostPtr
				>PUSHBI 4

				>SYSCALL SPrintF
				bcs .90

				pha
				>PUSHB hSocket
				>PUSHW ZPSendBufPtr
				pla
				>PUSHYA					Byte count
				>LIBCALL hLIBTCPIP,LIBTCPIP.Send

.90				php
				pha
				lda hSendBuf
				>SYSCALL FreeMem
				pla
				plp

.9
CS.RUN.REQUEST.RTS
				rts
*--------------------------------------
CS.RUN.RESPONSE jsr Init.TimeOut

.1				>SLEEP

				lda hSocket
				>LIBCALL hLIBTCPIP,LIBTCPIP.Recv
				bcc .2

				cmp #E.NODATA
				bne .80

				jsr CS.RUN.CtrlC
				bcs CS.RUN.REQUEST.RTS

				lda TimeOut
				bne .1

				bit bHeader
				bmi .1

.80				jmp .8

.2				jsr CS.RUN.GETRESPONSE

				bit bHeader
				bmi .6

				jsr CS.RUN.GETHEADER

				sec
				ror bHeader

.6				lda hFile
				bne .7

				ldy #S.PS.hStdOut
				lda (pPS),y

.7				>PUSHA
				>PUSHW ZPRespBufPtr
				>PUSHW ZPRespBufLen
				>SYSCALL FWrite
				bcs .9

				lda hRespBuf
				stz hRespBuf
				>SYSCALL FreeMem

				lda ZPRespBufLen
				clc
				adc Received
				sta Received

				lda ZPRespBufLen+1
				adc Received+1
				sta Received+1

				bcc .70

				inc Received+2
				bne .70

				inc Received+3

.70				lda hFile
				beq .71

				>PUSHW L.MSG.Progress
				>PUSHL Received
				>PUSHBI 4

				>SYSCALL PrintF
				bcs .9

.71				jmp CS.RUN.RESPONSE

.8				bit bHeader
				bpl .99

				>PUSHW L.MSG.CRLF
				>PUSHBI 0
				>SYSCALL PrintF

				jsr CS.RUN.CHECKLEN
				bcc .9

.99				lda #MLI.E.IO
				sec
.9				rts
*--------------------------------------
CS.RUN.GETRESPONSE
				sta hRespBuf
				>SYSCALL GetMemPtr
				>STYA ZPRespBufPtr

				ldy #S.IP.TOTAL.LENGTH+1
				lda (ZPRespBufPtr),y
				sec
				sbc #S.TCP-S.ETH.EII
				sta ZPRespBufLen

				dey

				lda (ZPRespBufPtr),y
				sbc /S.TCP-S.ETH.EII
				sta ZPRespBufLen+1

				lda ZPRespBufPtr
				clc
				adc #S.TCP
				sta ZPRespBufPtr
				bcc .8

				inc ZPRespBufPtr+1

.8				rts
*--------------------------------------
CS.RUN.GETHEADER
.1				ldy #$ff

.2				iny

				lda (ZPRespBufPtr),y
				eor #C.CR
				bne .2

				sta (ZPRespBufPtr),y

				iny						skip CR
				iny						skip LF

				sty ArgIndex

				>LDYA ZPRespBufPtr
				>STYA ZPPtr

				lda ZPRespBufLen
				sec
				sbc ArgIndex
				sta ZPRespBufLen
				bcs .3

				dec ZPRespBufLen+1

.3				lda ArgIndex
				tay
				clc
				adc ZPRespBufPtr
				sta ZPRespBufPtr
				bcc .4

				inc ZPRespBufPtr+1

.4				dey
				dey
				beq .8

				ldy #$ff

.5				iny
				lda (ZPPtr),y
				cmp HEAD.ContentLength,y
				bne .1

				cmp #C.SPACE
				bne .5

				tya
				sec						skip SPACE
				adc ZPPtr
				tay
				lda ZPPtr+1
				adc #0

				>SYSCALL AToL
				>PULLL Length

				>PUSHW L.MSG.FileLength
				>PUSHL Length
				>PUSHBI 4
				>SYSCALL PrintF
				jmp .1

.8				clc

.9				rts
*--------------------------------------
CS.RUN.CHECKLEN	ldx #3

				sec

.1				lda Received,x
				eor Length,x
				bne .9

				dex
				bpl .1

				clc

.9				rts
*--------------------------------------
CS.RUN.CtrlC	ldy #S.PS.hStdIn
				lda (pPS),y
				>SYSCALL FEOF
				bcs .8

				tay
				bne .8					CC

				>SYSCALL GetChar
				bcs .9

				cmp #$03				Ctrl-C
				beq .9					CS
				
.8				clc				
.9				rts			
*--------------------------------------
CS.DOEVENT		lda (pEvent)
				bpl .9					is it a TIMER event?

				lda TimeOut
				beq .9

				dec TimeOut

.9				sec						do not discard TIMER event
				rts
*--------------------------------------
CS.QUIT			lda hSocket
				beq .1

				>LIBCALL hLIBTCPIP,LIBTCPIP.Shutdown

.1				lda hReqBuf
				beq .2

				>SYSCALL FreeMem

.2				lda hEncodedBuf
				beq .3

				>SYSCALL FreeMem

.3				lda hRespBuf
				beq .4

				>SYSCALL FreeMem

.4				lda hFile
				beq .5

				>SYSCALL FClose

.5				lda hLIBTCPIP
				beq .8

				>SYSCALL UnloadLib
.8				clc
				rts
*--------------------------------------
Init.TimeOut	lda #TIMEOUT.MAX
				sta TimeOut
				rts
*--------------------------------------
CS.END
LIBTCPIP		.AZ "libtcpip"
hLIBTCPIP		.BS 1
MSG.IPKO		.CZ "TCP/IP Not Loaded/Configured."
MSG.USAGE		.CS "Usage : HTTPGET <ip|host> [port]\r\n"
				.CS "   -U : Url\r\n"
				.CS "   -F : UrlFile\r\n"
				.CS "   -O : OutputFile"
MSG.CRLF		.CS "\r\n"
MSG.NULL		.DA #0
MSG.UNKNOWN		.CZ "%s: Unknown host\r\n"
MSG.CONNECT		.CZ "Connecting to %d.%d.%d.%d:%D (%s)..."
MSG.SKTKO		.CZ "Failed to Open Socket."
MSG.CONNECTED	.CZ "Connected."
MSG.SKTERR		.CZ "Socket Error : $%h\r\n"
MSG.IOERR		.CZ "I/O Error : $%h\r\n"
MSG.FileLength	.CZ "File Length : %10u Bytes\r\n"
MSG.Progress	.CZ "\rReceived    : %10u"
*--------------------------------------
SA.LOCAL		.DA #AF.INET			S.SOCKADDR.AF
				.BS 1
				.BS 4					S.SOCKADDR.ADDR
				.BS 2					S.SOCKADDR.PORT
*--------------------------------------
SA.REMOTE		.DA #AF.INET			S.SOCKADDR.AF
				.BS 1
				.BS 4					S.SOCKADDR.ADDR
				.DA TCP.PORT.HTTP
*--------------------------------------
URI.ToEncode	.DA #C.LF,#C.CR,#C.SPACE,#'"'
				.AS "%-.\^_`{|}~"
URI.ToEncode.Cnt	.EQ	*-URI.ToEncode
*--------------------------------------
HEAD.ContentLength	.AZ "Content-Length: "
*--------------------------------------
HTTP.GET		.AS "GET /%s HTTP/1.1"
				.DA #C.CR,#C.LF
				.AS "User-Agent: A2osX.HTTPGET"
				.DA #C.CR,#C.LF
				.AS "Host: %s"
				.DA #C.CR,#C.LF
				.AS "Connection: close"
				.DA #C.CR,#C.LF
				.DA #C.CR,#C.LF
				.DA #0
*--------------------------------------
Received		.BS 4
Length			.BS 4
*--------------------------------------
				.DUMMY
				.OR 0
DS.START
DS.END			.ED
*--------------------------------------
MAN
SAVE usr/src/bin/httpget.s
ASM
