From 5551cbfb2ba36c14eb289c0326a3d4e650158929 Mon Sep 17 00:00:00 2001 From: sieveprime <primesieve@yahoo.com> Date: Sun, 23 Feb 2025 11:33:12 -0600 Subject: [PATCH] Add STOR capability to FTP client --- src/Home/Net/Programs/FTPClient.ZC | 131 ++++++++++++++++++++++++----- 1 file changed, 111 insertions(+), 20 deletions(-) diff --git a/src/Home/Net/Programs/FTPClient.ZC b/src/Home/Net/Programs/FTPClient.ZC index feb1f5ed..c29c92e0 100755 --- a/src/Home/Net/Programs/FTPClient.ZC +++ b/src/Home/Net/Programs/FTPClient.ZC @@ -144,6 +144,44 @@ I64 FTPFileDownload(CTCPSocket *data_socket, U8 *dest) return -1; } +I64 FTPFileUpload(CTCPSocket *data_socket, U8 *source) +{ // New upload function + CFile *f; + I64 read_bytes, total_sent = 0, res; + U8 buf[BLK_SIZE]; + I64 offset; + + progress4 = 0; + f = FOpen(source, "r"); + if (!f) + { + ST_ERR_ST "Failed to open %s for reading\n", source; + return -1; + } + + while ((read_bytes = FBlkRead(f, buf)) > 0) + { + offset = 0; + while (offset < read_bytes) + { + res = TCPSocketSend(data_socket, buf + offset, read_bytes - offset); + if (res <= 0) + { + ST_ERR_ST "Failed to send data\n"; + FClose(f); + return -1; + } + offset += res; + total_sent += res; + progress4 += res; + } + } + + FClose(f); + TCPSocketClose(data_socket); + return total_sent; +} + I64 FTPFileView(U8 *filename=NULL, CTask *parent=NULL, CTask **_pu_task=NULL) { U8 *st = MStrPrint("Cd(\"%Q\");Plain(\"%Q\");", __DIR__, filename); @@ -223,7 +261,6 @@ I64 FTPClient(U8 *hostname=NULL, U16 port=21) if (!hostname) hostname = StrGet("\nEnter FTP server address (URL or IPV4): "); - if (!IPV4AddressParse(hostname, &addr)) { error = DNSAddressInfoGet(hostname, NULL, &result); @@ -238,7 +275,7 @@ I64 FTPClient(U8 *hostname=NULL, U16 port=21) if (current->family == AF_INET) { temp_ipv4 = current->address; - addr = EndianU32(temp_ipv4->address); // why does it need EndianU32 + addr = EndianU32(temp_ipv4->address); break; } current = current->next; @@ -249,7 +286,6 @@ I64 FTPClient(U8 *hostname=NULL, U16 port=21) NetErr("FTP Client: Failed to resolve address."); return -1; } - } ipv4_address.port = EndianU16(port); @@ -271,7 +307,6 @@ I64 FTPClient(U8 *hostname=NULL, U16 port=21) FTPMessageGet(message_socket, buf); - "\n\nType HELP for command list.\n\n"; while (TRUE) { @@ -282,7 +317,7 @@ I64 FTPClient(U8 *hostname=NULL, U16 port=21) { switch (tk) { - case TK_IDENT: // command + case TK_IDENT: "COMMAND:%s\n", cc->cur_str; for (i = 0; i < StrLen(cc->cur_str); i++) cc->cur_str[i] = ToUpper(cc->cur_str[i]); @@ -374,7 +409,6 @@ I64 FTPClient(U8 *hostname=NULL, U16 port=21) goto lex_done; } - temp = MStrPrint("RETR %s\r\n", input_str); TCPSocketSendString(message_socket, temp); FTPFileDownload(data_socket, dest); @@ -384,8 +418,62 @@ I64 FTPClient(U8 *hostname=NULL, U16 port=21) FTPFileView(dest); goto lex_done; + } + else if (!StrCompare(cc->cur_str, "STOR") || // New STOR case + !StrCompare(cc->cur_str, "PUT")) + { + StrFirstRemove(input_str, " "); + if (!StrCompare(input_str, "")) + { + ST_ERR_ST "Must provide argument!\n"; + goto lex_done; + } + if (!FileExists(input_str)) + { + ST_ERR_ST "File %s does not exist!\n", input_str; + goto lex_done; + } + U8 *remote_filename = FTPFilePrompt(input_str); + if (remote_filename == NULL) + { + ST_ERR_ST "Remote filename cannot be empty!"; + goto lex_done; + } + + TCPSocketSendString(message_socket, "PASV\r\n"); + if (FTPReplyPassiveParse(message_socket, &data_ipv4) != 0) + { + ST_ERR_ST "Error parsing server response to PASV command!\n"; + Free(remote_filename); + goto lex_done; + } + + data_socket = TCPSocket(AF_INET); + data_socket->timeout = 2 * JIFFY_FREQ; + + if (TCPSocketConnect(data_socket, &data_ipv4) != 0) + { + ST_ERR_ST "Failed to connect data socket!"; + TCPSocketClose(data_socket); + Free(remote_filename); + goto lex_done; + } + + temp = MStrPrint("STOR %s\r\n", remote_filename); + TCPSocketSendString(message_socket, temp); + Free(temp); + Free(remote_filename); + + I64 upload_result = FTPFileUpload(data_socket, input_str); + if (upload_result < 0) + ST_ERR_ST "Upload failed!\n"); + else + "\n%lld bytes uploaded successfully.\n", upload_result; + + FTPMessageGet(message_socket, buf); + goto lex_done; } else if (!StrCompare(cc->cur_str, "VIEW") || !StrCompare(cc->cur_str, "CAT")) @@ -423,6 +511,12 @@ I64 FTPClient(U8 *hostname=NULL, U16 port=21) goto lex_done; } else if (!StrCompare(cc->cur_str, "USER")) + { + StrFirstRemove(input_str, " "); + if (!StrCompare(input_str, "")) + { + ST_ERR_ST "Must provide argument!\n"); + else if (!StrCompare(cc->cur_str, "USER")) { StrFirstRemove(input_str, " "); if (!StrCompare(input_str, "")) @@ -439,7 +533,6 @@ I64 FTPClient(U8 *hostname=NULL, U16 port=21) Free(temp); goto lex_done; - } else if (!StrCompare(cc->cur_str, "PASS")) { @@ -458,7 +551,6 @@ I64 FTPClient(U8 *hostname=NULL, U16 port=21) Free(temp); goto lex_done; - } else if (!StrCompare(cc->cur_str, "QUIT") || !StrCompare(cc->cur_str, "EXIT") || @@ -482,17 +574,16 @@ Command List: (Alternate names separated by '/'; names case-insensitive) - -CWD/CD <path> = Change Working Directory to <path>. -LIST/DIR/LS = List directory contents. -PWD = Print name of current directory. -RETR/GET <file> = Download copy of <file> from server. -VIEW/CAT <file> = Print the contents of <file> to the screen. -USER <username> = Set username to <username>. -PASS <password> = Set password to <password>. -QUIT/EXIT/BYE = End FTP session.\n\n"; +CWD/CD <path> = Change Working Directory to <path> +LIST/DIR/LS = List directory contents +PWD = Print current directory +RETR/GET <file> = Download file from server +STOR/PUT <file> = Upload file to server +VIEW/CAT <file> = View file contents +USER <username> = Set username +PASS <password> = Set password +QUIT/EXIT/BYE = End session\n\n"; } - break; default: @@ -503,6 +594,6 @@ QUIT/EXIT/BYE = End FTP session.\n\n"; lex_done: CompCtrlDel(cc); } -}; +} -FTPClient; \ No newline at end of file +FTPClient;