Annotation of XML/nanoftp.c, revision 1.11

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

Webmaster