nanoftp.c
上传用户:sy_wanhua
上传日期:2013-07-25
资源大小:3048k
文件大小:42k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

C/C++

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