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