2001-02-23 20:55:21 +03:00
/*
* nanoftp . c : basic FTP client support
*
* Reference : RFC 959
*/
# ifdef TESTING
# define STANDALONE
# define HAVE_UNISTD_H
# define HAVE_SYS_SOCKET_H
# define HAVE_NETINET_IN_H
# define HAVE_NETDB_H
# define HAVE_SYS_TIME_H
2001-12-31 19:16:02 +03:00
# endif /* TESTING */
2001-02-23 20:55:21 +03:00
2002-03-18 22:37:11 +03:00
# define IN_LIBXML
2001-07-18 23:30:27 +04:00
# include "libxml.h"
2001-02-23 20:55:21 +03:00
# ifdef LIBXML_FTP_ENABLED
# include <string.h>
# include <stdlib.h>
2022-03-02 02:29:17 +03:00
# include <errno.h>
2001-02-23 20:55:21 +03:00
# ifdef HAVE_UNISTD_H
# include <unistd.h>
2022-11-22 10:20:53 +03:00
# elif defined (_WIN32)
# include <io.h>
2001-02-23 20:55:21 +03:00
# endif
# ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
# endif
# ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
# endif
# ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
# endif
# ifdef HAVE_NETDB_H
# include <netdb.h>
# endif
# ifdef HAVE_FCNTL_H
2012-09-11 09:26:36 +04:00
# include <fcntl.h>
2001-02-23 20:55:21 +03:00
# endif
# ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
# endif
# ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
# endif
2003-07-07 18:42:44 +04:00
# ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
# endif
2001-02-23 20:55:21 +03:00
# include <libxml/xmlmemory.h>
2001-10-13 13:15:48 +04:00
# include <libxml/parser.h>
2001-02-23 20:55:21 +03:00
# include <libxml/xmlerror.h>
2003-01-10 19:09:51 +03:00
# include <libxml/uri.h>
2001-10-13 13:15:48 +04:00
# include <libxml/nanoftp.h>
2001-10-17 19:58:35 +04:00
# include <libxml/globals.h>
2001-02-23 20:55:21 +03:00
2022-08-26 02:22:33 +03:00
# include "private/error.h"
# include "private/io.h"
2001-02-23 20:55:21 +03:00
/* #define DEBUG_FTP 1 */
# ifdef STANDALONE
# ifndef DEBUG_FTP
# define DEBUG_FTP 1
# endif
# endif
2003-08-14 05:23:25 +04:00
2022-03-01 00:42:10 +03:00
# if defined(_WIN32)
2003-08-14 05:23:25 +04:00
# include <wsockcompat.h>
# endif
2001-02-23 20:55:21 +03:00
/**
* A couple portability macros
*/
# ifndef _WINSOCKAPI_
# define closesocket(s) close(s)
2003-09-29 17:20:24 +04:00
# endif
2003-09-29 17:29:09 +04:00
2005-04-06 01:48:57 +04:00
# ifndef XML_SOCKLEN_T
# define XML_SOCKLEN_T unsigned int
# endif
2022-09-04 04:19:01 +03:00
# define GETHOSTBYNAME_ARG_CAST (char *)
# define SEND_ARG2_CAST (char *)
2001-02-23 20:55:21 +03:00
# define FTP_COMMAND_OK 200
# define FTP_SYNTAX_ERROR 500
# define FTP_GET_PASSWD 331
2005-05-06 15:40:56 +04:00
# define FTP_BUF_SIZE 1024
2001-02-23 20:55:21 +03:00
2004-02-10 15:48:57 +03:00
# define XML_NANO_MAX_URLBUF 4096
2001-02-23 20:55:21 +03:00
typedef struct xmlNanoFTPCtxt {
char * protocol ; /* the protocol name */
char * hostname ; /* the host name */
int port ; /* the port */
char * path ; /* the path within the URL */
char * user ; /* user string */
char * passwd ; /* passwd string */
2003-06-21 18:20:04 +04:00
# ifdef SUPPORT_IP6
struct sockaddr_storage ftpAddr ; /* this is large enough to hold IPv6 address*/
# else
2001-02-23 20:55:21 +03:00
struct sockaddr_in ftpAddr ; /* the socket address struct */
2003-06-21 18:20:04 +04:00
# endif
2001-02-23 20:55:21 +03:00
int passive ; /* currently we support only passive !!! */
SOCKET controlFd ; /* the file descriptor for the control socket */
SOCKET dataFd ; /* the file descriptor for the data socket */
int state ; /* WRITE / READ / CLOSED */
int returnValue ; /* the protocol return value */
/* buffer for data received from the control connection */
char controlBuf [ FTP_BUF_SIZE + 1 ] ;
int controlBufIndex ;
int controlBufUsed ;
int controlBufAnswer ;
} xmlNanoFTPCtxt , * xmlNanoFTPCtxtPtr ;
static int initialized = 0 ;
static char * proxy = NULL ; /* the proxy name if any */
static int proxyPort = 0 ; /* the proxy port if any */
static char * proxyUser = NULL ; /* user for proxy authentication */
static char * proxyPasswd = NULL ; /* passwd for proxy authentication */
static int proxyType = 0 ; /* uses TYPE or a@b ? */
2003-06-21 18:20:04 +04:00
# ifdef SUPPORT_IP6
2003-07-08 16:16:59 +04:00
static
int have_ipv6 ( void ) {
2003-06-21 18:20:04 +04:00
int s ;
s = socket ( AF_INET6 , SOCK_STREAM , 0 ) ;
if ( s ! = - 1 ) {
close ( s ) ;
return ( 1 ) ;
}
return ( 0 ) ;
}
# endif
2003-10-10 23:36:36 +04:00
/**
* xmlFTPErrMemory :
2020-03-08 19:19:42 +03:00
* @ extra : extra information
2003-10-10 23:36:36 +04:00
*
* Handle an out of memory condition
*/
static void
xmlFTPErrMemory ( const char * extra )
{
__xmlSimpleError ( XML_FROM_FTP , XML_ERR_NO_MEMORY , NULL , NULL , extra ) ;
}
2001-02-23 20:55:21 +03:00
/**
* xmlNanoFTPInit :
*
* Initialize the FTP protocol layer .
2020-03-08 19:19:42 +03:00
* Currently it just checks for proxy information ,
2001-02-23 20:55:21 +03:00
* and get the hostname
*/
void
xmlNanoFTPInit ( void ) {
const char * env ;
# ifdef _WINSOCKAPI_
2012-09-11 09:26:36 +04:00
WSADATA wsaData ;
2001-02-23 20:55:21 +03:00
# endif
if ( initialized )
return ;
# ifdef _WINSOCKAPI_
if ( WSAStartup ( MAKEWORD ( 1 , 1 ) , & wsaData ) ! = 0 )
return ;
# endif
proxyPort = 21 ;
env = getenv ( " no_proxy " ) ;
2004-08-16 04:39:03 +04:00
if ( env & & ( ( env [ 0 ] = = ' * ' ) & & ( env [ 1 ] = = 0 ) ) )
2001-02-23 20:55:21 +03:00
return ;
env = getenv ( " ftp_proxy " ) ;
if ( env ! = NULL ) {
xmlNanoFTPScanProxy ( env ) ;
} else {
env = getenv ( " FTP_PROXY " ) ;
if ( env ! = NULL ) {
xmlNanoFTPScanProxy ( env ) ;
}
}
env = getenv ( " ftp_proxy_user " ) ;
if ( env ! = NULL ) {
proxyUser = xmlMemStrdup ( env ) ;
}
env = getenv ( " ftp_proxy_password " ) ;
if ( env ! = NULL ) {
proxyPasswd = xmlMemStrdup ( env ) ;
}
initialized = 1 ;
}
/**
2001-03-10 15:32:04 +03:00
* xmlNanoFTPCleanup :
2001-02-23 20:55:21 +03:00
*
2020-03-08 19:19:42 +03:00
* Cleanup the FTP protocol layer . This cleanup proxy information .
2001-02-23 20:55:21 +03:00
*/
void
xmlNanoFTPCleanup ( void ) {
if ( proxy ! = NULL ) {
xmlFree ( proxy ) ;
proxy = NULL ;
}
if ( proxyUser ! = NULL ) {
xmlFree ( proxyUser ) ;
proxyUser = NULL ;
}
if ( proxyPasswd ! = NULL ) {
xmlFree ( proxyPasswd ) ;
proxyPasswd = NULL ;
}
# ifdef _WINSOCKAPI_
if ( initialized )
WSACleanup ( ) ;
# endif
initialized = 0 ;
}
/**
* xmlNanoFTPProxy :
* @ host : the proxy host name
* @ port : the proxy port
* @ user : the proxy user name
* @ passwd : the proxy password
* @ type : the type of proxy 1 for using SITE , 2 for USER a @ b
*
2020-03-08 19:19:42 +03:00
* Setup the FTP proxy information .
2001-02-23 20:55:21 +03:00
* This can also be done by using ftp_proxy ftp_proxy_user and
* ftp_proxy_password environment variables .
*/
void
xmlNanoFTPProxy ( const char * host , int port , const char * user ,
const char * passwd , int type ) {
2004-11-02 17:52:23 +03:00
if ( proxy ! = NULL ) {
2001-02-23 20:55:21 +03:00
xmlFree ( proxy ) ;
2004-11-02 17:52:23 +03:00
proxy = NULL ;
}
if ( proxyUser ! = NULL ) {
2001-02-23 20:55:21 +03:00
xmlFree ( proxyUser ) ;
2004-11-02 17:52:23 +03:00
proxyUser = NULL ;
}
if ( proxyPasswd ! = NULL ) {
2001-02-23 20:55:21 +03:00
xmlFree ( proxyPasswd ) ;
2004-11-02 17:52:23 +03:00
proxyPasswd = NULL ;
}
2001-02-23 20:55:21 +03:00
if ( host )
proxy = xmlMemStrdup ( host ) ;
if ( user )
proxyUser = xmlMemStrdup ( user ) ;
if ( passwd )
proxyPasswd = xmlMemStrdup ( passwd ) ;
proxyPort = port ;
proxyType = type ;
}
/**
* xmlNanoFTPScanURL :
* @ ctx : an FTP context
* @ URL : The URL used to initialize the context
*
* ( Re ) Initialize an FTP context by parsing the URL and finding
* the protocol host port and path it indicates .
*/
static void
xmlNanoFTPScanURL ( void * ctx , const char * URL ) {
xmlNanoFTPCtxtPtr ctxt = ( xmlNanoFTPCtxtPtr ) ctx ;
2005-02-13 11:18:52 +03:00
xmlURIPtr uri ;
2001-02-23 20:55:21 +03:00
2005-02-13 11:18:52 +03:00
/*
* Clear any existing data from the context
*/
2012-09-11 09:26:36 +04:00
if ( ctxt - > protocol ! = NULL ) {
2001-02-23 20:55:21 +03:00
xmlFree ( ctxt - > protocol ) ;
ctxt - > protocol = NULL ;
}
2012-09-11 09:26:36 +04:00
if ( ctxt - > hostname ! = NULL ) {
2001-02-23 20:55:21 +03:00
xmlFree ( ctxt - > hostname ) ;
ctxt - > hostname = NULL ;
}
2012-09-11 09:26:36 +04:00
if ( ctxt - > path ! = NULL ) {
2001-02-23 20:55:21 +03:00
xmlFree ( ctxt - > path ) ;
ctxt - > path = NULL ;
}
if ( URL = = NULL ) return ;
2005-08-07 14:46:19 +04:00
uri = xmlParseURIRaw ( URL , 1 ) ;
2005-02-13 11:18:52 +03:00
if ( uri = = NULL )
return ;
2001-11-20 11:35:07 +03:00
2005-02-13 11:18:52 +03:00
if ( ( uri - > scheme = = NULL ) | | ( uri - > server = = NULL ) ) {
xmlFreeURI ( uri ) ;
return ;
}
2012-09-11 09:26:36 +04:00
2005-02-13 11:18:52 +03:00
ctxt - > protocol = xmlMemStrdup ( uri - > scheme ) ;
ctxt - > hostname = xmlMemStrdup ( uri - > server ) ;
if ( uri - > path ! = NULL )
ctxt - > path = xmlMemStrdup ( uri - > path ) ;
else
ctxt - > path = xmlMemStrdup ( " / " ) ;
if ( uri - > port ! = 0 )
ctxt - > port = uri - > port ;
if ( uri - > user ! = NULL ) {
char * cptr ;
if ( ( cptr = strchr ( uri - > user , ' : ' ) ) = = NULL )
ctxt - > user = xmlMemStrdup ( uri - > user ) ;
else {
ctxt - > user = ( char * ) xmlStrndup ( ( xmlChar * ) uri - > user ,
( cptr - uri - > user ) ) ;
ctxt - > passwd = xmlMemStrdup ( cptr + 1 ) ;
2003-06-21 18:20:04 +04:00
}
2005-02-13 11:18:52 +03:00
}
2003-06-21 18:20:04 +04:00
2005-02-13 11:18:52 +03:00
xmlFreeURI ( uri ) ;
2003-06-21 18:20:04 +04:00
2001-02-23 20:55:21 +03:00
}
/**
* xmlNanoFTPUpdateURL :
* @ ctx : an FTP context
* @ URL : The URL used to update the context
*
* Update an FTP context by parsing the URL and finding
2012-09-11 09:26:36 +04:00
* new path it indicates . If there is an error in the
2001-02-23 20:55:21 +03:00
* protocol , hostname , port or other information , the
* error is raised . It indicates a new connection has to
* be established .
*
* Returns 0 if Ok , - 1 in case of error ( other host ) .
*/
int
xmlNanoFTPUpdateURL ( void * ctx , const char * URL ) {
xmlNanoFTPCtxtPtr ctxt = ( xmlNanoFTPCtxtPtr ) ctx ;
2005-02-13 11:18:52 +03:00
xmlURIPtr uri ;
2001-02-23 20:55:21 +03:00
if ( URL = = NULL )
return ( - 1 ) ;
if ( ctxt = = NULL )
return ( - 1 ) ;
if ( ctxt - > protocol = = NULL )
return ( - 1 ) ;
if ( ctxt - > hostname = = NULL )
return ( - 1 ) ;
2003-06-21 18:20:04 +04:00
2005-08-07 14:46:19 +04:00
uri = xmlParseURIRaw ( URL , 1 ) ;
2005-02-13 11:18:52 +03:00
if ( uri = = NULL )
return ( - 1 ) ;
2003-06-21 18:20:04 +04:00
2005-02-13 11:18:52 +03:00
if ( ( uri - > scheme = = NULL ) | | ( uri - > server = = NULL ) ) {
xmlFreeURI ( uri ) ;
return ( - 1 ) ;
}
if ( ( strcmp ( ctxt - > protocol , uri - > scheme ) ) | |
( strcmp ( ctxt - > hostname , uri - > server ) ) | |
( ( uri - > port ! = 0 ) & & ( ctxt - > port ! = uri - > port ) ) ) {
xmlFreeURI ( uri ) ;
return ( - 1 ) ;
}
2003-06-21 18:20:04 +04:00
2005-02-13 11:18:52 +03:00
if ( uri - > port ! = 0 )
ctxt - > port = uri - > port ;
2003-06-21 18:20:04 +04:00
2001-02-23 20:55:21 +03:00
if ( ctxt - > path ! = NULL ) {
xmlFree ( ctxt - > path ) ;
ctxt - > path = NULL ;
}
2012-09-11 09:26:36 +04:00
if ( uri - > path = = NULL )
2001-02-23 20:55:21 +03:00
ctxt - > path = xmlMemStrdup ( " / " ) ;
2005-02-13 11:18:52 +03:00
else
ctxt - > path = xmlMemStrdup ( uri - > path ) ;
xmlFreeURI ( uri ) ;
2001-02-23 20:55:21 +03:00
return ( 0 ) ;
}
/**
* xmlNanoFTPScanProxy :
* @ URL : The proxy URL used to initialize the proxy context
*
* ( Re ) Initialize the FTP Proxy context by parsing the URL and finding
* the protocol host port it indicates .
* Should be like ftp : //myproxy/ or ftp://myproxy:3128/
2020-03-08 19:19:42 +03:00
* A NULL URL cleans up proxy information .
2001-02-23 20:55:21 +03:00
*/
void
xmlNanoFTPScanProxy ( const char * URL ) {
2005-02-13 11:18:52 +03:00
xmlURIPtr uri ;
2001-02-23 20:55:21 +03:00
2012-09-11 09:26:36 +04:00
if ( proxy ! = NULL ) {
2001-02-23 20:55:21 +03:00
xmlFree ( proxy ) ;
proxy = NULL ;
}
2005-02-13 11:18:52 +03:00
proxyPort = 0 ;
2001-02-23 20:55:21 +03:00
# ifdef DEBUG_FTP
if ( URL = = NULL )
2005-02-13 11:18:52 +03:00
xmlGenericError ( xmlGenericErrorContext ,
" Removing FTP proxy info \n " ) ;
2001-02-23 20:55:21 +03:00
else
2005-02-13 11:18:52 +03:00
xmlGenericError ( xmlGenericErrorContext ,
" Using FTP proxy %s \n " , URL ) ;
2001-02-23 20:55:21 +03:00
# endif
if ( URL = = NULL ) return ;
2003-06-21 18:20:04 +04:00
2005-08-07 14:46:19 +04:00
uri = xmlParseURIRaw ( URL , 1 ) ;
2005-02-13 11:18:52 +03:00
if ( ( uri = = NULL ) | | ( uri - > scheme = = NULL ) | |
( strcmp ( uri - > scheme , " ftp " ) ) | | ( uri - > server = = NULL ) ) {
__xmlIOErr ( XML_FROM_FTP , XML_FTP_URL_SYNTAX , " Syntax Error \n " ) ;
if ( uri ! = NULL )
xmlFreeURI ( uri ) ;
return ;
2001-02-23 20:55:21 +03:00
}
2012-09-11 09:26:36 +04:00
2005-02-13 11:18:52 +03:00
proxy = xmlMemStrdup ( uri - > server ) ;
if ( uri - > port ! = 0 )
proxyPort = uri - > port ;
xmlFreeURI ( uri ) ;
2001-02-23 20:55:21 +03:00
}
/**
* xmlNanoFTPNewCtxt :
* @ URL : The URL used to initialize the context
*
* Allocate and initialize a new FTP context .
*
* Returns an FTP context or NULL in case of error .
*/
void *
xmlNanoFTPNewCtxt ( const char * URL ) {
xmlNanoFTPCtxtPtr ret ;
2003-01-10 19:09:51 +03:00
char * unescaped ;
2001-02-23 20:55:21 +03:00
ret = ( xmlNanoFTPCtxtPtr ) xmlMalloc ( sizeof ( xmlNanoFTPCtxt ) ) ;
2003-10-10 23:36:36 +04:00
if ( ret = = NULL ) {
xmlFTPErrMemory ( " allocating FTP context " ) ;
return ( NULL ) ;
}
2001-02-23 20:55:21 +03:00
memset ( ret , 0 , sizeof ( xmlNanoFTPCtxt ) ) ;
ret - > port = 21 ;
ret - > passive = 1 ;
ret - > returnValue = 0 ;
ret - > controlBufIndex = 0 ;
ret - > controlBufUsed = 0 ;
2010-11-04 14:08:08 +03:00
ret - > controlFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
2003-01-10 19:09:51 +03:00
unescaped = xmlURIUnescapeString ( URL , 0 , NULL ) ;
2004-11-04 02:25:47 +03:00
if ( unescaped ! = NULL ) {
2003-01-10 19:09:51 +03:00
xmlNanoFTPScanURL ( ret , unescaped ) ;
2004-11-04 02:25:47 +03:00
xmlFree ( unescaped ) ;
} else if ( URL ! = NULL )
2001-02-23 20:55:21 +03:00
xmlNanoFTPScanURL ( ret , URL ) ;
return ( ret ) ;
}
/**
* xmlNanoFTPFreeCtxt :
* @ ctx : an FTP context
*
* Frees the context after closing the connection .
*/
void
xmlNanoFTPFreeCtxt ( void * ctx ) {
xmlNanoFTPCtxtPtr ctxt = ( xmlNanoFTPCtxtPtr ) ctx ;
if ( ctxt = = NULL ) return ;
if ( ctxt - > hostname ! = NULL ) xmlFree ( ctxt - > hostname ) ;
if ( ctxt - > protocol ! = NULL ) xmlFree ( ctxt - > protocol ) ;
if ( ctxt - > path ! = NULL ) xmlFree ( ctxt - > path ) ;
2017-09-06 02:31:31 +03:00
if ( ctxt - > user ! = NULL ) xmlFree ( ctxt - > user ) ;
if ( ctxt - > passwd ! = NULL ) xmlFree ( ctxt - > passwd ) ;
2001-02-23 20:55:21 +03:00
ctxt - > passive = 1 ;
2010-11-04 14:08:08 +03:00
if ( ctxt - > controlFd ! = INVALID_SOCKET ) closesocket ( ctxt - > controlFd ) ;
ctxt - > controlFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
ctxt - > controlBufIndex = - 1 ;
ctxt - > controlBufUsed = - 1 ;
xmlFree ( ctxt ) ;
}
/**
* xmlNanoFTPParseResponse :
* @ buf : the buffer containing the response
* @ len : the buffer length
2012-09-11 09:26:36 +04:00
*
2001-02-23 20:55:21 +03:00
* Parsing of the server answer , we just extract the code .
*
* returns 0 for errors
* + XXX for last line of response
* - XXX for response to be continued
*/
static int
2001-03-24 20:00:36 +03:00
xmlNanoFTPParseResponse ( char * buf , int len ) {
2001-02-23 20:55:21 +03:00
int val = 0 ;
if ( len < 3 ) return ( - 1 ) ;
2012-09-11 09:26:36 +04:00
if ( ( * buf > = ' 0 ' ) & & ( * buf < = ' 9 ' ) )
2001-02-23 20:55:21 +03:00
val = val * 10 + ( * buf - ' 0 ' ) ;
else
return ( 0 ) ;
buf + + ;
2012-09-11 09:26:36 +04:00
if ( ( * buf > = ' 0 ' ) & & ( * buf < = ' 9 ' ) )
2001-02-23 20:55:21 +03:00
val = val * 10 + ( * buf - ' 0 ' ) ;
else
return ( 0 ) ;
buf + + ;
2012-09-11 09:26:36 +04:00
if ( ( * buf > = ' 0 ' ) & & ( * buf < = ' 9 ' ) )
2001-02-23 20:55:21 +03:00
val = val * 10 + ( * buf - ' 0 ' ) ;
else
return ( 0 ) ;
buf + + ;
2012-09-11 09:26:36 +04:00
if ( * buf = = ' - ' )
2001-02-23 20:55:21 +03:00
return ( - val ) ;
return ( val ) ;
}
/**
* xmlNanoFTPGetMore :
* @ ctx : an FTP context
*
* Read more information from the FTP control connection
* Returns the number of bytes read , < 0 indicates an error
*/
static int
xmlNanoFTPGetMore ( void * ctx ) {
xmlNanoFTPCtxtPtr ctxt = ( xmlNanoFTPCtxtPtr ) ctx ;
int len ;
int size ;
2010-11-04 14:08:08 +03:00
if ( ( ctxt = = NULL ) | | ( ctxt - > controlFd = = INVALID_SOCKET ) ) return ( - 1 ) ;
2004-11-05 14:50:11 +03:00
2001-02-23 20:55:21 +03:00
if ( ( ctxt - > controlBufIndex < 0 ) | | ( ctxt - > controlBufIndex > FTP_BUF_SIZE ) ) {
# ifdef DEBUG_FTP
xmlGenericError ( xmlGenericErrorContext ,
" xmlNanoFTPGetMore : controlBufIndex = %d \n " ,
ctxt - > controlBufIndex ) ;
# endif
return ( - 1 ) ;
}
if ( ( ctxt - > controlBufUsed < 0 ) | | ( ctxt - > controlBufUsed > FTP_BUF_SIZE ) ) {
# ifdef DEBUG_FTP
xmlGenericError ( xmlGenericErrorContext ,
" xmlNanoFTPGetMore : controlBufUsed = %d \n " ,
ctxt - > controlBufUsed ) ;
# endif
return ( - 1 ) ;
}
if ( ctxt - > controlBufIndex > ctxt - > controlBufUsed ) {
# ifdef DEBUG_FTP
xmlGenericError ( xmlGenericErrorContext ,
" xmlNanoFTPGetMore : controlBufIndex > controlBufUsed %d > %d \n " ,
ctxt - > controlBufIndex , ctxt - > controlBufUsed ) ;
# endif
return ( - 1 ) ;
}
/*
* First pack the control buffer
*/
if ( ctxt - > controlBufIndex > 0 ) {
memmove ( & ctxt - > controlBuf [ 0 ] , & ctxt - > controlBuf [ ctxt - > controlBufIndex ] ,
ctxt - > controlBufUsed - ctxt - > controlBufIndex ) ;
ctxt - > controlBufUsed - = ctxt - > controlBufIndex ;
ctxt - > controlBufIndex = 0 ;
}
size = FTP_BUF_SIZE - ctxt - > controlBufUsed ;
if ( size = = 0 ) {
# ifdef DEBUG_FTP
xmlGenericError ( xmlGenericErrorContext ,
" xmlNanoFTPGetMore : buffer full %d \n " , ctxt - > controlBufUsed ) ;
# endif
return ( 0 ) ;
}
/*
2001-10-10 13:45:09 +04:00
* Read the amount left on the control connection
2001-02-23 20:55:21 +03:00
*/
if ( ( len = recv ( ctxt - > controlFd , & ctxt - > controlBuf [ ctxt - > controlBufIndex ] ,
size , 0 ) ) < 0 ) {
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_FTP , 0 , " recv failed " ) ;
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > controlFd ) ; ctxt - > controlFd = INVALID_SOCKET ;
ctxt - > controlFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
}
# ifdef DEBUG_FTP
xmlGenericError ( xmlGenericErrorContext ,
" xmlNanoFTPGetMore : read %d [%d - %d] \n " , len ,
ctxt - > controlBufUsed , ctxt - > controlBufUsed + len ) ;
# endif
ctxt - > controlBufUsed + = len ;
ctxt - > controlBuf [ ctxt - > controlBufUsed ] = 0 ;
return ( len ) ;
}
/**
* xmlNanoFTPReadResponse :
* @ ctx : an FTP context
*
* Read the response from the FTP server after a command .
* Returns the code number
*/
static int
xmlNanoFTPReadResponse ( void * ctx ) {
xmlNanoFTPCtxtPtr ctxt = ( xmlNanoFTPCtxtPtr ) ctx ;
char * ptr , * end ;
int len ;
int res = - 1 , cur = - 1 ;
2010-11-04 14:08:08 +03:00
if ( ( ctxt = = NULL ) | | ( ctxt - > controlFd = = INVALID_SOCKET ) ) return ( - 1 ) ;
2004-11-05 14:50:11 +03:00
2001-02-23 20:55:21 +03:00
get_more :
/*
* Assumes everything up to controlBuf [ controlBufIndex ] has been read
* and analyzed .
*/
len = xmlNanoFTPGetMore ( ctx ) ;
if ( len < 0 ) {
return ( - 1 ) ;
}
if ( ( ctxt - > controlBufUsed = = 0 ) & & ( len = = 0 ) ) {
return ( - 1 ) ;
}
ptr = & ctxt - > controlBuf [ ctxt - > controlBufIndex ] ;
end = & ctxt - > controlBuf [ ctxt - > controlBufUsed ] ;
# ifdef DEBUG_FTP
xmlGenericError ( xmlGenericErrorContext ,
" \n <<< \n %s \n -- \n " , ptr ) ;
# endif
while ( ptr < end ) {
2001-03-24 20:00:36 +03:00
cur = xmlNanoFTPParseResponse ( ptr , end - ptr ) ;
2001-02-23 20:55:21 +03:00
if ( cur > 0 ) {
/*
* Successfully scanned the control code , scratch
* till the end of the line , but keep the index to be
* able to analyze the result if needed .
*/
res = cur ;
ptr + = 3 ;
ctxt - > controlBufAnswer = ptr - ctxt - > controlBuf ;
while ( ( ptr < end ) & & ( * ptr ! = ' \n ' ) ) ptr + + ;
if ( * ptr = = ' \n ' ) ptr + + ;
if ( * ptr = = ' \r ' ) ptr + + ;
break ;
}
while ( ( ptr < end ) & & ( * ptr ! = ' \n ' ) ) ptr + + ;
if ( ptr > = end ) {
ctxt - > controlBufIndex = ctxt - > controlBufUsed ;
goto get_more ;
}
if ( * ptr ! = ' \r ' ) ptr + + ;
}
if ( res < 0 ) goto get_more ;
ctxt - > controlBufIndex = ptr - ctxt - > controlBuf ;
# ifdef DEBUG_FTP
ptr = & ctxt - > controlBuf [ ctxt - > controlBufIndex ] ;
xmlGenericError ( xmlGenericErrorContext , " \n --- \n %s \n -- \n " , ptr ) ;
# endif
# ifdef DEBUG_FTP
xmlGenericError ( xmlGenericErrorContext , " Got %d \n " , res ) ;
# endif
return ( res / 100 ) ;
}
/**
* xmlNanoFTPGetResponse :
* @ ctx : an FTP context
*
* Get the response from the FTP server after a command .
* Returns the code number
*/
int
xmlNanoFTPGetResponse ( void * ctx ) {
int res ;
res = xmlNanoFTPReadResponse ( ctx ) ;
return ( res ) ;
}
/**
* xmlNanoFTPCheckResponse :
* @ ctx : an FTP context
*
* Check if there is a response from the FTP server after a command .
* Returns the code number , or 0
*/
int
xmlNanoFTPCheckResponse ( void * ctx ) {
xmlNanoFTPCtxtPtr ctxt = ( xmlNanoFTPCtxtPtr ) ctx ;
fd_set rfd ;
struct timeval tv ;
2010-11-04 14:08:08 +03:00
if ( ( ctxt = = NULL ) | | ( ctxt - > controlFd = = INVALID_SOCKET ) ) return ( - 1 ) ;
2001-02-23 20:55:21 +03:00
tv . tv_sec = 0 ;
tv . tv_usec = 0 ;
FD_ZERO ( & rfd ) ;
FD_SET ( ctxt - > controlFd , & rfd ) ;
switch ( select ( ctxt - > controlFd + 1 , & rfd , NULL , NULL , & tv ) ) {
case 0 :
return ( 0 ) ;
case - 1 :
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_FTP , 0 , " select " ) ;
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
2012-09-11 09:26:36 +04:00
2001-02-23 20:55:21 +03:00
}
return ( xmlNanoFTPReadResponse ( ctx ) ) ;
}
/**
2001-12-31 19:16:02 +03:00
* Send the user authentication
2001-02-23 20:55:21 +03:00
*/
static int
xmlNanoFTPSendUser ( void * ctx ) {
xmlNanoFTPCtxtPtr ctxt = ( xmlNanoFTPCtxtPtr ) ctx ;
char buf [ 200 ] ;
int len ;
int res ;
if ( ctxt - > user = = NULL )
2002-06-14 21:07:10 +04:00
snprintf ( buf , sizeof ( buf ) , " USER anonymous \r \n " ) ;
2001-02-23 20:55:21 +03:00
else
snprintf ( buf , sizeof ( buf ) , " USER %s \r \n " , ctxt - > user ) ;
buf [ sizeof ( buf ) - 1 ] = 0 ;
len = strlen ( buf ) ;
# ifdef DEBUG_FTP
2001-10-29 14:48:19 +03:00
xmlGenericError ( xmlGenericErrorContext , " %s " , buf ) ;
2001-02-23 20:55:21 +03:00
# endif
2013-12-12 11:23:09 +04:00
res = send ( ctxt - > controlFd , SEND_ARG2_CAST buf , len , 0 ) ;
2003-10-10 23:36:36 +04:00
if ( res < 0 ) {
__xmlIOErr ( XML_FROM_FTP , 0 , " send failed " ) ;
return ( res ) ;
}
2001-02-23 20:55:21 +03:00
return ( 0 ) ;
}
/**
2001-12-31 19:16:02 +03:00
* Send the password authentication
2001-02-23 20:55:21 +03:00
*/
static int
xmlNanoFTPSendPasswd ( void * ctx ) {
xmlNanoFTPCtxtPtr ctxt = ( xmlNanoFTPCtxtPtr ) ctx ;
char buf [ 200 ] ;
int len ;
int res ;
if ( ctxt - > passwd = = NULL )
2001-10-19 13:48:35 +04:00
snprintf ( buf , sizeof ( buf ) , " PASS anonymous@ \r \n " ) ;
2001-02-23 20:55:21 +03:00
else
snprintf ( buf , sizeof ( buf ) , " PASS %s \r \n " , ctxt - > passwd ) ;
buf [ sizeof ( buf ) - 1 ] = 0 ;
len = strlen ( buf ) ;
# ifdef DEBUG_FTP
2001-10-29 14:48:19 +03:00
xmlGenericError ( xmlGenericErrorContext , " %s " , buf ) ;
2001-02-23 20:55:21 +03:00
# endif
2013-12-12 11:23:09 +04:00
res = send ( ctxt - > controlFd , SEND_ARG2_CAST buf , len , 0 ) ;
2003-10-10 23:36:36 +04:00
if ( res < 0 ) {
__xmlIOErr ( XML_FROM_FTP , 0 , " send failed " ) ;
return ( res ) ;
}
2001-02-23 20:55:21 +03:00
return ( 0 ) ;
}
/**
* xmlNanoFTPQuit :
* @ ctx : an FTP context
*
* Send a QUIT command to the server
*
* Returns - 1 in case of error , 0 otherwise
*/
int
xmlNanoFTPQuit ( void * ctx ) {
xmlNanoFTPCtxtPtr ctxt = ( xmlNanoFTPCtxtPtr ) ctx ;
char buf [ 200 ] ;
2003-10-10 23:36:36 +04:00
int len , res ;
2001-02-23 20:55:21 +03:00
2010-11-04 14:08:08 +03:00
if ( ( ctxt = = NULL ) | | ( ctxt - > controlFd = = INVALID_SOCKET ) ) return ( - 1 ) ;
2004-11-05 14:50:11 +03:00
2002-06-14 21:07:10 +04:00
snprintf ( buf , sizeof ( buf ) , " QUIT \r \n " ) ;
2001-02-23 20:55:21 +03:00
len = strlen ( buf ) ;
# ifdef DEBUG_FTP
2001-10-29 14:48:19 +03:00
xmlGenericError ( xmlGenericErrorContext , " %s " , buf ) ; /* Just to be consistent, even though we know it can't have a % in it */
2001-02-23 20:55:21 +03:00
# endif
2013-12-12 11:23:09 +04:00
res = send ( ctxt - > controlFd , SEND_ARG2_CAST buf , len , 0 ) ;
2003-10-10 23:36:36 +04:00
if ( res < 0 ) {
__xmlIOErr ( XML_FROM_FTP , 0 , " send failed " ) ;
return ( res ) ;
}
2001-02-23 20:55:21 +03:00
return ( 0 ) ;
}
/**
* xmlNanoFTPConnect :
* @ ctx : an FTP context
*
* Tries to open a control connection
*
* Returns - 1 in case of error , 0 otherwise
*/
int
xmlNanoFTPConnect ( void * ctx ) {
xmlNanoFTPCtxtPtr ctxt = ( xmlNanoFTPCtxtPtr ) ctx ;
struct hostent * hp ;
int port ;
int res ;
2003-07-08 16:16:59 +04:00
int addrlen = sizeof ( struct sockaddr_in ) ;
2001-02-23 20:55:21 +03:00
if ( ctxt = = NULL )
return ( - 1 ) ;
if ( ctxt - > hostname = = NULL )
return ( - 1 ) ;
/*
* do the blocking DNS query .
*/
if ( proxy ) {
port = proxyPort ;
} else {
port = ctxt - > port ;
}
if ( port = = 0 )
port = 21 ;
2003-06-21 18:20:04 +04:00
memset ( & ctxt - > ftpAddr , 0 , sizeof ( ctxt - > ftpAddr ) ) ;
# ifdef SUPPORT_IP6
if ( have_ipv6 ( ) ) {
2003-07-08 16:16:59 +04:00
struct addrinfo hints , * tmp , * result ;
2003-06-21 18:20:04 +04:00
result = NULL ;
memset ( & hints , 0 , sizeof ( hints ) ) ;
hints . ai_socktype = SOCK_STREAM ;
if ( proxy ) {
2003-10-10 23:36:36 +04:00
if ( getaddrinfo ( proxy , NULL , & hints , & result ) ! = 0 ) {
__xmlIOErr ( XML_FROM_FTP , 0 , " getaddrinfo failed " ) ;
2003-06-21 18:20:04 +04:00
return ( - 1 ) ;
2003-10-10 23:36:36 +04:00
}
2003-06-21 18:20:04 +04:00
}
else
2003-10-10 23:36:36 +04:00
if ( getaddrinfo ( ctxt - > hostname , NULL , & hints , & result ) ! = 0 ) {
__xmlIOErr ( XML_FROM_FTP , 0 , " getaddrinfo failed " ) ;
2003-06-21 18:20:04 +04:00
return ( - 1 ) ;
2003-10-10 23:36:36 +04:00
}
2003-06-21 18:20:04 +04:00
2003-07-08 16:16:59 +04:00
for ( tmp = result ; tmp ; tmp = tmp - > ai_next )
if ( tmp - > ai_family = = AF_INET | | tmp - > ai_family = = AF_INET6 )
2003-06-21 18:20:04 +04:00
break ;
2003-07-10 18:04:33 +04:00
if ( ! tmp ) {
if ( result )
freeaddrinfo ( result ) ;
2004-10-27 13:39:50 +04:00
__xmlIOErr ( XML_FROM_FTP , 0 , " getaddrinfo failed " ) ;
2003-07-10 18:04:33 +04:00
return ( - 1 ) ;
}
2017-10-21 15:01:10 +03:00
if ( ( size_t ) tmp - > ai_addrlen > sizeof ( ctxt - > ftpAddr ) ) {
2014-10-06 15:28:29 +04:00
if ( result )
freeaddrinfo ( result ) ;
2004-10-27 13:39:50 +04:00
__xmlIOErr ( XML_FROM_FTP , 0 , " gethostbyname address mismatch " ) ;
return ( - 1 ) ;
}
if ( tmp - > ai_family = = AF_INET6 ) {
memcpy ( & ctxt - > ftpAddr , tmp - > ai_addr , tmp - > ai_addrlen ) ;
( ( struct sockaddr_in6 * ) & ctxt - > ftpAddr ) - > sin6_port = htons ( port ) ;
ctxt - > controlFd = socket ( AF_INET6 , SOCK_STREAM , 0 ) ;
}
2003-07-10 18:04:33 +04:00
else {
2004-10-27 13:39:50 +04:00
memcpy ( & ctxt - > ftpAddr , tmp - > ai_addr , tmp - > ai_addrlen ) ;
( ( struct sockaddr_in * ) & ctxt - > ftpAddr ) - > sin_port = htons ( port ) ;
ctxt - > controlFd = socket ( AF_INET , SOCK_STREAM , 0 ) ;
2003-06-21 18:20:04 +04:00
}
2004-10-27 13:39:50 +04:00
addrlen = tmp - > ai_addrlen ;
freeaddrinfo ( result ) ;
2003-06-21 18:20:04 +04:00
}
else
# endif
{
if ( proxy )
2013-12-12 11:23:09 +04:00
hp = gethostbyname ( GETHOSTBYNAME_ARG_CAST proxy ) ;
2003-06-21 18:20:04 +04:00
else
2013-12-12 11:23:09 +04:00
hp = gethostbyname ( GETHOSTBYNAME_ARG_CAST ctxt - > hostname ) ;
2003-10-10 23:36:36 +04:00
if ( hp = = NULL ) {
__xmlIOErr ( XML_FROM_FTP , 0 , " gethostbyname failed " ) ;
2003-06-21 18:20:04 +04:00
return ( - 1 ) ;
2003-10-10 23:36:36 +04:00
}
2004-10-27 21:29:04 +04:00
if ( ( unsigned int ) hp - > h_length >
2004-10-27 13:39:50 +04:00
sizeof ( ( ( struct sockaddr_in * ) & ctxt - > ftpAddr ) - > sin_addr ) ) {
__xmlIOErr ( XML_FROM_FTP , 0 , " gethostbyname address mismatch " ) ;
return ( - 1 ) ;
}
2003-06-21 18:20:04 +04:00
2004-10-27 13:39:50 +04:00
/*
* Prepare the socket
*/
2003-06-21 18:20:04 +04:00
( ( struct sockaddr_in * ) & ctxt - > ftpAddr ) - > sin_family = AF_INET ;
memcpy ( & ( ( struct sockaddr_in * ) & ctxt - > ftpAddr ) - > sin_addr ,
hp - > h_addr_list [ 0 ] , hp - > h_length ) ;
2012-04-02 11:45:13 +04:00
( ( struct sockaddr_in * ) & ctxt - > ftpAddr ) - > sin_port =
( unsigned short ) htons ( ( unsigned short ) port ) ;
2003-06-21 18:20:04 +04:00
ctxt - > controlFd = socket ( AF_INET , SOCK_STREAM , 0 ) ;
addrlen = sizeof ( struct sockaddr_in ) ;
}
2010-11-04 14:08:08 +03:00
if ( ctxt - > controlFd = = INVALID_SOCKET ) {
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_FTP , 0 , " socket failed " ) ;
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
2003-10-10 23:36:36 +04:00
}
2001-02-23 20:55:21 +03:00
/*
* Do the connect .
*/
if ( connect ( ctxt - > controlFd , ( struct sockaddr * ) & ctxt - > ftpAddr ,
2003-06-21 18:20:04 +04:00
addrlen ) < 0 ) {
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_FTP , 0 , " Failed to create a connection " ) ;
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > controlFd ) ; ctxt - > controlFd = INVALID_SOCKET ;
ctxt - > controlFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
}
/*
* Wait for the HELLO from the server .
*/
res = xmlNanoFTPGetResponse ( ctxt ) ;
if ( res ! = 2 ) {
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > controlFd ) ; ctxt - > controlFd = INVALID_SOCKET ;
ctxt - > controlFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
}
/*
* State diagram for the login operation on the FTP server
*
* Reference : RFC 959
*
* 1
* + - - - + USER + - - - + - - - - - - - - - - - - - > + - - - +
* | B | - - - - - - - - - - > | W | 2 - - - - > | E |
* + - - - + + - - - + - - - - - - | - - > + - - - +
* | | | | |
* 3 | | 4 , 5 | | |
* - - - - - - - - - - - - - - - - - - - | | |
* | | | | |
* | | | | |
* | - - - - - - - - - |
* | 1 | | | |
* V | | | |
* + - - - + PASS + - - - + 2 | - - - - - - > + - - - +
* | | - - - - - - - - - - > | W | - - - - - - - - - - - - - > | S |
* + - - - + + - - - + - - - - - - - - - - > + - - - +
* | | | | |
* 3 | | 4 , 5 | | |
* - - - - - - - - - - - - - - - - - - - - - - |
* | | | | |
* | | | | |
* | - - - - - - - - - - -
* | 1 , 3 | | | |
* V | 2 | | |
* + - - - + ACCT + - - - + - - | - - - - - > + - - - +
* | | - - - - - - - - - - > | W | 4 , 5 - - - - - - - - > | F |
* + - - - + + - - - + - - - - - - - - - - - - - > + - - - +
*
* Of course in case of using a proxy this get really nasty and is not
* standardized at all : - (
*/
if ( proxy ) {
int len ;
char buf [ 400 ] ;
if ( proxyUser ! = NULL ) {
/*
* We need proxy auth
*/
snprintf ( buf , sizeof ( buf ) , " USER %s \r \n " , proxyUser ) ;
buf [ sizeof ( buf ) - 1 ] = 0 ;
len = strlen ( buf ) ;
# ifdef DEBUG_FTP
2001-10-29 14:48:19 +03:00
xmlGenericError ( xmlGenericErrorContext , " %s " , buf ) ;
2001-02-23 20:55:21 +03:00
# endif
2013-12-12 11:23:09 +04:00
res = send ( ctxt - > controlFd , SEND_ARG2_CAST buf , len , 0 ) ;
2001-02-23 20:55:21 +03:00
if ( res < 0 ) {
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_FTP , 0 , " send failed " ) ;
2001-02-23 20:55:21 +03:00
closesocket ( ctxt - > controlFd ) ;
2010-11-04 14:08:08 +03:00
ctxt - > controlFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( res ) ;
}
res = xmlNanoFTPGetResponse ( ctxt ) ;
switch ( res ) {
case 2 :
if ( proxyPasswd = = NULL )
break ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2001-02-23 20:55:21 +03:00
case 3 :
if ( proxyPasswd ! = NULL )
snprintf ( buf , sizeof ( buf ) , " PASS %s \r \n " , proxyPasswd ) ;
else
2001-10-19 13:48:35 +04:00
snprintf ( buf , sizeof ( buf ) , " PASS anonymous@ \r \n " ) ;
2001-02-23 20:55:21 +03:00
buf [ sizeof ( buf ) - 1 ] = 0 ;
len = strlen ( buf ) ;
# ifdef DEBUG_FTP
2001-10-29 14:48:19 +03:00
xmlGenericError ( xmlGenericErrorContext , " %s " , buf ) ;
2001-02-23 20:55:21 +03:00
# endif
2013-12-12 11:23:09 +04:00
res = send ( ctxt - > controlFd , SEND_ARG2_CAST buf , len , 0 ) ;
2001-02-23 20:55:21 +03:00
if ( res < 0 ) {
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_FTP , 0 , " send failed " ) ;
2001-02-23 20:55:21 +03:00
closesocket ( ctxt - > controlFd ) ;
2010-11-04 14:08:08 +03:00
ctxt - > controlFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( res ) ;
}
res = xmlNanoFTPGetResponse ( ctxt ) ;
if ( res > 3 ) {
closesocket ( ctxt - > controlFd ) ;
2010-11-04 14:08:08 +03:00
ctxt - > controlFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
}
break ;
case 1 :
break ;
case 4 :
case 5 :
case - 1 :
default :
closesocket ( ctxt - > controlFd ) ;
2010-11-04 14:08:08 +03:00
ctxt - > controlFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
}
}
/*
* We assume we don ' t need more authentication to the proxy
* and that it succeeded : - \
*/
switch ( proxyType ) {
case 0 :
2001-12-31 19:16:02 +03:00
/* we will try in sequence */
2001-02-23 20:55:21 +03:00
case 1 :
/* Using SITE command */
snprintf ( buf , sizeof ( buf ) , " SITE %s \r \n " , ctxt - > hostname ) ;
buf [ sizeof ( buf ) - 1 ] = 0 ;
len = strlen ( buf ) ;
# ifdef DEBUG_FTP
2001-10-29 14:48:19 +03:00
xmlGenericError ( xmlGenericErrorContext , " %s " , buf ) ;
2001-02-23 20:55:21 +03:00
# endif
2013-12-12 11:23:09 +04:00
res = send ( ctxt - > controlFd , SEND_ARG2_CAST buf , len , 0 ) ;
2001-02-23 20:55:21 +03:00
if ( res < 0 ) {
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_FTP , 0 , " send failed " ) ;
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > controlFd ) ; ctxt - > controlFd = INVALID_SOCKET ;
ctxt - > controlFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( res ) ;
}
res = xmlNanoFTPGetResponse ( ctxt ) ;
if ( res = = 2 ) {
/* we assume it worked :-\ 1 is error for SITE command */
proxyType = 1 ;
break ;
2012-09-11 09:26:36 +04:00
}
2001-02-23 20:55:21 +03:00
if ( proxyType = = 1 ) {
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > controlFd ) ; ctxt - > controlFd = INVALID_SOCKET ;
ctxt - > controlFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
}
2017-10-21 14:49:31 +03:00
/* Falls through. */
2001-02-23 20:55:21 +03:00
case 2 :
/* USER user@host command */
if ( ctxt - > user = = NULL )
snprintf ( buf , sizeof ( buf ) , " USER anonymous@%s \r \n " ,
ctxt - > hostname ) ;
else
snprintf ( buf , sizeof ( buf ) , " USER %s@%s \r \n " ,
ctxt - > user , ctxt - > hostname ) ;
buf [ sizeof ( buf ) - 1 ] = 0 ;
len = strlen ( buf ) ;
# ifdef DEBUG_FTP
2001-10-29 14:48:19 +03:00
xmlGenericError ( xmlGenericErrorContext , " %s " , buf ) ;
2001-02-23 20:55:21 +03:00
# endif
2013-12-12 11:23:09 +04:00
res = send ( ctxt - > controlFd , SEND_ARG2_CAST buf , len , 0 ) ;
2001-02-23 20:55:21 +03:00
if ( res < 0 ) {
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_FTP , 0 , " send failed " ) ;
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > controlFd ) ; ctxt - > controlFd = INVALID_SOCKET ;
ctxt - > controlFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( res ) ;
}
res = xmlNanoFTPGetResponse ( ctxt ) ;
if ( ( res = = 1 ) | | ( res = = 2 ) ) {
/* we assume it worked :-\ */
proxyType = 2 ;
return ( 0 ) ;
2012-09-11 09:26:36 +04:00
}
2001-02-23 20:55:21 +03:00
if ( ctxt - > passwd = = NULL )
2001-10-19 13:48:35 +04:00
snprintf ( buf , sizeof ( buf ) , " PASS anonymous@ \r \n " ) ;
2001-02-23 20:55:21 +03:00
else
snprintf ( buf , sizeof ( buf ) , " PASS %s \r \n " , ctxt - > passwd ) ;
buf [ sizeof ( buf ) - 1 ] = 0 ;
len = strlen ( buf ) ;
# ifdef DEBUG_FTP
2001-10-29 14:48:19 +03:00
xmlGenericError ( xmlGenericErrorContext , " %s " , buf ) ;
2001-02-23 20:55:21 +03:00
# endif
2013-12-12 11:23:09 +04:00
res = send ( ctxt - > controlFd , SEND_ARG2_CAST buf , len , 0 ) ;
2001-02-23 20:55:21 +03:00
if ( res < 0 ) {
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_FTP , 0 , " send failed " ) ;
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > controlFd ) ; ctxt - > controlFd = INVALID_SOCKET ;
ctxt - > controlFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( res ) ;
}
res = xmlNanoFTPGetResponse ( ctxt ) ;
if ( ( res = = 1 ) | | ( res = = 2 ) ) {
/* we assume it worked :-\ */
proxyType = 2 ;
return ( 0 ) ;
}
if ( proxyType = = 2 ) {
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > controlFd ) ; ctxt - > controlFd = INVALID_SOCKET ;
ctxt - > controlFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
}
2017-10-21 14:49:31 +03:00
/* Falls through. */
2001-02-23 20:55:21 +03:00
case 3 :
/*
* If you need support for other Proxy authentication scheme
* send the code or at least the sequence in use .
*/
default :
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > controlFd ) ; ctxt - > controlFd = INVALID_SOCKET ;
ctxt - > controlFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
}
}
/*
* Non - proxy handling .
*/
res = xmlNanoFTPSendUser ( ctxt ) ;
if ( res < 0 ) {
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > controlFd ) ; ctxt - > controlFd = INVALID_SOCKET ;
ctxt - > controlFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
}
res = xmlNanoFTPGetResponse ( ctxt ) ;
switch ( res ) {
case 2 :
return ( 0 ) ;
case 3 :
break ;
case 1 :
case 4 :
case 5 :
case - 1 :
default :
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > controlFd ) ; ctxt - > controlFd = INVALID_SOCKET ;
ctxt - > controlFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
}
res = xmlNanoFTPSendPasswd ( ctxt ) ;
if ( res < 0 ) {
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > controlFd ) ; ctxt - > controlFd = INVALID_SOCKET ;
ctxt - > controlFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
}
res = xmlNanoFTPGetResponse ( ctxt ) ;
switch ( res ) {
case 2 :
break ;
case 3 :
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_FTP , XML_FTP_ACCNT ,
" FTP server asking for ACCNT on anonymous \n " ) ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2001-02-23 20:55:21 +03:00
case 1 :
case 4 :
case 5 :
case - 1 :
default :
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > controlFd ) ; ctxt - > controlFd = INVALID_SOCKET ;
ctxt - > controlFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
}
return ( 0 ) ;
}
/**
* xmlNanoFTPConnectTo :
* @ server : an FTP server name
* @ port : the port ( use 21 if 0 )
*
* Tries to open a control connection to the given server / port
*
* Returns an fTP context or NULL if it failed
*/
void *
xmlNanoFTPConnectTo ( const char * server , int port ) {
xmlNanoFTPCtxtPtr ctxt ;
int res ;
xmlNanoFTPInit ( ) ;
2012-09-11 09:26:36 +04:00
if ( server = = NULL )
2001-02-23 20:55:21 +03:00
return ( NULL ) ;
2004-11-05 14:50:11 +03:00
if ( port < = 0 )
return ( NULL ) ;
2001-02-23 20:55:21 +03:00
ctxt = ( xmlNanoFTPCtxtPtr ) xmlNanoFTPNewCtxt ( NULL ) ;
2014-07-14 13:50:27 +04:00
if ( ctxt = = NULL )
return ( NULL ) ;
2001-02-23 20:55:21 +03:00
ctxt - > hostname = xmlMemStrdup ( server ) ;
2014-07-14 13:50:27 +04:00
if ( ctxt - > hostname = = NULL ) {
xmlNanoFTPFreeCtxt ( ctxt ) ;
return ( NULL ) ;
}
2020-01-02 16:14:48 +03:00
ctxt - > port = port ;
2001-02-23 20:55:21 +03:00
res = xmlNanoFTPConnect ( ctxt ) ;
if ( res < 0 ) {
xmlNanoFTPFreeCtxt ( ctxt ) ;
return ( NULL ) ;
}
return ( ctxt ) ;
}
/**
* xmlNanoFTPCwd :
* @ ctx : an FTP context
* @ directory : a directory on the server
*
* Tries to change the remote directory
*
2020-03-08 19:19:42 +03:00
* Returns - 1 in case of error , 1 if CWD worked , 0 if it failed
2001-02-23 20:55:21 +03:00
*/
int
2004-11-04 20:34:35 +03:00
xmlNanoFTPCwd ( void * ctx , const char * directory ) {
2001-02-23 20:55:21 +03:00
xmlNanoFTPCtxtPtr ctxt = ( xmlNanoFTPCtxtPtr ) ctx ;
char buf [ 400 ] ;
int len ;
int res ;
2010-11-04 14:08:08 +03:00
if ( ( ctxt = = NULL ) | | ( ctxt - > controlFd = = INVALID_SOCKET ) ) return ( - 1 ) ;
2005-02-13 11:18:52 +03:00
if ( directory = = NULL ) return 0 ;
2004-11-05 14:50:11 +03:00
2001-02-23 20:55:21 +03:00
/*
* Expected response code for CWD :
*
* CWD
* 250
* 500 , 501 , 502 , 421 , 530 , 550
*/
snprintf ( buf , sizeof ( buf ) , " CWD %s \r \n " , directory ) ;
buf [ sizeof ( buf ) - 1 ] = 0 ;
len = strlen ( buf ) ;
# ifdef DEBUG_FTP
2001-10-29 14:48:19 +03:00
xmlGenericError ( xmlGenericErrorContext , " %s " , buf ) ;
2001-02-23 20:55:21 +03:00
# endif
2013-12-12 11:23:09 +04:00
res = send ( ctxt - > controlFd , SEND_ARG2_CAST buf , len , 0 ) ;
2003-10-10 23:36:36 +04:00
if ( res < 0 ) {
__xmlIOErr ( XML_FROM_FTP , 0 , " send failed " ) ;
return ( res ) ;
}
2001-02-23 20:55:21 +03:00
res = xmlNanoFTPGetResponse ( ctxt ) ;
if ( res = = 4 ) {
return ( - 1 ) ;
}
if ( res = = 2 ) return ( 1 ) ;
if ( res = = 5 ) {
return ( 0 ) ;
}
return ( 0 ) ;
}
2003-03-05 19:45:40 +03:00
/**
* xmlNanoFTPDele :
* @ ctx : an FTP context
* @ file : a file or directory on the server
*
* Tries to delete an item ( file or directory ) from server
*
2020-03-08 19:19:42 +03:00
* Returns - 1 in case of error , 1 if DELE worked , 0 if it failed
2003-03-05 19:45:40 +03:00
*/
int
2004-11-04 20:34:35 +03:00
xmlNanoFTPDele ( void * ctx , const char * file ) {
2003-03-05 19:45:40 +03:00
xmlNanoFTPCtxtPtr ctxt = ( xmlNanoFTPCtxtPtr ) ctx ;
char buf [ 400 ] ;
int len ;
int res ;
2014-07-14 13:50:27 +04:00
if ( ( ctxt = = NULL ) | | ( ctxt - > controlFd = = INVALID_SOCKET ) | |
( file = = NULL ) ) return ( - 1 ) ;
2004-11-05 14:50:11 +03:00
2003-03-05 19:45:40 +03:00
/*
* Expected response code for DELE :
*
* DELE
* 250
* 450 , 550
* 500 , 501 , 502 , 421 , 530
*/
2012-09-11 09:26:36 +04:00
2003-03-05 19:45:40 +03:00
snprintf ( buf , sizeof ( buf ) , " DELE %s \r \n " , file ) ;
buf [ sizeof ( buf ) - 1 ] = 0 ;
len = strlen ( buf ) ;
# ifdef DEBUG_FTP
xmlGenericError ( xmlGenericErrorContext , " %s " , buf ) ;
# endif
2013-12-12 11:23:09 +04:00
res = send ( ctxt - > controlFd , SEND_ARG2_CAST buf , len , 0 ) ;
2003-10-10 23:36:36 +04:00
if ( res < 0 ) {
__xmlIOErr ( XML_FROM_FTP , 0 , " send failed " ) ;
return ( res ) ;
}
2003-03-05 19:45:40 +03:00
res = xmlNanoFTPGetResponse ( ctxt ) ;
if ( res = = 4 ) {
return ( - 1 ) ;
}
if ( res = = 2 ) return ( 1 ) ;
if ( res = = 5 ) {
return ( 0 ) ;
}
return ( 0 ) ;
}
2001-02-23 20:55:21 +03:00
/**
* xmlNanoFTPGetConnection :
* @ ctx : an FTP context
*
* Try to open a data connection to the server . Currently only
* passive mode is supported .
*
2020-03-08 19:19:42 +03:00
* Returns - 1 in case of error , 0 otherwise
2001-02-23 20:55:21 +03:00
*/
2010-11-04 14:08:08 +03:00
SOCKET
2001-02-23 20:55:21 +03:00
xmlNanoFTPGetConnection ( void * ctx ) {
xmlNanoFTPCtxtPtr ctxt = ( xmlNanoFTPCtxtPtr ) ctx ;
char buf [ 200 ] , * cur ;
int len , i ;
int res ;
unsigned char ad [ 6 ] , * adp , * portp ;
unsigned int temp [ 6 ] ;
2003-06-21 18:20:04 +04:00
# ifdef SUPPORT_IP6
struct sockaddr_storage dataAddr ;
# else
2001-02-23 20:55:21 +03:00
struct sockaddr_in dataAddr ;
2003-06-21 18:20:04 +04:00
# endif
2005-03-31 14:24:24 +04:00
XML_SOCKLEN_T dataAddrLen ;
2001-02-23 20:55:21 +03:00
2010-11-04 14:08:08 +03:00
if ( ctxt = = NULL ) return INVALID_SOCKET ;
2004-11-05 14:50:11 +03:00
2003-06-21 18:20:04 +04:00
memset ( & dataAddr , 0 , sizeof ( dataAddr ) ) ;
# ifdef SUPPORT_IP6
if ( ( ctxt - > ftpAddr ) . ss_family = = AF_INET6 ) {
ctxt - > dataFd = socket ( AF_INET6 , SOCK_STREAM , IPPROTO_TCP ) ;
( ( struct sockaddr_in6 * ) & dataAddr ) - > sin6_family = AF_INET6 ;
dataAddrLen = sizeof ( struct sockaddr_in6 ) ;
} else
# endif
{
ctxt - > dataFd = socket ( AF_INET , SOCK_STREAM , IPPROTO_TCP ) ;
( ( struct sockaddr_in * ) & dataAddr ) - > sin_family = AF_INET ;
dataAddrLen = sizeof ( struct sockaddr_in ) ;
}
2010-11-04 14:08:08 +03:00
if ( ctxt - > dataFd = = INVALID_SOCKET ) {
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_FTP , 0 , " socket failed " ) ;
2010-11-04 14:08:08 +03:00
return INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
}
if ( ctxt - > passive ) {
2003-06-21 18:20:04 +04:00
# ifdef SUPPORT_IP6
if ( ( ctxt - > ftpAddr ) . ss_family = = AF_INET6 )
snprintf ( buf , sizeof ( buf ) , " EPSV \r \n " ) ;
else
# endif
snprintf ( buf , sizeof ( buf ) , " PASV \r \n " ) ;
len = strlen ( buf ) ;
2001-02-23 20:55:21 +03:00
# ifdef DEBUG_FTP
2001-10-29 14:48:19 +03:00
xmlGenericError ( xmlGenericErrorContext , " %s " , buf ) ;
2001-02-23 20:55:21 +03:00
# endif
2013-12-12 11:23:09 +04:00
res = send ( ctxt - > controlFd , SEND_ARG2_CAST buf , len , 0 ) ;
2001-02-23 20:55:21 +03:00
if ( res < 0 ) {
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_FTP , 0 , " send failed " ) ;
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > dataFd ) ; ctxt - > dataFd = INVALID_SOCKET ;
return INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
}
res = xmlNanoFTPReadResponse ( ctx ) ;
if ( res ! = 2 ) {
if ( res = = 5 ) {
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > dataFd ) ; ctxt - > dataFd = INVALID_SOCKET ;
return INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
} else {
/*
* retry with an active connection
*/
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > dataFd ) ; ctxt - > dataFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
ctxt - > passive = 0 ;
}
}
2012-09-11 09:26:36 +04:00
cur = & ctxt - > controlBuf [ ctxt - > controlBufAnswer ] ;
2001-02-23 20:55:21 +03:00
while ( ( ( * cur < ' 0 ' ) | | ( * cur > ' 9 ' ) ) & & * cur ! = ' \0 ' ) cur + + ;
2003-06-21 18:20:04 +04:00
# ifdef SUPPORT_IP6
if ( ( ctxt - > ftpAddr ) . ss_family = = AF_INET6 ) {
if ( sscanf ( cur , " %u " , & temp [ 0 ] ) ! = 1 ) {
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_FTP , XML_FTP_EPSV_ANSWER ,
2003-06-21 18:20:04 +04:00
" Invalid answer to EPSV \n " ) ;
2010-11-04 14:08:08 +03:00
if ( ctxt - > dataFd ! = INVALID_SOCKET ) {
closesocket ( ctxt - > dataFd ) ; ctxt - > dataFd = INVALID_SOCKET ;
2003-06-21 18:20:04 +04:00
}
2010-11-04 14:08:08 +03:00
return INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
}
2003-06-21 18:20:04 +04:00
memcpy ( & ( ( struct sockaddr_in6 * ) & dataAddr ) - > sin6_addr , & ( ( struct sockaddr_in6 * ) & ctxt - > ftpAddr ) - > sin6_addr , sizeof ( struct in6_addr ) ) ;
( ( struct sockaddr_in6 * ) & dataAddr ) - > sin6_port = htons ( temp [ 0 ] ) ;
2001-02-23 20:55:21 +03:00
}
2003-06-21 18:20:04 +04:00
else
# endif
{
if ( sscanf ( cur , " %u,%u,%u,%u,%u,%u " , & temp [ 0 ] , & temp [ 1 ] , & temp [ 2 ] ,
& temp [ 3 ] , & temp [ 4 ] , & temp [ 5 ] ) ! = 6 ) {
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_FTP , XML_FTP_PASV_ANSWER ,
2003-06-21 18:20:04 +04:00
" Invalid answer to PASV \n " ) ;
2010-11-04 14:08:08 +03:00
if ( ctxt - > dataFd ! = INVALID_SOCKET ) {
closesocket ( ctxt - > dataFd ) ; ctxt - > dataFd = INVALID_SOCKET ;
2003-06-21 18:20:04 +04:00
}
2010-11-04 14:08:08 +03:00
return INVALID_SOCKET ;
2003-06-21 18:20:04 +04:00
}
for ( i = 0 ; i < 6 ; i + + ) ad [ i ] = ( unsigned char ) ( temp [ i ] & 0xff ) ;
memcpy ( & ( ( struct sockaddr_in * ) & dataAddr ) - > sin_addr , & ad [ 0 ] , 4 ) ;
memcpy ( & ( ( struct sockaddr_in * ) & dataAddr ) - > sin_port , & ad [ 4 ] , 2 ) ;
}
2001-02-23 20:55:21 +03:00
if ( connect ( ctxt - > dataFd , ( struct sockaddr * ) & dataAddr , dataAddrLen ) < 0 ) {
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_FTP , 0 , " Failed to create a data connection " ) ;
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > dataFd ) ; ctxt - > dataFd = INVALID_SOCKET ;
return INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
}
} else {
getsockname ( ctxt - > dataFd , ( struct sockaddr * ) & dataAddr , & dataAddrLen ) ;
2003-06-21 18:20:04 +04:00
# ifdef SUPPORT_IP6
if ( ( ctxt - > ftpAddr ) . ss_family = = AF_INET6 )
( ( struct sockaddr_in6 * ) & dataAddr ) - > sin6_port = 0 ;
else
# endif
( ( struct sockaddr_in * ) & dataAddr ) - > sin_port = 0 ;
2001-02-23 20:55:21 +03:00
if ( bind ( ctxt - > dataFd , ( struct sockaddr * ) & dataAddr , dataAddrLen ) < 0 ) {
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_FTP , 0 , " bind failed " ) ;
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > dataFd ) ; ctxt - > dataFd = INVALID_SOCKET ;
return INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
}
getsockname ( ctxt - > dataFd , ( struct sockaddr * ) & dataAddr , & dataAddrLen ) ;
if ( listen ( ctxt - > dataFd , 1 ) < 0 ) {
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_FTP , 0 , " listen failed " ) ;
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > dataFd ) ; ctxt - > dataFd = INVALID_SOCKET ;
return INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
}
2003-06-21 18:20:04 +04:00
# ifdef SUPPORT_IP6
if ( ( ctxt - > ftpAddr ) . ss_family = = AF_INET6 ) {
char buf6 [ INET6_ADDRSTRLEN ] ;
inet_ntop ( AF_INET6 , & ( ( struct sockaddr_in6 * ) & dataAddr ) - > sin6_addr ,
buf6 , INET6_ADDRSTRLEN ) ;
2003-07-08 16:16:59 +04:00
adp = ( unsigned char * ) buf6 ;
2003-06-21 18:20:04 +04:00
portp = ( unsigned char * ) & ( ( struct sockaddr_in6 * ) & dataAddr ) - > sin6_port ;
snprintf ( buf , sizeof ( buf ) , " EPRT |2|%s|%s| \r \n " , adp , portp ) ;
} else
# endif
{
adp = ( unsigned char * ) & ( ( struct sockaddr_in * ) & dataAddr ) - > sin_addr ;
portp = ( unsigned char * ) & ( ( struct sockaddr_in * ) & dataAddr ) - > sin_port ;
snprintf ( buf , sizeof ( buf ) , " PORT %d,%d,%d,%d,%d,%d \r \n " ,
adp [ 0 ] & 0xff , adp [ 1 ] & 0xff , adp [ 2 ] & 0xff , adp [ 3 ] & 0xff ,
portp [ 0 ] & 0xff , portp [ 1 ] & 0xff ) ;
}
2001-02-23 20:55:21 +03:00
buf [ sizeof ( buf ) - 1 ] = 0 ;
len = strlen ( buf ) ;
# ifdef DEBUG_FTP
2001-10-29 14:48:19 +03:00
xmlGenericError ( xmlGenericErrorContext , " %s " , buf ) ;
2001-02-23 20:55:21 +03:00
# endif
2013-12-12 11:23:09 +04:00
res = send ( ctxt - > controlFd , SEND_ARG2_CAST buf , len , 0 ) ;
2001-02-23 20:55:21 +03:00
if ( res < 0 ) {
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_FTP , 0 , " send failed " ) ;
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > dataFd ) ; ctxt - > dataFd = INVALID_SOCKET ;
return INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
}
res = xmlNanoFTPGetResponse ( ctxt ) ;
if ( res ! = 2 ) {
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > dataFd ) ; ctxt - > dataFd = INVALID_SOCKET ;
return INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
}
}
return ( ctxt - > dataFd ) ;
2012-09-11 09:26:36 +04:00
2001-02-23 20:55:21 +03:00
}
/**
* xmlNanoFTPCloseConnection :
* @ ctx : an FTP context
*
* Close the data connection from the server
*
2020-03-08 19:19:42 +03:00
* Returns - 1 in case of error , 0 otherwise
2001-02-23 20:55:21 +03:00
*/
int
xmlNanoFTPCloseConnection ( void * ctx ) {
xmlNanoFTPCtxtPtr ctxt = ( xmlNanoFTPCtxtPtr ) ctx ;
int res ;
fd_set rfd , efd ;
struct timeval tv ;
2010-11-04 14:08:08 +03:00
if ( ( ctxt = = NULL ) | | ( ctxt - > controlFd = = INVALID_SOCKET ) ) return ( - 1 ) ;
2004-11-05 14:50:11 +03:00
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > dataFd ) ; ctxt - > dataFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
tv . tv_sec = 15 ;
tv . tv_usec = 0 ;
FD_ZERO ( & rfd ) ;
FD_SET ( ctxt - > controlFd , & rfd ) ;
FD_ZERO ( & efd ) ;
FD_SET ( ctxt - > controlFd , & efd ) ;
res = select ( ctxt - > controlFd + 1 , & rfd , NULL , & efd , & tv ) ;
if ( res < 0 ) {
# ifdef DEBUG_FTP
perror ( " select " ) ;
# endif
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > controlFd ) ; ctxt - > controlFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
}
if ( res = = 0 ) {
# ifdef DEBUG_FTP
xmlGenericError ( xmlGenericErrorContext ,
" xmlNanoFTPCloseConnection: timeout \n " ) ;
# endif
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > controlFd ) ; ctxt - > controlFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
} else {
res = xmlNanoFTPGetResponse ( ctxt ) ;
if ( res ! = 2 ) {
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > controlFd ) ; ctxt - > controlFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
}
}
return ( 0 ) ;
}
/**
* xmlNanoFTPParseList :
* @ list : some data listing received from the server
* @ callback : the user callback
* @ userData : the user callback data
*
2012-09-11 09:26:36 +04:00
* Parse at most one entry from the listing .
2001-02-23 20:55:21 +03:00
*
2020-03-08 19:19:42 +03:00
* Returns - 1 in case of error , the length of data parsed otherwise
2001-02-23 20:55:21 +03:00
*/
static int
xmlNanoFTPParseList ( const char * list , ftpListCallback callback , void * userData ) {
const char * cur = list ;
char filename [ 151 ] ;
char attrib [ 11 ] ;
char owner [ 11 ] ;
char group [ 11 ] ;
char month [ 4 ] ;
int year = 0 ;
int minute = 0 ;
int hour = 0 ;
int day = 0 ;
unsigned long size = 0 ;
int links = 0 ;
int i ;
if ( ! strncmp ( cur , " total " , 5 ) ) {
cur + = 5 ;
while ( * cur = = ' ' ) cur + + ;
while ( ( * cur > = ' 0 ' ) & & ( * cur < = ' 9 ' ) )
links = ( links * 10 ) + ( * cur + + - ' 0 ' ) ;
while ( ( * cur = = ' ' ) | | ( * cur = = ' \n ' ) | | ( * cur = = ' \r ' ) )
cur + + ;
return ( cur - list ) ;
} else if ( * list = = ' + ' ) {
return ( 0 ) ;
} else {
while ( ( * cur = = ' ' ) | | ( * cur = = ' \n ' ) | | ( * cur = = ' \r ' ) )
cur + + ;
if ( * cur = = 0 ) return ( 0 ) ;
i = 0 ;
while ( * cur ! = ' ' ) {
2012-09-11 09:26:36 +04:00
if ( i < 10 )
2001-02-23 20:55:21 +03:00
attrib [ i + + ] = * cur ;
cur + + ;
if ( * cur = = 0 ) return ( 0 ) ;
}
attrib [ 10 ] = 0 ;
while ( * cur = = ' ' ) cur + + ;
if ( * cur = = 0 ) return ( 0 ) ;
while ( ( * cur > = ' 0 ' ) & & ( * cur < = ' 9 ' ) )
links = ( links * 10 ) + ( * cur + + - ' 0 ' ) ;
while ( * cur = = ' ' ) cur + + ;
if ( * cur = = 0 ) return ( 0 ) ;
i = 0 ;
while ( * cur ! = ' ' ) {
2012-09-11 09:26:36 +04:00
if ( i < 10 )
2001-02-23 20:55:21 +03:00
owner [ i + + ] = * cur ;
cur + + ;
if ( * cur = = 0 ) return ( 0 ) ;
}
owner [ i ] = 0 ;
while ( * cur = = ' ' ) cur + + ;
if ( * cur = = 0 ) return ( 0 ) ;
i = 0 ;
while ( * cur ! = ' ' ) {
2012-09-11 09:26:36 +04:00
if ( i < 10 )
2001-02-23 20:55:21 +03:00
group [ i + + ] = * cur ;
cur + + ;
if ( * cur = = 0 ) return ( 0 ) ;
}
group [ i ] = 0 ;
while ( * cur = = ' ' ) cur + + ;
if ( * cur = = 0 ) return ( 0 ) ;
while ( ( * cur > = ' 0 ' ) & & ( * cur < = ' 9 ' ) )
size = ( size * 10 ) + ( * cur + + - ' 0 ' ) ;
while ( * cur = = ' ' ) cur + + ;
if ( * cur = = 0 ) return ( 0 ) ;
i = 0 ;
while ( * cur ! = ' ' ) {
if ( i < 3 )
month [ i + + ] = * cur ;
cur + + ;
if ( * cur = = 0 ) return ( 0 ) ;
}
month [ i ] = 0 ;
while ( * cur = = ' ' ) cur + + ;
if ( * cur = = 0 ) return ( 0 ) ;
while ( ( * cur > = ' 0 ' ) & & ( * cur < = ' 9 ' ) )
day = ( day * 10 ) + ( * cur + + - ' 0 ' ) ;
while ( * cur = = ' ' ) cur + + ;
if ( * cur = = 0 ) return ( 0 ) ;
if ( ( cur [ 1 ] = = 0 ) | | ( cur [ 2 ] = = 0 ) ) return ( 0 ) ;
if ( ( cur [ 1 ] = = ' : ' ) | | ( cur [ 2 ] = = ' : ' ) ) {
while ( ( * cur > = ' 0 ' ) & & ( * cur < = ' 9 ' ) )
hour = ( hour * 10 ) + ( * cur + + - ' 0 ' ) ;
if ( * cur = = ' : ' ) cur + + ;
while ( ( * cur > = ' 0 ' ) & & ( * cur < = ' 9 ' ) )
minute = ( minute * 10 ) + ( * cur + + - ' 0 ' ) ;
} else {
while ( ( * cur > = ' 0 ' ) & & ( * cur < = ' 9 ' ) )
year = ( year * 10 ) + ( * cur + + - ' 0 ' ) ;
}
while ( * cur = = ' ' ) cur + + ;
if ( * cur = = 0 ) return ( 0 ) ;
i = 0 ;
while ( ( * cur ! = ' \n ' ) & & ( * cur ! = ' \r ' ) ) {
if ( i < 150 )
filename [ i + + ] = * cur ;
cur + + ;
if ( * cur = = 0 ) return ( 0 ) ;
}
filename [ i ] = 0 ;
if ( ( * cur ! = ' \n ' ) & & ( * cur ! = ' \r ' ) )
return ( 0 ) ;
while ( ( * cur = = ' \n ' ) | | ( * cur = = ' \r ' ) )
cur + + ;
}
if ( callback ! = NULL ) {
callback ( userData , filename , attrib , owner , group , size , links ,
year , month , day , hour , minute ) ;
}
return ( cur - list ) ;
}
/**
* xmlNanoFTPList :
* @ ctx : an FTP context
* @ callback : the user callback
* @ userData : the user callback data
* @ filename : optional files to list
*
* Do a listing on the server . All files info are passed back
* in the callbacks .
*
2020-03-08 19:19:42 +03:00
* Returns - 1 in case of error , 0 otherwise
2001-02-23 20:55:21 +03:00
*/
int
xmlNanoFTPList ( void * ctx , ftpListCallback callback , void * userData ,
2004-11-04 20:34:35 +03:00
const char * filename ) {
2001-02-23 20:55:21 +03:00
xmlNanoFTPCtxtPtr ctxt = ( xmlNanoFTPCtxtPtr ) ctx ;
char buf [ 4096 + 1 ] ;
int len , res ;
2001-03-24 20:00:36 +03:00
int indx = 0 , base ;
2001-02-23 20:55:21 +03:00
fd_set rfd , efd ;
struct timeval tv ;
2005-02-13 11:18:52 +03:00
if ( ctxt = = NULL ) return ( - 1 ) ;
2001-02-23 20:55:21 +03:00
if ( filename = = NULL ) {
if ( xmlNanoFTPCwd ( ctxt , ctxt - > path ) < 1 )
return ( - 1 ) ;
ctxt - > dataFd = xmlNanoFTPGetConnection ( ctxt ) ;
2010-11-04 14:08:08 +03:00
if ( ctxt - > dataFd = = INVALID_SOCKET )
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
2002-06-14 21:07:10 +04:00
snprintf ( buf , sizeof ( buf ) , " LIST -L \r \n " ) ;
2001-02-23 20:55:21 +03:00
} else {
if ( filename [ 0 ] ! = ' / ' ) {
if ( xmlNanoFTPCwd ( ctxt , ctxt - > path ) < 1 )
return ( - 1 ) ;
}
ctxt - > dataFd = xmlNanoFTPGetConnection ( ctxt ) ;
2010-11-04 14:08:08 +03:00
if ( ctxt - > dataFd = = INVALID_SOCKET )
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
snprintf ( buf , sizeof ( buf ) , " LIST -L %s \r \n " , filename ) ;
}
buf [ sizeof ( buf ) - 1 ] = 0 ;
len = strlen ( buf ) ;
# ifdef DEBUG_FTP
2001-10-29 14:48:19 +03:00
xmlGenericError ( xmlGenericErrorContext , " %s " , buf ) ;
2001-02-23 20:55:21 +03:00
# endif
2013-12-12 11:23:09 +04:00
res = send ( ctxt - > controlFd , SEND_ARG2_CAST buf , len , 0 ) ;
2001-02-23 20:55:21 +03:00
if ( res < 0 ) {
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_FTP , 0 , " send failed " ) ;
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > dataFd ) ; ctxt - > dataFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( res ) ;
}
res = xmlNanoFTPReadResponse ( ctxt ) ;
if ( res ! = 1 ) {
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > dataFd ) ; ctxt - > dataFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( - res ) ;
}
do {
tv . tv_sec = 1 ;
tv . tv_usec = 0 ;
FD_ZERO ( & rfd ) ;
FD_SET ( ctxt - > dataFd , & rfd ) ;
FD_ZERO ( & efd ) ;
FD_SET ( ctxt - > dataFd , & efd ) ;
res = select ( ctxt - > dataFd + 1 , & rfd , NULL , & efd , & tv ) ;
if ( res < 0 ) {
# ifdef DEBUG_FTP
perror ( " select " ) ;
# endif
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > dataFd ) ; ctxt - > dataFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
}
if ( res = = 0 ) {
res = xmlNanoFTPCheckResponse ( ctxt ) ;
if ( res < 0 ) {
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > dataFd ) ; ctxt - > dataFd = INVALID_SOCKET ;
ctxt - > dataFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
}
if ( res = = 2 ) {
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > dataFd ) ; ctxt - > dataFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( 0 ) ;
}
continue ;
}
2001-03-24 20:00:36 +03:00
if ( ( len = recv ( ctxt - > dataFd , & buf [ indx ] , sizeof ( buf ) - ( indx + 1 ) , 0 ) ) < 0 ) {
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_FTP , 0 , " recv " ) ;
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > dataFd ) ; ctxt - > dataFd = INVALID_SOCKET ;
ctxt - > dataFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
}
# ifdef DEBUG_FTP
2001-03-24 20:00:36 +03:00
write ( 1 , & buf [ indx ] , len ) ;
2001-02-23 20:55:21 +03:00
# endif
2001-03-24 20:00:36 +03:00
indx + = len ;
buf [ indx ] = 0 ;
2001-02-23 20:55:21 +03:00
base = 0 ;
do {
res = xmlNanoFTPParseList ( & buf [ base ] , callback , userData ) ;
base + = res ;
} while ( res > 0 ) ;
2001-03-24 20:00:36 +03:00
memmove ( & buf [ 0 ] , & buf [ base ] , indx - base ) ;
indx - = base ;
2001-02-23 20:55:21 +03:00
} while ( len ! = 0 ) ;
xmlNanoFTPCloseConnection ( ctxt ) ;
return ( 0 ) ;
}
/**
* xmlNanoFTPGetSocket :
* @ ctx : an FTP context
* @ filename : the file to retrieve ( or NULL if path is in context ) .
*
* Initiate fetch of the given file from the server .
*
* Returns the socket for the data connection , or < 0 in case of error
*/
2010-11-04 14:08:08 +03:00
SOCKET
2001-02-23 20:55:21 +03:00
xmlNanoFTPGetSocket ( void * ctx , const char * filename ) {
xmlNanoFTPCtxtPtr ctxt = ( xmlNanoFTPCtxtPtr ) ctx ;
char buf [ 300 ] ;
int res , len ;
2004-11-05 14:50:11 +03:00
if ( ctx = = NULL )
2010-11-04 14:08:08 +03:00
return INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
if ( ( filename = = NULL ) & & ( ctxt - > path = = NULL ) )
2010-11-04 14:08:08 +03:00
return INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
ctxt - > dataFd = xmlNanoFTPGetConnection ( ctxt ) ;
2010-11-04 14:08:08 +03:00
if ( ctxt - > dataFd = = INVALID_SOCKET )
return INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
2002-06-14 21:07:10 +04:00
snprintf ( buf , sizeof ( buf ) , " TYPE I \r \n " ) ;
2001-02-23 20:55:21 +03:00
len = strlen ( buf ) ;
# ifdef DEBUG_FTP
2001-10-29 14:48:19 +03:00
xmlGenericError ( xmlGenericErrorContext , " %s " , buf ) ;
2001-02-23 20:55:21 +03:00
# endif
2013-12-12 11:23:09 +04:00
res = send ( ctxt - > controlFd , SEND_ARG2_CAST buf , len , 0 ) ;
2001-02-23 20:55:21 +03:00
if ( res < 0 ) {
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_FTP , 0 , " send failed " ) ;
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > dataFd ) ; ctxt - > dataFd = INVALID_SOCKET ;
return INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
}
res = xmlNanoFTPReadResponse ( ctxt ) ;
if ( res ! = 2 ) {
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > dataFd ) ; ctxt - > dataFd = INVALID_SOCKET ;
return INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
}
if ( filename = = NULL )
snprintf ( buf , sizeof ( buf ) , " RETR %s \r \n " , ctxt - > path ) ;
else
snprintf ( buf , sizeof ( buf ) , " RETR %s \r \n " , filename ) ;
buf [ sizeof ( buf ) - 1 ] = 0 ;
len = strlen ( buf ) ;
# ifdef DEBUG_FTP
2001-10-29 14:48:19 +03:00
xmlGenericError ( xmlGenericErrorContext , " %s " , buf ) ;
2001-02-23 20:55:21 +03:00
# endif
2013-12-12 11:23:09 +04:00
res = send ( ctxt - > controlFd , SEND_ARG2_CAST buf , len , 0 ) ;
2001-02-23 20:55:21 +03:00
if ( res < 0 ) {
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_FTP , 0 , " send failed " ) ;
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > dataFd ) ; ctxt - > dataFd = INVALID_SOCKET ;
return INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
}
res = xmlNanoFTPReadResponse ( ctxt ) ;
if ( res ! = 1 ) {
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > dataFd ) ; ctxt - > dataFd = INVALID_SOCKET ;
return INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
}
return ( ctxt - > dataFd ) ;
}
/**
* xmlNanoFTPGet :
* @ ctx : an FTP context
* @ callback : the user callback
* @ userData : the user callback data
* @ filename : the file to retrieve
*
* Fetch the given file from the server . All data are passed back
* in the callbacks . The last callback has a size of 0 block .
*
2020-03-08 19:19:42 +03:00
* Returns - 1 in case of error , 0 otherwise
2001-02-23 20:55:21 +03:00
*/
int
xmlNanoFTPGet ( void * ctx , ftpDataCallback callback , void * userData ,
const char * filename ) {
xmlNanoFTPCtxtPtr ctxt = ( xmlNanoFTPCtxtPtr ) ctx ;
char buf [ 4096 ] ;
int len = 0 , res ;
fd_set rfd ;
struct timeval tv ;
2005-02-13 11:18:52 +03:00
if ( ctxt = = NULL ) return ( - 1 ) ;
2001-02-23 20:55:21 +03:00
if ( ( filename = = NULL ) & & ( ctxt - > path = = NULL ) )
return ( - 1 ) ;
if ( callback = = NULL )
return ( - 1 ) ;
2010-11-04 14:08:08 +03:00
if ( xmlNanoFTPGetSocket ( ctxt , filename ) = = INVALID_SOCKET )
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
do {
tv . tv_sec = 1 ;
tv . tv_usec = 0 ;
FD_ZERO ( & rfd ) ;
FD_SET ( ctxt - > dataFd , & rfd ) ;
res = select ( ctxt - > dataFd + 1 , & rfd , NULL , NULL , & tv ) ;
if ( res < 0 ) {
# ifdef DEBUG_FTP
perror ( " select " ) ;
# endif
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > dataFd ) ; ctxt - > dataFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
}
if ( res = = 0 ) {
res = xmlNanoFTPCheckResponse ( ctxt ) ;
if ( res < 0 ) {
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > dataFd ) ; ctxt - > dataFd = INVALID_SOCKET ;
ctxt - > dataFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
}
if ( res = = 2 ) {
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > dataFd ) ; ctxt - > dataFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( 0 ) ;
}
continue ;
}
if ( ( len = recv ( ctxt - > dataFd , buf , sizeof ( buf ) , 0 ) ) < 0 ) {
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_FTP , 0 , " recv failed " ) ;
2001-02-23 20:55:21 +03:00
callback ( userData , buf , len ) ;
2010-11-04 14:08:08 +03:00
closesocket ( ctxt - > dataFd ) ; ctxt - > dataFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
return ( - 1 ) ;
}
callback ( userData , buf , len ) ;
} while ( len ! = 0 ) ;
return ( xmlNanoFTPCloseConnection ( ctxt ) ) ;
}
/**
* xmlNanoFTPRead :
* @ ctx : the FTP context
* @ dest : a buffer
* @ len : the buffer length
*
* This function tries to read @ len bytes from the existing FTP connection
* and saves them in @ dest . This is a blocking call .
*
* Returns the number of byte read . 0 is an indication of an end of connection .
* - 1 indicates a parameter error .
*/
int
xmlNanoFTPRead ( void * ctx , void * dest , int len ) {
xmlNanoFTPCtxtPtr ctxt = ( xmlNanoFTPCtxtPtr ) ctx ;
if ( ctx = = NULL ) return ( - 1 ) ;
2010-11-04 14:08:08 +03:00
if ( ctxt - > dataFd = = INVALID_SOCKET ) return ( 0 ) ;
2001-02-23 20:55:21 +03:00
if ( dest = = NULL ) return ( - 1 ) ;
if ( len < = 0 ) return ( 0 ) ;
len = recv ( ctxt - > dataFd , dest , len , 0 ) ;
if ( len < = 0 ) {
2005-02-13 11:18:52 +03:00
if ( len < 0 )
__xmlIOErr ( XML_FROM_FTP , 0 , " recv failed " ) ;
2001-02-23 20:55:21 +03:00
xmlNanoFTPCloseConnection ( ctxt ) ;
}
2003-10-10 23:36:36 +04:00
# ifdef DEBUG_FTP
xmlGenericError ( xmlGenericErrorContext , " Recvd %d bytes \n " , len ) ;
# endif
2001-02-23 20:55:21 +03:00
return ( len ) ;
}
/**
* xmlNanoFTPOpen :
* @ URL : the URL to the resource
*
* Start to fetch the given ftp : // resource
*
2012-09-11 09:26:36 +04:00
* Returns an FTP context , or NULL
2001-02-23 20:55:21 +03:00
*/
void *
xmlNanoFTPOpen ( const char * URL ) {
xmlNanoFTPCtxtPtr ctxt ;
2010-11-04 14:08:08 +03:00
SOCKET sock ;
2001-02-23 20:55:21 +03:00
xmlNanoFTPInit ( ) ;
if ( URL = = NULL ) return ( NULL ) ;
if ( strncmp ( " ftp:// " , URL , 6 ) ) return ( NULL ) ;
ctxt = ( xmlNanoFTPCtxtPtr ) xmlNanoFTPNewCtxt ( URL ) ;
if ( ctxt = = NULL ) return ( NULL ) ;
if ( xmlNanoFTPConnect ( ctxt ) < 0 ) {
xmlNanoFTPFreeCtxt ( ctxt ) ;
return ( NULL ) ;
}
sock = xmlNanoFTPGetSocket ( ctxt , ctxt - > path ) ;
2010-11-04 14:08:08 +03:00
if ( sock = = INVALID_SOCKET ) {
2001-02-23 20:55:21 +03:00
xmlNanoFTPFreeCtxt ( ctxt ) ;
return ( NULL ) ;
}
return ( ctxt ) ;
}
/**
* xmlNanoFTPClose :
* @ ctx : an FTP context
*
* Close the connection and both control and transport
*
2020-03-08 19:19:42 +03:00
* Returns - 1 in case of error , 0 otherwise
2001-02-23 20:55:21 +03:00
*/
int
xmlNanoFTPClose ( void * ctx ) {
xmlNanoFTPCtxtPtr ctxt = ( xmlNanoFTPCtxtPtr ) ctx ;
if ( ctxt = = NULL )
return ( - 1 ) ;
2010-11-04 14:08:08 +03:00
if ( ctxt - > dataFd ! = INVALID_SOCKET ) {
2001-02-23 20:55:21 +03:00
closesocket ( ctxt - > dataFd ) ;
2010-11-04 14:08:08 +03:00
ctxt - > dataFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
}
2010-11-04 14:08:08 +03:00
if ( ctxt - > controlFd ! = INVALID_SOCKET ) {
2001-02-23 20:55:21 +03:00
xmlNanoFTPQuit ( ctxt ) ;
closesocket ( ctxt - > controlFd ) ;
2010-11-04 14:08:08 +03:00
ctxt - > controlFd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
}
xmlNanoFTPFreeCtxt ( ctxt ) ;
return ( 0 ) ;
}
# ifdef STANDALONE
/************************************************************************
2012-09-11 09:26:36 +04:00
* *
* Basic test in Standalone mode *
* *
2001-02-23 20:55:21 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-12-10 18:19:08 +03:00
static
2001-02-23 20:55:21 +03:00
void ftpList ( void * userData , const char * filename , const char * attrib ,
const char * owner , const char * group , unsigned long size , int links ,
int year , const char * month , int day , int hour , int minute ) {
xmlGenericError ( xmlGenericErrorContext ,
" %s %s %s %ld %s \n " , attrib , owner , group , size , filename ) ;
}
2002-12-10 18:19:08 +03:00
static
2001-02-23 20:55:21 +03:00
void ftpData ( void * userData , const char * data , int len ) {
if ( userData = = NULL ) return ;
if ( len < = 0 ) {
2003-10-29 16:39:15 +03:00
fclose ( ( FILE * ) userData ) ;
2001-02-23 20:55:21 +03:00
return ;
2012-09-11 09:26:36 +04:00
}
2003-10-29 16:39:15 +03:00
fwrite ( data , len , 1 , ( FILE * ) userData ) ;
2001-02-23 20:55:21 +03:00
}
int main ( int argc , char * * argv ) {
void * ctxt ;
FILE * output ;
char * tstfile = NULL ;
xmlNanoFTPInit ( ) ;
if ( argc > 1 ) {
ctxt = xmlNanoFTPNewCtxt ( argv [ 1 ] ) ;
if ( xmlNanoFTPConnect ( ctxt ) < 0 ) {
xmlGenericError ( xmlGenericErrorContext ,
" Couldn't connect to %s \n " , argv [ 1 ] ) ;
exit ( 1 ) ;
}
if ( argc > 2 )
tstfile = argv [ 2 ] ;
} else
ctxt = xmlNanoFTPConnectTo ( " localhost " , 0 ) ;
if ( ctxt = = NULL ) {
xmlGenericError ( xmlGenericErrorContext ,
" Couldn't connect to localhost \n " ) ;
exit ( 1 ) ;
}
xmlNanoFTPList ( ctxt , ftpList , NULL , tstfile ) ;
output = fopen ( " /tmp/tstdata " , " w " ) ;
if ( output ! = NULL ) {
if ( xmlNanoFTPGet ( ctxt , ftpData , ( void * ) output , tstfile ) < 0 )
xmlGenericError ( xmlGenericErrorContext ,
" Failed to get file \n " ) ;
2012-09-11 09:26:36 +04:00
2001-02-23 20:55:21 +03:00
}
xmlNanoFTPClose ( ctxt ) ;
xmlMemoryDump ( ) ;
exit ( 0 ) ;
}
# endif /* STANDALONE */
# else /* !LIBXML_FTP_ENABLED */
# ifdef STANDALONE
# include <stdio.h>
int main ( int argc , char * * argv ) {
xmlGenericError ( xmlGenericErrorContext ,
" %s : FTP support not compiled in \n " , argv [ 0 ] ) ;
return ( 0 ) ;
}
# endif /* STANDALONE */
# endif /* LIBXML_FTP_ENABLED */