From d2f2fdecede82a844f80b1363f9a101dd0df789a Mon Sep 17 00:00:00 2001 From: nishi Date: Wed, 14 Feb 2024 01:28:20 +0000 Subject: [PATCH] ftp works git-svn-id: file:///raid/svn-main/nishi-libw3/trunk@213 d27a3e52-49c5-7645-884c-6793ebffc270 --- Example/Makefile | 3 + Example/ftp-list/Makefile | 18 ++++ Example/ftp-list/ftp-list.c | 66 ++++++++++++++ Library/Core.c | 4 + Library/FTP.c | 171 ++++++++++++++++++++++++++++++++++++ Library/URL.c | 3 + Library/W3FTP.h | 4 + Makefile | 3 + W3Version.h.p | 2 +- 9 files changed, 273 insertions(+), 1 deletion(-) create mode 100644 Example/ftp-list/Makefile create mode 100644 Example/ftp-list/ftp-list.c diff --git a/Example/Makefile b/Example/Makefile index b92f3a1..a75b6c5 100644 --- a/Example/Makefile +++ b/Example/Makefile @@ -10,6 +10,7 @@ examples: $(MAKE) -C ./interactive CC=$(CC) SUFFIX=$(SUFFIX) $(MAKE) -C ./pop3-list CC=$(CC) SUFFIX=$(SUFFIX) $(MAKE) -C ./w3b CC=$(CC) SUFFIX=$(SUFFIX) + $(MAKE) -C ./ftp-list CC=$(CC) SUFFIX=$(SUFFIX) ifeq ($(TCL),YES) $(MAKE) -C ./tclw3 CC=$(CC) TCL_LIBS="$(TCL_LIBS)" TCL_CFLAGS="$(TCL_CFLAGS)" SUFFIX=$(SUFFIX) endif @@ -19,6 +20,7 @@ install: $(MAKE) -C ./interactive CC=$(CC) PREFIX=$(PREFIX) SUFFIX=$(SUFFIX) install $(MAKE) -C ./pop3-list CC=$(CC) PREFIX=$(PREFIX) SUFFIX=$(SUFFIX) install $(MAKE) -C ./w3b CC=$(CC) PREFIX=$(PREFIX) SUFFIX=$(SUFFIX) install + $(MAKE) -C ./ftp-list CC=$(CC) PREFIX=$(PREFIX) SUFFIX=$(SUFFIX) install ifeq ($(TCL),YES) $(MAKE) -C ./tclw3 CC=$(CC) PREFIX=$(PREFIX) SUFFIX=$(SUFFIX) install endif @@ -29,6 +31,7 @@ clean: $(MAKE) -C ./interactive SUFFIX=$(SUFFIX) clean $(MAKE) -C ./pop3-list SUFFIX=$(SUFFIX) clean $(MAKE) -C ./w3b SUFFIX=$(SUFFIX) clean + $(MAKE) -C ./ftp-list SUFFIX=$(SUFFIX) clean ifeq ($(TCL),YES) $(MAKE) -C ./tclw3 CC=$(CC) SUFFIX=$(SUFFIX) clean endif diff --git a/Example/ftp-list/Makefile b/Example/ftp-list/Makefile new file mode 100644 index 0000000..0125761 --- /dev/null +++ b/Example/ftp-list/Makefile @@ -0,0 +1,18 @@ +# $Id$ +.PHONY: clean install + +./ftp-list$(SUFFIX): ./ftp-list.o $(RESFILE) + $(CC) -g -o $@ -L ../../Library $^ -lw3 + +./%.o: ./%.c + $(CC) -g -c -o $@ -I ../../Library $< + +../libw3.res: + $(MAKE) -C .. ./libw3.res WINDRES=$(WINDRES) + +clean: + rm -f ftp-list *.o *.so *.core *~ *.exe *.res + +install: ./ftp-list + mkdir -p $(PREFIX)/bin + cp ./ftp-list $(PREFIX)/bin/w3-ftp-list diff --git a/Example/ftp-list/ftp-list.c b/Example/ftp-list/ftp-list.c new file mode 100644 index 0000000..cf8937f --- /dev/null +++ b/Example/ftp-list/ftp-list.c @@ -0,0 +1,66 @@ +/* + * $Id$ + * + * Lists the FTP files + */ + +#include +#include + +#include +#include /* It has some useful functions, you know */ + +#include +#include +#include +#include +#include +#include + +void resp_handler(struct W3* w3, int status, char* data){ + printf("%d\n%s\n", status, data); + if(status == 230){ + W3_Set_Method(w3, "LIST"); + W3_Set_Path(w3, "/"); + W3_FTP_Send_Request(w3); + }else if(status == 226){ + W3_FTP_Disconnect(w3); + } +} + +void data_handler(struct W3* w3, char* data, size_t size){ + write(1, data, size); +} + +int main(int argc, char** argv) { + if(argc < 2) { + fprintf(stderr, "%s: usage: %s url\n", argv[0], argv[0]); + return 1; + } + W3_Library_Init(); + struct W3URL* w3url = W3_Parse_URL(argv[1]); + if(w3url != NULL){ + bool err = false; + if(w3url->username == NULL){ + err = true; + fprintf(stderr, "%s: missing username\n", argv[0]); + } + if(w3url->password == NULL){ + err = true; + fprintf(stderr, "%s: missing password\n", argv[0]); + } + if(err){ + W3_Free_URL(w3url); + return 1; + } + struct W3* w3 = W3_Create("ftp", w3url->host, w3url->port); + W3_FTP_Set_Username(w3, w3url->username); + W3_FTP_Set_Password(w3, w3url->password); + W3_On(w3, "ftpresp", resp_handler); + W3_On(w3, "data", data_handler); + W3_Send_Request(w3); + W3_Free_URL(w3url); + }else{ + return 1; + } +} diff --git a/Library/Core.c b/Library/Core.c index e11e851..8f0d6d9 100644 --- a/Library/Core.c +++ b/Library/Core.c @@ -11,6 +11,7 @@ #include "W3HTTP.h" #include "W3POP3.h" #include "W3Nex.h" +#include "W3FTP.h" #ifdef SSL_SUPPORT #include "W3Gemini.h" #endif @@ -92,6 +93,7 @@ struct W3* W3_Create(const char* protocol, const char* hostname, int port) { } else if(strcmp(protocol, "finger") == 0) { } else if(strcmp(protocol, "gopher") == 0) { } else if(strcmp(protocol, "pop3") == 0) { + } else if(strcmp(protocol, "ftp") == 0) { } else { __W3_Debug("Protocol", "Not suppported"); W3_Free(w3); @@ -161,6 +163,8 @@ void W3_Send_Request(struct W3* w3) { __W3_Finger_Request(w3); } else if(strcmp(w3->protocol, "nex") == 0) { __W3_Nex_Request(w3); + } else if(strcmp(w3->protocol, "ftp") == 0) { + __W3_FTP_Request(w3); } else if(strcmp(w3->protocol, "file") == 0) { __W3_File_Request(w3); } diff --git a/Library/FTP.c b/Library/FTP.c index a25ed39..4f275dc 100644 --- a/Library/FTP.c +++ b/Library/FTP.c @@ -2,11 +2,182 @@ #include "W3FTP.h" #include "W3Core.h" +#include "W3DNS.h" #include "W3Util.h" #include #include +extern int strcasecmp(const char* s1, const char* s2); + +void __W3_FTP_Start_Passive(struct W3* w3){ + __W3_Auto_Write(w3, "PASV\r\n", 6); +} + void __W3_FTP_Request(struct W3* w3) { + if(__W3_Get_Prop(w3, "FTP_USERNAME") == NULL || __W3_Get_Prop(w3, "FTP_PASSWORD") == NULL) { + __W3_Debug("LibW3-FTP", "Set the username/password"); + void* funcptr = __W3_Get_Event(w3, "error"); + if(funcptr != NULL) { + void (*func)(struct W3*, const char*) = (void (*)(struct W3*, const char*))funcptr; + func(w3, "did-not-auth"); + } + return; + } __W3_Debug("LibW3-FTP", "Sending the request"); + int cond = 1; + w3->generic = &cond; + char* buf = malloc(w3->readsize); + bool cont = false; + int status = 0; + bool gotstatus = false; + char* buffer = malloc(1); + buffer[0] = 0; + char* cbuf = malloc(2); + cbuf[1] = 0; + int auth = 0; + int pasvsock = -1; + while(true) { + int len = __W3_Auto_Read(w3, buf, w3->readsize); + if(len <= 0) break; + int i; + for(i = 0; i < len; i++){ + if((buf[i] == ' ' || buf[i] == '-') && !gotstatus){ + cont = buf[i] == '-'; + gotstatus = true; + }else if(!gotstatus){ + status = status * 10; + status += buf[i] - '0'; + }else if(buf[i] != '\r' && buf[i] != '\n'){ + cbuf[0] = buf[i]; + char* tmp = buffer; + buffer = __W3_Concat(tmp, cbuf); + free(tmp); + }else if(buf[i] == '\n'){ + gotstatus = false; + cbuf[0] = '\n'; + char* tmp = buffer; + buffer = __W3_Concat(tmp, cbuf); + free(tmp); + if(!cont){ + if(status == 220 && auth == 0){ + __W3_Auto_Write(w3, "USER ", 5); + __W3_Auto_Write(w3, __W3_Get_Prop(w3, "FTP_USERNAME"), strlen(__W3_Get_Prop(w3, "FTP_USERNAME"))); + __W3_Auto_Write(w3, "\r\n", 2); + auth = 1; + }else if(status == 331 && auth == 1){ + __W3_Auto_Write(w3, "PASS ", 5); + __W3_Auto_Write(w3, __W3_Get_Prop(w3, "FTP_PASSWORD"), strlen(__W3_Get_Prop(w3, "FTP_PASSWORD"))); + __W3_Auto_Write(w3, "\r\n", 2); + auth = 2; + }else if(status == 230 && auth == 2){ + auth = 3; + }else if(auth < 3){ + __W3_Debug("LibW3-FTP", "Login failed"); + void* funcptr = __W3_Get_Event(w3, "error"); + if(funcptr != NULL) { + void (*func)(struct W3*, const char*) = (void (*)(struct W3*, const char*))funcptr; + func(w3, "login-fail"); + } + goto ftp_stop; + }else if(auth == 3){ + if(status == 227 && (cond & 1)){ + /* Passive mode */ + int j; + int cnt = 0; + bool pasv = false; + char* addr = malloc(1); + addr[0] = 0; + char* numbuf = malloc(1); + numbuf[0] = 0; + int port = 0; + for(j = 0; buffer[j] != 0; j++){ + if(buffer[j] == '('){ + pasv = true; + }else if(pasv){ + if(buffer[j] == ',' || (pasv && buffer[j] == ')')){ + cnt++; + if(cnt < 4){ + cbuf[0] = '.'; + char* tmp = addr; + addr = __W3_Concat(tmp, cbuf); + free(tmp); + }else{ + port = port << 8; + port |= atoi(numbuf); + free(numbuf); + numbuf = malloc(1); + numbuf[0] = 0; + } + if(buffer[j] == ')') break; + }else{ + if(cnt < 4){ + cbuf[0] = buffer[j]; + char* tmp = addr; + addr = __W3_Concat(tmp, cbuf); + free(tmp); + }else{ + cbuf[0] = buffer[j]; + char* tmp = numbuf; + numbuf = __W3_Concat(tmp, cbuf); + free(tmp); + } + } + } + } + free(numbuf); + pasvsock = __W3_DNS_Connect(addr, false, port, +#ifdef SSL_SUPPORT + NULL, NULL +#endif + ); + free(addr); + if(strcasecmp(w3->method, "LIST") == 0){ + __W3_Auto_Write(w3, "LIST ", 5); + __W3_Auto_Write(w3, w3->path, strlen(w3->path)); + __W3_Auto_Write(w3, "\r\n", 2); + } + char* ftpbuf = malloc(w3->readsize); + while(true){ + int ftplen = recv(pasvsock, ftpbuf, w3->readsize, 0); + if(ftplen <= 0) break; + void* funcptr = __W3_Get_Event(w3, "data"); + if(funcptr != NULL) { + void (*func)(struct W3*, char*, size_t) = (void (*)(struct W3*, char*, size_t))funcptr; + func(w3, ftpbuf, ftplen); + } + } + free(ftpbuf); + } + } + void* funcptr = __W3_Get_Event(w3, "ftpresp"); + if(funcptr != NULL) { + void (*func)(struct W3*, int, char*) = (void (*)(struct W3*, int, char*))funcptr; + func(w3, status, buffer); + } + free(buffer); + buffer = malloc(1); + buffer[0] = 0; + } + status = 0; + } + } + } +ftp_stop:; + free(cbuf); + free(buffer); + free(buf); +} + +void W3_FTP_Set_Username(struct W3* w3, const char* username) { __W3_Add_Prop(w3, "FTP_USERNAME", username); } + +void W3_FTP_Set_Password(struct W3* w3, const char* password) { __W3_Add_Prop(w3, "FTP_PASSWORD", password); } + +void W3_FTP_Send_Request(struct W3* w3) { + if(strcasecmp(w3->method, "LIST") == 0){ + __W3_FTP_Start_Passive(w3); + *((int*)w3->generic) |= 1; + } } + +void W3_FTP_Disconnect(struct W3* w3) { __W3_Auto_Write(w3, "QUIT\r\n", 6); } diff --git a/Library/URL.c b/Library/URL.c index 2763719..2626720 100644 --- a/Library/URL.c +++ b/Library/URL.c @@ -126,8 +126,11 @@ struct W3URL* W3_Parse_URL(const char* _url) { r->port = 79; }else if(strcmp(r->protocol, "nex") == 0) { r->port = 1900; + }else if(strcmp(r->protocol, "ftp") == 0) { + r->port = 21; } + } r->host = __W3_Strdup(url + start + (atmark == 0 ? 0 : (atmark - 1))); char* str = malloc(strlen(r->host) + 64); diff --git a/Library/W3FTP.h b/Library/W3FTP.h index 15da012..a4d9284 100644 --- a/Library/W3FTP.h +++ b/Library/W3FTP.h @@ -9,6 +9,10 @@ extern "C" { #include "W3Core.h" void __W3_FTP_Request(struct W3* w3); +void W3_FTP_Set_Username(struct W3* w3, const char* username); +void W3_FTP_Set_Password(struct W3* w3, const char* password); +void W3_FTP_Send_Request(struct W3* w3); +void W3_FTP_Disconnect(struct W3* w3); #ifdef __cplusplus } diff --git a/Makefile b/Makefile index 7234eb3..d1c0e5b 100644 --- a/Makefile +++ b/Makefile @@ -146,6 +146,7 @@ ifeq ($(TCL),YES) mkdir -p w3-$(VERSION)/Example/tclw3/bin mkdir -p w3-$(VERSION)/Example/tclw3/lib endif + mkdir -p w3-$(VERSION)/Example/ftp-list mkdir -p w3-$(VERSION)/Example/pop3-list mkdir -p w3-$(VERSION)/Example/interactive mkdir -p w3-$(VERSION)/Example/fetch @@ -157,6 +158,7 @@ ifeq ($(WINDOWS),YES) cp ./Example/interactive/interactive.exe w3-$(VERSION)/Example/interactive/ cp ./Example/pop3-list/pop3-list.exe w3-$(VERSION)/Example/pop3-list/ cp ./Example/w3b/w3b.exe w3-$(VERSION)/Example/w3b/ + cp ./Example/ftp-list/ftp-list.exe w3-$(VERSION)/Example/ftp-list/ ifeq ($(TCL),YES) cp ./Example/tclw3/tclw3.exe w3-$(VERSION)/Example/tclw3/bin/ cp /usr/$(MINGW)/sys-root/mingw/bin/tcl86.dll w3-$(VERSION)/Example/tclw3/bin/ @@ -171,6 +173,7 @@ else cp ./Example/interactive/interactive w3-$(VERSION)/Example/interactive/ cp ./Example/pop3-list/pop3-list w3-$(VERSION)/Example/pop3-list/ cp ./Example/w3b/w3b w3-$(VERSION)/Example/w3b/ + cp ./Example/ftp-list/ftp-list w3-$(VERSION)/Example/ftp-list/ ifeq ($(TCL),YES) cp ./Example/tclw3/tclw3 w3-$(VERSION)/Example/tclw3/bin/ endif diff --git a/W3Version.h.p b/W3Version.h.p index e740f9f..c2b02bc 100644 --- a/W3Version.h.p +++ b/W3Version.h.p @@ -6,7 +6,7 @@ extern "C" { #endif -#define LIBW3_VERSION "2.11" \ +#define LIBW3_VERSION "2.11A" \ SUFFIX #ifdef __cplusplus -- 2.43.0