ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

nanoftp.c
Go to the documentation of this file.
00001 /*
00002  * nanoftp.c: basic FTP client support
00003  *
00004  *  Reference: RFC 959
00005  */
00006 
00007 #ifdef TESTING
00008 #define STANDALONE
00009 #define HAVE_STDLIB_H
00010 #define HAVE_UNISTD_H
00011 #define HAVE_SYS_SOCKET_H
00012 #define HAVE_NETINET_IN_H
00013 #define HAVE_NETDB_H
00014 #define HAVE_SYS_TIME_H
00015 #else /* TESTING */
00016 #define NEED_SOCKETS
00017 #endif /* TESTING */
00018 
00019 #define IN_LIBXML
00020 #include "libxml.h"
00021 
00022 #ifdef LIBXML_FTP_ENABLED
00023 #include <string.h>
00024 
00025 #ifdef HAVE_STDLIB_H
00026 #include <stdlib.h>
00027 #endif
00028 #ifdef HAVE_UNISTD_H
00029 #include <unistd.h>
00030 #endif
00031 #ifdef HAVE_SYS_SOCKET_H
00032 #include <sys/socket.h>
00033 #endif
00034 #ifdef HAVE_NETINET_IN_H
00035 #include <netinet/in.h>
00036 #endif
00037 #ifdef HAVE_ARPA_INET_H
00038 #include <arpa/inet.h>
00039 #endif
00040 #ifdef HAVE_NETDB_H
00041 #include <netdb.h>
00042 #endif
00043 #ifdef HAVE_FCNTL_H
00044 #include <fcntl.h> 
00045 #endif
00046 #ifdef HAVE_ERRNO_H
00047 #include <errno.h>
00048 #endif
00049 #ifdef HAVE_SYS_TIME_H
00050 #include <sys/time.h>
00051 #endif
00052 #ifdef HAVE_SYS_SELECT_H
00053 #include <sys/select.h>
00054 #endif
00055 #ifdef HAVE_SYS_SOCKET_H
00056 #include <sys/socket.h>
00057 #endif
00058 #ifdef HAVE_SYS_TYPES_H
00059 #include <sys/types.h>
00060 #endif
00061 #ifdef HAVE_STRINGS_H
00062 #include <strings.h>
00063 #endif
00064 
00065 #include <libxml/xmlmemory.h>
00066 #include <libxml/parser.h>
00067 #include <libxml/xmlerror.h>
00068 #include <libxml/uri.h>
00069 #include <libxml/nanoftp.h>
00070 #include <libxml/globals.h>
00071 
00072 /* #define DEBUG_FTP 1  */
00073 #ifdef STANDALONE
00074 #ifndef DEBUG_FTP
00075 #define DEBUG_FTP 1
00076 #endif
00077 #endif
00078 
00079 
00080 #if defined(__MINGW32__) || defined(_WIN32_WCE)
00081 #ifndef _WINSOCKAPI_
00082 #define _WINSOCKAPI_
00083 #endif
00084 #include <wsockcompat.h>
00085 #include <winsock2.h>
00086 #undef XML_SOCKLEN_T
00087 #define XML_SOCKLEN_T unsigned int
00088 #endif
00089 
00093 #ifndef _WINSOCKAPI_
00094 #if !defined(__BEOS__) || defined(__HAIKU__)
00095 #define closesocket(s) close(s)
00096 #endif
00097 #endif
00098 
00099 #ifdef __BEOS__
00100 #ifndef PF_INET
00101 #define PF_INET AF_INET
00102 #endif
00103 #endif
00104 
00105 #ifdef _AIX
00106 #ifdef HAVE_BROKEN_SS_FAMILY
00107 #define ss_family __ss_family
00108 #endif
00109 #endif
00110 
00111 #ifndef XML_SOCKLEN_T
00112 #define XML_SOCKLEN_T unsigned int
00113 #endif
00114 
00115 #define FTP_COMMAND_OK      200
00116 #define FTP_SYNTAX_ERROR    500
00117 #define FTP_GET_PASSWD      331
00118 #define FTP_BUF_SIZE        1024
00119 
00120 #define XML_NANO_MAX_URLBUF 4096
00121 
00122 typedef struct xmlNanoFTPCtxt {
00123     char *protocol; /* the protocol name */
00124     char *hostname; /* the host name */
00125     int port;       /* the port */
00126     char *path;     /* the path within the URL */
00127     char *user;     /* user string */
00128     char *passwd;   /* passwd string */
00129 #ifdef SUPPORT_IP6
00130     struct sockaddr_storage ftpAddr; /* this is large enough to hold IPv6 address*/
00131 #else
00132     struct sockaddr_in ftpAddr; /* the socket address struct */
00133 #endif
00134     int passive;    /* currently we support only passive !!! */
00135     SOCKET controlFd;   /* the file descriptor for the control socket */
00136     SOCKET dataFd;  /* the file descriptor for the data socket */
00137     int state;      /* WRITE / READ / CLOSED */
00138     int returnValue;    /* the protocol return value */
00139     /* buffer for data received from the control connection */
00140     char controlBuf[FTP_BUF_SIZE + 1];
00141     int controlBufIndex;
00142     int controlBufUsed;
00143     int controlBufAnswer;
00144 } xmlNanoFTPCtxt, *xmlNanoFTPCtxtPtr;
00145 
00146 static int initialized = 0;
00147 static char *proxy = NULL;  /* the proxy name if any */
00148 static int proxyPort = 0;   /* the proxy port if any */
00149 static char *proxyUser = NULL;  /* user for proxy authentication */
00150 static char *proxyPasswd = NULL;/* passwd for proxy authentication */
00151 static int proxyType = 0;   /* uses TYPE or a@b ? */
00152 
00153 #ifdef SUPPORT_IP6
00154 static
00155 int have_ipv6(void) {
00156     int s;
00157 
00158     s = socket (AF_INET6, SOCK_STREAM, 0);
00159     if (s != -1) {
00160     close (s);
00161     return (1);
00162     }
00163     return (0);
00164 }
00165 #endif
00166 
00173 static void
00174 xmlFTPErrMemory(const char *extra)
00175 {
00176     __xmlSimpleError(XML_FROM_FTP, XML_ERR_NO_MEMORY, NULL, NULL, extra);
00177 }
00178 
00187 void
00188 xmlNanoFTPInit(void) {
00189     const char *env;
00190 #ifdef _WINSOCKAPI_
00191     WSADATA wsaData;    
00192 #endif
00193 
00194     if (initialized)
00195     return;
00196 
00197 #ifdef _WINSOCKAPI_
00198     if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
00199     return;
00200 #endif
00201 
00202     proxyPort = 21;
00203     env = getenv("no_proxy");
00204     if (env && ((env[0] == '*' ) && (env[1] == 0)))
00205     return;
00206     env = getenv("ftp_proxy");
00207     if (env != NULL) {
00208     xmlNanoFTPScanProxy(env);
00209     } else {
00210     env = getenv("FTP_PROXY");
00211     if (env != NULL) {
00212         xmlNanoFTPScanProxy(env);
00213     }
00214     }
00215     env = getenv("ftp_proxy_user");
00216     if (env != NULL) {
00217     proxyUser = xmlMemStrdup(env);
00218     }
00219     env = getenv("ftp_proxy_password");
00220     if (env != NULL) {
00221     proxyPasswd = xmlMemStrdup(env);
00222     }
00223     initialized = 1;
00224 }
00225 
00232 void
00233 xmlNanoFTPCleanup(void) {
00234     if (proxy != NULL) {
00235     xmlFree(proxy);
00236     proxy = NULL;
00237     }
00238     if (proxyUser != NULL) {
00239     xmlFree(proxyUser);
00240     proxyUser = NULL;
00241     }
00242     if (proxyPasswd != NULL) {
00243     xmlFree(proxyPasswd);
00244     proxyPasswd = NULL;
00245     }
00246 #ifdef _WINSOCKAPI_
00247     if (initialized)
00248     WSACleanup();
00249 #endif
00250     initialized = 0;
00251 }
00252 
00266 void
00267 xmlNanoFTPProxy(const char *host, int port, const char *user,
00268             const char *passwd, int type) {
00269     if (proxy != NULL) {
00270     xmlFree(proxy);
00271     proxy = NULL;
00272     }
00273     if (proxyUser != NULL) {
00274     xmlFree(proxyUser);
00275     proxyUser = NULL;
00276     }
00277     if (proxyPasswd != NULL) {
00278     xmlFree(proxyPasswd);
00279     proxyPasswd = NULL;
00280     }
00281     if (host)
00282     proxy = xmlMemStrdup(host);
00283     if (user)
00284     proxyUser = xmlMemStrdup(user);
00285     if (passwd)
00286     proxyPasswd = xmlMemStrdup(passwd);
00287     proxyPort = port;
00288     proxyType = type;
00289 }
00290 
00300 static void
00301 xmlNanoFTPScanURL(void *ctx, const char *URL) {
00302     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
00303     xmlURIPtr uri;
00304 
00305     /*
00306      * Clear any existing data from the context
00307      */
00308     if (ctxt->protocol != NULL) { 
00309         xmlFree(ctxt->protocol);
00310     ctxt->protocol = NULL;
00311     }
00312     if (ctxt->hostname != NULL) { 
00313         xmlFree(ctxt->hostname);
00314     ctxt->hostname = NULL;
00315     }
00316     if (ctxt->path != NULL) { 
00317         xmlFree(ctxt->path);
00318     ctxt->path = NULL;
00319     }
00320     if (URL == NULL) return;
00321 
00322     uri = xmlParseURIRaw(URL, 1);
00323     if (uri == NULL)
00324     return;
00325 
00326     if ((uri->scheme == NULL) || (uri->server == NULL)) {
00327     xmlFreeURI(uri);
00328     return;
00329     }
00330     
00331     ctxt->protocol = xmlMemStrdup(uri->scheme);
00332     ctxt->hostname = xmlMemStrdup(uri->server);
00333     if (uri->path != NULL)
00334     ctxt->path = xmlMemStrdup(uri->path);
00335     else
00336     ctxt->path = xmlMemStrdup("/");
00337     if (uri->port != 0)
00338     ctxt->port = uri->port;
00339 
00340     if (uri->user != NULL) {
00341     char *cptr;
00342     if ((cptr=strchr(uri->user, ':')) == NULL)
00343         ctxt->user = xmlMemStrdup(uri->user);
00344     else {
00345         ctxt->user = (char *)xmlStrndup((xmlChar *)uri->user,
00346                 (cptr - uri->user));
00347         ctxt->passwd = xmlMemStrdup(cptr+1);
00348     }
00349     }
00350 
00351     xmlFreeURI(uri);
00352 
00353 }
00354 
00369 int
00370 xmlNanoFTPUpdateURL(void *ctx, const char *URL) {
00371     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
00372     xmlURIPtr uri;
00373 
00374     if (URL == NULL)
00375     return(-1);
00376     if (ctxt == NULL)
00377     return(-1);
00378     if (ctxt->protocol == NULL)
00379     return(-1);
00380     if (ctxt->hostname == NULL)
00381     return(-1);
00382 
00383     uri = xmlParseURIRaw(URL, 1);
00384     if (uri == NULL)
00385     return(-1);
00386 
00387     if ((uri->scheme == NULL) || (uri->server == NULL)) {
00388     xmlFreeURI(uri);
00389     return(-1);
00390     }
00391     if ((strcmp(ctxt->protocol, uri->scheme)) ||
00392     (strcmp(ctxt->hostname, uri->server)) ||
00393     ((uri->port != 0) && (ctxt->port != uri->port))) {
00394     xmlFreeURI(uri);
00395     return(-1);
00396     }
00397 
00398     if (uri->port != 0)
00399     ctxt->port = uri->port;
00400 
00401     if (ctxt->path != NULL) {
00402     xmlFree(ctxt->path);
00403     ctxt->path = NULL;
00404     }
00405 
00406     if (uri->path == NULL) 
00407         ctxt->path = xmlMemStrdup("/");
00408     else
00409     ctxt->path = xmlMemStrdup(uri->path);
00410 
00411     xmlFreeURI(uri);
00412 
00413     return(0);
00414 }
00415 
00426 void
00427 xmlNanoFTPScanProxy(const char *URL) {
00428     xmlURIPtr uri;
00429 
00430     if (proxy != NULL) { 
00431         xmlFree(proxy);
00432     proxy = NULL;
00433     }
00434     proxyPort = 0;
00435 
00436 #ifdef DEBUG_FTP
00437     if (URL == NULL)
00438     xmlGenericError(xmlGenericErrorContext,
00439         "Removing FTP proxy info\n");
00440     else
00441     xmlGenericError(xmlGenericErrorContext,
00442         "Using FTP proxy %s\n", URL);
00443 #endif
00444     if (URL == NULL) return;
00445 
00446     uri = xmlParseURIRaw(URL, 1);
00447     if ((uri == NULL) || (uri->scheme == NULL) ||
00448     (strcmp(uri->scheme, "ftp")) || (uri->server == NULL)) {
00449     __xmlIOErr(XML_FROM_FTP, XML_FTP_URL_SYNTAX, "Syntax Error\n");
00450     if (uri != NULL)
00451         xmlFreeURI(uri);
00452     return;
00453     }
00454     
00455     proxy = xmlMemStrdup(uri->server);
00456     if (uri->port != 0)
00457     proxyPort = uri->port;
00458 
00459     xmlFreeURI(uri);
00460 }
00461 
00471 void*
00472 xmlNanoFTPNewCtxt(const char *URL) {
00473     xmlNanoFTPCtxtPtr ret;
00474     char *unescaped;
00475 
00476     ret = (xmlNanoFTPCtxtPtr) xmlMalloc(sizeof(xmlNanoFTPCtxt));
00477     if (ret == NULL) {
00478         xmlFTPErrMemory("allocating FTP context");
00479         return(NULL);
00480     }
00481 
00482     memset(ret, 0, sizeof(xmlNanoFTPCtxt));
00483     ret->port = 21;
00484     ret->passive = 1;
00485     ret->returnValue = 0;
00486     ret->controlBufIndex = 0;
00487     ret->controlBufUsed = 0;
00488     ret->controlFd = INVALID_SOCKET;
00489 
00490     unescaped = xmlURIUnescapeString(URL, 0, NULL);
00491     if (unescaped != NULL) {
00492     xmlNanoFTPScanURL(ret, unescaped);
00493     xmlFree(unescaped);
00494     } else if (URL != NULL)
00495     xmlNanoFTPScanURL(ret, URL);
00496 
00497     return(ret);
00498 }
00499 
00507 void
00508 xmlNanoFTPFreeCtxt(void * ctx) {
00509     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
00510     if (ctxt == NULL) return;
00511     if (ctxt->hostname != NULL) xmlFree(ctxt->hostname);
00512     if (ctxt->protocol != NULL) xmlFree(ctxt->protocol);
00513     if (ctxt->path != NULL) xmlFree(ctxt->path);
00514     ctxt->passive = 1;
00515     if (ctxt->controlFd != INVALID_SOCKET) closesocket(ctxt->controlFd);
00516     ctxt->controlFd = INVALID_SOCKET;
00517     ctxt->controlBufIndex = -1;
00518     ctxt->controlBufUsed = -1;
00519     xmlFree(ctxt);
00520 }
00521 
00533 static int
00534 xmlNanoFTPParseResponse(char *buf, int len) {
00535     int val = 0;
00536 
00537     if (len < 3) return(-1);
00538     if ((*buf >= '0') && (*buf <= '9')) 
00539         val = val * 10 + (*buf - '0');
00540     else
00541         return(0);
00542     buf++;
00543     if ((*buf >= '0') && (*buf <= '9')) 
00544         val = val * 10 + (*buf - '0');
00545     else
00546         return(0);
00547     buf++;
00548     if ((*buf >= '0') && (*buf <= '9')) 
00549         val = val * 10 + (*buf - '0');
00550     else
00551         return(0);
00552     buf++;
00553     if (*buf == '-') 
00554         return(-val);
00555     return(val);
00556 }
00557 
00565 static int
00566 xmlNanoFTPGetMore(void *ctx) {
00567     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
00568     int len;
00569     int size;
00570 
00571     if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1);
00572 
00573     if ((ctxt->controlBufIndex < 0) || (ctxt->controlBufIndex > FTP_BUF_SIZE)) {
00574 #ifdef DEBUG_FTP
00575         xmlGenericError(xmlGenericErrorContext,
00576         "xmlNanoFTPGetMore : controlBufIndex = %d\n",
00577         ctxt->controlBufIndex);
00578 #endif
00579     return(-1);
00580     }
00581 
00582     if ((ctxt->controlBufUsed < 0) || (ctxt->controlBufUsed > FTP_BUF_SIZE)) {
00583 #ifdef DEBUG_FTP
00584         xmlGenericError(xmlGenericErrorContext,
00585         "xmlNanoFTPGetMore : controlBufUsed = %d\n",
00586         ctxt->controlBufUsed);
00587 #endif
00588     return(-1);
00589     }
00590     if (ctxt->controlBufIndex > ctxt->controlBufUsed) {
00591 #ifdef DEBUG_FTP
00592         xmlGenericError(xmlGenericErrorContext,
00593         "xmlNanoFTPGetMore : controlBufIndex > controlBufUsed %d > %d\n",
00594            ctxt->controlBufIndex, ctxt->controlBufUsed);
00595 #endif
00596     return(-1);
00597     }
00598 
00599     /*
00600      * First pack the control buffer
00601      */
00602     if (ctxt->controlBufIndex > 0) {
00603     memmove(&ctxt->controlBuf[0], &ctxt->controlBuf[ctxt->controlBufIndex],
00604         ctxt->controlBufUsed - ctxt->controlBufIndex);
00605     ctxt->controlBufUsed -= ctxt->controlBufIndex;
00606     ctxt->controlBufIndex = 0;
00607     }
00608     size = FTP_BUF_SIZE - ctxt->controlBufUsed;
00609     if (size == 0) {
00610 #ifdef DEBUG_FTP
00611         xmlGenericError(xmlGenericErrorContext,
00612         "xmlNanoFTPGetMore : buffer full %d \n", ctxt->controlBufUsed);
00613 #endif
00614     return(0);
00615     }
00616 
00617     /*
00618      * Read the amount left on the control connection
00619      */
00620     if ((len = recv(ctxt->controlFd, &ctxt->controlBuf[ctxt->controlBufIndex],
00621             size, 0)) < 0) {
00622     __xmlIOErr(XML_FROM_FTP, 0, "recv failed");
00623     closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
00624         ctxt->controlFd = INVALID_SOCKET;
00625         return(-1);
00626     }
00627 #ifdef DEBUG_FTP
00628     xmlGenericError(xmlGenericErrorContext,
00629         "xmlNanoFTPGetMore : read %d [%d - %d]\n", len,
00630        ctxt->controlBufUsed, ctxt->controlBufUsed + len);
00631 #endif
00632     ctxt->controlBufUsed += len;
00633     ctxt->controlBuf[ctxt->controlBufUsed] = 0;
00634 
00635     return(len);
00636 }
00637 
00645 static int
00646 xmlNanoFTPReadResponse(void *ctx) {
00647     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
00648     char *ptr, *end;
00649     int len;
00650     int res = -1, cur = -1;
00651 
00652     if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1);
00653 
00654 get_more:
00655     /*
00656      * Assumes everything up to controlBuf[controlBufIndex] has been read
00657      * and analyzed.
00658      */
00659     len = xmlNanoFTPGetMore(ctx);
00660     if (len < 0) {
00661         return(-1);
00662     }
00663     if ((ctxt->controlBufUsed == 0) && (len == 0)) {
00664         return(-1);
00665     }
00666     ptr = &ctxt->controlBuf[ctxt->controlBufIndex];
00667     end = &ctxt->controlBuf[ctxt->controlBufUsed];
00668 
00669 #ifdef DEBUG_FTP
00670     xmlGenericError(xmlGenericErrorContext,
00671         "\n<<<\n%s\n--\n", ptr);
00672 #endif
00673     while (ptr < end) {
00674         cur = xmlNanoFTPParseResponse(ptr, end - ptr);
00675     if (cur > 0) {
00676         /*
00677          * Successfully scanned the control code, scratch
00678          * till the end of the line, but keep the index to be
00679          * able to analyze the result if needed.
00680          */
00681         res = cur;
00682         ptr += 3;
00683         ctxt->controlBufAnswer = ptr - ctxt->controlBuf;
00684         while ((ptr < end) && (*ptr != '\n')) ptr++;
00685         if (*ptr == '\n') ptr++;
00686         if (*ptr == '\r') ptr++;
00687         break;
00688     }
00689     while ((ptr < end) && (*ptr != '\n')) ptr++;
00690     if (ptr >= end) {
00691         ctxt->controlBufIndex = ctxt->controlBufUsed;
00692         goto get_more;
00693     }
00694     if (*ptr != '\r') ptr++;
00695     }
00696 
00697     if (res < 0) goto get_more;
00698     ctxt->controlBufIndex = ptr - ctxt->controlBuf;
00699 #ifdef DEBUG_FTP
00700     ptr = &ctxt->controlBuf[ctxt->controlBufIndex];
00701     xmlGenericError(xmlGenericErrorContext, "\n---\n%s\n--\n", ptr);
00702 #endif
00703 
00704 #ifdef DEBUG_FTP
00705     xmlGenericError(xmlGenericErrorContext, "Got %d\n", res);
00706 #endif
00707     return(res / 100);
00708 }
00709 
00718 int
00719 xmlNanoFTPGetResponse(void *ctx) {
00720     int res;
00721 
00722     res = xmlNanoFTPReadResponse(ctx);
00723 
00724     return(res);
00725 }
00726 
00735 int
00736 xmlNanoFTPCheckResponse(void *ctx) {
00737     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
00738     fd_set rfd;
00739     struct timeval tv;
00740 
00741     if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1);
00742     tv.tv_sec = 0;
00743     tv.tv_usec = 0;
00744     FD_ZERO(&rfd);
00745     FD_SET(ctxt->controlFd, &rfd);
00746     switch(select(ctxt->controlFd + 1, &rfd, NULL, NULL, &tv)) {
00747     case 0:
00748         return(0);
00749     case -1:
00750         __xmlIOErr(XML_FROM_FTP, 0, "select");
00751         return(-1);
00752             
00753     }
00754 
00755     return(xmlNanoFTPReadResponse(ctx));
00756 }
00757 
00762 static int
00763 xmlNanoFTPSendUser(void *ctx) {
00764     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
00765     char buf[200];
00766     int len;
00767     int res;
00768 
00769     if (ctxt->user == NULL)
00770     snprintf(buf, sizeof(buf), "USER anonymous\r\n");
00771     else
00772     snprintf(buf, sizeof(buf), "USER %s\r\n", ctxt->user);
00773     buf[sizeof(buf) - 1] = 0;
00774     len = strlen(buf);
00775 #ifdef DEBUG_FTP
00776     xmlGenericError(xmlGenericErrorContext, "%s", buf);
00777 #endif
00778     res = send(ctxt->controlFd, buf, len, 0);
00779     if (res < 0) {
00780     __xmlIOErr(XML_FROM_FTP, 0, "send failed");
00781     return(res);
00782     }
00783     return(0);
00784 }
00785 
00790 static int
00791 xmlNanoFTPSendPasswd(void *ctx) {
00792     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
00793     char buf[200];
00794     int len;
00795     int res;
00796 
00797     if (ctxt->passwd == NULL)
00798     snprintf(buf, sizeof(buf), "PASS anonymous@\r\n");
00799     else
00800     snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd);
00801     buf[sizeof(buf) - 1] = 0;
00802     len = strlen(buf);
00803 #ifdef DEBUG_FTP
00804     xmlGenericError(xmlGenericErrorContext, "%s", buf);
00805 #endif
00806     res = send(ctxt->controlFd, buf, len, 0);
00807     if (res < 0) {
00808     __xmlIOErr(XML_FROM_FTP, 0, "send failed");
00809     return(res);
00810     }
00811     return(0);
00812 }
00813 
00824 int
00825 xmlNanoFTPQuit(void *ctx) {
00826     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
00827     char buf[200];
00828     int len, res;
00829 
00830     if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1);
00831 
00832     snprintf(buf, sizeof(buf), "QUIT\r\n");
00833     len = strlen(buf);
00834 #ifdef DEBUG_FTP
00835     xmlGenericError(xmlGenericErrorContext, "%s", buf); /* Just to be consistent, even though we know it can't have a % in it */
00836 #endif
00837     res = send(ctxt->controlFd, buf, len, 0);
00838     if (res < 0) {
00839     __xmlIOErr(XML_FROM_FTP, 0, "send failed");
00840     return(res);
00841     }
00842     return(0);
00843 }
00844 
00854 int
00855 xmlNanoFTPConnect(void *ctx) {
00856     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
00857     struct hostent *hp;
00858     int port;
00859     int res;
00860     int addrlen = sizeof (struct sockaddr_in);
00861 
00862     if (ctxt == NULL)
00863     return(-1);
00864     if (ctxt->hostname == NULL)
00865     return(-1);
00866 
00867     /*
00868      * do the blocking DNS query.
00869      */
00870     if (proxy) {
00871         port = proxyPort;
00872     } else {
00873     port = ctxt->port;
00874     }
00875     if (port == 0)
00876     port = 21;
00877 
00878     memset (&ctxt->ftpAddr, 0, sizeof(ctxt->ftpAddr));
00879 
00880 #ifdef SUPPORT_IP6
00881     if (have_ipv6 ()) {
00882     struct addrinfo hints, *tmp, *result;
00883 
00884     result = NULL;
00885     memset (&hints, 0, sizeof(hints));
00886     hints.ai_socktype = SOCK_STREAM;
00887 
00888     if (proxy) {
00889         if (getaddrinfo (proxy, NULL, &hints, &result) != 0) {
00890         __xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed");
00891         return (-1);
00892         }
00893     }
00894     else
00895         if (getaddrinfo (ctxt->hostname, NULL, &hints, &result) != 0) {
00896         __xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed");
00897         return (-1);
00898         }
00899 
00900     for (tmp = result; tmp; tmp = tmp->ai_next)
00901         if (tmp->ai_family == AF_INET || tmp->ai_family == AF_INET6)
00902         break;
00903 
00904     if (!tmp) {
00905         if (result)
00906         freeaddrinfo (result);
00907         __xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed");
00908         return (-1);
00909     }
00910     if (tmp->ai_addrlen > sizeof(ctxt->ftpAddr)) {
00911         __xmlIOErr(XML_FROM_FTP, 0, "gethostbyname address mismatch");
00912         return (-1);
00913     }
00914     if (tmp->ai_family == AF_INET6) {
00915         memcpy (&ctxt->ftpAddr, tmp->ai_addr, tmp->ai_addrlen);
00916         ((struct sockaddr_in6 *) &ctxt->ftpAddr)->sin6_port = htons (port);
00917         ctxt->controlFd = socket (AF_INET6, SOCK_STREAM, 0);
00918     }
00919     else {
00920         memcpy (&ctxt->ftpAddr, tmp->ai_addr, tmp->ai_addrlen);
00921         ((struct sockaddr_in *) &ctxt->ftpAddr)->sin_port = htons (port);
00922         ctxt->controlFd = socket (AF_INET, SOCK_STREAM, 0);
00923     }
00924     addrlen = tmp->ai_addrlen;
00925     freeaddrinfo (result);
00926     }
00927     else
00928 #endif
00929     {
00930     if (proxy)
00931         hp = gethostbyname (proxy);
00932     else
00933         hp = gethostbyname (ctxt->hostname);
00934     if (hp == NULL) {
00935         __xmlIOErr(XML_FROM_FTP, 0, "gethostbyname failed");
00936         return (-1);
00937     }
00938     if ((unsigned int) hp->h_length >
00939         sizeof(((struct sockaddr_in *)&ctxt->ftpAddr)->sin_addr)) {
00940         __xmlIOErr(XML_FROM_FTP, 0, "gethostbyname address mismatch");
00941         return (-1);
00942     }
00943 
00944     /*
00945      * Prepare the socket
00946      */
00947     ((struct sockaddr_in *)&ctxt->ftpAddr)->sin_family = AF_INET;
00948     memcpy (&((struct sockaddr_in *)&ctxt->ftpAddr)->sin_addr,
00949         hp->h_addr_list[0], hp->h_length);
00950     ((struct sockaddr_in *)&ctxt->ftpAddr)->sin_port = (u_short)htons ((unsigned short)port);
00951     ctxt->controlFd = socket (AF_INET, SOCK_STREAM, 0);
00952     addrlen = sizeof (struct sockaddr_in);
00953     }
00954 
00955     if (ctxt->controlFd == INVALID_SOCKET) {
00956     __xmlIOErr(XML_FROM_FTP, 0, "socket failed");
00957         return(-1);
00958     }
00959 
00960     /*
00961      * Do the connect.
00962      */
00963     if (connect(ctxt->controlFd, (struct sockaddr *) &ctxt->ftpAddr,
00964         addrlen) < 0) {
00965     __xmlIOErr(XML_FROM_FTP, 0, "Failed to create a connection");
00966         closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
00967         ctxt->controlFd = INVALID_SOCKET;
00968     return(-1);
00969     }
00970 
00971     /*
00972      * Wait for the HELLO from the server.
00973      */
00974     res = xmlNanoFTPGetResponse(ctxt);
00975     if (res != 2) {
00976         closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
00977         ctxt->controlFd = INVALID_SOCKET;
00978     return(-1);
00979     }
00980 
00981     /*
00982      * State diagram for the login operation on the FTP server
00983      *
00984      * Reference: RFC 959
00985      *
00986      *                       1
00987      * +---+   USER    +---+------------->+---+
00988      * | B |---------->| W | 2       ---->| E |
00989      * +---+           +---+------  |  -->+---+
00990      *                  | |       | | |
00991      *                3 | | 4,5   | | |
00992      *    --------------   -----  | | |
00993      *   |                      | | | |
00994      *   |                      | | | |
00995      *   |                 ---------  |
00996      *   |               1|     | |   |
00997      *   V                |     | |   |
00998      * +---+   PASS    +---+ 2  |  ------>+---+
00999      * |   |---------->| W |------------->| S |
01000      * +---+           +---+   ---------->+---+
01001      *                  | |   | |     |
01002      *                3 | |4,5| |     |
01003      *    --------------   --------   |
01004      *   |                    | |  |  |
01005      *   |                    | |  |  |
01006      *   |                 -----------
01007      *   |             1,3|   | |  |
01008      *   V                |  2| |  |
01009      * +---+   ACCT    +---+--  |   ----->+---+
01010      * |   |---------->| W | 4,5 -------->| F |
01011      * +---+           +---+------------->+---+
01012      *
01013      * Of course in case of using a proxy this get really nasty and is not
01014      * standardized at all :-(
01015      */
01016     if (proxy) {
01017         int len;
01018     char buf[400];
01019 
01020         if (proxyUser != NULL) {
01021         /*
01022          * We need proxy auth
01023          */
01024         snprintf(buf, sizeof(buf), "USER %s\r\n", proxyUser);
01025             buf[sizeof(buf) - 1] = 0;
01026             len = strlen(buf);
01027 #ifdef DEBUG_FTP
01028         xmlGenericError(xmlGenericErrorContext, "%s", buf);
01029 #endif
01030         res = send(ctxt->controlFd, buf, len, 0);
01031         if (res < 0) {
01032         __xmlIOErr(XML_FROM_FTP, 0, "send failed");
01033         closesocket(ctxt->controlFd);
01034         ctxt->controlFd = INVALID_SOCKET;
01035             return(res);
01036         }
01037         res = xmlNanoFTPGetResponse(ctxt);
01038         switch (res) {
01039         case 2:
01040             if (proxyPasswd == NULL)
01041             break;
01042         case 3:
01043             if (proxyPasswd != NULL)
01044             snprintf(buf, sizeof(buf), "PASS %s\r\n", proxyPasswd);
01045             else
01046             snprintf(buf, sizeof(buf), "PASS anonymous@\r\n");
01047                     buf[sizeof(buf) - 1] = 0;
01048                     len = strlen(buf);
01049 #ifdef DEBUG_FTP
01050             xmlGenericError(xmlGenericErrorContext, "%s", buf);
01051 #endif
01052             res = send(ctxt->controlFd, buf, len, 0);
01053             if (res < 0) {
01054             __xmlIOErr(XML_FROM_FTP, 0, "send failed");
01055             closesocket(ctxt->controlFd);
01056             ctxt->controlFd = INVALID_SOCKET;
01057             return(res);
01058             }
01059             res = xmlNanoFTPGetResponse(ctxt);
01060             if (res > 3) {
01061             closesocket(ctxt->controlFd);
01062             ctxt->controlFd = INVALID_SOCKET;
01063             return(-1);
01064             }
01065             break;
01066         case 1:
01067             break;
01068         case 4:
01069         case 5:
01070         case -1:
01071         default:
01072             closesocket(ctxt->controlFd);
01073             ctxt->controlFd = INVALID_SOCKET;
01074             return(-1);
01075         }
01076     }
01077 
01078     /*
01079      * We assume we don't need more authentication to the proxy
01080      * and that it succeeded :-\
01081      */
01082     switch (proxyType) {
01083         case 0:
01084         /* we will try in sequence */
01085         case 1:
01086         /* Using SITE command */
01087         snprintf(buf, sizeof(buf), "SITE %s\r\n", ctxt->hostname);
01088                 buf[sizeof(buf) - 1] = 0;
01089                 len = strlen(buf);
01090 #ifdef DEBUG_FTP
01091         xmlGenericError(xmlGenericErrorContext, "%s", buf);
01092 #endif
01093         res = send(ctxt->controlFd, buf, len, 0);
01094         if (res < 0) {
01095             __xmlIOErr(XML_FROM_FTP, 0, "send failed");
01096             closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
01097             ctxt->controlFd = INVALID_SOCKET;
01098             return(res);
01099         }
01100         res = xmlNanoFTPGetResponse(ctxt);
01101         if (res == 2) {
01102             /* we assume it worked :-\ 1 is error for SITE command */
01103             proxyType = 1;
01104             break;
01105         }    
01106         if (proxyType == 1) {
01107             closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
01108             ctxt->controlFd = INVALID_SOCKET;
01109             return(-1);
01110         }
01111         case 2:
01112         /* USER user@host command */
01113         if (ctxt->user == NULL)
01114             snprintf(buf, sizeof(buf), "USER anonymous@%s\r\n",
01115                        ctxt->hostname);
01116         else
01117             snprintf(buf, sizeof(buf), "USER %s@%s\r\n",
01118                        ctxt->user, ctxt->hostname);
01119                 buf[sizeof(buf) - 1] = 0;
01120                 len = strlen(buf);
01121 #ifdef DEBUG_FTP
01122         xmlGenericError(xmlGenericErrorContext, "%s", buf);
01123 #endif
01124         res = send(ctxt->controlFd, buf, len, 0);
01125         if (res < 0) {
01126             __xmlIOErr(XML_FROM_FTP, 0, "send failed");
01127             closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
01128             ctxt->controlFd = INVALID_SOCKET;
01129             return(res);
01130         }
01131         res = xmlNanoFTPGetResponse(ctxt);
01132         if ((res == 1) || (res == 2)) {
01133             /* we assume it worked :-\ */
01134             proxyType = 2;
01135             return(0);
01136         }    
01137         if (ctxt->passwd == NULL)
01138             snprintf(buf, sizeof(buf), "PASS anonymous@\r\n");
01139         else
01140             snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd);
01141                 buf[sizeof(buf) - 1] = 0;
01142                 len = strlen(buf);
01143 #ifdef DEBUG_FTP
01144         xmlGenericError(xmlGenericErrorContext, "%s", buf);
01145 #endif
01146         res = send(ctxt->controlFd, buf, len, 0);
01147         if (res < 0) {
01148             __xmlIOErr(XML_FROM_FTP, 0, "send failed");
01149             closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
01150             ctxt->controlFd = INVALID_SOCKET;
01151             return(res);
01152         }
01153         res = xmlNanoFTPGetResponse(ctxt);
01154         if ((res == 1) || (res == 2)) {
01155             /* we assume it worked :-\ */
01156             proxyType = 2;
01157             return(0);
01158         }
01159         if (proxyType == 2) {
01160             closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
01161             ctxt->controlFd = INVALID_SOCKET;
01162             return(-1);
01163         }
01164         case 3:
01165         /*
01166          * If you need support for other Proxy authentication scheme
01167          * send the code or at least the sequence in use.
01168          */
01169         default:
01170         closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
01171         ctxt->controlFd = INVALID_SOCKET;
01172         return(-1);
01173     }
01174     }
01175     /*
01176      * Non-proxy handling.
01177      */
01178     res = xmlNanoFTPSendUser(ctxt);
01179     if (res < 0) {
01180         closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
01181         ctxt->controlFd = INVALID_SOCKET;
01182     return(-1);
01183     }
01184     res = xmlNanoFTPGetResponse(ctxt);
01185     switch (res) {
01186     case 2:
01187         return(0);
01188     case 3:
01189         break;
01190     case 1:
01191     case 4:
01192     case 5:
01193         case -1:
01194     default:
01195         closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
01196         ctxt->controlFd = INVALID_SOCKET;
01197         return(-1);
01198     }
01199     res = xmlNanoFTPSendPasswd(ctxt);
01200     if (res < 0) {
01201         closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
01202         ctxt->controlFd = INVALID_SOCKET;
01203     return(-1);
01204     }
01205     res = xmlNanoFTPGetResponse(ctxt);
01206     switch (res) {
01207     case 2:
01208         break;
01209     case 3:
01210         __xmlIOErr(XML_FROM_FTP, XML_FTP_ACCNT,
01211                "FTP server asking for ACCNT on anonymous\n");
01212     case 1:
01213     case 4:
01214     case 5:
01215         case -1:
01216     default:
01217         closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
01218         ctxt->controlFd = INVALID_SOCKET;
01219         return(-1);
01220     }
01221 
01222     return(0);
01223 }
01224 
01235 void*
01236 xmlNanoFTPConnectTo(const char *server, int port) {
01237     xmlNanoFTPCtxtPtr ctxt;
01238     int res;
01239 
01240     xmlNanoFTPInit();
01241     if (server == NULL) 
01242     return(NULL);
01243     if (port <= 0)
01244     return(NULL);
01245     ctxt = (xmlNanoFTPCtxtPtr) xmlNanoFTPNewCtxt(NULL);
01246     ctxt->hostname = xmlMemStrdup(server);
01247     if (port != 0)
01248     ctxt->port = port;
01249     res = xmlNanoFTPConnect(ctxt);
01250     if (res < 0) {
01251     xmlNanoFTPFreeCtxt(ctxt);
01252     return(NULL);
01253     }
01254     return(ctxt);
01255 }
01256 
01267 int
01268 xmlNanoFTPCwd(void *ctx, const char *directory) {
01269     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
01270     char buf[400];
01271     int len;
01272     int res;
01273 
01274     if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1);
01275     if (directory == NULL) return 0;
01276 
01277     /*
01278      * Expected response code for CWD:
01279      *
01280      * CWD
01281      *     250
01282      *     500, 501, 502, 421, 530, 550
01283      */
01284     snprintf(buf, sizeof(buf), "CWD %s\r\n", directory);
01285     buf[sizeof(buf) - 1] = 0;
01286     len = strlen(buf);
01287 #ifdef DEBUG_FTP
01288     xmlGenericError(xmlGenericErrorContext, "%s", buf);
01289 #endif
01290     res = send(ctxt->controlFd, buf, len, 0);
01291     if (res < 0) {
01292     __xmlIOErr(XML_FROM_FTP, 0, "send failed");
01293     return(res);
01294     }
01295     res = xmlNanoFTPGetResponse(ctxt);
01296     if (res == 4) {
01297     return(-1);
01298     }
01299     if (res == 2) return(1);
01300     if (res == 5) {
01301     return(0);
01302     }
01303     return(0);
01304 }
01305 
01316 int
01317 xmlNanoFTPDele(void *ctx, const char *file) {
01318     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
01319     char buf[400];
01320     int len;
01321     int res;
01322 
01323     if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET) || (file == NULL)) return(-1);
01324     if (file == NULL) return (0);
01325 
01326     /*
01327      * Expected response code for DELE:
01328      *
01329      * DELE
01330      *       250
01331      *       450, 550
01332      *       500, 501, 502, 421, 530
01333      */
01334      
01335     snprintf(buf, sizeof(buf), "DELE %s\r\n", file);
01336     buf[sizeof(buf) - 1] = 0;
01337     len = strlen(buf);
01338 #ifdef DEBUG_FTP
01339     xmlGenericError(xmlGenericErrorContext, "%s", buf);
01340 #endif
01341     res = send(ctxt->controlFd, buf, len, 0);
01342     if (res < 0) {
01343     __xmlIOErr(XML_FROM_FTP, 0, "send failed");
01344     return(res);
01345     }
01346     res = xmlNanoFTPGetResponse(ctxt);
01347     if (res == 4) {
01348     return(-1);
01349     }
01350     if (res == 2) return(1);
01351     if (res == 5) {
01352     return(0);
01353     }
01354     return(0);
01355 }
01366 SOCKET
01367 xmlNanoFTPGetConnection(void *ctx) {
01368     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
01369     char buf[200], *cur;
01370     int len, i;
01371     int res;
01372     unsigned char ad[6], *adp, *portp;
01373     unsigned int temp[6];
01374 #ifdef SUPPORT_IP6
01375     struct sockaddr_storage dataAddr;
01376 #else
01377     struct sockaddr_in dataAddr;
01378 #endif
01379     XML_SOCKLEN_T dataAddrLen;
01380 
01381     if (ctxt == NULL) return INVALID_SOCKET;
01382 
01383     memset (&dataAddr, 0, sizeof(dataAddr));
01384 #ifdef SUPPORT_IP6
01385     if ((ctxt->ftpAddr).ss_family == AF_INET6) {
01386     ctxt->dataFd = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP);
01387     ((struct sockaddr_in6 *)&dataAddr)->sin6_family = AF_INET6;
01388     dataAddrLen = sizeof(struct sockaddr_in6);
01389     } else
01390 #endif
01391     {
01392     ctxt->dataFd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
01393     ((struct sockaddr_in *)&dataAddr)->sin_family = AF_INET;
01394     dataAddrLen = sizeof (struct sockaddr_in);
01395     }
01396 
01397     if (ctxt->dataFd == INVALID_SOCKET) {
01398     __xmlIOErr(XML_FROM_FTP, 0, "socket failed");
01399     return INVALID_SOCKET;
01400     }
01401 
01402     if (ctxt->passive) {
01403 #ifdef SUPPORT_IP6
01404     if ((ctxt->ftpAddr).ss_family == AF_INET6)
01405         snprintf (buf, sizeof(buf), "EPSV\r\n");
01406     else
01407 #endif
01408         snprintf (buf, sizeof(buf), "PASV\r\n");
01409         len = strlen (buf);
01410 #ifdef DEBUG_FTP
01411     xmlGenericError(xmlGenericErrorContext, "%s", buf);
01412 #endif
01413     res = send(ctxt->controlFd, buf, len, 0);
01414     if (res < 0) {
01415         __xmlIOErr(XML_FROM_FTP, 0, "send failed");
01416         closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
01417         return INVALID_SOCKET;
01418     }
01419         res = xmlNanoFTPReadResponse(ctx);
01420     if (res != 2) {
01421         if (res == 5) {
01422             closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
01423         return INVALID_SOCKET;
01424         } else {
01425         /*
01426          * retry with an active connection
01427          */
01428             closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
01429             ctxt->passive = 0;
01430         }
01431     }
01432     cur = &ctxt->controlBuf[ctxt->controlBufAnswer]; 
01433     while (((*cur < '0') || (*cur > '9')) && *cur != '\0') cur++;
01434 #ifdef SUPPORT_IP6
01435     if ((ctxt->ftpAddr).ss_family == AF_INET6) {
01436         if (sscanf (cur, "%u", &temp[0]) != 1) {
01437         __xmlIOErr(XML_FROM_FTP, XML_FTP_EPSV_ANSWER,
01438             "Invalid answer to EPSV\n");
01439         if (ctxt->dataFd != INVALID_SOCKET) {
01440             closesocket (ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
01441         }
01442         return INVALID_SOCKET;
01443         }
01444         memcpy (&((struct sockaddr_in6 *)&dataAddr)->sin6_addr, &((struct sockaddr_in6 *)&ctxt->ftpAddr)->sin6_addr, sizeof(struct in6_addr));
01445         ((struct sockaddr_in6 *)&dataAddr)->sin6_port = htons (temp[0]);
01446     }
01447     else
01448 #endif
01449     {
01450         if (sscanf (cur, "%u,%u,%u,%u,%u,%u", &temp[0], &temp[1], &temp[2],
01451         &temp[3], &temp[4], &temp[5]) != 6) {
01452         __xmlIOErr(XML_FROM_FTP, XML_FTP_PASV_ANSWER,
01453             "Invalid answer to PASV\n");
01454         if (ctxt->dataFd != INVALID_SOCKET) {
01455             closesocket (ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
01456         }
01457         return INVALID_SOCKET;
01458         }
01459         for (i=0; i<6; i++) ad[i] = (unsigned char) (temp[i] & 0xff);
01460         memcpy (&((struct sockaddr_in *)&dataAddr)->sin_addr, &ad[0], 4);
01461         memcpy (&((struct sockaddr_in *)&dataAddr)->sin_port, &ad[4], 2);
01462     }
01463 
01464     if (connect(ctxt->dataFd, (struct sockaddr *) &dataAddr, dataAddrLen) < 0) {
01465         __xmlIOErr(XML_FROM_FTP, 0, "Failed to create a data connection");
01466         closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
01467         return INVALID_SOCKET;
01468     }
01469     } else {
01470         getsockname(ctxt->dataFd, (struct sockaddr *) &dataAddr, &dataAddrLen);
01471 #ifdef SUPPORT_IP6
01472     if ((ctxt->ftpAddr).ss_family == AF_INET6)
01473         ((struct sockaddr_in6 *)&dataAddr)->sin6_port = 0;
01474     else
01475 #endif
01476         ((struct sockaddr_in *)&dataAddr)->sin_port = 0;
01477 
01478     if (bind(ctxt->dataFd, (struct sockaddr *) &dataAddr, dataAddrLen) < 0) {
01479         __xmlIOErr(XML_FROM_FTP, 0, "bind failed");
01480         closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
01481         return INVALID_SOCKET;
01482     }
01483         getsockname(ctxt->dataFd, (struct sockaddr *) &dataAddr, &dataAddrLen);
01484 
01485     if (listen(ctxt->dataFd, 1) < 0) {
01486         __xmlIOErr(XML_FROM_FTP, 0, "listen failed");
01487         closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
01488         return INVALID_SOCKET;
01489     }
01490 #ifdef SUPPORT_IP6
01491     if ((ctxt->ftpAddr).ss_family == AF_INET6) {
01492         char buf6[INET6_ADDRSTRLEN];
01493         inet_ntop (AF_INET6, &((struct sockaddr_in6 *)&dataAddr)->sin6_addr,
01494             buf6, INET6_ADDRSTRLEN);
01495         adp = (unsigned char *) buf6;
01496         portp = (unsigned char *) &((struct sockaddr_in6 *)&dataAddr)->sin6_port;
01497         snprintf (buf, sizeof(buf), "EPRT |2|%s|%s|\r\n", adp, portp);
01498         } else
01499 #endif
01500     {
01501         adp = (unsigned char *) &((struct sockaddr_in *)&dataAddr)->sin_addr;
01502         portp = (unsigned char *) &((struct sockaddr_in *)&dataAddr)->sin_port;
01503         snprintf (buf, sizeof(buf), "PORT %d,%d,%d,%d,%d,%d\r\n",
01504         adp[0] & 0xff, adp[1] & 0xff, adp[2] & 0xff, adp[3] & 0xff,
01505         portp[0] & 0xff, portp[1] & 0xff);
01506     }
01507 
01508         buf[sizeof(buf) - 1] = 0;
01509         len = strlen(buf);
01510 #ifdef DEBUG_FTP
01511     xmlGenericError(xmlGenericErrorContext, "%s", buf);
01512 #endif
01513 
01514     res = send(ctxt->controlFd, buf, len, 0);
01515     if (res < 0) {
01516         __xmlIOErr(XML_FROM_FTP, 0, "send failed");
01517         closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
01518         return INVALID_SOCKET;
01519     }
01520         res = xmlNanoFTPGetResponse(ctxt);
01521     if (res != 2) {
01522         closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
01523         return INVALID_SOCKET;
01524         }
01525     }
01526     return(ctxt->dataFd);
01527     
01528 }
01529 
01539 int
01540 xmlNanoFTPCloseConnection(void *ctx) {
01541     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
01542     int res;
01543     fd_set rfd, efd;
01544     struct timeval tv;
01545 
01546     if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1);
01547 
01548     closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
01549     tv.tv_sec = 15;
01550     tv.tv_usec = 0;
01551     FD_ZERO(&rfd);
01552     FD_SET(ctxt->controlFd, &rfd);
01553     FD_ZERO(&efd);
01554     FD_SET(ctxt->controlFd, &efd);
01555     res = select(ctxt->controlFd + 1, &rfd, NULL, &efd, &tv);
01556     if (res < 0) {
01557 #ifdef DEBUG_FTP
01558     perror("select");
01559 #endif
01560     closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
01561     return(-1);
01562     }
01563     if (res == 0) {
01564 #ifdef DEBUG_FTP
01565     xmlGenericError(xmlGenericErrorContext,
01566         "xmlNanoFTPCloseConnection: timeout\n");
01567 #endif
01568     closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
01569     } else {
01570     res = xmlNanoFTPGetResponse(ctxt);
01571     if (res != 2) {
01572         closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
01573         return(-1);
01574     }
01575     }
01576     return(0);
01577 }
01578 
01590 static int
01591 xmlNanoFTPParseList(const char *list, ftpListCallback callback, void *userData) {
01592     const char *cur = list;
01593     char filename[151];
01594     char attrib[11];
01595     char owner[11];
01596     char group[11];
01597     char month[4];
01598     int year = 0;
01599     int minute = 0;
01600     int hour = 0;
01601     int day = 0;
01602     unsigned long size = 0;
01603     int links = 0;
01604     int i;
01605 
01606     if (!strncmp(cur, "total", 5)) {
01607         cur += 5;
01608     while (*cur == ' ') cur++;
01609     while ((*cur >= '0') && (*cur <= '9'))
01610         links = (links * 10) + (*cur++ - '0');
01611     while ((*cur == ' ') || (*cur == '\n')  || (*cur == '\r'))
01612         cur++;
01613     return(cur - list);
01614     } else if (*list == '+') {
01615     return(0);
01616     } else {
01617     while ((*cur == ' ') || (*cur == '\n')  || (*cur == '\r'))
01618         cur++;
01619     if (*cur == 0) return(0);
01620     i = 0;
01621     while (*cur != ' ') {
01622         if (i < 10) 
01623         attrib[i++] = *cur;
01624         cur++;
01625         if (*cur == 0) return(0);
01626     }
01627     attrib[10] = 0;
01628     while (*cur == ' ') cur++;
01629     if (*cur == 0) return(0);
01630     while ((*cur >= '0') && (*cur <= '9'))
01631         links = (links * 10) + (*cur++ - '0');
01632     while (*cur == ' ') cur++;
01633     if (*cur == 0) return(0);
01634     i = 0;
01635     while (*cur != ' ') {
01636         if (i < 10) 
01637         owner[i++] = *cur;
01638         cur++;
01639         if (*cur == 0) return(0);
01640     }
01641     owner[i] = 0;
01642     while (*cur == ' ') cur++;
01643     if (*cur == 0) return(0);
01644     i = 0;
01645     while (*cur != ' ') {
01646         if (i < 10) 
01647         group[i++] = *cur;
01648         cur++;
01649         if (*cur == 0) return(0);
01650     }
01651     group[i] = 0;
01652     while (*cur == ' ') cur++;
01653     if (*cur == 0) return(0);
01654     while ((*cur >= '0') && (*cur <= '9'))
01655         size = (size * 10) + (*cur++ - '0');
01656     while (*cur == ' ') cur++;
01657     if (*cur == 0) return(0);
01658     i = 0;
01659     while (*cur != ' ') {
01660         if (i < 3)
01661         month[i++] = *cur;
01662         cur++;
01663         if (*cur == 0) return(0);
01664     }
01665     month[i] = 0;
01666     while (*cur == ' ') cur++;
01667     if (*cur == 0) return(0);
01668         while ((*cur >= '0') && (*cur <= '9'))
01669         day = (day * 10) + (*cur++ - '0');
01670     while (*cur == ' ') cur++;
01671     if (*cur == 0) return(0);
01672     if ((cur[1] == 0) || (cur[2] == 0)) return(0);
01673     if ((cur[1] == ':') || (cur[2] == ':')) {
01674         while ((*cur >= '0') && (*cur <= '9'))
01675         hour = (hour * 10) + (*cur++ - '0');
01676         if (*cur == ':') cur++;
01677         while ((*cur >= '0') && (*cur <= '9'))
01678         minute = (minute * 10) + (*cur++ - '0');
01679     } else {
01680         while ((*cur >= '0') && (*cur <= '9'))
01681         year = (year * 10) + (*cur++ - '0');
01682     }
01683     while (*cur == ' ') cur++;
01684     if (*cur == 0) return(0);
01685     i = 0;
01686     while ((*cur != '\n')  && (*cur != '\r')) {
01687         if (i < 150)
01688         filename[i++] = *cur;
01689         cur++;
01690         if (*cur == 0) return(0);
01691     }
01692     filename[i] = 0;
01693     if ((*cur != '\n') && (*cur != '\r'))
01694         return(0);
01695     while ((*cur == '\n')  || (*cur == '\r'))
01696         cur++;
01697     }
01698     if (callback != NULL) {
01699         callback(userData, filename, attrib, owner, group, size, links,
01700          year, month, day, hour, minute);
01701     }
01702     return(cur - list);
01703 }
01704 
01718 int
01719 xmlNanoFTPList(void *ctx, ftpListCallback callback, void *userData,
01720            const char *filename) {
01721     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
01722     char buf[4096 + 1];
01723     int len, res;
01724     int indx = 0, base;
01725     fd_set rfd, efd;
01726     struct timeval tv;
01727 
01728     if (ctxt == NULL) return (-1);
01729     if (filename == NULL) {
01730         if (xmlNanoFTPCwd(ctxt, ctxt->path) < 1)
01731         return(-1);
01732     ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
01733     if (ctxt->dataFd == INVALID_SOCKET)
01734         return(-1);
01735     snprintf(buf, sizeof(buf), "LIST -L\r\n");
01736     } else {
01737     if (filename[0] != '/') {
01738         if (xmlNanoFTPCwd(ctxt, ctxt->path) < 1)
01739         return(-1);
01740     }
01741     ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
01742     if (ctxt->dataFd == INVALID_SOCKET)
01743         return(-1);
01744     snprintf(buf, sizeof(buf), "LIST -L %s\r\n", filename);
01745     }
01746     buf[sizeof(buf) - 1] = 0;
01747     len = strlen(buf);
01748 #ifdef DEBUG_FTP
01749     xmlGenericError(xmlGenericErrorContext, "%s", buf);
01750 #endif
01751     res = send(ctxt->controlFd, buf, len, 0);
01752     if (res < 0) {
01753     __xmlIOErr(XML_FROM_FTP, 0, "send failed");
01754     closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
01755     return(res);
01756     }
01757     res = xmlNanoFTPReadResponse(ctxt);
01758     if (res != 1) {
01759     closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
01760     return(-res);
01761     }
01762 
01763     do {
01764     tv.tv_sec = 1;
01765     tv.tv_usec = 0;
01766     FD_ZERO(&rfd);
01767     FD_SET(ctxt->dataFd, &rfd);
01768     FD_ZERO(&efd);
01769     FD_SET(ctxt->dataFd, &efd);
01770     res = select(ctxt->dataFd + 1, &rfd, NULL, &efd, &tv);
01771     if (res < 0) {
01772 #ifdef DEBUG_FTP
01773         perror("select");
01774 #endif
01775         closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
01776         return(-1);
01777     }
01778     if (res == 0) {
01779         res = xmlNanoFTPCheckResponse(ctxt);
01780         if (res < 0) {
01781         closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
01782         ctxt->dataFd = INVALID_SOCKET;
01783         return(-1);
01784         }
01785         if (res == 2) {
01786         closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
01787         return(0);
01788         }
01789 
01790         continue;
01791     }
01792 
01793     if ((len = recv(ctxt->dataFd, &buf[indx], sizeof(buf) - (indx + 1), 0)) < 0) {
01794         __xmlIOErr(XML_FROM_FTP, 0, "recv");
01795         closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
01796         ctxt->dataFd = INVALID_SOCKET;
01797         return(-1);
01798     }
01799 #ifdef DEBUG_FTP
01800         write(1, &buf[indx], len);
01801 #endif
01802     indx += len;
01803     buf[indx] = 0;
01804     base = 0;
01805     do {
01806         res = xmlNanoFTPParseList(&buf[base], callback, userData);
01807         base += res;
01808     } while (res > 0);
01809 
01810     memmove(&buf[0], &buf[base], indx - base);
01811     indx -= base;
01812     } while (len != 0);
01813     xmlNanoFTPCloseConnection(ctxt);
01814     return(0);
01815 }
01816 
01828 SOCKET
01829 xmlNanoFTPGetSocket(void *ctx, const char *filename) {
01830     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
01831     char buf[300];
01832     int res, len;
01833     if (ctx == NULL)
01834     return INVALID_SOCKET;
01835     if ((filename == NULL) && (ctxt->path == NULL))
01836     return INVALID_SOCKET;
01837     ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
01838     if (ctxt->dataFd == INVALID_SOCKET)
01839     return INVALID_SOCKET;
01840 
01841     snprintf(buf, sizeof(buf), "TYPE I\r\n");
01842     len = strlen(buf);
01843 #ifdef DEBUG_FTP
01844     xmlGenericError(xmlGenericErrorContext, "%s", buf);
01845 #endif
01846     res = send(ctxt->controlFd, buf, len, 0);
01847     if (res < 0) {
01848     __xmlIOErr(XML_FROM_FTP, 0, "send failed");
01849     closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
01850     return INVALID_SOCKET;
01851     }
01852     res = xmlNanoFTPReadResponse(ctxt);
01853     if (res != 2) {
01854     closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
01855     return INVALID_SOCKET;
01856     }
01857     if (filename == NULL)
01858     snprintf(buf, sizeof(buf), "RETR %s\r\n", ctxt->path);
01859     else
01860     snprintf(buf, sizeof(buf), "RETR %s\r\n", filename);
01861     buf[sizeof(buf) - 1] = 0;
01862     len = strlen(buf);
01863 #ifdef DEBUG_FTP
01864     xmlGenericError(xmlGenericErrorContext, "%s", buf);
01865 #endif
01866     res = send(ctxt->controlFd, buf, len, 0);
01867     if (res < 0) {
01868     __xmlIOErr(XML_FROM_FTP, 0, "send failed");
01869     closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
01870     return INVALID_SOCKET;
01871     }
01872     res = xmlNanoFTPReadResponse(ctxt);
01873     if (res != 1) {
01874     closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
01875     return INVALID_SOCKET;
01876     }
01877     return(ctxt->dataFd);
01878 }
01879 
01893 int
01894 xmlNanoFTPGet(void *ctx, ftpDataCallback callback, void *userData,
01895           const char *filename) {
01896     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
01897     char buf[4096];
01898     int len = 0, res;
01899     fd_set rfd;
01900     struct timeval tv;
01901 
01902     if (ctxt == NULL) return(-1);
01903     if ((filename == NULL) && (ctxt->path == NULL))
01904     return(-1);
01905     if (callback == NULL)
01906     return(-1);
01907     if (xmlNanoFTPGetSocket(ctxt, filename) == INVALID_SOCKET)
01908     return(-1);
01909 
01910     do {
01911     tv.tv_sec = 1;
01912     tv.tv_usec = 0;
01913     FD_ZERO(&rfd);
01914     FD_SET(ctxt->dataFd, &rfd);
01915     res = select(ctxt->dataFd + 1, &rfd, NULL, NULL, &tv);
01916     if (res < 0) {
01917 #ifdef DEBUG_FTP
01918         perror("select");
01919 #endif
01920         closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
01921         return(-1);
01922     }
01923     if (res == 0) {
01924         res = xmlNanoFTPCheckResponse(ctxt);
01925         if (res < 0) {
01926         closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
01927         ctxt->dataFd = INVALID_SOCKET;
01928         return(-1);
01929         }
01930         if (res == 2) {
01931         closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
01932         return(0);
01933         }
01934 
01935         continue;
01936     }
01937     if ((len = recv(ctxt->dataFd, buf, sizeof(buf), 0)) < 0) {
01938         __xmlIOErr(XML_FROM_FTP, 0, "recv failed");
01939         callback(userData, buf, len);
01940         closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
01941         return(-1);
01942     }
01943     callback(userData, buf, len);
01944     } while (len != 0);
01945 
01946     return(xmlNanoFTPCloseConnection(ctxt));
01947 }
01948 
01961 int
01962 xmlNanoFTPRead(void *ctx, void *dest, int len) {
01963     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
01964 
01965     if (ctx == NULL) return(-1);
01966     if (ctxt->dataFd == INVALID_SOCKET) return(0);
01967     if (dest == NULL) return(-1);
01968     if (len <= 0) return(0);
01969 
01970     len = recv(ctxt->dataFd, dest, len, 0);
01971     if (len <= 0) {
01972     if (len < 0)
01973         __xmlIOErr(XML_FROM_FTP, 0, "recv failed");
01974     xmlNanoFTPCloseConnection(ctxt);
01975     }
01976 #ifdef DEBUG_FTP
01977     xmlGenericError(xmlGenericErrorContext, "Recvd %d bytes\n", len);
01978 #endif
01979     return(len);
01980 }
01981 
01991 void*
01992 xmlNanoFTPOpen(const char *URL) {
01993     xmlNanoFTPCtxtPtr ctxt;
01994     SOCKET sock;
01995 
01996     xmlNanoFTPInit();
01997     if (URL == NULL) return(NULL);
01998     if (strncmp("ftp://", URL, 6)) return(NULL);
01999 
02000     ctxt = (xmlNanoFTPCtxtPtr) xmlNanoFTPNewCtxt(URL);
02001     if (ctxt == NULL) return(NULL);
02002     if (xmlNanoFTPConnect(ctxt) < 0) {
02003     xmlNanoFTPFreeCtxt(ctxt);
02004     return(NULL);
02005     }
02006     sock = xmlNanoFTPGetSocket(ctxt, ctxt->path);
02007     if (sock == INVALID_SOCKET) {
02008     xmlNanoFTPFreeCtxt(ctxt);
02009     return(NULL);
02010     }
02011     return(ctxt);
02012 }
02013 
02023 int
02024 xmlNanoFTPClose(void *ctx) {
02025     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
02026 
02027     if (ctxt == NULL)
02028     return(-1);
02029 
02030     if (ctxt->dataFd != INVALID_SOCKET) {
02031     closesocket(ctxt->dataFd);
02032     ctxt->dataFd = INVALID_SOCKET;
02033     }
02034     if (ctxt->controlFd != INVALID_SOCKET) {
02035     xmlNanoFTPQuit(ctxt);
02036     closesocket(ctxt->controlFd);
02037     ctxt->controlFd = INVALID_SOCKET;
02038     }
02039     xmlNanoFTPFreeCtxt(ctxt);
02040     return(0);
02041 }
02042 
02043 #ifdef STANDALONE
02044 /************************************************************************
02045  *                                  *
02046  *          Basic test in Standalone mode           *
02047  *                                  *
02048  ************************************************************************/
02049 static
02050 void ftpList(void *userData, const char *filename, const char* attrib,
02051          const char *owner, const char *group, unsigned long size, int links,
02052          int year, const char *month, int day, int hour, int minute) {
02053     xmlGenericError(xmlGenericErrorContext,
02054         "%s %s %s %ld %s\n", attrib, owner, group, size, filename);
02055 }
02056 static
02057 void ftpData(void *userData, const char *data, int len) {
02058     if (userData == NULL) return;
02059     if (len <= 0) {
02060     fclose((FILE*)userData);
02061     return;
02062     }   
02063     fwrite(data, len, 1, (FILE*)userData);
02064 }
02065 
02066 int main(int argc, char **argv) {
02067     void *ctxt;
02068     FILE *output;
02069     char *tstfile = NULL;
02070 
02071     xmlNanoFTPInit();
02072     if (argc > 1) {
02073     ctxt = xmlNanoFTPNewCtxt(argv[1]);
02074     if (xmlNanoFTPConnect(ctxt) < 0) {
02075         xmlGenericError(xmlGenericErrorContext,
02076             "Couldn't connect to %s\n", argv[1]);
02077         exit(1);
02078     }
02079     if (argc > 2)
02080         tstfile = argv[2];
02081     } else
02082     ctxt = xmlNanoFTPConnectTo("localhost", 0);
02083     if (ctxt == NULL) {
02084         xmlGenericError(xmlGenericErrorContext,
02085         "Couldn't connect to localhost\n");
02086         exit(1);
02087     }
02088     xmlNanoFTPList(ctxt, ftpList, NULL, tstfile);
02089     output = fopen("/tmp/tstdata", "w");
02090     if (output != NULL) {
02091     if (xmlNanoFTPGet(ctxt, ftpData, (void *) output, tstfile) < 0)
02092         xmlGenericError(xmlGenericErrorContext,
02093             "Failed to get file\n");
02094     
02095     }
02096     xmlNanoFTPClose(ctxt);
02097     xmlMemoryDump();
02098     exit(0);
02099 }
02100 #endif /* STANDALONE */
02101 #else /* !LIBXML_FTP_ENABLED */
02102 #ifdef STANDALONE
02103 #include <stdio.h>
02104 int main(int argc, char **argv) {
02105     xmlGenericError(xmlGenericErrorContext,
02106         "%s : FTP support not compiled in\n", argv[0]);
02107     return(0);
02108 }
02109 #endif /* STANDALONE */
02110 #endif /* LIBXML_FTP_ENABLED */
02111 #define bottom_nanoftp
02112 #include "elfgcchack.h"

Generated on Sat May 26 2012 04:33:19 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.