Annotation of embedaddon/libxml2/nanoftp.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * nanoftp.c: basic FTP client support
        !             3:  *
        !             4:  *  Reference: RFC 959
        !             5:  */
        !             6: 
        !             7: #ifdef TESTING
        !             8: #define STANDALONE
        !             9: #define HAVE_STDLIB_H
        !            10: #define HAVE_UNISTD_H
        !            11: #define HAVE_SYS_SOCKET_H
        !            12: #define HAVE_NETINET_IN_H
        !            13: #define HAVE_NETDB_H
        !            14: #define HAVE_SYS_TIME_H
        !            15: #else /* TESTING */
        !            16: #define NEED_SOCKETS
        !            17: #endif /* TESTING */
        !            18: 
        !            19: #define IN_LIBXML
        !            20: #include "libxml.h"
        !            21: 
        !            22: #ifdef LIBXML_FTP_ENABLED
        !            23: #include <string.h>
        !            24: 
        !            25: #ifdef HAVE_STDLIB_H
        !            26: #include <stdlib.h>
        !            27: #endif
        !            28: #ifdef HAVE_UNISTD_H
        !            29: #include <unistd.h>
        !            30: #endif
        !            31: #ifdef HAVE_SYS_SOCKET_H
        !            32: #include <sys/socket.h>
        !            33: #endif
        !            34: #ifdef HAVE_NETINET_IN_H
        !            35: #include <netinet/in.h>
        !            36: #endif
        !            37: #ifdef HAVE_ARPA_INET_H
        !            38: #include <arpa/inet.h>
        !            39: #endif
        !            40: #ifdef HAVE_NETDB_H
        !            41: #include <netdb.h>
        !            42: #endif
        !            43: #ifdef HAVE_FCNTL_H
        !            44: #include <fcntl.h> 
        !            45: #endif
        !            46: #ifdef HAVE_ERRNO_H
        !            47: #include <errno.h>
        !            48: #endif
        !            49: #ifdef HAVE_SYS_TIME_H
        !            50: #include <sys/time.h>
        !            51: #endif
        !            52: #ifdef HAVE_SYS_SELECT_H
        !            53: #include <sys/select.h>
        !            54: #endif
        !            55: #ifdef HAVE_SYS_SOCKET_H
        !            56: #include <sys/socket.h>
        !            57: #endif
        !            58: #ifdef HAVE_SYS_TYPES_H
        !            59: #include <sys/types.h>
        !            60: #endif
        !            61: #ifdef HAVE_STRINGS_H
        !            62: #include <strings.h>
        !            63: #endif
        !            64: 
        !            65: #include <libxml/xmlmemory.h>
        !            66: #include <libxml/parser.h>
        !            67: #include <libxml/xmlerror.h>
        !            68: #include <libxml/uri.h>
        !            69: #include <libxml/nanoftp.h>
        !            70: #include <libxml/globals.h>
        !            71: 
        !            72: /* #define DEBUG_FTP 1  */
        !            73: #ifdef STANDALONE
        !            74: #ifndef DEBUG_FTP
        !            75: #define DEBUG_FTP 1
        !            76: #endif
        !            77: #endif
        !            78: 
        !            79: 
        !            80: #if defined(__MINGW32__) || defined(_WIN32_WCE)
        !            81: #ifndef _WINSOCKAPI_
        !            82: #define _WINSOCKAPI_
        !            83: #endif
        !            84: #include <wsockcompat.h>
        !            85: #include <winsock2.h>
        !            86: #undef XML_SOCKLEN_T
        !            87: #define XML_SOCKLEN_T unsigned int
        !            88: #endif
        !            89: 
        !            90: /**
        !            91:  * A couple portability macros
        !            92:  */
        !            93: #ifndef _WINSOCKAPI_
        !            94: #if !defined(__BEOS__) || defined(__HAIKU__)
        !            95: #define closesocket(s) close(s)
        !            96: #endif
        !            97: #endif
        !            98: 
        !            99: #ifdef __BEOS__
        !           100: #ifndef PF_INET
        !           101: #define PF_INET AF_INET
        !           102: #endif
        !           103: #endif
        !           104: 
        !           105: #ifdef _AIX
        !           106: #ifdef HAVE_BROKEN_SS_FAMILY
        !           107: #define ss_family __ss_family
        !           108: #endif
        !           109: #endif
        !           110: 
        !           111: #ifndef XML_SOCKLEN_T
        !           112: #define XML_SOCKLEN_T unsigned int
        !           113: #endif
        !           114: 
        !           115: #define FTP_COMMAND_OK         200
        !           116: #define FTP_SYNTAX_ERROR       500
        !           117: #define FTP_GET_PASSWD         331
        !           118: #define FTP_BUF_SIZE           1024
        !           119: 
        !           120: #define XML_NANO_MAX_URLBUF    4096
        !           121: 
        !           122: typedef struct xmlNanoFTPCtxt {
        !           123:     char *protocol;    /* the protocol name */
        !           124:     char *hostname;    /* the host name */
        !           125:     int port;          /* the port */
        !           126:     char *path;                /* the path within the URL */
        !           127:     char *user;                /* user string */
        !           128:     char *passwd;      /* passwd string */
        !           129: #ifdef SUPPORT_IP6
        !           130:     struct sockaddr_storage ftpAddr; /* this is large enough to hold IPv6 address*/
        !           131: #else
        !           132:     struct sockaddr_in ftpAddr; /* the socket address struct */
        !           133: #endif
        !           134:     int passive;       /* currently we support only passive !!! */
        !           135:     SOCKET controlFd;  /* the file descriptor for the control socket */
        !           136:     SOCKET dataFd;     /* the file descriptor for the data socket */
        !           137:     int state;         /* WRITE / READ / CLOSED */
        !           138:     int returnValue;   /* the protocol return value */
        !           139:     /* buffer for data received from the control connection */
        !           140:     char controlBuf[FTP_BUF_SIZE + 1];
        !           141:     int controlBufIndex;
        !           142:     int controlBufUsed;
        !           143:     int controlBufAnswer;
        !           144: } xmlNanoFTPCtxt, *xmlNanoFTPCtxtPtr;
        !           145: 
        !           146: static int initialized = 0;
        !           147: static char *proxy = NULL;     /* the proxy name if any */
        !           148: static int proxyPort = 0;      /* the proxy port if any */
        !           149: static char *proxyUser = NULL; /* user for proxy authentication */
        !           150: static char *proxyPasswd = NULL;/* passwd for proxy authentication */
        !           151: static int proxyType = 0;      /* uses TYPE or a@b ? */
        !           152: 
        !           153: #ifdef SUPPORT_IP6
        !           154: static
        !           155: int have_ipv6(void) {
        !           156:     int s;
        !           157: 
        !           158:     s = socket (AF_INET6, SOCK_STREAM, 0);
        !           159:     if (s != -1) {
        !           160:        close (s);
        !           161:        return (1);
        !           162:     }
        !           163:     return (0);
        !           164: }
        !           165: #endif
        !           166: 
        !           167: /**
        !           168:  * xmlFTPErrMemory:
        !           169:  * @extra:  extra informations
        !           170:  *
        !           171:  * Handle an out of memory condition
        !           172:  */
        !           173: static void
        !           174: xmlFTPErrMemory(const char *extra)
        !           175: {
        !           176:     __xmlSimpleError(XML_FROM_FTP, XML_ERR_NO_MEMORY, NULL, NULL, extra);
        !           177: }
        !           178: 
        !           179: /**
        !           180:  * xmlNanoFTPInit:
        !           181:  *
        !           182:  * Initialize the FTP protocol layer.
        !           183:  * Currently it just checks for proxy informations,
        !           184:  * and get the hostname
        !           185:  */
        !           186: 
        !           187: void
        !           188: xmlNanoFTPInit(void) {
        !           189:     const char *env;
        !           190: #ifdef _WINSOCKAPI_
        !           191:     WSADATA wsaData;    
        !           192: #endif
        !           193: 
        !           194:     if (initialized)
        !           195:        return;
        !           196: 
        !           197: #ifdef _WINSOCKAPI_
        !           198:     if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
        !           199:        return;
        !           200: #endif
        !           201: 
        !           202:     proxyPort = 21;
        !           203:     env = getenv("no_proxy");
        !           204:     if (env && ((env[0] == '*' ) && (env[1] == 0)))
        !           205:        return;
        !           206:     env = getenv("ftp_proxy");
        !           207:     if (env != NULL) {
        !           208:        xmlNanoFTPScanProxy(env);
        !           209:     } else {
        !           210:        env = getenv("FTP_PROXY");
        !           211:        if (env != NULL) {
        !           212:            xmlNanoFTPScanProxy(env);
        !           213:        }
        !           214:     }
        !           215:     env = getenv("ftp_proxy_user");
        !           216:     if (env != NULL) {
        !           217:        proxyUser = xmlMemStrdup(env);
        !           218:     }
        !           219:     env = getenv("ftp_proxy_password");
        !           220:     if (env != NULL) {
        !           221:        proxyPasswd = xmlMemStrdup(env);
        !           222:     }
        !           223:     initialized = 1;
        !           224: }
        !           225: 
        !           226: /**
        !           227:  * xmlNanoFTPCleanup:
        !           228:  *
        !           229:  * Cleanup the FTP protocol layer. This cleanup proxy informations.
        !           230:  */
        !           231: 
        !           232: void
        !           233: xmlNanoFTPCleanup(void) {
        !           234:     if (proxy != NULL) {
        !           235:        xmlFree(proxy);
        !           236:        proxy = NULL;
        !           237:     }
        !           238:     if (proxyUser != NULL) {
        !           239:        xmlFree(proxyUser);
        !           240:        proxyUser = NULL;
        !           241:     }
        !           242:     if (proxyPasswd != NULL) {
        !           243:        xmlFree(proxyPasswd);
        !           244:        proxyPasswd = NULL;
        !           245:     }
        !           246: #ifdef _WINSOCKAPI_
        !           247:     if (initialized)
        !           248:        WSACleanup();
        !           249: #endif
        !           250:     initialized = 0;
        !           251: }
        !           252: 
        !           253: /**
        !           254:  * xmlNanoFTPProxy:
        !           255:  * @host:  the proxy host name
        !           256:  * @port:  the proxy port
        !           257:  * @user:  the proxy user name
        !           258:  * @passwd:  the proxy password
        !           259:  * @type:  the type of proxy 1 for using SITE, 2 for USER a@b
        !           260:  *
        !           261:  * Setup the FTP proxy informations.
        !           262:  * This can also be done by using ftp_proxy ftp_proxy_user and
        !           263:  * ftp_proxy_password environment variables.
        !           264:  */
        !           265: 
        !           266: void
        !           267: xmlNanoFTPProxy(const char *host, int port, const char *user,
        !           268:                const char *passwd, int type) {
        !           269:     if (proxy != NULL) {
        !           270:        xmlFree(proxy);
        !           271:        proxy = NULL;
        !           272:     }
        !           273:     if (proxyUser != NULL) {
        !           274:        xmlFree(proxyUser);
        !           275:        proxyUser = NULL;
        !           276:     }
        !           277:     if (proxyPasswd != NULL) {
        !           278:        xmlFree(proxyPasswd);
        !           279:        proxyPasswd = NULL;
        !           280:     }
        !           281:     if (host)
        !           282:        proxy = xmlMemStrdup(host);
        !           283:     if (user)
        !           284:        proxyUser = xmlMemStrdup(user);
        !           285:     if (passwd)
        !           286:        proxyPasswd = xmlMemStrdup(passwd);
        !           287:     proxyPort = port;
        !           288:     proxyType = type;
        !           289: }
        !           290: 
        !           291: /**
        !           292:  * xmlNanoFTPScanURL:
        !           293:  * @ctx:  an FTP context
        !           294:  * @URL:  The URL used to initialize the context
        !           295:  *
        !           296:  * (Re)Initialize an FTP context by parsing the URL and finding
        !           297:  * the protocol host port and path it indicates.
        !           298:  */
        !           299: 
        !           300: static void
        !           301: xmlNanoFTPScanURL(void *ctx, const char *URL) {
        !           302:     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
        !           303:     xmlURIPtr uri;
        !           304: 
        !           305:     /*
        !           306:      * Clear any existing data from the context
        !           307:      */
        !           308:     if (ctxt->protocol != NULL) { 
        !           309:         xmlFree(ctxt->protocol);
        !           310:        ctxt->protocol = NULL;
        !           311:     }
        !           312:     if (ctxt->hostname != NULL) { 
        !           313:         xmlFree(ctxt->hostname);
        !           314:        ctxt->hostname = NULL;
        !           315:     }
        !           316:     if (ctxt->path != NULL) { 
        !           317:         xmlFree(ctxt->path);
        !           318:        ctxt->path = NULL;
        !           319:     }
        !           320:     if (URL == NULL) return;
        !           321: 
        !           322:     uri = xmlParseURIRaw(URL, 1);
        !           323:     if (uri == NULL)
        !           324:        return;
        !           325: 
        !           326:     if ((uri->scheme == NULL) || (uri->server == NULL)) {
        !           327:        xmlFreeURI(uri);
        !           328:        return;
        !           329:     }
        !           330:     
        !           331:     ctxt->protocol = xmlMemStrdup(uri->scheme);
        !           332:     ctxt->hostname = xmlMemStrdup(uri->server);
        !           333:     if (uri->path != NULL)
        !           334:        ctxt->path = xmlMemStrdup(uri->path);
        !           335:     else
        !           336:        ctxt->path = xmlMemStrdup("/");
        !           337:     if (uri->port != 0)
        !           338:        ctxt->port = uri->port;
        !           339: 
        !           340:     if (uri->user != NULL) {
        !           341:        char *cptr;
        !           342:        if ((cptr=strchr(uri->user, ':')) == NULL)
        !           343:            ctxt->user = xmlMemStrdup(uri->user);
        !           344:        else {
        !           345:            ctxt->user = (char *)xmlStrndup((xmlChar *)uri->user,
        !           346:                            (cptr - uri->user));
        !           347:            ctxt->passwd = xmlMemStrdup(cptr+1);
        !           348:        }
        !           349:     }
        !           350: 
        !           351:     xmlFreeURI(uri);
        !           352: 
        !           353: }
        !           354: 
        !           355: /**
        !           356:  * xmlNanoFTPUpdateURL:
        !           357:  * @ctx:  an FTP context
        !           358:  * @URL:  The URL used to update the context
        !           359:  *
        !           360:  * Update an FTP context by parsing the URL and finding
        !           361:  * new path it indicates. If there is an error in the 
        !           362:  * protocol, hostname, port or other information, the
        !           363:  * error is raised. It indicates a new connection has to
        !           364:  * be established.
        !           365:  *
        !           366:  * Returns 0 if Ok, -1 in case of error (other host).
        !           367:  */
        !           368: 
        !           369: int
        !           370: xmlNanoFTPUpdateURL(void *ctx, const char *URL) {
        !           371:     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
        !           372:     xmlURIPtr uri;
        !           373: 
        !           374:     if (URL == NULL)
        !           375:        return(-1);
        !           376:     if (ctxt == NULL)
        !           377:        return(-1);
        !           378:     if (ctxt->protocol == NULL)
        !           379:        return(-1);
        !           380:     if (ctxt->hostname == NULL)
        !           381:        return(-1);
        !           382: 
        !           383:     uri = xmlParseURIRaw(URL, 1);
        !           384:     if (uri == NULL)
        !           385:        return(-1);
        !           386: 
        !           387:     if ((uri->scheme == NULL) || (uri->server == NULL)) {
        !           388:        xmlFreeURI(uri);
        !           389:        return(-1);
        !           390:     }
        !           391:     if ((strcmp(ctxt->protocol, uri->scheme)) ||
        !           392:        (strcmp(ctxt->hostname, uri->server)) ||
        !           393:        ((uri->port != 0) && (ctxt->port != uri->port))) {
        !           394:        xmlFreeURI(uri);
        !           395:        return(-1);
        !           396:     }
        !           397: 
        !           398:     if (uri->port != 0)
        !           399:        ctxt->port = uri->port;
        !           400: 
        !           401:     if (ctxt->path != NULL) {
        !           402:        xmlFree(ctxt->path);
        !           403:        ctxt->path = NULL;
        !           404:     }
        !           405: 
        !           406:     if (uri->path == NULL) 
        !           407:         ctxt->path = xmlMemStrdup("/");
        !           408:     else
        !           409:        ctxt->path = xmlMemStrdup(uri->path);
        !           410: 
        !           411:     xmlFreeURI(uri);
        !           412: 
        !           413:     return(0);
        !           414: }
        !           415: 
        !           416: /**
        !           417:  * xmlNanoFTPScanProxy:
        !           418:  * @URL:  The proxy URL used to initialize the proxy context
        !           419:  *
        !           420:  * (Re)Initialize the FTP Proxy context by parsing the URL and finding
        !           421:  * the protocol host port it indicates.
        !           422:  * Should be like ftp://myproxy/ or ftp://myproxy:3128/
        !           423:  * A NULL URL cleans up proxy informations.
        !           424:  */
        !           425: 
        !           426: void
        !           427: xmlNanoFTPScanProxy(const char *URL) {
        !           428:     xmlURIPtr uri;
        !           429: 
        !           430:     if (proxy != NULL) { 
        !           431:         xmlFree(proxy);
        !           432:        proxy = NULL;
        !           433:     }
        !           434:     proxyPort = 0;
        !           435: 
        !           436: #ifdef DEBUG_FTP
        !           437:     if (URL == NULL)
        !           438:        xmlGenericError(xmlGenericErrorContext,
        !           439:                "Removing FTP proxy info\n");
        !           440:     else
        !           441:        xmlGenericError(xmlGenericErrorContext,
        !           442:                "Using FTP proxy %s\n", URL);
        !           443: #endif
        !           444:     if (URL == NULL) return;
        !           445: 
        !           446:     uri = xmlParseURIRaw(URL, 1);
        !           447:     if ((uri == NULL) || (uri->scheme == NULL) ||
        !           448:        (strcmp(uri->scheme, "ftp")) || (uri->server == NULL)) {
        !           449:        __xmlIOErr(XML_FROM_FTP, XML_FTP_URL_SYNTAX, "Syntax Error\n");
        !           450:        if (uri != NULL)
        !           451:            xmlFreeURI(uri);
        !           452:        return;
        !           453:     }
        !           454:     
        !           455:     proxy = xmlMemStrdup(uri->server);
        !           456:     if (uri->port != 0)
        !           457:        proxyPort = uri->port;
        !           458: 
        !           459:     xmlFreeURI(uri);
        !           460: }
        !           461: 
        !           462: /**
        !           463:  * xmlNanoFTPNewCtxt:
        !           464:  * @URL:  The URL used to initialize the context
        !           465:  *
        !           466:  * Allocate and initialize a new FTP context.
        !           467:  *
        !           468:  * Returns an FTP context or NULL in case of error.
        !           469:  */
        !           470: 
        !           471: void*
        !           472: xmlNanoFTPNewCtxt(const char *URL) {
        !           473:     xmlNanoFTPCtxtPtr ret;
        !           474:     char *unescaped;
        !           475: 
        !           476:     ret = (xmlNanoFTPCtxtPtr) xmlMalloc(sizeof(xmlNanoFTPCtxt));
        !           477:     if (ret == NULL) {
        !           478:         xmlFTPErrMemory("allocating FTP context");
        !           479:         return(NULL);
        !           480:     }
        !           481: 
        !           482:     memset(ret, 0, sizeof(xmlNanoFTPCtxt));
        !           483:     ret->port = 21;
        !           484:     ret->passive = 1;
        !           485:     ret->returnValue = 0;
        !           486:     ret->controlBufIndex = 0;
        !           487:     ret->controlBufUsed = 0;
        !           488:     ret->controlFd = INVALID_SOCKET;
        !           489: 
        !           490:     unescaped = xmlURIUnescapeString(URL, 0, NULL);
        !           491:     if (unescaped != NULL) {
        !           492:        xmlNanoFTPScanURL(ret, unescaped);
        !           493:        xmlFree(unescaped);
        !           494:     } else if (URL != NULL)
        !           495:        xmlNanoFTPScanURL(ret, URL);
        !           496: 
        !           497:     return(ret);
        !           498: }
        !           499: 
        !           500: /**
        !           501:  * xmlNanoFTPFreeCtxt:
        !           502:  * @ctx:  an FTP context
        !           503:  *
        !           504:  * Frees the context after closing the connection.
        !           505:  */
        !           506: 
        !           507: void
        !           508: xmlNanoFTPFreeCtxt(void * ctx) {
        !           509:     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
        !           510:     if (ctxt == NULL) return;
        !           511:     if (ctxt->hostname != NULL) xmlFree(ctxt->hostname);
        !           512:     if (ctxt->protocol != NULL) xmlFree(ctxt->protocol);
        !           513:     if (ctxt->path != NULL) xmlFree(ctxt->path);
        !           514:     ctxt->passive = 1;
        !           515:     if (ctxt->controlFd != INVALID_SOCKET) closesocket(ctxt->controlFd);
        !           516:     ctxt->controlFd = INVALID_SOCKET;
        !           517:     ctxt->controlBufIndex = -1;
        !           518:     ctxt->controlBufUsed = -1;
        !           519:     xmlFree(ctxt);
        !           520: }
        !           521: 
        !           522: /**
        !           523:  * xmlNanoFTPParseResponse:
        !           524:  * @buf:  the buffer containing the response
        !           525:  * @len:  the buffer length
        !           526:  * 
        !           527:  * Parsing of the server answer, we just extract the code.
        !           528:  *
        !           529:  * returns 0 for errors
        !           530:  *     +XXX for last line of response
        !           531:  *     -XXX for response to be continued
        !           532:  */
        !           533: static int
        !           534: xmlNanoFTPParseResponse(char *buf, int len) {
        !           535:     int val = 0;
        !           536: 
        !           537:     if (len < 3) return(-1);
        !           538:     if ((*buf >= '0') && (*buf <= '9')) 
        !           539:         val = val * 10 + (*buf - '0');
        !           540:     else
        !           541:         return(0);
        !           542:     buf++;
        !           543:     if ((*buf >= '0') && (*buf <= '9')) 
        !           544:         val = val * 10 + (*buf - '0');
        !           545:     else
        !           546:         return(0);
        !           547:     buf++;
        !           548:     if ((*buf >= '0') && (*buf <= '9')) 
        !           549:         val = val * 10 + (*buf - '0');
        !           550:     else
        !           551:         return(0);
        !           552:     buf++;
        !           553:     if (*buf == '-') 
        !           554:         return(-val);
        !           555:     return(val);
        !           556: }
        !           557: 
        !           558: /**
        !           559:  * xmlNanoFTPGetMore:
        !           560:  * @ctx:  an FTP context
        !           561:  *
        !           562:  * Read more information from the FTP control connection
        !           563:  * Returns the number of bytes read, < 0 indicates an error
        !           564:  */
        !           565: static int
        !           566: xmlNanoFTPGetMore(void *ctx) {
        !           567:     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
        !           568:     int len;
        !           569:     int size;
        !           570: 
        !           571:     if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1);
        !           572: 
        !           573:     if ((ctxt->controlBufIndex < 0) || (ctxt->controlBufIndex > FTP_BUF_SIZE)) {
        !           574: #ifdef DEBUG_FTP
        !           575:         xmlGenericError(xmlGenericErrorContext,
        !           576:                "xmlNanoFTPGetMore : controlBufIndex = %d\n",
        !           577:                ctxt->controlBufIndex);
        !           578: #endif
        !           579:        return(-1);
        !           580:     }
        !           581: 
        !           582:     if ((ctxt->controlBufUsed < 0) || (ctxt->controlBufUsed > FTP_BUF_SIZE)) {
        !           583: #ifdef DEBUG_FTP
        !           584:         xmlGenericError(xmlGenericErrorContext,
        !           585:                "xmlNanoFTPGetMore : controlBufUsed = %d\n",
        !           586:                ctxt->controlBufUsed);
        !           587: #endif
        !           588:        return(-1);
        !           589:     }
        !           590:     if (ctxt->controlBufIndex > ctxt->controlBufUsed) {
        !           591: #ifdef DEBUG_FTP
        !           592:         xmlGenericError(xmlGenericErrorContext,
        !           593:                "xmlNanoFTPGetMore : controlBufIndex > controlBufUsed %d > %d\n",
        !           594:               ctxt->controlBufIndex, ctxt->controlBufUsed);
        !           595: #endif
        !           596:        return(-1);
        !           597:     }
        !           598: 
        !           599:     /*
        !           600:      * First pack the control buffer
        !           601:      */
        !           602:     if (ctxt->controlBufIndex > 0) {
        !           603:        memmove(&ctxt->controlBuf[0], &ctxt->controlBuf[ctxt->controlBufIndex],
        !           604:                ctxt->controlBufUsed - ctxt->controlBufIndex);
        !           605:        ctxt->controlBufUsed -= ctxt->controlBufIndex;
        !           606:        ctxt->controlBufIndex = 0;
        !           607:     }
        !           608:     size = FTP_BUF_SIZE - ctxt->controlBufUsed;
        !           609:     if (size == 0) {
        !           610: #ifdef DEBUG_FTP
        !           611:         xmlGenericError(xmlGenericErrorContext,
        !           612:                "xmlNanoFTPGetMore : buffer full %d \n", ctxt->controlBufUsed);
        !           613: #endif
        !           614:        return(0);
        !           615:     }
        !           616: 
        !           617:     /*
        !           618:      * Read the amount left on the control connection
        !           619:      */
        !           620:     if ((len = recv(ctxt->controlFd, &ctxt->controlBuf[ctxt->controlBufIndex],
        !           621:                    size, 0)) < 0) {
        !           622:        __xmlIOErr(XML_FROM_FTP, 0, "recv failed");
        !           623:        closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
        !           624:         ctxt->controlFd = INVALID_SOCKET;
        !           625:         return(-1);
        !           626:     }
        !           627: #ifdef DEBUG_FTP
        !           628:     xmlGenericError(xmlGenericErrorContext,
        !           629:            "xmlNanoFTPGetMore : read %d [%d - %d]\n", len,
        !           630:           ctxt->controlBufUsed, ctxt->controlBufUsed + len);
        !           631: #endif
        !           632:     ctxt->controlBufUsed += len;
        !           633:     ctxt->controlBuf[ctxt->controlBufUsed] = 0;
        !           634: 
        !           635:     return(len);
        !           636: }
        !           637: 
        !           638: /**
        !           639:  * xmlNanoFTPReadResponse:
        !           640:  * @ctx:  an FTP context
        !           641:  *
        !           642:  * Read the response from the FTP server after a command.
        !           643:  * Returns the code number
        !           644:  */
        !           645: static int
        !           646: xmlNanoFTPReadResponse(void *ctx) {
        !           647:     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
        !           648:     char *ptr, *end;
        !           649:     int len;
        !           650:     int res = -1, cur = -1;
        !           651: 
        !           652:     if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1);
        !           653: 
        !           654: get_more:
        !           655:     /*
        !           656:      * Assumes everything up to controlBuf[controlBufIndex] has been read
        !           657:      * and analyzed.
        !           658:      */
        !           659:     len = xmlNanoFTPGetMore(ctx);
        !           660:     if (len < 0) {
        !           661:         return(-1);
        !           662:     }
        !           663:     if ((ctxt->controlBufUsed == 0) && (len == 0)) {
        !           664:         return(-1);
        !           665:     }
        !           666:     ptr = &ctxt->controlBuf[ctxt->controlBufIndex];
        !           667:     end = &ctxt->controlBuf[ctxt->controlBufUsed];
        !           668: 
        !           669: #ifdef DEBUG_FTP
        !           670:     xmlGenericError(xmlGenericErrorContext,
        !           671:            "\n<<<\n%s\n--\n", ptr);
        !           672: #endif
        !           673:     while (ptr < end) {
        !           674:         cur = xmlNanoFTPParseResponse(ptr, end - ptr);
        !           675:        if (cur > 0) {
        !           676:            /*
        !           677:             * Successfully scanned the control code, scratch
        !           678:             * till the end of the line, but keep the index to be
        !           679:             * able to analyze the result if needed.
        !           680:             */
        !           681:            res = cur;
        !           682:            ptr += 3;
        !           683:            ctxt->controlBufAnswer = ptr - ctxt->controlBuf;
        !           684:            while ((ptr < end) && (*ptr != '\n')) ptr++;
        !           685:            if (*ptr == '\n') ptr++;
        !           686:            if (*ptr == '\r') ptr++;
        !           687:            break;
        !           688:        }
        !           689:        while ((ptr < end) && (*ptr != '\n')) ptr++;
        !           690:        if (ptr >= end) {
        !           691:            ctxt->controlBufIndex = ctxt->controlBufUsed;
        !           692:            goto get_more;
        !           693:        }
        !           694:        if (*ptr != '\r') ptr++;
        !           695:     }
        !           696: 
        !           697:     if (res < 0) goto get_more;
        !           698:     ctxt->controlBufIndex = ptr - ctxt->controlBuf;
        !           699: #ifdef DEBUG_FTP
        !           700:     ptr = &ctxt->controlBuf[ctxt->controlBufIndex];
        !           701:     xmlGenericError(xmlGenericErrorContext, "\n---\n%s\n--\n", ptr);
        !           702: #endif
        !           703: 
        !           704: #ifdef DEBUG_FTP
        !           705:     xmlGenericError(xmlGenericErrorContext, "Got %d\n", res);
        !           706: #endif
        !           707:     return(res / 100);
        !           708: }
        !           709: 
        !           710: /**
        !           711:  * xmlNanoFTPGetResponse:
        !           712:  * @ctx:  an FTP context
        !           713:  *
        !           714:  * Get the response from the FTP server after a command.
        !           715:  * Returns the code number
        !           716:  */
        !           717: 
        !           718: int
        !           719: xmlNanoFTPGetResponse(void *ctx) {
        !           720:     int res;
        !           721: 
        !           722:     res = xmlNanoFTPReadResponse(ctx);
        !           723: 
        !           724:     return(res);
        !           725: }
        !           726: 
        !           727: /**
        !           728:  * xmlNanoFTPCheckResponse:
        !           729:  * @ctx:  an FTP context
        !           730:  *
        !           731:  * Check if there is a response from the FTP server after a command.
        !           732:  * Returns the code number, or 0
        !           733:  */
        !           734: 
        !           735: int
        !           736: xmlNanoFTPCheckResponse(void *ctx) {
        !           737:     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
        !           738:     fd_set rfd;
        !           739:     struct timeval tv;
        !           740: 
        !           741:     if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1);
        !           742:     tv.tv_sec = 0;
        !           743:     tv.tv_usec = 0;
        !           744:     FD_ZERO(&rfd);
        !           745:     FD_SET(ctxt->controlFd, &rfd);
        !           746:     switch(select(ctxt->controlFd + 1, &rfd, NULL, NULL, &tv)) {
        !           747:        case 0:
        !           748:            return(0);
        !           749:        case -1:
        !           750:            __xmlIOErr(XML_FROM_FTP, 0, "select");
        !           751:            return(-1);
        !           752:                        
        !           753:     }
        !           754: 
        !           755:     return(xmlNanoFTPReadResponse(ctx));
        !           756: }
        !           757: 
        !           758: /**
        !           759:  * Send the user authentication
        !           760:  */
        !           761: 
        !           762: static int
        !           763: xmlNanoFTPSendUser(void *ctx) {
        !           764:     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
        !           765:     char buf[200];
        !           766:     int len;
        !           767:     int res;
        !           768: 
        !           769:     if (ctxt->user == NULL)
        !           770:        snprintf(buf, sizeof(buf), "USER anonymous\r\n");
        !           771:     else
        !           772:        snprintf(buf, sizeof(buf), "USER %s\r\n", ctxt->user);
        !           773:     buf[sizeof(buf) - 1] = 0;
        !           774:     len = strlen(buf);
        !           775: #ifdef DEBUG_FTP
        !           776:     xmlGenericError(xmlGenericErrorContext, "%s", buf);
        !           777: #endif
        !           778:     res = send(ctxt->controlFd, buf, len, 0);
        !           779:     if (res < 0) {
        !           780:        __xmlIOErr(XML_FROM_FTP, 0, "send failed");
        !           781:        return(res);
        !           782:     }
        !           783:     return(0);
        !           784: }
        !           785: 
        !           786: /**
        !           787:  * Send the password authentication
        !           788:  */
        !           789: 
        !           790: static int
        !           791: xmlNanoFTPSendPasswd(void *ctx) {
        !           792:     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
        !           793:     char buf[200];
        !           794:     int len;
        !           795:     int res;
        !           796: 
        !           797:     if (ctxt->passwd == NULL)
        !           798:        snprintf(buf, sizeof(buf), "PASS anonymous@\r\n");
        !           799:     else
        !           800:        snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd);
        !           801:     buf[sizeof(buf) - 1] = 0;
        !           802:     len = strlen(buf);
        !           803: #ifdef DEBUG_FTP
        !           804:     xmlGenericError(xmlGenericErrorContext, "%s", buf);
        !           805: #endif
        !           806:     res = send(ctxt->controlFd, buf, len, 0);
        !           807:     if (res < 0) {
        !           808:        __xmlIOErr(XML_FROM_FTP, 0, "send failed");
        !           809:        return(res);
        !           810:     }
        !           811:     return(0);
        !           812: }
        !           813: 
        !           814: /**
        !           815:  * xmlNanoFTPQuit:
        !           816:  * @ctx:  an FTP context
        !           817:  *
        !           818:  * Send a QUIT command to the server
        !           819:  *
        !           820:  * Returns -1 in case of error, 0 otherwise
        !           821:  */
        !           822: 
        !           823: 
        !           824: int
        !           825: xmlNanoFTPQuit(void *ctx) {
        !           826:     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
        !           827:     char buf[200];
        !           828:     int len, res;
        !           829: 
        !           830:     if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1);
        !           831: 
        !           832:     snprintf(buf, sizeof(buf), "QUIT\r\n");
        !           833:     len = strlen(buf);
        !           834: #ifdef DEBUG_FTP
        !           835:     xmlGenericError(xmlGenericErrorContext, "%s", buf); /* Just to be consistent, even though we know it can't have a % in it */
        !           836: #endif
        !           837:     res = send(ctxt->controlFd, buf, len, 0);
        !           838:     if (res < 0) {
        !           839:        __xmlIOErr(XML_FROM_FTP, 0, "send failed");
        !           840:        return(res);
        !           841:     }
        !           842:     return(0);
        !           843: }
        !           844: 
        !           845: /**
        !           846:  * xmlNanoFTPConnect:
        !           847:  * @ctx:  an FTP context
        !           848:  *
        !           849:  * Tries to open a control connection
        !           850:  *
        !           851:  * Returns -1 in case of error, 0 otherwise
        !           852:  */
        !           853: 
        !           854: int
        !           855: xmlNanoFTPConnect(void *ctx) {
        !           856:     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
        !           857:     struct hostent *hp;
        !           858:     int port;
        !           859:     int res;
        !           860:     int addrlen = sizeof (struct sockaddr_in);
        !           861: 
        !           862:     if (ctxt == NULL)
        !           863:        return(-1);
        !           864:     if (ctxt->hostname == NULL)
        !           865:        return(-1);
        !           866: 
        !           867:     /*
        !           868:      * do the blocking DNS query.
        !           869:      */
        !           870:     if (proxy) {
        !           871:         port = proxyPort;
        !           872:     } else {
        !           873:        port = ctxt->port;
        !           874:     }
        !           875:     if (port == 0)
        !           876:        port = 21;
        !           877: 
        !           878:     memset (&ctxt->ftpAddr, 0, sizeof(ctxt->ftpAddr));
        !           879: 
        !           880: #ifdef SUPPORT_IP6
        !           881:     if (have_ipv6 ()) {
        !           882:        struct addrinfo hints, *tmp, *result;
        !           883: 
        !           884:        result = NULL;
        !           885:        memset (&hints, 0, sizeof(hints));
        !           886:        hints.ai_socktype = SOCK_STREAM;
        !           887: 
        !           888:        if (proxy) {
        !           889:            if (getaddrinfo (proxy, NULL, &hints, &result) != 0) {
        !           890:                __xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed");
        !           891:                return (-1);
        !           892:            }
        !           893:        }
        !           894:        else
        !           895:            if (getaddrinfo (ctxt->hostname, NULL, &hints, &result) != 0) {
        !           896:                __xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed");
        !           897:                return (-1);
        !           898:            }
        !           899: 
        !           900:        for (tmp = result; tmp; tmp = tmp->ai_next)
        !           901:            if (tmp->ai_family == AF_INET || tmp->ai_family == AF_INET6)
        !           902:                break;
        !           903: 
        !           904:        if (!tmp) {
        !           905:            if (result)
        !           906:                freeaddrinfo (result);
        !           907:            __xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed");
        !           908:            return (-1);
        !           909:        }
        !           910:        if (tmp->ai_addrlen > sizeof(ctxt->ftpAddr)) {
        !           911:            __xmlIOErr(XML_FROM_FTP, 0, "gethostbyname address mismatch");
        !           912:            return (-1);
        !           913:        }
        !           914:        if (tmp->ai_family == AF_INET6) {
        !           915:            memcpy (&ctxt->ftpAddr, tmp->ai_addr, tmp->ai_addrlen);
        !           916:            ((struct sockaddr_in6 *) &ctxt->ftpAddr)->sin6_port = htons (port);
        !           917:            ctxt->controlFd = socket (AF_INET6, SOCK_STREAM, 0);
        !           918:        }
        !           919:        else {
        !           920:            memcpy (&ctxt->ftpAddr, tmp->ai_addr, tmp->ai_addrlen);
        !           921:            ((struct sockaddr_in *) &ctxt->ftpAddr)->sin_port = htons (port);
        !           922:            ctxt->controlFd = socket (AF_INET, SOCK_STREAM, 0);
        !           923:        }
        !           924:        addrlen = tmp->ai_addrlen;
        !           925:        freeaddrinfo (result);
        !           926:     }
        !           927:     else
        !           928: #endif
        !           929:     {
        !           930:        if (proxy)
        !           931:            hp = gethostbyname (proxy);
        !           932:        else
        !           933:            hp = gethostbyname (ctxt->hostname);
        !           934:        if (hp == NULL) {
        !           935:            __xmlIOErr(XML_FROM_FTP, 0, "gethostbyname failed");
        !           936:            return (-1);
        !           937:        }
        !           938:        if ((unsigned int) hp->h_length >
        !           939:            sizeof(((struct sockaddr_in *)&ctxt->ftpAddr)->sin_addr)) {
        !           940:            __xmlIOErr(XML_FROM_FTP, 0, "gethostbyname address mismatch");
        !           941:            return (-1);
        !           942:        }
        !           943: 
        !           944:        /*
        !           945:         * Prepare the socket
        !           946:         */
        !           947:        ((struct sockaddr_in *)&ctxt->ftpAddr)->sin_family = AF_INET;
        !           948:        memcpy (&((struct sockaddr_in *)&ctxt->ftpAddr)->sin_addr,
        !           949:                hp->h_addr_list[0], hp->h_length);
        !           950:        ((struct sockaddr_in *)&ctxt->ftpAddr)->sin_port = (u_short)htons ((unsigned short)port);
        !           951:        ctxt->controlFd = socket (AF_INET, SOCK_STREAM, 0);
        !           952:        addrlen = sizeof (struct sockaddr_in);
        !           953:     }
        !           954: 
        !           955:     if (ctxt->controlFd == INVALID_SOCKET) {
        !           956:        __xmlIOErr(XML_FROM_FTP, 0, "socket failed");
        !           957:         return(-1);
        !           958:     }
        !           959: 
        !           960:     /*
        !           961:      * Do the connect.
        !           962:      */
        !           963:     if (connect(ctxt->controlFd, (struct sockaddr *) &ctxt->ftpAddr,
        !           964:            addrlen) < 0) {
        !           965:        __xmlIOErr(XML_FROM_FTP, 0, "Failed to create a connection");
        !           966:         closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
        !           967:         ctxt->controlFd = INVALID_SOCKET;
        !           968:        return(-1);
        !           969:     }
        !           970: 
        !           971:     /*
        !           972:      * Wait for the HELLO from the server.
        !           973:      */
        !           974:     res = xmlNanoFTPGetResponse(ctxt);
        !           975:     if (res != 2) {
        !           976:         closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
        !           977:         ctxt->controlFd = INVALID_SOCKET;
        !           978:        return(-1);
        !           979:     }
        !           980: 
        !           981:     /*
        !           982:      * State diagram for the login operation on the FTP server
        !           983:      *
        !           984:      * Reference: RFC 959
        !           985:      *
        !           986:      *                       1
        !           987:      * +---+   USER    +---+------------->+---+
        !           988:      * | B |---------->| W | 2       ---->| E |
        !           989:      * +---+           +---+------  |  -->+---+
        !           990:      *                  | |       | | |
        !           991:      *                3 | | 4,5   | | |
        !           992:      *    --------------   -----  | | |
        !           993:      *   |                      | | | |
        !           994:      *   |                      | | | |
        !           995:      *   |                 ---------  |
        !           996:      *   |               1|     | |   |
        !           997:      *   V                |     | |   |
        !           998:      * +---+   PASS    +---+ 2  |  ------>+---+
        !           999:      * |   |---------->| W |------------->| S |
        !          1000:      * +---+           +---+   ---------->+---+
        !          1001:      *                  | |   | |     |
        !          1002:      *                3 | |4,5| |     |
        !          1003:      *    --------------   --------   |
        !          1004:      *   |                    | |  |  |
        !          1005:      *   |                    | |  |  |
        !          1006:      *   |                 -----------
        !          1007:      *   |             1,3|   | |  |
        !          1008:      *   V                |  2| |  |
        !          1009:      * +---+   ACCT    +---+--  |   ----->+---+
        !          1010:      * |   |---------->| W | 4,5 -------->| F |
        !          1011:      * +---+           +---+------------->+---+
        !          1012:      *
        !          1013:      * Of course in case of using a proxy this get really nasty and is not
        !          1014:      * standardized at all :-(
        !          1015:      */
        !          1016:     if (proxy) {
        !          1017:         int len;
        !          1018:        char buf[400];
        !          1019: 
        !          1020:         if (proxyUser != NULL) {
        !          1021:            /*
        !          1022:             * We need proxy auth
        !          1023:             */
        !          1024:            snprintf(buf, sizeof(buf), "USER %s\r\n", proxyUser);
        !          1025:             buf[sizeof(buf) - 1] = 0;
        !          1026:             len = strlen(buf);
        !          1027: #ifdef DEBUG_FTP
        !          1028:            xmlGenericError(xmlGenericErrorContext, "%s", buf);
        !          1029: #endif
        !          1030:            res = send(ctxt->controlFd, buf, len, 0);
        !          1031:            if (res < 0) {
        !          1032:                __xmlIOErr(XML_FROM_FTP, 0, "send failed");
        !          1033:                closesocket(ctxt->controlFd);
        !          1034:                ctxt->controlFd = INVALID_SOCKET;
        !          1035:                return(res);
        !          1036:            }
        !          1037:            res = xmlNanoFTPGetResponse(ctxt);
        !          1038:            switch (res) {
        !          1039:                case 2:
        !          1040:                    if (proxyPasswd == NULL)
        !          1041:                        break;
        !          1042:                case 3:
        !          1043:                    if (proxyPasswd != NULL)
        !          1044:                        snprintf(buf, sizeof(buf), "PASS %s\r\n", proxyPasswd);
        !          1045:                    else
        !          1046:                        snprintf(buf, sizeof(buf), "PASS anonymous@\r\n");
        !          1047:                     buf[sizeof(buf) - 1] = 0;
        !          1048:                     len = strlen(buf);
        !          1049: #ifdef DEBUG_FTP
        !          1050:                    xmlGenericError(xmlGenericErrorContext, "%s", buf);
        !          1051: #endif
        !          1052:                    res = send(ctxt->controlFd, buf, len, 0);
        !          1053:                    if (res < 0) {
        !          1054:                        __xmlIOErr(XML_FROM_FTP, 0, "send failed");
        !          1055:                        closesocket(ctxt->controlFd);
        !          1056:                        ctxt->controlFd = INVALID_SOCKET;
        !          1057:                        return(res);
        !          1058:                    }
        !          1059:                    res = xmlNanoFTPGetResponse(ctxt);
        !          1060:                    if (res > 3) {
        !          1061:                        closesocket(ctxt->controlFd);
        !          1062:                        ctxt->controlFd = INVALID_SOCKET;
        !          1063:                        return(-1);
        !          1064:                    }
        !          1065:                    break;
        !          1066:                case 1:
        !          1067:                    break;
        !          1068:                case 4:
        !          1069:                case 5:
        !          1070:                case -1:
        !          1071:                default:
        !          1072:                    closesocket(ctxt->controlFd);
        !          1073:                    ctxt->controlFd = INVALID_SOCKET;
        !          1074:                    return(-1);
        !          1075:            }
        !          1076:        }
        !          1077: 
        !          1078:        /*
        !          1079:         * We assume we don't need more authentication to the proxy
        !          1080:         * and that it succeeded :-\
        !          1081:         */
        !          1082:        switch (proxyType) {
        !          1083:            case 0:
        !          1084:                /* we will try in sequence */
        !          1085:            case 1:
        !          1086:                /* Using SITE command */
        !          1087:                snprintf(buf, sizeof(buf), "SITE %s\r\n", ctxt->hostname);
        !          1088:                 buf[sizeof(buf) - 1] = 0;
        !          1089:                 len = strlen(buf);
        !          1090: #ifdef DEBUG_FTP
        !          1091:                xmlGenericError(xmlGenericErrorContext, "%s", buf);
        !          1092: #endif
        !          1093:                res = send(ctxt->controlFd, buf, len, 0);
        !          1094:                if (res < 0) {
        !          1095:                    __xmlIOErr(XML_FROM_FTP, 0, "send failed");
        !          1096:                    closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
        !          1097:                    ctxt->controlFd = INVALID_SOCKET;
        !          1098:                    return(res);
        !          1099:                }
        !          1100:                res = xmlNanoFTPGetResponse(ctxt);
        !          1101:                if (res == 2) {
        !          1102:                    /* we assume it worked :-\ 1 is error for SITE command */
        !          1103:                    proxyType = 1;
        !          1104:                    break;
        !          1105:                }    
        !          1106:                if (proxyType == 1) {
        !          1107:                    closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
        !          1108:                    ctxt->controlFd = INVALID_SOCKET;
        !          1109:                    return(-1);
        !          1110:                }
        !          1111:            case 2:
        !          1112:                /* USER user@host command */
        !          1113:                if (ctxt->user == NULL)
        !          1114:                    snprintf(buf, sizeof(buf), "USER anonymous@%s\r\n",
        !          1115:                                   ctxt->hostname);
        !          1116:                else
        !          1117:                    snprintf(buf, sizeof(buf), "USER %s@%s\r\n",
        !          1118:                                   ctxt->user, ctxt->hostname);
        !          1119:                 buf[sizeof(buf) - 1] = 0;
        !          1120:                 len = strlen(buf);
        !          1121: #ifdef DEBUG_FTP
        !          1122:                xmlGenericError(xmlGenericErrorContext, "%s", buf);
        !          1123: #endif
        !          1124:                res = send(ctxt->controlFd, buf, len, 0);
        !          1125:                if (res < 0) {
        !          1126:                    __xmlIOErr(XML_FROM_FTP, 0, "send failed");
        !          1127:                    closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
        !          1128:                    ctxt->controlFd = INVALID_SOCKET;
        !          1129:                    return(res);
        !          1130:                }
        !          1131:                res = xmlNanoFTPGetResponse(ctxt);
        !          1132:                if ((res == 1) || (res == 2)) {
        !          1133:                    /* we assume it worked :-\ */
        !          1134:                    proxyType = 2;
        !          1135:                    return(0);
        !          1136:                }    
        !          1137:                if (ctxt->passwd == NULL)
        !          1138:                    snprintf(buf, sizeof(buf), "PASS anonymous@\r\n");
        !          1139:                else
        !          1140:                    snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd);
        !          1141:                 buf[sizeof(buf) - 1] = 0;
        !          1142:                 len = strlen(buf);
        !          1143: #ifdef DEBUG_FTP
        !          1144:                xmlGenericError(xmlGenericErrorContext, "%s", buf);
        !          1145: #endif
        !          1146:                res = send(ctxt->controlFd, buf, len, 0);
        !          1147:                if (res < 0) {
        !          1148:                    __xmlIOErr(XML_FROM_FTP, 0, "send failed");
        !          1149:                    closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
        !          1150:                    ctxt->controlFd = INVALID_SOCKET;
        !          1151:                    return(res);
        !          1152:                }
        !          1153:                res = xmlNanoFTPGetResponse(ctxt);
        !          1154:                if ((res == 1) || (res == 2)) {
        !          1155:                    /* we assume it worked :-\ */
        !          1156:                    proxyType = 2;
        !          1157:                    return(0);
        !          1158:                }
        !          1159:                if (proxyType == 2) {
        !          1160:                    closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
        !          1161:                    ctxt->controlFd = INVALID_SOCKET;
        !          1162:                    return(-1);
        !          1163:                }
        !          1164:            case 3:
        !          1165:                /*
        !          1166:                 * If you need support for other Proxy authentication scheme
        !          1167:                 * send the code or at least the sequence in use.
        !          1168:                 */
        !          1169:            default:
        !          1170:                closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
        !          1171:                ctxt->controlFd = INVALID_SOCKET;
        !          1172:                return(-1);
        !          1173:        }
        !          1174:     }
        !          1175:     /*
        !          1176:      * Non-proxy handling.
        !          1177:      */
        !          1178:     res = xmlNanoFTPSendUser(ctxt);
        !          1179:     if (res < 0) {
        !          1180:         closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
        !          1181:         ctxt->controlFd = INVALID_SOCKET;
        !          1182:        return(-1);
        !          1183:     }
        !          1184:     res = xmlNanoFTPGetResponse(ctxt);
        !          1185:     switch (res) {
        !          1186:        case 2:
        !          1187:            return(0);
        !          1188:        case 3:
        !          1189:            break;
        !          1190:        case 1:
        !          1191:        case 4:
        !          1192:        case 5:
        !          1193:         case -1:
        !          1194:        default:
        !          1195:            closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
        !          1196:            ctxt->controlFd = INVALID_SOCKET;
        !          1197:            return(-1);
        !          1198:     }
        !          1199:     res = xmlNanoFTPSendPasswd(ctxt);
        !          1200:     if (res < 0) {
        !          1201:         closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
        !          1202:         ctxt->controlFd = INVALID_SOCKET;
        !          1203:        return(-1);
        !          1204:     }
        !          1205:     res = xmlNanoFTPGetResponse(ctxt);
        !          1206:     switch (res) {
        !          1207:        case 2:
        !          1208:            break;
        !          1209:        case 3:
        !          1210:            __xmlIOErr(XML_FROM_FTP, XML_FTP_ACCNT,
        !          1211:                       "FTP server asking for ACCNT on anonymous\n");
        !          1212:        case 1:
        !          1213:        case 4:
        !          1214:        case 5:
        !          1215:         case -1:
        !          1216:        default:
        !          1217:            closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
        !          1218:            ctxt->controlFd = INVALID_SOCKET;
        !          1219:            return(-1);
        !          1220:     }
        !          1221: 
        !          1222:     return(0);
        !          1223: }
        !          1224: 
        !          1225: /**
        !          1226:  * xmlNanoFTPConnectTo:
        !          1227:  * @server:  an FTP server name
        !          1228:  * @port:  the port (use 21 if 0)
        !          1229:  *
        !          1230:  * Tries to open a control connection to the given server/port
        !          1231:  *
        !          1232:  * Returns an fTP context or NULL if it failed
        !          1233:  */
        !          1234: 
        !          1235: void*
        !          1236: xmlNanoFTPConnectTo(const char *server, int port) {
        !          1237:     xmlNanoFTPCtxtPtr ctxt;
        !          1238:     int res;
        !          1239: 
        !          1240:     xmlNanoFTPInit();
        !          1241:     if (server == NULL) 
        !          1242:        return(NULL);
        !          1243:     if (port <= 0)
        !          1244:        return(NULL);
        !          1245:     ctxt = (xmlNanoFTPCtxtPtr) xmlNanoFTPNewCtxt(NULL);
        !          1246:     ctxt->hostname = xmlMemStrdup(server);
        !          1247:     if (port != 0)
        !          1248:        ctxt->port = port;
        !          1249:     res = xmlNanoFTPConnect(ctxt);
        !          1250:     if (res < 0) {
        !          1251:        xmlNanoFTPFreeCtxt(ctxt);
        !          1252:        return(NULL);
        !          1253:     }
        !          1254:     return(ctxt);
        !          1255: }
        !          1256: 
        !          1257: /**
        !          1258:  * xmlNanoFTPCwd:
        !          1259:  * @ctx:  an FTP context
        !          1260:  * @directory:  a directory on the server
        !          1261:  *
        !          1262:  * Tries to change the remote directory
        !          1263:  *
        !          1264:  * Returns -1 incase of error, 1 if CWD worked, 0 if it failed
        !          1265:  */
        !          1266: 
        !          1267: int
        !          1268: xmlNanoFTPCwd(void *ctx, const char *directory) {
        !          1269:     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
        !          1270:     char buf[400];
        !          1271:     int len;
        !          1272:     int res;
        !          1273: 
        !          1274:     if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1);
        !          1275:     if (directory == NULL) return 0;
        !          1276: 
        !          1277:     /*
        !          1278:      * Expected response code for CWD:
        !          1279:      *
        !          1280:      * CWD
        !          1281:      *     250
        !          1282:      *     500, 501, 502, 421, 530, 550
        !          1283:      */
        !          1284:     snprintf(buf, sizeof(buf), "CWD %s\r\n", directory);
        !          1285:     buf[sizeof(buf) - 1] = 0;
        !          1286:     len = strlen(buf);
        !          1287: #ifdef DEBUG_FTP
        !          1288:     xmlGenericError(xmlGenericErrorContext, "%s", buf);
        !          1289: #endif
        !          1290:     res = send(ctxt->controlFd, buf, len, 0);
        !          1291:     if (res < 0) {
        !          1292:        __xmlIOErr(XML_FROM_FTP, 0, "send failed");
        !          1293:        return(res);
        !          1294:     }
        !          1295:     res = xmlNanoFTPGetResponse(ctxt);
        !          1296:     if (res == 4) {
        !          1297:        return(-1);
        !          1298:     }
        !          1299:     if (res == 2) return(1);
        !          1300:     if (res == 5) {
        !          1301:        return(0);
        !          1302:     }
        !          1303:     return(0);
        !          1304: }
        !          1305: 
        !          1306: /**
        !          1307:  * xmlNanoFTPDele:
        !          1308:  * @ctx:  an FTP context
        !          1309:  * @file:  a file or directory on the server
        !          1310:  *
        !          1311:  * Tries to delete an item (file or directory) from server
        !          1312:  *
        !          1313:  * Returns -1 incase of error, 1 if DELE worked, 0 if it failed
        !          1314:  */
        !          1315: 
        !          1316: int
        !          1317: xmlNanoFTPDele(void *ctx, const char *file) {
        !          1318:     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
        !          1319:     char buf[400];
        !          1320:     int len;
        !          1321:     int res;
        !          1322: 
        !          1323:     if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET) || (file == NULL)) return(-1);
        !          1324:     if (file == NULL) return (0);
        !          1325: 
        !          1326:     /*
        !          1327:      * Expected response code for DELE:
        !          1328:      *
        !          1329:      * DELE
        !          1330:      *       250
        !          1331:      *       450, 550
        !          1332:      *       500, 501, 502, 421, 530
        !          1333:      */
        !          1334:         
        !          1335:     snprintf(buf, sizeof(buf), "DELE %s\r\n", file);
        !          1336:     buf[sizeof(buf) - 1] = 0;
        !          1337:     len = strlen(buf);
        !          1338: #ifdef DEBUG_FTP
        !          1339:     xmlGenericError(xmlGenericErrorContext, "%s", buf);
        !          1340: #endif
        !          1341:     res = send(ctxt->controlFd, buf, len, 0);
        !          1342:     if (res < 0) {
        !          1343:        __xmlIOErr(XML_FROM_FTP, 0, "send failed");
        !          1344:        return(res);
        !          1345:     }
        !          1346:     res = xmlNanoFTPGetResponse(ctxt);
        !          1347:     if (res == 4) {
        !          1348:        return(-1);
        !          1349:     }
        !          1350:     if (res == 2) return(1);
        !          1351:     if (res == 5) {
        !          1352:        return(0);
        !          1353:     }
        !          1354:     return(0);
        !          1355: }
        !          1356: /**
        !          1357:  * xmlNanoFTPGetConnection:
        !          1358:  * @ctx:  an FTP context
        !          1359:  *
        !          1360:  * Try to open a data connection to the server. Currently only
        !          1361:  * passive mode is supported.
        !          1362:  *
        !          1363:  * Returns -1 incase of error, 0 otherwise
        !          1364:  */
        !          1365: 
        !          1366: SOCKET
        !          1367: xmlNanoFTPGetConnection(void *ctx) {
        !          1368:     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
        !          1369:     char buf[200], *cur;
        !          1370:     int len, i;
        !          1371:     int res;
        !          1372:     unsigned char ad[6], *adp, *portp;
        !          1373:     unsigned int temp[6];
        !          1374: #ifdef SUPPORT_IP6
        !          1375:     struct sockaddr_storage dataAddr;
        !          1376: #else
        !          1377:     struct sockaddr_in dataAddr;
        !          1378: #endif
        !          1379:     XML_SOCKLEN_T dataAddrLen;
        !          1380: 
        !          1381:     if (ctxt == NULL) return INVALID_SOCKET;
        !          1382: 
        !          1383:     memset (&dataAddr, 0, sizeof(dataAddr));
        !          1384: #ifdef SUPPORT_IP6
        !          1385:     if ((ctxt->ftpAddr).ss_family == AF_INET6) {
        !          1386:        ctxt->dataFd = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP);
        !          1387:        ((struct sockaddr_in6 *)&dataAddr)->sin6_family = AF_INET6;
        !          1388:        dataAddrLen = sizeof(struct sockaddr_in6);
        !          1389:     } else
        !          1390: #endif
        !          1391:     {
        !          1392:        ctxt->dataFd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
        !          1393:        ((struct sockaddr_in *)&dataAddr)->sin_family = AF_INET;
        !          1394:        dataAddrLen = sizeof (struct sockaddr_in);
        !          1395:     }
        !          1396: 
        !          1397:     if (ctxt->dataFd == INVALID_SOCKET) {
        !          1398:        __xmlIOErr(XML_FROM_FTP, 0, "socket failed");
        !          1399:        return INVALID_SOCKET;
        !          1400:     }
        !          1401: 
        !          1402:     if (ctxt->passive) {
        !          1403: #ifdef SUPPORT_IP6
        !          1404:        if ((ctxt->ftpAddr).ss_family == AF_INET6)
        !          1405:            snprintf (buf, sizeof(buf), "EPSV\r\n");
        !          1406:        else
        !          1407: #endif
        !          1408:            snprintf (buf, sizeof(buf), "PASV\r\n");
        !          1409:         len = strlen (buf);
        !          1410: #ifdef DEBUG_FTP
        !          1411:        xmlGenericError(xmlGenericErrorContext, "%s", buf);
        !          1412: #endif
        !          1413:        res = send(ctxt->controlFd, buf, len, 0);
        !          1414:        if (res < 0) {
        !          1415:            __xmlIOErr(XML_FROM_FTP, 0, "send failed");
        !          1416:            closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
        !          1417:            return INVALID_SOCKET;
        !          1418:        }
        !          1419:         res = xmlNanoFTPReadResponse(ctx);
        !          1420:        if (res != 2) {
        !          1421:            if (res == 5) {
        !          1422:                closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
        !          1423:                return INVALID_SOCKET;
        !          1424:            } else {
        !          1425:                /*
        !          1426:                 * retry with an active connection
        !          1427:                 */
        !          1428:                closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
        !          1429:                ctxt->passive = 0;
        !          1430:            }
        !          1431:        }
        !          1432:        cur = &ctxt->controlBuf[ctxt->controlBufAnswer]; 
        !          1433:        while (((*cur < '0') || (*cur > '9')) && *cur != '\0') cur++;
        !          1434: #ifdef SUPPORT_IP6
        !          1435:        if ((ctxt->ftpAddr).ss_family == AF_INET6) {
        !          1436:            if (sscanf (cur, "%u", &temp[0]) != 1) {
        !          1437:                __xmlIOErr(XML_FROM_FTP, XML_FTP_EPSV_ANSWER,
        !          1438:                        "Invalid answer to EPSV\n");
        !          1439:                if (ctxt->dataFd != INVALID_SOCKET) {
        !          1440:                    closesocket (ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
        !          1441:                }
        !          1442:                return INVALID_SOCKET;
        !          1443:            }
        !          1444:            memcpy (&((struct sockaddr_in6 *)&dataAddr)->sin6_addr, &((struct sockaddr_in6 *)&ctxt->ftpAddr)->sin6_addr, sizeof(struct in6_addr));
        !          1445:            ((struct sockaddr_in6 *)&dataAddr)->sin6_port = htons (temp[0]);
        !          1446:        }
        !          1447:        else
        !          1448: #endif
        !          1449:        {
        !          1450:            if (sscanf (cur, "%u,%u,%u,%u,%u,%u", &temp[0], &temp[1], &temp[2],
        !          1451:                &temp[3], &temp[4], &temp[5]) != 6) {
        !          1452:                __xmlIOErr(XML_FROM_FTP, XML_FTP_PASV_ANSWER,
        !          1453:                        "Invalid answer to PASV\n");
        !          1454:                if (ctxt->dataFd != INVALID_SOCKET) {
        !          1455:                    closesocket (ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
        !          1456:                }
        !          1457:                return INVALID_SOCKET;
        !          1458:            }
        !          1459:            for (i=0; i<6; i++) ad[i] = (unsigned char) (temp[i] & 0xff);
        !          1460:            memcpy (&((struct sockaddr_in *)&dataAddr)->sin_addr, &ad[0], 4);
        !          1461:            memcpy (&((struct sockaddr_in *)&dataAddr)->sin_port, &ad[4], 2);
        !          1462:        }
        !          1463: 
        !          1464:        if (connect(ctxt->dataFd, (struct sockaddr *) &dataAddr, dataAddrLen) < 0) {
        !          1465:            __xmlIOErr(XML_FROM_FTP, 0, "Failed to create a data connection");
        !          1466:            closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
        !          1467:            return INVALID_SOCKET;
        !          1468:        }
        !          1469:     } else {
        !          1470:         getsockname(ctxt->dataFd, (struct sockaddr *) &dataAddr, &dataAddrLen);
        !          1471: #ifdef SUPPORT_IP6
        !          1472:        if ((ctxt->ftpAddr).ss_family == AF_INET6)
        !          1473:            ((struct sockaddr_in6 *)&dataAddr)->sin6_port = 0;
        !          1474:        else
        !          1475: #endif
        !          1476:            ((struct sockaddr_in *)&dataAddr)->sin_port = 0;
        !          1477: 
        !          1478:        if (bind(ctxt->dataFd, (struct sockaddr *) &dataAddr, dataAddrLen) < 0) {
        !          1479:            __xmlIOErr(XML_FROM_FTP, 0, "bind failed");
        !          1480:            closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
        !          1481:            return INVALID_SOCKET;
        !          1482:        }
        !          1483:         getsockname(ctxt->dataFd, (struct sockaddr *) &dataAddr, &dataAddrLen);
        !          1484: 
        !          1485:        if (listen(ctxt->dataFd, 1) < 0) {
        !          1486:            __xmlIOErr(XML_FROM_FTP, 0, "listen failed");
        !          1487:            closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
        !          1488:            return INVALID_SOCKET;
        !          1489:        }
        !          1490: #ifdef SUPPORT_IP6
        !          1491:        if ((ctxt->ftpAddr).ss_family == AF_INET6) {
        !          1492:            char buf6[INET6_ADDRSTRLEN];
        !          1493:            inet_ntop (AF_INET6, &((struct sockaddr_in6 *)&dataAddr)->sin6_addr,
        !          1494:                    buf6, INET6_ADDRSTRLEN);
        !          1495:            adp = (unsigned char *) buf6;
        !          1496:            portp = (unsigned char *) &((struct sockaddr_in6 *)&dataAddr)->sin6_port;
        !          1497:            snprintf (buf, sizeof(buf), "EPRT |2|%s|%s|\r\n", adp, portp);
        !          1498:         } else
        !          1499: #endif
        !          1500:        {
        !          1501:            adp = (unsigned char *) &((struct sockaddr_in *)&dataAddr)->sin_addr;
        !          1502:            portp = (unsigned char *) &((struct sockaddr_in *)&dataAddr)->sin_port;
        !          1503:            snprintf (buf, sizeof(buf), "PORT %d,%d,%d,%d,%d,%d\r\n",
        !          1504:            adp[0] & 0xff, adp[1] & 0xff, adp[2] & 0xff, adp[3] & 0xff,
        !          1505:            portp[0] & 0xff, portp[1] & 0xff);
        !          1506:        }
        !          1507: 
        !          1508:         buf[sizeof(buf) - 1] = 0;
        !          1509:         len = strlen(buf);
        !          1510: #ifdef DEBUG_FTP
        !          1511:        xmlGenericError(xmlGenericErrorContext, "%s", buf);
        !          1512: #endif
        !          1513: 
        !          1514:        res = send(ctxt->controlFd, buf, len, 0);
        !          1515:        if (res < 0) {
        !          1516:            __xmlIOErr(XML_FROM_FTP, 0, "send failed");
        !          1517:            closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
        !          1518:            return INVALID_SOCKET;
        !          1519:        }
        !          1520:         res = xmlNanoFTPGetResponse(ctxt);
        !          1521:        if (res != 2) {
        !          1522:            closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
        !          1523:            return INVALID_SOCKET;
        !          1524:         }
        !          1525:     }
        !          1526:     return(ctxt->dataFd);
        !          1527:     
        !          1528: }
        !          1529: 
        !          1530: /**
        !          1531:  * xmlNanoFTPCloseConnection:
        !          1532:  * @ctx:  an FTP context
        !          1533:  *
        !          1534:  * Close the data connection from the server
        !          1535:  *
        !          1536:  * Returns -1 incase of error, 0 otherwise
        !          1537:  */
        !          1538: 
        !          1539: int
        !          1540: xmlNanoFTPCloseConnection(void *ctx) {
        !          1541:     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
        !          1542:     int res;
        !          1543:     fd_set rfd, efd;
        !          1544:     struct timeval tv;
        !          1545: 
        !          1546:     if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1);
        !          1547: 
        !          1548:     closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
        !          1549:     tv.tv_sec = 15;
        !          1550:     tv.tv_usec = 0;
        !          1551:     FD_ZERO(&rfd);
        !          1552:     FD_SET(ctxt->controlFd, &rfd);
        !          1553:     FD_ZERO(&efd);
        !          1554:     FD_SET(ctxt->controlFd, &efd);
        !          1555:     res = select(ctxt->controlFd + 1, &rfd, NULL, &efd, &tv);
        !          1556:     if (res < 0) {
        !          1557: #ifdef DEBUG_FTP
        !          1558:        perror("select");
        !          1559: #endif
        !          1560:        closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
        !          1561:        return(-1);
        !          1562:     }
        !          1563:     if (res == 0) {
        !          1564: #ifdef DEBUG_FTP
        !          1565:        xmlGenericError(xmlGenericErrorContext,
        !          1566:                "xmlNanoFTPCloseConnection: timeout\n");
        !          1567: #endif
        !          1568:        closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
        !          1569:     } else {
        !          1570:        res = xmlNanoFTPGetResponse(ctxt);
        !          1571:        if (res != 2) {
        !          1572:            closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
        !          1573:            return(-1);
        !          1574:        }
        !          1575:     }
        !          1576:     return(0);
        !          1577: }
        !          1578: 
        !          1579: /**
        !          1580:  * xmlNanoFTPParseList:
        !          1581:  * @list:  some data listing received from the server
        !          1582:  * @callback:  the user callback
        !          1583:  * @userData:  the user callback data
        !          1584:  *
        !          1585:  * Parse at most one entry from the listing. 
        !          1586:  *
        !          1587:  * Returns -1 incase of error, the length of data parsed otherwise
        !          1588:  */
        !          1589: 
        !          1590: static int
        !          1591: xmlNanoFTPParseList(const char *list, ftpListCallback callback, void *userData) {
        !          1592:     const char *cur = list;
        !          1593:     char filename[151];
        !          1594:     char attrib[11];
        !          1595:     char owner[11];
        !          1596:     char group[11];
        !          1597:     char month[4];
        !          1598:     int year = 0;
        !          1599:     int minute = 0;
        !          1600:     int hour = 0;
        !          1601:     int day = 0;
        !          1602:     unsigned long size = 0;
        !          1603:     int links = 0;
        !          1604:     int i;
        !          1605: 
        !          1606:     if (!strncmp(cur, "total", 5)) {
        !          1607:         cur += 5;
        !          1608:        while (*cur == ' ') cur++;
        !          1609:        while ((*cur >= '0') && (*cur <= '9'))
        !          1610:            links = (links * 10) + (*cur++ - '0');
        !          1611:        while ((*cur == ' ') || (*cur == '\n')  || (*cur == '\r'))
        !          1612:            cur++;
        !          1613:        return(cur - list);
        !          1614:     } else if (*list == '+') {
        !          1615:        return(0);
        !          1616:     } else {
        !          1617:        while ((*cur == ' ') || (*cur == '\n')  || (*cur == '\r'))
        !          1618:            cur++;
        !          1619:        if (*cur == 0) return(0);
        !          1620:        i = 0;
        !          1621:        while (*cur != ' ') {
        !          1622:            if (i < 10) 
        !          1623:                attrib[i++] = *cur;
        !          1624:            cur++;
        !          1625:            if (*cur == 0) return(0);
        !          1626:        }
        !          1627:        attrib[10] = 0;
        !          1628:        while (*cur == ' ') cur++;
        !          1629:        if (*cur == 0) return(0);
        !          1630:        while ((*cur >= '0') && (*cur <= '9'))
        !          1631:            links = (links * 10) + (*cur++ - '0');
        !          1632:        while (*cur == ' ') cur++;
        !          1633:        if (*cur == 0) return(0);
        !          1634:        i = 0;
        !          1635:        while (*cur != ' ') {
        !          1636:            if (i < 10) 
        !          1637:                owner[i++] = *cur;
        !          1638:            cur++;
        !          1639:            if (*cur == 0) return(0);
        !          1640:        }
        !          1641:        owner[i] = 0;
        !          1642:        while (*cur == ' ') cur++;
        !          1643:        if (*cur == 0) return(0);
        !          1644:        i = 0;
        !          1645:        while (*cur != ' ') {
        !          1646:            if (i < 10) 
        !          1647:                group[i++] = *cur;
        !          1648:            cur++;
        !          1649:            if (*cur == 0) return(0);
        !          1650:        }
        !          1651:        group[i] = 0;
        !          1652:        while (*cur == ' ') cur++;
        !          1653:        if (*cur == 0) return(0);
        !          1654:        while ((*cur >= '0') && (*cur <= '9'))
        !          1655:            size = (size * 10) + (*cur++ - '0');
        !          1656:        while (*cur == ' ') cur++;
        !          1657:        if (*cur == 0) return(0);
        !          1658:        i = 0;
        !          1659:        while (*cur != ' ') {
        !          1660:            if (i < 3)
        !          1661:                month[i++] = *cur;
        !          1662:            cur++;
        !          1663:            if (*cur == 0) return(0);
        !          1664:        }
        !          1665:        month[i] = 0;
        !          1666:        while (*cur == ' ') cur++;
        !          1667:        if (*cur == 0) return(0);
        !          1668:         while ((*cur >= '0') && (*cur <= '9'))
        !          1669:            day = (day * 10) + (*cur++ - '0');
        !          1670:        while (*cur == ' ') cur++;
        !          1671:        if (*cur == 0) return(0);
        !          1672:        if ((cur[1] == 0) || (cur[2] == 0)) return(0);
        !          1673:        if ((cur[1] == ':') || (cur[2] == ':')) {
        !          1674:            while ((*cur >= '0') && (*cur <= '9'))
        !          1675:                hour = (hour * 10) + (*cur++ - '0');
        !          1676:            if (*cur == ':') cur++;
        !          1677:            while ((*cur >= '0') && (*cur <= '9'))
        !          1678:                minute = (minute * 10) + (*cur++ - '0');
        !          1679:        } else {
        !          1680:            while ((*cur >= '0') && (*cur <= '9'))
        !          1681:                year = (year * 10) + (*cur++ - '0');
        !          1682:        }
        !          1683:        while (*cur == ' ') cur++;
        !          1684:        if (*cur == 0) return(0);
        !          1685:        i = 0;
        !          1686:        while ((*cur != '\n')  && (*cur != '\r')) {
        !          1687:            if (i < 150)
        !          1688:                filename[i++] = *cur;
        !          1689:            cur++;
        !          1690:            if (*cur == 0) return(0);
        !          1691:        }
        !          1692:        filename[i] = 0;
        !          1693:        if ((*cur != '\n') && (*cur != '\r'))
        !          1694:            return(0);
        !          1695:        while ((*cur == '\n')  || (*cur == '\r'))
        !          1696:            cur++;
        !          1697:     }
        !          1698:     if (callback != NULL) {
        !          1699:         callback(userData, filename, attrib, owner, group, size, links,
        !          1700:                 year, month, day, hour, minute);
        !          1701:     }
        !          1702:     return(cur - list);
        !          1703: }
        !          1704: 
        !          1705: /**
        !          1706:  * xmlNanoFTPList:
        !          1707:  * @ctx:  an FTP context
        !          1708:  * @callback:  the user callback
        !          1709:  * @userData:  the user callback data
        !          1710:  * @filename:  optional files to list
        !          1711:  *
        !          1712:  * Do a listing on the server. All files info are passed back
        !          1713:  * in the callbacks.
        !          1714:  *
        !          1715:  * Returns -1 incase of error, 0 otherwise
        !          1716:  */
        !          1717: 
        !          1718: int
        !          1719: xmlNanoFTPList(void *ctx, ftpListCallback callback, void *userData,
        !          1720:               const char *filename) {
        !          1721:     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
        !          1722:     char buf[4096 + 1];
        !          1723:     int len, res;
        !          1724:     int indx = 0, base;
        !          1725:     fd_set rfd, efd;
        !          1726:     struct timeval tv;
        !          1727: 
        !          1728:     if (ctxt == NULL) return (-1);
        !          1729:     if (filename == NULL) {
        !          1730:         if (xmlNanoFTPCwd(ctxt, ctxt->path) < 1)
        !          1731:            return(-1);
        !          1732:        ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
        !          1733:        if (ctxt->dataFd == INVALID_SOCKET)
        !          1734:            return(-1);
        !          1735:        snprintf(buf, sizeof(buf), "LIST -L\r\n");
        !          1736:     } else {
        !          1737:        if (filename[0] != '/') {
        !          1738:            if (xmlNanoFTPCwd(ctxt, ctxt->path) < 1)
        !          1739:                return(-1);
        !          1740:        }
        !          1741:        ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
        !          1742:        if (ctxt->dataFd == INVALID_SOCKET)
        !          1743:            return(-1);
        !          1744:        snprintf(buf, sizeof(buf), "LIST -L %s\r\n", filename);
        !          1745:     }
        !          1746:     buf[sizeof(buf) - 1] = 0;
        !          1747:     len = strlen(buf);
        !          1748: #ifdef DEBUG_FTP
        !          1749:     xmlGenericError(xmlGenericErrorContext, "%s", buf);
        !          1750: #endif
        !          1751:     res = send(ctxt->controlFd, buf, len, 0);
        !          1752:     if (res < 0) {
        !          1753:        __xmlIOErr(XML_FROM_FTP, 0, "send failed");
        !          1754:        closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
        !          1755:        return(res);
        !          1756:     }
        !          1757:     res = xmlNanoFTPReadResponse(ctxt);
        !          1758:     if (res != 1) {
        !          1759:        closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
        !          1760:        return(-res);
        !          1761:     }
        !          1762: 
        !          1763:     do {
        !          1764:        tv.tv_sec = 1;
        !          1765:        tv.tv_usec = 0;
        !          1766:        FD_ZERO(&rfd);
        !          1767:        FD_SET(ctxt->dataFd, &rfd);
        !          1768:        FD_ZERO(&efd);
        !          1769:        FD_SET(ctxt->dataFd, &efd);
        !          1770:        res = select(ctxt->dataFd + 1, &rfd, NULL, &efd, &tv);
        !          1771:        if (res < 0) {
        !          1772: #ifdef DEBUG_FTP
        !          1773:            perror("select");
        !          1774: #endif
        !          1775:            closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
        !          1776:            return(-1);
        !          1777:        }
        !          1778:        if (res == 0) {
        !          1779:            res = xmlNanoFTPCheckResponse(ctxt);
        !          1780:            if (res < 0) {
        !          1781:                closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
        !          1782:                ctxt->dataFd = INVALID_SOCKET;
        !          1783:                return(-1);
        !          1784:            }
        !          1785:            if (res == 2) {
        !          1786:                closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
        !          1787:                return(0);
        !          1788:            }
        !          1789: 
        !          1790:            continue;
        !          1791:        }
        !          1792: 
        !          1793:        if ((len = recv(ctxt->dataFd, &buf[indx], sizeof(buf) - (indx + 1), 0)) < 0) {
        !          1794:            __xmlIOErr(XML_FROM_FTP, 0, "recv");
        !          1795:            closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
        !          1796:            ctxt->dataFd = INVALID_SOCKET;
        !          1797:            return(-1);
        !          1798:        }
        !          1799: #ifdef DEBUG_FTP
        !          1800:         write(1, &buf[indx], len);
        !          1801: #endif
        !          1802:        indx += len;
        !          1803:        buf[indx] = 0;
        !          1804:        base = 0;
        !          1805:        do {
        !          1806:            res = xmlNanoFTPParseList(&buf[base], callback, userData);
        !          1807:            base += res;
        !          1808:        } while (res > 0);
        !          1809: 
        !          1810:        memmove(&buf[0], &buf[base], indx - base);
        !          1811:        indx -= base;
        !          1812:     } while (len != 0);
        !          1813:     xmlNanoFTPCloseConnection(ctxt);
        !          1814:     return(0);
        !          1815: }
        !          1816: 
        !          1817: /**
        !          1818:  * xmlNanoFTPGetSocket:
        !          1819:  * @ctx:  an FTP context
        !          1820:  * @filename:  the file to retrieve (or NULL if path is in context).
        !          1821:  *
        !          1822:  * Initiate fetch of the given file from the server.
        !          1823:  *
        !          1824:  * Returns the socket for the data connection, or <0 in case of error
        !          1825:  */
        !          1826: 
        !          1827: 
        !          1828: SOCKET
        !          1829: xmlNanoFTPGetSocket(void *ctx, const char *filename) {
        !          1830:     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
        !          1831:     char buf[300];
        !          1832:     int res, len;
        !          1833:     if (ctx == NULL)
        !          1834:        return INVALID_SOCKET;
        !          1835:     if ((filename == NULL) && (ctxt->path == NULL))
        !          1836:        return INVALID_SOCKET;
        !          1837:     ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
        !          1838:     if (ctxt->dataFd == INVALID_SOCKET)
        !          1839:        return INVALID_SOCKET;
        !          1840: 
        !          1841:     snprintf(buf, sizeof(buf), "TYPE I\r\n");
        !          1842:     len = strlen(buf);
        !          1843: #ifdef DEBUG_FTP
        !          1844:     xmlGenericError(xmlGenericErrorContext, "%s", buf);
        !          1845: #endif
        !          1846:     res = send(ctxt->controlFd, buf, len, 0);
        !          1847:     if (res < 0) {
        !          1848:        __xmlIOErr(XML_FROM_FTP, 0, "send failed");
        !          1849:        closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
        !          1850:        return INVALID_SOCKET;
        !          1851:     }
        !          1852:     res = xmlNanoFTPReadResponse(ctxt);
        !          1853:     if (res != 2) {
        !          1854:        closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
        !          1855:        return INVALID_SOCKET;
        !          1856:     }
        !          1857:     if (filename == NULL)
        !          1858:        snprintf(buf, sizeof(buf), "RETR %s\r\n", ctxt->path);
        !          1859:     else
        !          1860:        snprintf(buf, sizeof(buf), "RETR %s\r\n", filename);
        !          1861:     buf[sizeof(buf) - 1] = 0;
        !          1862:     len = strlen(buf);
        !          1863: #ifdef DEBUG_FTP
        !          1864:     xmlGenericError(xmlGenericErrorContext, "%s", buf);
        !          1865: #endif
        !          1866:     res = send(ctxt->controlFd, buf, len, 0);
        !          1867:     if (res < 0) {
        !          1868:        __xmlIOErr(XML_FROM_FTP, 0, "send failed");
        !          1869:        closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
        !          1870:        return INVALID_SOCKET;
        !          1871:     }
        !          1872:     res = xmlNanoFTPReadResponse(ctxt);
        !          1873:     if (res != 1) {
        !          1874:        closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
        !          1875:        return INVALID_SOCKET;
        !          1876:     }
        !          1877:     return(ctxt->dataFd);
        !          1878: }
        !          1879: 
        !          1880: /**
        !          1881:  * xmlNanoFTPGet:
        !          1882:  * @ctx:  an FTP context
        !          1883:  * @callback:  the user callback
        !          1884:  * @userData:  the user callback data
        !          1885:  * @filename:  the file to retrieve
        !          1886:  *
        !          1887:  * Fetch the given file from the server. All data are passed back
        !          1888:  * in the callbacks. The last callback has a size of 0 block.
        !          1889:  *
        !          1890:  * Returns -1 incase of error, 0 otherwise
        !          1891:  */
        !          1892: 
        !          1893: int
        !          1894: xmlNanoFTPGet(void *ctx, ftpDataCallback callback, void *userData,
        !          1895:              const char *filename) {
        !          1896:     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
        !          1897:     char buf[4096];
        !          1898:     int len = 0, res;
        !          1899:     fd_set rfd;
        !          1900:     struct timeval tv;
        !          1901: 
        !          1902:     if (ctxt == NULL) return(-1);
        !          1903:     if ((filename == NULL) && (ctxt->path == NULL))
        !          1904:        return(-1);
        !          1905:     if (callback == NULL)
        !          1906:        return(-1);
        !          1907:     if (xmlNanoFTPGetSocket(ctxt, filename) == INVALID_SOCKET)
        !          1908:        return(-1);
        !          1909: 
        !          1910:     do {
        !          1911:        tv.tv_sec = 1;
        !          1912:        tv.tv_usec = 0;
        !          1913:        FD_ZERO(&rfd);
        !          1914:        FD_SET(ctxt->dataFd, &rfd);
        !          1915:        res = select(ctxt->dataFd + 1, &rfd, NULL, NULL, &tv);
        !          1916:        if (res < 0) {
        !          1917: #ifdef DEBUG_FTP
        !          1918:            perror("select");
        !          1919: #endif
        !          1920:            closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
        !          1921:            return(-1);
        !          1922:        }
        !          1923:        if (res == 0) {
        !          1924:            res = xmlNanoFTPCheckResponse(ctxt);
        !          1925:            if (res < 0) {
        !          1926:                closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
        !          1927:                ctxt->dataFd = INVALID_SOCKET;
        !          1928:                return(-1);
        !          1929:            }
        !          1930:            if (res == 2) {
        !          1931:                closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
        !          1932:                return(0);
        !          1933:            }
        !          1934: 
        !          1935:            continue;
        !          1936:        }
        !          1937:        if ((len = recv(ctxt->dataFd, buf, sizeof(buf), 0)) < 0) {
        !          1938:            __xmlIOErr(XML_FROM_FTP, 0, "recv failed");
        !          1939:            callback(userData, buf, len);
        !          1940:            closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
        !          1941:            return(-1);
        !          1942:        }
        !          1943:        callback(userData, buf, len);
        !          1944:     } while (len != 0);
        !          1945: 
        !          1946:     return(xmlNanoFTPCloseConnection(ctxt));
        !          1947: }
        !          1948: 
        !          1949: /**
        !          1950:  * xmlNanoFTPRead:
        !          1951:  * @ctx:  the FTP context
        !          1952:  * @dest:  a buffer
        !          1953:  * @len:  the buffer length
        !          1954:  *
        !          1955:  * This function tries to read @len bytes from the existing FTP connection
        !          1956:  * and saves them in @dest. This is a blocking call.
        !          1957:  *
        !          1958:  * Returns the number of byte read. 0 is an indication of an end of connection.
        !          1959:  *         -1 indicates a parameter error.
        !          1960:  */
        !          1961: int
        !          1962: xmlNanoFTPRead(void *ctx, void *dest, int len) {
        !          1963:     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
        !          1964: 
        !          1965:     if (ctx == NULL) return(-1);
        !          1966:     if (ctxt->dataFd == INVALID_SOCKET) return(0);
        !          1967:     if (dest == NULL) return(-1);
        !          1968:     if (len <= 0) return(0);
        !          1969: 
        !          1970:     len = recv(ctxt->dataFd, dest, len, 0);
        !          1971:     if (len <= 0) {
        !          1972:        if (len < 0)
        !          1973:            __xmlIOErr(XML_FROM_FTP, 0, "recv failed");
        !          1974:        xmlNanoFTPCloseConnection(ctxt);
        !          1975:     }
        !          1976: #ifdef DEBUG_FTP
        !          1977:     xmlGenericError(xmlGenericErrorContext, "Recvd %d bytes\n", len);
        !          1978: #endif
        !          1979:     return(len);
        !          1980: }
        !          1981: 
        !          1982: /**
        !          1983:  * xmlNanoFTPOpen:
        !          1984:  * @URL: the URL to the resource
        !          1985:  *
        !          1986:  * Start to fetch the given ftp:// resource
        !          1987:  *
        !          1988:  * Returns an FTP context, or NULL 
        !          1989:  */
        !          1990: 
        !          1991: void*
        !          1992: xmlNanoFTPOpen(const char *URL) {
        !          1993:     xmlNanoFTPCtxtPtr ctxt;
        !          1994:     SOCKET sock;
        !          1995: 
        !          1996:     xmlNanoFTPInit();
        !          1997:     if (URL == NULL) return(NULL);
        !          1998:     if (strncmp("ftp://", URL, 6)) return(NULL);
        !          1999: 
        !          2000:     ctxt = (xmlNanoFTPCtxtPtr) xmlNanoFTPNewCtxt(URL);
        !          2001:     if (ctxt == NULL) return(NULL);
        !          2002:     if (xmlNanoFTPConnect(ctxt) < 0) {
        !          2003:        xmlNanoFTPFreeCtxt(ctxt);
        !          2004:        return(NULL);
        !          2005:     }
        !          2006:     sock = xmlNanoFTPGetSocket(ctxt, ctxt->path);
        !          2007:     if (sock == INVALID_SOCKET) {
        !          2008:        xmlNanoFTPFreeCtxt(ctxt);
        !          2009:        return(NULL);
        !          2010:     }
        !          2011:     return(ctxt);
        !          2012: }
        !          2013: 
        !          2014: /**
        !          2015:  * xmlNanoFTPClose:
        !          2016:  * @ctx: an FTP context
        !          2017:  *
        !          2018:  * Close the connection and both control and transport
        !          2019:  *
        !          2020:  * Returns -1 incase of error, 0 otherwise
        !          2021:  */
        !          2022: 
        !          2023: int
        !          2024: xmlNanoFTPClose(void *ctx) {
        !          2025:     xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
        !          2026: 
        !          2027:     if (ctxt == NULL)
        !          2028:        return(-1);
        !          2029: 
        !          2030:     if (ctxt->dataFd != INVALID_SOCKET) {
        !          2031:        closesocket(ctxt->dataFd);
        !          2032:        ctxt->dataFd = INVALID_SOCKET;
        !          2033:     }
        !          2034:     if (ctxt->controlFd != INVALID_SOCKET) {
        !          2035:        xmlNanoFTPQuit(ctxt);
        !          2036:        closesocket(ctxt->controlFd);
        !          2037:        ctxt->controlFd = INVALID_SOCKET;
        !          2038:     }
        !          2039:     xmlNanoFTPFreeCtxt(ctxt);
        !          2040:     return(0);
        !          2041: }
        !          2042: 
        !          2043: #ifdef STANDALONE
        !          2044: /************************************************************************
        !          2045:  *                                                                     *
        !          2046:  *                     Basic test in Standalone mode                   *
        !          2047:  *                                                                     *
        !          2048:  ************************************************************************/
        !          2049: static
        !          2050: void ftpList(void *userData, const char *filename, const char* attrib,
        !          2051:             const char *owner, const char *group, unsigned long size, int links,
        !          2052:             int year, const char *month, int day, int hour, int minute) {
        !          2053:     xmlGenericError(xmlGenericErrorContext,
        !          2054:            "%s %s %s %ld %s\n", attrib, owner, group, size, filename);
        !          2055: }
        !          2056: static
        !          2057: void ftpData(void *userData, const char *data, int len) {
        !          2058:     if (userData == NULL) return;
        !          2059:     if (len <= 0) {
        !          2060:        fclose((FILE*)userData);
        !          2061:        return;
        !          2062:     }  
        !          2063:     fwrite(data, len, 1, (FILE*)userData);
        !          2064: }
        !          2065: 
        !          2066: int main(int argc, char **argv) {
        !          2067:     void *ctxt;
        !          2068:     FILE *output;
        !          2069:     char *tstfile = NULL;
        !          2070: 
        !          2071:     xmlNanoFTPInit();
        !          2072:     if (argc > 1) {
        !          2073:        ctxt = xmlNanoFTPNewCtxt(argv[1]);
        !          2074:        if (xmlNanoFTPConnect(ctxt) < 0) {
        !          2075:            xmlGenericError(xmlGenericErrorContext,
        !          2076:                    "Couldn't connect to %s\n", argv[1]);
        !          2077:            exit(1);
        !          2078:        }
        !          2079:        if (argc > 2)
        !          2080:            tstfile = argv[2];
        !          2081:     } else
        !          2082:        ctxt = xmlNanoFTPConnectTo("localhost", 0);
        !          2083:     if (ctxt == NULL) {
        !          2084:         xmlGenericError(xmlGenericErrorContext,
        !          2085:                "Couldn't connect to localhost\n");
        !          2086:         exit(1);
        !          2087:     }
        !          2088:     xmlNanoFTPList(ctxt, ftpList, NULL, tstfile);
        !          2089:     output = fopen("/tmp/tstdata", "w");
        !          2090:     if (output != NULL) {
        !          2091:        if (xmlNanoFTPGet(ctxt, ftpData, (void *) output, tstfile) < 0)
        !          2092:            xmlGenericError(xmlGenericErrorContext,
        !          2093:                    "Failed to get file\n");
        !          2094:        
        !          2095:     }
        !          2096:     xmlNanoFTPClose(ctxt);
        !          2097:     xmlMemoryDump();
        !          2098:     exit(0);
        !          2099: }
        !          2100: #endif /* STANDALONE */
        !          2101: #else /* !LIBXML_FTP_ENABLED */
        !          2102: #ifdef STANDALONE
        !          2103: #include <stdio.h>
        !          2104: int main(int argc, char **argv) {
        !          2105:     xmlGenericError(xmlGenericErrorContext,
        !          2106:            "%s : FTP support not compiled in\n", argv[0]);
        !          2107:     return(0);
        !          2108: }
        !          2109: #endif /* STANDALONE */
        !          2110: #endif /* LIBXML_FTP_ENABLED */
        !          2111: #define bottom_nanoftp
        !          2112: #include "elfgcchack.h"

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>