mirror of
https://github.com/dimoniche/changer.git
synced 2026-01-30 01:03:30 +03:00
876 lines
24 KiB
C
876 lines
24 KiB
C
#include <includes.h>
|
|
#include "app_serv.h"
|
|
#include "ftp_client.h"
|
|
#include <string.h>
|
|
#include "time.h"
|
|
#include "host_app.h"
|
|
|
|
#if uC_TCPIP_MODULE > 0
|
|
/**
|
|
* @brief Removes all trailing whitespace from a string
|
|
* @param[in,out] s Pointer to a NULL-terminated character string
|
|
**/
|
|
void strRemoveTrailingSpace(char *s)
|
|
{
|
|
char *end;
|
|
|
|
// Search for the first whitespace to remove
|
|
// at the end of the string
|
|
for (end = NULL; *s != '\0'; s++)
|
|
{
|
|
if (*s != ' ')
|
|
end = NULL;
|
|
else if (!end)
|
|
end = s;
|
|
}
|
|
|
|
// Trim whitespace from the end
|
|
if (end) *end = '\0';
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Convert a binary IPv4 address to dot-decimal notation
|
|
* @param[in] ipAddr Binary representation of the IPv4 address
|
|
* @param[out] str NULL-terminated string representing the IPv4 address
|
|
* @return Pointer to the formatted string
|
|
**/
|
|
char *ipv4AddrToString(uint32_t ipAddr, char *str)
|
|
{
|
|
uint8_t *p;
|
|
static char buffer[16];
|
|
|
|
// The str parameter is optional
|
|
if (!str) str = buffer;
|
|
|
|
// Cast the address to byte array
|
|
p = (uint8_t *) &ipAddr;
|
|
// Format IPv4 address
|
|
sprintf(str, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
|
|
|
|
// Return a pointer to the formatted string
|
|
return str;
|
|
}
|
|
|
|
/**
|
|
* @brief Establish a connection with the specified FTP server
|
|
* @param[in] context Pointer to the FTP client context
|
|
* @param[in] interface Underlying network interface (optional parameter)
|
|
* @param[in] serverAddr IP address of the FTP server
|
|
* @param[in] serverPort Port number
|
|
* @param[in] flags Connection options
|
|
* @return Error code
|
|
**/
|
|
|
|
int ftpConnect(FtpClientContext *context, uint32_t *serverAddr, uint16_t serverPort, uint32_t flags)
|
|
{
|
|
int error;
|
|
uint32_t replyCode;
|
|
NET_ERR err;
|
|
|
|
// Invalid context?
|
|
if (context == NULL)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
// Clear context
|
|
memset(context, 0, sizeof(FtpClientContext));
|
|
|
|
// Save the IP address of the FTP server
|
|
context->serverAddr = *serverAddr;
|
|
|
|
// Use passive mode?
|
|
if (flags & FTP_PASSIVE_MODE)
|
|
context->passiveMode = 1;
|
|
else
|
|
context->passiveMode = 0;
|
|
|
|
// Open control socket
|
|
context->controlSocket = HostConnectSocket(context->serverAddr, serverPort, FTP_CLIENT_DEFAULT_TIMEOUT, &err);
|
|
if ((err != NET_SOCK_ERR_NONE) || (context->controlSocket < 0))
|
|
{
|
|
return ERROR_OPEN_FAILED;
|
|
}
|
|
|
|
// Wait for the connection greeting reply
|
|
error = ftpSendCommand(context, NULL, &replyCode);
|
|
// Any communication error to report?
|
|
if (error >= 0)
|
|
{
|
|
// Check FTP response code
|
|
if (!FTP_REPLY_CODE_2YZ(replyCode))
|
|
error = ERROR_UNEXPECTED_RESPONSE;
|
|
}
|
|
|
|
// Any error to report?
|
|
if (error < 0)
|
|
{
|
|
// Clean up side effects
|
|
NetSock_Close(context->controlSocket, &err);
|
|
context->controlSocket = -1;
|
|
}
|
|
|
|
// Return status code
|
|
return error;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Login to the FTP server using the provided username and password
|
|
* @param[in] context Pointer to the FTP client context
|
|
* @param[in] username The username to login under
|
|
* @param[in] password The password to use
|
|
* @param[in] account Account name
|
|
* @return Error code
|
|
**/
|
|
int ftpLogin(FtpClientContext *context, const char *username, const char *password, const char *account)
|
|
{
|
|
int error;
|
|
uint32_t replyCode;
|
|
|
|
// Invalid context?
|
|
if (context == NULL)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
// Format the USER command
|
|
sprintf((char*)context->buffer, "USER %s\r\n", username);
|
|
|
|
// Send the command to the server
|
|
error = ftpSendCommand(context, (char const*)context->buffer, &replyCode);
|
|
// Any error to report?
|
|
if (error) return error;
|
|
|
|
// Check FTP response code
|
|
if (FTP_REPLY_CODE_2YZ(replyCode))
|
|
return 0;
|
|
else if(!FTP_REPLY_CODE_3YZ(replyCode))
|
|
return ERROR_UNEXPECTED_RESPONSE;
|
|
|
|
// Format the PASS command
|
|
sprintf((char*)context->buffer, "PASS %s\r\n", password);
|
|
|
|
// Send the command to the server
|
|
error = ftpSendCommand(context, (char const*)context->buffer, &replyCode);
|
|
// Any error to report?
|
|
if (error) return error;
|
|
|
|
// Check FTP response code
|
|
if(FTP_REPLY_CODE_2YZ(replyCode))
|
|
return 0;
|
|
else if(!FTP_REPLY_CODE_3YZ(replyCode))
|
|
return ERROR_UNEXPECTED_RESPONSE;
|
|
|
|
// Format the ACCT command
|
|
sprintf((char*)context->buffer, "ACCT %s\r\n", account);
|
|
|
|
// Send the command to the server
|
|
error = ftpSendCommand(context, (char const*)context->buffer, &replyCode);
|
|
// Any error to report?
|
|
if (error) return error;
|
|
|
|
// Check FTP response code
|
|
if (!FTP_REPLY_CODE_2YZ(replyCode))
|
|
return ERROR_UNEXPECTED_RESPONSE;
|
|
|
|
// Successful processing
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Set the port to be used in data connection
|
|
* @param[in] context Pointer to the FTP client context
|
|
* @param[in] ipAddr Host address
|
|
* @param[in] port Port number
|
|
* @return Error code
|
|
**/
|
|
int ftpSetPort(FtpClientContext *context, const uint32_t *ipAddr, uint16_t port)
|
|
{
|
|
int error;
|
|
uint32_t replyCode;
|
|
char *p;
|
|
|
|
// Invalid context?
|
|
if (context == NULL)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
#if 1
|
|
// IPv4 FTP client?
|
|
if (1)//(ipAddr->length == sizeof(Ipv4Addr))
|
|
{
|
|
// Format the PORT command
|
|
strcpy((char*)context->buffer, "PORT ");
|
|
|
|
// Append host address
|
|
ipv4AddrToString((uint32_t)ipAddr, (char*)context->buffer + 5);
|
|
|
|
// Parse the resulting string
|
|
for (p = (char*)context->buffer; *p != '\0'; p++)
|
|
{
|
|
// Change dots to commas
|
|
if (*p == '.') *p = ',';
|
|
}
|
|
|
|
// Append port number
|
|
sprintf(p, "%d,%d\r\n", (port >> 8), (port & 0xFF));
|
|
}
|
|
else
|
|
#endif
|
|
// Invalid IP address?
|
|
{
|
|
// Report an error
|
|
return ERROR_INVALID_ADDRESS;
|
|
}
|
|
|
|
// Send the command to the server
|
|
error = ftpSendCommand(context, (char const*)context->buffer, &replyCode);
|
|
// Any error to report?
|
|
if (error) return error;
|
|
|
|
// Check FTP response code
|
|
if (!FTP_REPLY_CODE_2YZ(replyCode))
|
|
return ERROR_UNEXPECTED_RESPONSE;
|
|
|
|
// Successful processing
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Enter passive mode
|
|
* @param[in] context Pointer to the FTP client context
|
|
* @param[out] port The port number the server is listening on
|
|
* @return Error code
|
|
**/
|
|
int ftpSetPassiveMode(FtpClientContext *context, uint16_t *port)
|
|
{
|
|
int error;
|
|
uint32_t replyCode;
|
|
char delimiter;
|
|
char *p;
|
|
|
|
// Invalid context?
|
|
if (context == NULL)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
#if 1 //(IPV4_SUPPORT == ENABLED)
|
|
// IPv4 FTP server?
|
|
if (1)//(context->serverAddr.length == sizeof(Ipv4Addr))
|
|
{
|
|
// Send the command to the server
|
|
error = ftpSendCommand(context, "PASV\r\n", &replyCode);
|
|
// Any error to report?
|
|
if (error) return error;
|
|
|
|
// Check FTP response code
|
|
if (!FTP_REPLY_CODE_2YZ(replyCode))
|
|
return ERROR_UNEXPECTED_RESPONSE;
|
|
|
|
// Delimiter character
|
|
delimiter = ',';
|
|
|
|
// Retrieve the low byte of the port number
|
|
p = strrchr((char const*)context->buffer, delimiter);
|
|
// Failed to parse the response?
|
|
if (!p) return ERROR_INVALID_SYNTAX;
|
|
|
|
// Convert the resulting string
|
|
*port = atoi(p + 1);
|
|
// Split the string
|
|
*p = '\0';
|
|
|
|
// Retrieve the high byte of the port number
|
|
p = strrchr((char const*)context->buffer, delimiter);
|
|
// Failed to parse the response?
|
|
if (!p) return ERROR_INVALID_SYNTAX;
|
|
|
|
// Convert the resulting string
|
|
*port |= atoi(p + 1) << 8;
|
|
}
|
|
else
|
|
#endif
|
|
//Invalid IP address?
|
|
{
|
|
// Report an error
|
|
return ERROR_INVALID_ADDRESS;
|
|
}
|
|
|
|
// Successful processing
|
|
return FTP_NO_ERROR;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Set representation type
|
|
* @param[in] context Pointer to the FTP client context
|
|
* @param[in] type Single character identifying the desired type
|
|
* @return Error code
|
|
**/
|
|
int ftpSetType(FtpClientContext *context, char type)
|
|
{
|
|
int error;
|
|
uint32_t replyCode;
|
|
|
|
// Invalid context?
|
|
if (context == NULL)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
// Format the TYPE command
|
|
sprintf((char*)context->buffer, "TYPE %c\r\n", type);
|
|
|
|
// Send the command to the server
|
|
error = ftpSendCommand(context, (char const*)context->buffer, &replyCode);
|
|
// Any error to report?
|
|
if (error) return error;
|
|
|
|
// Check FTP response code
|
|
if(!FTP_REPLY_CODE_2YZ(replyCode))
|
|
return ERROR_UNEXPECTED_RESPONSE;
|
|
|
|
// Successful processing
|
|
return FTP_NO_ERROR;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the working directory from the FTP server
|
|
* @param[in] context Pointer to the FTP client context
|
|
* @param[out] path Output buffer where to store the current directory
|
|
* @param[in] size Size of the output buffer
|
|
* @return Error code
|
|
**/
|
|
int ftpGetWorkingDir(FtpClientContext *context, char *path, uint32_t size)
|
|
{
|
|
int error;
|
|
uint32_t length;
|
|
uint32_t replyCode;
|
|
char *p;
|
|
|
|
//Invalid context?
|
|
if (context == NULL)
|
|
return ERROR_INVALID_PARAMETER;
|
|
// Check parameters
|
|
if (path == NULL || size == 0)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
// Send the command to the server
|
|
error = ftpSendCommand(context, "PWD\r\n", &replyCode);
|
|
// Any error to report?
|
|
if (error) return error;
|
|
|
|
// Check FTP response code
|
|
if (!FTP_REPLY_CODE_2YZ(replyCode))
|
|
return ERROR_UNEXPECTED_RESPONSE;
|
|
|
|
// Search for the last double quote
|
|
p = strrchr((char*)context->buffer, '\"');
|
|
// Failed to parse the response?
|
|
if (!p) return ERROR_INVALID_SYNTAX;
|
|
|
|
// Split the string
|
|
*p = '\0';
|
|
|
|
// Search for the first double quote
|
|
p = strchr((char const*)context->buffer, '\"');
|
|
// Failed to parse the response?
|
|
if (!p) return ERROR_INVALID_SYNTAX;
|
|
|
|
// Retrieve the length of the working directory
|
|
length = strlen(p + 1);
|
|
// Limit the number of characters to copy
|
|
if (length > size - 1)
|
|
{
|
|
length = size - 1;
|
|
}
|
|
|
|
// Copy the string
|
|
strncpy(path, p + 1, length);
|
|
// Properly terminate the string with a NULL character
|
|
path[length] = '\0';
|
|
|
|
// Successful processing
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Open a file for reading, writing, or appending
|
|
* @param[in] context Pointer to the FTP client context
|
|
* @param[in] path Path to the file to be be opened
|
|
* @param[in] flags Access mode
|
|
* @return Error code
|
|
**/
|
|
int ftpOpenFile(FtpClientContext *context, const char *path, uint32_t flags)
|
|
{
|
|
int error;
|
|
uint32_t replyCode;
|
|
uint32_t ipAddr;
|
|
uint16_t port;
|
|
NET_ERR err;
|
|
|
|
// Invalid context?
|
|
if (context == NULL)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
context->dataSocket = NetSock_Open(NET_SOCK_ADDR_FAMILY_IP_V4, NET_SOCK_TYPE_STREAM, NET_SOCK_PROTOCOL_TCP, &err);
|
|
if ((err != NET_SOCK_ERR_NONE) || (context->dataSocket < 0))
|
|
{
|
|
return ERROR_OPEN_FAILED;
|
|
}
|
|
|
|
// Start of exception handling block
|
|
do
|
|
{
|
|
//Set representation type
|
|
if (flags & FTP_TEXT_TYPE)
|
|
{
|
|
// Use ASCII type
|
|
error = ftpSetType(context, 'A');
|
|
// Any error to report?
|
|
if(error) break;
|
|
}
|
|
else
|
|
{
|
|
// Use image type
|
|
error = ftpSetType(context, 'I');
|
|
// Any error to report?
|
|
if(error) break;
|
|
}
|
|
|
|
// Check transfer mode
|
|
if (!context->passiveMode)
|
|
{
|
|
NET_SOCK_ADDR_IP server_sock_addr_ip;
|
|
|
|
Mem_Clr((void*)&server_sock_addr_ip, (CPU_SIZE_T)sizeof(server_sock_addr_ip));
|
|
server_sock_addr_ip.Family = NET_SOCK_ADDR_FAMILY_IP_V4;
|
|
server_sock_addr_ip.Addr = NET_UTIL_HOST_TO_NET_32(NET_SOCK_ADDR_IP_WILD_CARD);
|
|
server_sock_addr_ip.Port = NET_UTIL_HOST_TO_NET_16(FTP_DATA_PORT);
|
|
|
|
NetSock_Bind(context->dataSocket, (NET_SOCK_ADDR *)&server_sock_addr_ip, (NET_SOCK_ADDR_LEN)NET_SOCK_ADDR_SIZE, (NET_ERR *)&err);
|
|
if (err != NET_SOCK_ERR_NONE)
|
|
{
|
|
NetSock_Close(context->dataSocket, &err);
|
|
context->dataSocket = -1;
|
|
return -1;
|
|
}
|
|
|
|
NetSock_Listen(context->dataSocket, 1, &err);
|
|
if (err != NET_SOCK_ERR_NONE)
|
|
{
|
|
NetSock_Close(context->dataSocket, &err);
|
|
context->dataSocket = -1;
|
|
return -1;
|
|
}
|
|
|
|
ipAddr = server_sock_addr_ip.Addr;
|
|
port = FTP_DATA_PORT;
|
|
|
|
// Set the port to be used in data connection
|
|
error = ftpSetPort(context, &ipAddr, port);
|
|
// Any error to report?
|
|
if (error) break;
|
|
}
|
|
else
|
|
{
|
|
NET_SOCK_ADDR_IP server_sock_addr_ip;
|
|
CPU_INT32U time_stamp;
|
|
|
|
// Enter passive mode
|
|
error = ftpSetPassiveMode(context, &port);
|
|
// Any error to report?
|
|
if (error) break;
|
|
|
|
memset(&server_sock_addr_ip, 0, sizeof(server_sock_addr_ip));
|
|
server_sock_addr_ip.Family = NET_SOCK_ADDR_FAMILY_IP_V4;
|
|
server_sock_addr_ip.Addr = NET_UTIL_HOST_TO_NET_32(context->serverAddr);
|
|
server_sock_addr_ip.Port = NET_UTIL_HOST_TO_NET_16(port);
|
|
|
|
time_stamp = OSTimeGet();
|
|
NetSock_Conn((NET_SOCK_ID)context->dataSocket, (NET_SOCK_ADDR *)&server_sock_addr_ip, (NET_SOCK_ADDR_LEN)sizeof(server_sock_addr_ip), &err);
|
|
while (NetSock_IsConn((NET_SOCK_ID)context->dataSocket, &err) != DEF_YES)
|
|
{
|
|
if ((err != NET_SOCK_ERR_CONN_IN_PROGRESS) && (err != NET_SOCK_ERR_NONE))
|
|
{
|
|
break;
|
|
}
|
|
if (OSTimeGet() - time_stamp > FTP_CLIENT_DEFAULT_TIMEOUT)
|
|
{
|
|
error = -1;
|
|
break;
|
|
}
|
|
OSTimeDly(2);
|
|
}
|
|
|
|
if ((err != NET_SOCK_ERR_NONE) || (error))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Format the command
|
|
if (flags & FTP_FOR_WRITING)
|
|
sprintf((char*)context->buffer, "STOR %s\r\n", path);
|
|
else if(flags & FTP_FOR_APPENDING)
|
|
sprintf((char*)context->buffer, "APPE %s\r\n", path);
|
|
else
|
|
sprintf((char*)context->buffer, "RETR %s\r\n", path);
|
|
|
|
// Send the command to the server
|
|
error = ftpSendCommand(context, (char const*)context->buffer, &replyCode);
|
|
// Any error to report?
|
|
if (error) break;
|
|
|
|
// Check FTP response code
|
|
if (!FTP_REPLY_CODE_1YZ(replyCode))
|
|
{
|
|
// Report an error
|
|
error = ERROR_UNEXPECTED_RESPONSE;
|
|
break;
|
|
}
|
|
|
|
// Check transfer mode
|
|
if (!context->passiveMode)
|
|
{
|
|
NET_SOCK_ADDR_IP client_sock_addr_ip;
|
|
NET_SOCK_ADDR_LEN client_sock_addr_ip_size = sizeof(client_sock_addr_ip);
|
|
NET_SOCK_ID newSockID;
|
|
CPU_BOOLEAN attempt_conn;
|
|
CPU_INT32U time_stamp;
|
|
|
|
time_stamp = OSTimeGet();
|
|
do
|
|
{
|
|
if (NetNIC_ConnStatusGet() != DEF_ON)
|
|
{
|
|
err = NET_SOCK_ERR_NONE_AVAIL;
|
|
break;
|
|
}
|
|
|
|
if (OSTimeGet() - time_stamp > FTP_CLIENT_DEFAULT_TIMEOUT)
|
|
{
|
|
err = NET_SOCK_ERR_CONN_SIGNAL_TIMEOUT;
|
|
break;
|
|
}
|
|
|
|
OSTimeDly(2);
|
|
|
|
newSockID = NetSock_Accept((NET_SOCK_ID )context->dataSocket, (NET_SOCK_ADDR *)&client_sock_addr_ip, (NET_SOCK_ADDR_LEN *)&client_sock_addr_ip_size, (NET_ERR *)&err);
|
|
switch (err)
|
|
{
|
|
case NET_SOCK_ERR_NONE:
|
|
attempt_conn = DEF_NO;
|
|
break;
|
|
case NET_ERR_INIT_INCOMPLETE:
|
|
case NET_SOCK_ERR_NULL_PTR:
|
|
case NET_SOCK_ERR_NONE_AVAIL:
|
|
case NET_SOCK_ERR_CONN_ACCEPT_Q_NONE_AVAIL:
|
|
case NET_SOCK_ERR_CONN_SIGNAL_TIMEOUT:
|
|
case NET_OS_ERR_LOCK:
|
|
attempt_conn = DEF_YES;
|
|
break;
|
|
default:
|
|
attempt_conn = DEF_NO;
|
|
break;
|
|
}
|
|
} while (attempt_conn == DEF_YES);
|
|
|
|
// No connection request?
|
|
if ((newSockID < 0) || (err != NET_SOCK_ERR_NONE))
|
|
{
|
|
// Report an error
|
|
error = -1;
|
|
break;
|
|
}
|
|
|
|
// Close the listening socket
|
|
NetSock_Close(context->dataSocket, &err);
|
|
context->dataSocket = newSockID;
|
|
}
|
|
|
|
// End of exception handling block
|
|
} while(0);
|
|
|
|
// Any error to report?
|
|
if (error)
|
|
{
|
|
// Clean up side effects
|
|
NetSock_Close(context->dataSocket, &err);
|
|
context->dataSocket = -1;
|
|
}
|
|
|
|
// Return status code
|
|
return error;
|
|
}
|
|
|
|
/**
|
|
* @brief Write to a remote file
|
|
* @param[in] context Pointer to the FTP client context
|
|
* @param[in] data Pointer to a buffer containing the data to be written
|
|
* @param[in] length Number of data bytes to write
|
|
* @param[in] flags Set of flags that influences the behavior of this function
|
|
* @return Error code
|
|
**/
|
|
int ftpWriteFile(FtpClientContext *context, const void *data, uint32_t length, uint32_t flags)
|
|
{
|
|
// Invalid context?
|
|
if (context == NULL)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
OSTimeDly(10);
|
|
if (HostWriteDataTimeout(context->dataSocket, (char*)data, length, FTP_CLIENT_WRITE_TIMEOUT) != length)
|
|
{
|
|
return -1;
|
|
}
|
|
OSTimeDly(20);
|
|
|
|
// Transmit data to the FTP server
|
|
return FTP_NO_ERROR;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Close file
|
|
* @param[in] context Pointer to the FTP client context
|
|
* @return Error code
|
|
**/
|
|
int ftpCloseFile(FtpClientContext *context)
|
|
{
|
|
NET_ERR err;
|
|
int error;
|
|
uint32_t replyCode;
|
|
|
|
// Invalid context?
|
|
if (context == NULL)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
// Close the data socket
|
|
NetSock_Close(context->dataSocket, &err);
|
|
context->dataSocket = -1;
|
|
|
|
// Check the transfer status
|
|
error = ftpSendCommand(context, NULL, &replyCode);
|
|
// Any error to report?
|
|
if (error) return error;
|
|
|
|
// Check FTP response code
|
|
if (!FTP_REPLY_CODE_2YZ(replyCode))
|
|
return ERROR_UNEXPECTED_RESPONSE;
|
|
|
|
// Successful processing
|
|
return FTP_NO_ERROR;
|
|
}
|
|
|
|
/**
|
|
* @brief Delete a file
|
|
* @param[in] context Pointer to the FTP client context
|
|
* @param[in] path Path to the file to be be deleted
|
|
* @return Error code
|
|
**/
|
|
int ftpDeleteFile(FtpClientContext *context, const char *path)
|
|
{
|
|
int error;
|
|
uint32_t replyCode;
|
|
|
|
//Invalid context?
|
|
if(context == NULL)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
//Format the DELE command
|
|
sprintf((char*)context->buffer, "DELE %s\r\n", path);
|
|
|
|
//Send the command to the server
|
|
error = ftpSendCommand(context, (char const*)context->buffer, &replyCode);
|
|
//Any error to report?
|
|
if(error) return error;
|
|
|
|
//Check FTP response code
|
|
if(!FTP_REPLY_CODE_2YZ(replyCode))
|
|
return ERROR_UNEXPECTED_RESPONSE;
|
|
|
|
//Successful processing
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Close the connection with the FTP server
|
|
* @param[in] context Pointer to the FTP client context
|
|
* @return Error code
|
|
**/
|
|
int ftpClose(FtpClientContext *context)
|
|
{
|
|
NET_ERR err;
|
|
|
|
// Invalid context?
|
|
if (context == NULL)
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Close data socket
|
|
if (context->dataSocket >= 0)
|
|
{
|
|
NetSock_Close(context->dataSocket, &err);
|
|
context->dataSocket = -1;
|
|
}
|
|
|
|
// Close control socket
|
|
if (context->controlSocket)
|
|
{
|
|
NetSock_Close(context->controlSocket, &err);
|
|
context->controlSocket = -1;
|
|
}
|
|
|
|
// Successful processing
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Send FTP command and wait for a reply
|
|
* @param[in] context Pointer to the FTP client context
|
|
* @param[in] command Command line
|
|
* @param[out] replyCode Response code from the FTP server
|
|
* @return Error code
|
|
**/
|
|
int ftpSendCommand(FtpClientContext *context, const char *command, uint32_t *replyCode)
|
|
{
|
|
int length;
|
|
char *p;
|
|
|
|
// Any command line to send?
|
|
if (command)
|
|
{
|
|
if (HostWriteDataTimeout(context->controlSocket, (char*)command, strlen(command), FTP_CLIENT_WRITE_TIMEOUT) != strlen(command))
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
// Multiline replies are allowed for any command
|
|
while (1)
|
|
{
|
|
// Wait for a response from the server
|
|
NET_ERR err;
|
|
length = HostReadData(context->controlSocket, (char *)context->buffer, FTP_CLIENT_BUFFER_SIZE - 1, FTP_CLIENT_DEFAULT_TIMEOUT, &err);
|
|
if (length <= 0)
|
|
{
|
|
return ERROR_EMPTY_RECEIVE;
|
|
}
|
|
|
|
// Point to the beginning of the buffer
|
|
p = (char*)context->buffer;
|
|
// Properly terminate the string with a NULL character
|
|
p[length] = '\0';
|
|
|
|
// Remove trailing whitespace from the response
|
|
strRemoveTrailingSpace(p);
|
|
|
|
// Check the length of the response
|
|
if (strlen(p) >= 3)
|
|
{
|
|
// All replies begin with a three digit numeric code
|
|
if (isdigit(p[0]) && isdigit(p[1]) && isdigit(p[2]))
|
|
{
|
|
// A space character follows the response code for the last line
|
|
if (p[3] == ' ' || p[3] == '\0')
|
|
{
|
|
// Get the server response code
|
|
*replyCode = strtoul(p, NULL, 10);
|
|
// Exit immediately
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Successful processing
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Change the current working directory of the FTP session
|
|
* @param[in] context Pointer to the FTP client context
|
|
* @param[in] path The new current working directory
|
|
* @return Error code
|
|
**/
|
|
int ftpChangeWorkingDir(FtpClientContext *context, const char *path)
|
|
{
|
|
int error;
|
|
uint32_t replyCode;
|
|
|
|
//Invalid context?
|
|
if(context == NULL)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
//Format the CWD command
|
|
sprintf((char*)context->buffer, "CWD %s\r\n", path);
|
|
|
|
//Send the command to the server
|
|
error = ftpSendCommand(context, (char*)context->buffer, &replyCode);
|
|
//Any error to report?
|
|
if(error) return error;
|
|
|
|
//Check FTP response code
|
|
if(!FTP_REPLY_CODE_2YZ(replyCode))
|
|
return ERROR_UNEXPECTED_RESPONSE;
|
|
|
|
//Successful processing
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Create a new directory
|
|
* @param[in] context Pointer to the FTP client context
|
|
* @param[in] path The name of the new directory
|
|
* @return Error code
|
|
**/
|
|
int ftpMakeDir(FtpClientContext *context, const char *path)
|
|
{
|
|
int error;
|
|
uint32_t replyCode;
|
|
|
|
//Invalid context?
|
|
if(context == NULL)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
//Format the MKD command
|
|
sprintf((char*)context->buffer, "MKD %s\r\n", path);
|
|
|
|
//Send the command to the server
|
|
error = ftpSendCommand(context, (char*)context->buffer, &replyCode);
|
|
//Any error to report?
|
|
if(error) return error;
|
|
|
|
//Check FTP response code
|
|
if(!FTP_REPLY_CODE_2YZ(replyCode))
|
|
return ERROR_UNEXPECTED_RESPONSE;
|
|
|
|
//Successful processing
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Change the current working directory to the parent directory
|
|
* @param[in] context Pointer to the FTP client context
|
|
* @return Error code
|
|
**/
|
|
int ftpChangeToParentDir(FtpClientContext *context)
|
|
{
|
|
int error;
|
|
uint32_t replyCode;
|
|
|
|
//Invalid context?
|
|
if(context == NULL)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
//Send the command to the server
|
|
error = ftpSendCommand(context, "CDUP\r\n", &replyCode);
|
|
//Any error to report?
|
|
if(error) return error;
|
|
|
|
//Check FTP response code
|
|
if(!FTP_REPLY_CODE_2YZ(replyCode))
|
|
return ERROR_UNEXPECTED_RESPONSE;
|
|
|
|
//Successful processing
|
|
return 0;
|
|
}
|
|
#endif |