Annotation of embedaddon/libxml2/nanoftp.c, revision 1.1.1.2
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);
1.1.1.2 ! misho 950: ((struct sockaddr_in *)&ctxt->ftpAddr)->sin_port =
! 951: (unsigned short)htons ((unsigned short)port);
1.1 misho 952: ctxt->controlFd = socket (AF_INET, SOCK_STREAM, 0);
953: addrlen = sizeof (struct sockaddr_in);
954: }
955:
956: if (ctxt->controlFd == INVALID_SOCKET) {
957: __xmlIOErr(XML_FROM_FTP, 0, "socket failed");
958: return(-1);
959: }
960:
961: /*
962: * Do the connect.
963: */
964: if (connect(ctxt->controlFd, (struct sockaddr *) &ctxt->ftpAddr,
965: addrlen) < 0) {
966: __xmlIOErr(XML_FROM_FTP, 0, "Failed to create a connection");
967: closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
968: ctxt->controlFd = INVALID_SOCKET;
969: return(-1);
970: }
971:
972: /*
973: * Wait for the HELLO from the server.
974: */
975: res = xmlNanoFTPGetResponse(ctxt);
976: if (res != 2) {
977: closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
978: ctxt->controlFd = INVALID_SOCKET;
979: return(-1);
980: }
981:
982: /*
983: * State diagram for the login operation on the FTP server
984: *
985: * Reference: RFC 959
986: *
987: * 1
988: * +---+ USER +---+------------->+---+
989: * | B |---------->| W | 2 ---->| E |
990: * +---+ +---+------ | -->+---+
991: * | | | | |
992: * 3 | | 4,5 | | |
993: * -------------- ----- | | |
994: * | | | | |
995: * | | | | |
996: * | --------- |
997: * | 1| | | |
998: * V | | | |
999: * +---+ PASS +---+ 2 | ------>+---+
1000: * | |---------->| W |------------->| S |
1001: * +---+ +---+ ---------->+---+
1002: * | | | | |
1003: * 3 | |4,5| | |
1004: * -------------- -------- |
1005: * | | | | |
1006: * | | | | |
1007: * | -----------
1008: * | 1,3| | | |
1009: * V | 2| | |
1010: * +---+ ACCT +---+-- | ----->+---+
1011: * | |---------->| W | 4,5 -------->| F |
1012: * +---+ +---+------------->+---+
1013: *
1014: * Of course in case of using a proxy this get really nasty and is not
1015: * standardized at all :-(
1016: */
1017: if (proxy) {
1018: int len;
1019: char buf[400];
1020:
1021: if (proxyUser != NULL) {
1022: /*
1023: * We need proxy auth
1024: */
1025: snprintf(buf, sizeof(buf), "USER %s\r\n", proxyUser);
1026: buf[sizeof(buf) - 1] = 0;
1027: len = strlen(buf);
1028: #ifdef DEBUG_FTP
1029: xmlGenericError(xmlGenericErrorContext, "%s", buf);
1030: #endif
1031: res = send(ctxt->controlFd, buf, len, 0);
1032: if (res < 0) {
1033: __xmlIOErr(XML_FROM_FTP, 0, "send failed");
1034: closesocket(ctxt->controlFd);
1035: ctxt->controlFd = INVALID_SOCKET;
1036: return(res);
1037: }
1038: res = xmlNanoFTPGetResponse(ctxt);
1039: switch (res) {
1040: case 2:
1041: if (proxyPasswd == NULL)
1042: break;
1043: case 3:
1044: if (proxyPasswd != NULL)
1045: snprintf(buf, sizeof(buf), "PASS %s\r\n", proxyPasswd);
1046: else
1047: snprintf(buf, sizeof(buf), "PASS anonymous@\r\n");
1048: buf[sizeof(buf) - 1] = 0;
1049: len = strlen(buf);
1050: #ifdef DEBUG_FTP
1051: xmlGenericError(xmlGenericErrorContext, "%s", buf);
1052: #endif
1053: res = send(ctxt->controlFd, buf, len, 0);
1054: if (res < 0) {
1055: __xmlIOErr(XML_FROM_FTP, 0, "send failed");
1056: closesocket(ctxt->controlFd);
1057: ctxt->controlFd = INVALID_SOCKET;
1058: return(res);
1059: }
1060: res = xmlNanoFTPGetResponse(ctxt);
1061: if (res > 3) {
1062: closesocket(ctxt->controlFd);
1063: ctxt->controlFd = INVALID_SOCKET;
1064: return(-1);
1065: }
1066: break;
1067: case 1:
1068: break;
1069: case 4:
1070: case 5:
1071: case -1:
1072: default:
1073: closesocket(ctxt->controlFd);
1074: ctxt->controlFd = INVALID_SOCKET;
1075: return(-1);
1076: }
1077: }
1078:
1079: /*
1080: * We assume we don't need more authentication to the proxy
1081: * and that it succeeded :-\
1082: */
1083: switch (proxyType) {
1084: case 0:
1085: /* we will try in sequence */
1086: case 1:
1087: /* Using SITE command */
1088: snprintf(buf, sizeof(buf), "SITE %s\r\n", ctxt->hostname);
1089: buf[sizeof(buf) - 1] = 0;
1090: len = strlen(buf);
1091: #ifdef DEBUG_FTP
1092: xmlGenericError(xmlGenericErrorContext, "%s", buf);
1093: #endif
1094: res = send(ctxt->controlFd, buf, len, 0);
1095: if (res < 0) {
1096: __xmlIOErr(XML_FROM_FTP, 0, "send failed");
1097: closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
1098: ctxt->controlFd = INVALID_SOCKET;
1099: return(res);
1100: }
1101: res = xmlNanoFTPGetResponse(ctxt);
1102: if (res == 2) {
1103: /* we assume it worked :-\ 1 is error for SITE command */
1104: proxyType = 1;
1105: break;
1106: }
1107: if (proxyType == 1) {
1108: closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
1109: ctxt->controlFd = INVALID_SOCKET;
1110: return(-1);
1111: }
1112: case 2:
1113: /* USER user@host command */
1114: if (ctxt->user == NULL)
1115: snprintf(buf, sizeof(buf), "USER anonymous@%s\r\n",
1116: ctxt->hostname);
1117: else
1118: snprintf(buf, sizeof(buf), "USER %s@%s\r\n",
1119: ctxt->user, ctxt->hostname);
1120: buf[sizeof(buf) - 1] = 0;
1121: len = strlen(buf);
1122: #ifdef DEBUG_FTP
1123: xmlGenericError(xmlGenericErrorContext, "%s", buf);
1124: #endif
1125: res = send(ctxt->controlFd, buf, len, 0);
1126: if (res < 0) {
1127: __xmlIOErr(XML_FROM_FTP, 0, "send failed");
1128: closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
1129: ctxt->controlFd = INVALID_SOCKET;
1130: return(res);
1131: }
1132: res = xmlNanoFTPGetResponse(ctxt);
1133: if ((res == 1) || (res == 2)) {
1134: /* we assume it worked :-\ */
1135: proxyType = 2;
1136: return(0);
1137: }
1138: if (ctxt->passwd == NULL)
1139: snprintf(buf, sizeof(buf), "PASS anonymous@\r\n");
1140: else
1141: snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd);
1142: buf[sizeof(buf) - 1] = 0;
1143: len = strlen(buf);
1144: #ifdef DEBUG_FTP
1145: xmlGenericError(xmlGenericErrorContext, "%s", buf);
1146: #endif
1147: res = send(ctxt->controlFd, buf, len, 0);
1148: if (res < 0) {
1149: __xmlIOErr(XML_FROM_FTP, 0, "send failed");
1150: closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
1151: ctxt->controlFd = INVALID_SOCKET;
1152: return(res);
1153: }
1154: res = xmlNanoFTPGetResponse(ctxt);
1155: if ((res == 1) || (res == 2)) {
1156: /* we assume it worked :-\ */
1157: proxyType = 2;
1158: return(0);
1159: }
1160: if (proxyType == 2) {
1161: closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
1162: ctxt->controlFd = INVALID_SOCKET;
1163: return(-1);
1164: }
1165: case 3:
1166: /*
1167: * If you need support for other Proxy authentication scheme
1168: * send the code or at least the sequence in use.
1169: */
1170: default:
1171: closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
1172: ctxt->controlFd = INVALID_SOCKET;
1173: return(-1);
1174: }
1175: }
1176: /*
1177: * Non-proxy handling.
1178: */
1179: res = xmlNanoFTPSendUser(ctxt);
1180: if (res < 0) {
1181: closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
1182: ctxt->controlFd = INVALID_SOCKET;
1183: return(-1);
1184: }
1185: res = xmlNanoFTPGetResponse(ctxt);
1186: switch (res) {
1187: case 2:
1188: return(0);
1189: case 3:
1190: break;
1191: case 1:
1192: case 4:
1193: case 5:
1194: case -1:
1195: default:
1196: closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
1197: ctxt->controlFd = INVALID_SOCKET;
1198: return(-1);
1199: }
1200: res = xmlNanoFTPSendPasswd(ctxt);
1201: if (res < 0) {
1202: closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
1203: ctxt->controlFd = INVALID_SOCKET;
1204: return(-1);
1205: }
1206: res = xmlNanoFTPGetResponse(ctxt);
1207: switch (res) {
1208: case 2:
1209: break;
1210: case 3:
1211: __xmlIOErr(XML_FROM_FTP, XML_FTP_ACCNT,
1212: "FTP server asking for ACCNT on anonymous\n");
1213: case 1:
1214: case 4:
1215: case 5:
1216: case -1:
1217: default:
1218: closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
1219: ctxt->controlFd = INVALID_SOCKET;
1220: return(-1);
1221: }
1222:
1223: return(0);
1224: }
1225:
1226: /**
1227: * xmlNanoFTPConnectTo:
1228: * @server: an FTP server name
1229: * @port: the port (use 21 if 0)
1230: *
1231: * Tries to open a control connection to the given server/port
1232: *
1233: * Returns an fTP context or NULL if it failed
1234: */
1235:
1236: void*
1237: xmlNanoFTPConnectTo(const char *server, int port) {
1238: xmlNanoFTPCtxtPtr ctxt;
1239: int res;
1240:
1241: xmlNanoFTPInit();
1242: if (server == NULL)
1243: return(NULL);
1244: if (port <= 0)
1245: return(NULL);
1246: ctxt = (xmlNanoFTPCtxtPtr) xmlNanoFTPNewCtxt(NULL);
1247: ctxt->hostname = xmlMemStrdup(server);
1248: if (port != 0)
1249: ctxt->port = port;
1250: res = xmlNanoFTPConnect(ctxt);
1251: if (res < 0) {
1252: xmlNanoFTPFreeCtxt(ctxt);
1253: return(NULL);
1254: }
1255: return(ctxt);
1256: }
1257:
1258: /**
1259: * xmlNanoFTPCwd:
1260: * @ctx: an FTP context
1261: * @directory: a directory on the server
1262: *
1263: * Tries to change the remote directory
1264: *
1265: * Returns -1 incase of error, 1 if CWD worked, 0 if it failed
1266: */
1267:
1268: int
1269: xmlNanoFTPCwd(void *ctx, const char *directory) {
1270: xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
1271: char buf[400];
1272: int len;
1273: int res;
1274:
1275: if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1);
1276: if (directory == NULL) return 0;
1277:
1278: /*
1279: * Expected response code for CWD:
1280: *
1281: * CWD
1282: * 250
1283: * 500, 501, 502, 421, 530, 550
1284: */
1285: snprintf(buf, sizeof(buf), "CWD %s\r\n", directory);
1286: buf[sizeof(buf) - 1] = 0;
1287: len = strlen(buf);
1288: #ifdef DEBUG_FTP
1289: xmlGenericError(xmlGenericErrorContext, "%s", buf);
1290: #endif
1291: res = send(ctxt->controlFd, buf, len, 0);
1292: if (res < 0) {
1293: __xmlIOErr(XML_FROM_FTP, 0, "send failed");
1294: return(res);
1295: }
1296: res = xmlNanoFTPGetResponse(ctxt);
1297: if (res == 4) {
1298: return(-1);
1299: }
1300: if (res == 2) return(1);
1301: if (res == 5) {
1302: return(0);
1303: }
1304: return(0);
1305: }
1306:
1307: /**
1308: * xmlNanoFTPDele:
1309: * @ctx: an FTP context
1310: * @file: a file or directory on the server
1311: *
1312: * Tries to delete an item (file or directory) from server
1313: *
1314: * Returns -1 incase of error, 1 if DELE worked, 0 if it failed
1315: */
1316:
1317: int
1318: xmlNanoFTPDele(void *ctx, const char *file) {
1319: xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
1320: char buf[400];
1321: int len;
1322: int res;
1323:
1324: if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET) || (file == NULL)) return(-1);
1325: if (file == NULL) return (0);
1326:
1327: /*
1328: * Expected response code for DELE:
1329: *
1330: * DELE
1331: * 250
1332: * 450, 550
1333: * 500, 501, 502, 421, 530
1334: */
1335:
1336: snprintf(buf, sizeof(buf), "DELE %s\r\n", file);
1337: buf[sizeof(buf) - 1] = 0;
1338: len = strlen(buf);
1339: #ifdef DEBUG_FTP
1340: xmlGenericError(xmlGenericErrorContext, "%s", buf);
1341: #endif
1342: res = send(ctxt->controlFd, buf, len, 0);
1343: if (res < 0) {
1344: __xmlIOErr(XML_FROM_FTP, 0, "send failed");
1345: return(res);
1346: }
1347: res = xmlNanoFTPGetResponse(ctxt);
1348: if (res == 4) {
1349: return(-1);
1350: }
1351: if (res == 2) return(1);
1352: if (res == 5) {
1353: return(0);
1354: }
1355: return(0);
1356: }
1357: /**
1358: * xmlNanoFTPGetConnection:
1359: * @ctx: an FTP context
1360: *
1361: * Try to open a data connection to the server. Currently only
1362: * passive mode is supported.
1363: *
1364: * Returns -1 incase of error, 0 otherwise
1365: */
1366:
1367: SOCKET
1368: xmlNanoFTPGetConnection(void *ctx) {
1369: xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
1370: char buf[200], *cur;
1371: int len, i;
1372: int res;
1373: unsigned char ad[6], *adp, *portp;
1374: unsigned int temp[6];
1375: #ifdef SUPPORT_IP6
1376: struct sockaddr_storage dataAddr;
1377: #else
1378: struct sockaddr_in dataAddr;
1379: #endif
1380: XML_SOCKLEN_T dataAddrLen;
1381:
1382: if (ctxt == NULL) return INVALID_SOCKET;
1383:
1384: memset (&dataAddr, 0, sizeof(dataAddr));
1385: #ifdef SUPPORT_IP6
1386: if ((ctxt->ftpAddr).ss_family == AF_INET6) {
1387: ctxt->dataFd = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP);
1388: ((struct sockaddr_in6 *)&dataAddr)->sin6_family = AF_INET6;
1389: dataAddrLen = sizeof(struct sockaddr_in6);
1390: } else
1391: #endif
1392: {
1393: ctxt->dataFd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
1394: ((struct sockaddr_in *)&dataAddr)->sin_family = AF_INET;
1395: dataAddrLen = sizeof (struct sockaddr_in);
1396: }
1397:
1398: if (ctxt->dataFd == INVALID_SOCKET) {
1399: __xmlIOErr(XML_FROM_FTP, 0, "socket failed");
1400: return INVALID_SOCKET;
1401: }
1402:
1403: if (ctxt->passive) {
1404: #ifdef SUPPORT_IP6
1405: if ((ctxt->ftpAddr).ss_family == AF_INET6)
1406: snprintf (buf, sizeof(buf), "EPSV\r\n");
1407: else
1408: #endif
1409: snprintf (buf, sizeof(buf), "PASV\r\n");
1410: len = strlen (buf);
1411: #ifdef DEBUG_FTP
1412: xmlGenericError(xmlGenericErrorContext, "%s", buf);
1413: #endif
1414: res = send(ctxt->controlFd, buf, len, 0);
1415: if (res < 0) {
1416: __xmlIOErr(XML_FROM_FTP, 0, "send failed");
1417: closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
1418: return INVALID_SOCKET;
1419: }
1420: res = xmlNanoFTPReadResponse(ctx);
1421: if (res != 2) {
1422: if (res == 5) {
1423: closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
1424: return INVALID_SOCKET;
1425: } else {
1426: /*
1427: * retry with an active connection
1428: */
1429: closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
1430: ctxt->passive = 0;
1431: }
1432: }
1433: cur = &ctxt->controlBuf[ctxt->controlBufAnswer];
1434: while (((*cur < '0') || (*cur > '9')) && *cur != '\0') cur++;
1435: #ifdef SUPPORT_IP6
1436: if ((ctxt->ftpAddr).ss_family == AF_INET6) {
1437: if (sscanf (cur, "%u", &temp[0]) != 1) {
1438: __xmlIOErr(XML_FROM_FTP, XML_FTP_EPSV_ANSWER,
1439: "Invalid answer to EPSV\n");
1440: if (ctxt->dataFd != INVALID_SOCKET) {
1441: closesocket (ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
1442: }
1443: return INVALID_SOCKET;
1444: }
1445: memcpy (&((struct sockaddr_in6 *)&dataAddr)->sin6_addr, &((struct sockaddr_in6 *)&ctxt->ftpAddr)->sin6_addr, sizeof(struct in6_addr));
1446: ((struct sockaddr_in6 *)&dataAddr)->sin6_port = htons (temp[0]);
1447: }
1448: else
1449: #endif
1450: {
1451: if (sscanf (cur, "%u,%u,%u,%u,%u,%u", &temp[0], &temp[1], &temp[2],
1452: &temp[3], &temp[4], &temp[5]) != 6) {
1453: __xmlIOErr(XML_FROM_FTP, XML_FTP_PASV_ANSWER,
1454: "Invalid answer to PASV\n");
1455: if (ctxt->dataFd != INVALID_SOCKET) {
1456: closesocket (ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
1457: }
1458: return INVALID_SOCKET;
1459: }
1460: for (i=0; i<6; i++) ad[i] = (unsigned char) (temp[i] & 0xff);
1461: memcpy (&((struct sockaddr_in *)&dataAddr)->sin_addr, &ad[0], 4);
1462: memcpy (&((struct sockaddr_in *)&dataAddr)->sin_port, &ad[4], 2);
1463: }
1464:
1465: if (connect(ctxt->dataFd, (struct sockaddr *) &dataAddr, dataAddrLen) < 0) {
1466: __xmlIOErr(XML_FROM_FTP, 0, "Failed to create a data connection");
1467: closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
1468: return INVALID_SOCKET;
1469: }
1470: } else {
1471: getsockname(ctxt->dataFd, (struct sockaddr *) &dataAddr, &dataAddrLen);
1472: #ifdef SUPPORT_IP6
1473: if ((ctxt->ftpAddr).ss_family == AF_INET6)
1474: ((struct sockaddr_in6 *)&dataAddr)->sin6_port = 0;
1475: else
1476: #endif
1477: ((struct sockaddr_in *)&dataAddr)->sin_port = 0;
1478:
1479: if (bind(ctxt->dataFd, (struct sockaddr *) &dataAddr, dataAddrLen) < 0) {
1480: __xmlIOErr(XML_FROM_FTP, 0, "bind failed");
1481: closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
1482: return INVALID_SOCKET;
1483: }
1484: getsockname(ctxt->dataFd, (struct sockaddr *) &dataAddr, &dataAddrLen);
1485:
1486: if (listen(ctxt->dataFd, 1) < 0) {
1487: __xmlIOErr(XML_FROM_FTP, 0, "listen failed");
1488: closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
1489: return INVALID_SOCKET;
1490: }
1491: #ifdef SUPPORT_IP6
1492: if ((ctxt->ftpAddr).ss_family == AF_INET6) {
1493: char buf6[INET6_ADDRSTRLEN];
1494: inet_ntop (AF_INET6, &((struct sockaddr_in6 *)&dataAddr)->sin6_addr,
1495: buf6, INET6_ADDRSTRLEN);
1496: adp = (unsigned char *) buf6;
1497: portp = (unsigned char *) &((struct sockaddr_in6 *)&dataAddr)->sin6_port;
1498: snprintf (buf, sizeof(buf), "EPRT |2|%s|%s|\r\n", adp, portp);
1499: } else
1500: #endif
1501: {
1502: adp = (unsigned char *) &((struct sockaddr_in *)&dataAddr)->sin_addr;
1503: portp = (unsigned char *) &((struct sockaddr_in *)&dataAddr)->sin_port;
1504: snprintf (buf, sizeof(buf), "PORT %d,%d,%d,%d,%d,%d\r\n",
1505: adp[0] & 0xff, adp[1] & 0xff, adp[2] & 0xff, adp[3] & 0xff,
1506: portp[0] & 0xff, portp[1] & 0xff);
1507: }
1508:
1509: buf[sizeof(buf) - 1] = 0;
1510: len = strlen(buf);
1511: #ifdef DEBUG_FTP
1512: xmlGenericError(xmlGenericErrorContext, "%s", buf);
1513: #endif
1514:
1515: res = send(ctxt->controlFd, buf, len, 0);
1516: if (res < 0) {
1517: __xmlIOErr(XML_FROM_FTP, 0, "send failed");
1518: closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
1519: return INVALID_SOCKET;
1520: }
1521: res = xmlNanoFTPGetResponse(ctxt);
1522: if (res != 2) {
1523: closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
1524: return INVALID_SOCKET;
1525: }
1526: }
1527: return(ctxt->dataFd);
1528:
1529: }
1530:
1531: /**
1532: * xmlNanoFTPCloseConnection:
1533: * @ctx: an FTP context
1534: *
1535: * Close the data connection from the server
1536: *
1537: * Returns -1 incase of error, 0 otherwise
1538: */
1539:
1540: int
1541: xmlNanoFTPCloseConnection(void *ctx) {
1542: xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
1543: int res;
1544: fd_set rfd, efd;
1545: struct timeval tv;
1546:
1547: if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1);
1548:
1549: closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
1550: tv.tv_sec = 15;
1551: tv.tv_usec = 0;
1552: FD_ZERO(&rfd);
1553: FD_SET(ctxt->controlFd, &rfd);
1554: FD_ZERO(&efd);
1555: FD_SET(ctxt->controlFd, &efd);
1556: res = select(ctxt->controlFd + 1, &rfd, NULL, &efd, &tv);
1557: if (res < 0) {
1558: #ifdef DEBUG_FTP
1559: perror("select");
1560: #endif
1561: closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
1562: return(-1);
1563: }
1564: if (res == 0) {
1565: #ifdef DEBUG_FTP
1566: xmlGenericError(xmlGenericErrorContext,
1567: "xmlNanoFTPCloseConnection: timeout\n");
1568: #endif
1569: closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
1570: } else {
1571: res = xmlNanoFTPGetResponse(ctxt);
1572: if (res != 2) {
1573: closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
1574: return(-1);
1575: }
1576: }
1577: return(0);
1578: }
1579:
1580: /**
1581: * xmlNanoFTPParseList:
1582: * @list: some data listing received from the server
1583: * @callback: the user callback
1584: * @userData: the user callback data
1585: *
1586: * Parse at most one entry from the listing.
1587: *
1588: * Returns -1 incase of error, the length of data parsed otherwise
1589: */
1590:
1591: static int
1592: xmlNanoFTPParseList(const char *list, ftpListCallback callback, void *userData) {
1593: const char *cur = list;
1594: char filename[151];
1595: char attrib[11];
1596: char owner[11];
1597: char group[11];
1598: char month[4];
1599: int year = 0;
1600: int minute = 0;
1601: int hour = 0;
1602: int day = 0;
1603: unsigned long size = 0;
1604: int links = 0;
1605: int i;
1606:
1607: if (!strncmp(cur, "total", 5)) {
1608: cur += 5;
1609: while (*cur == ' ') cur++;
1610: while ((*cur >= '0') && (*cur <= '9'))
1611: links = (links * 10) + (*cur++ - '0');
1612: while ((*cur == ' ') || (*cur == '\n') || (*cur == '\r'))
1613: cur++;
1614: return(cur - list);
1615: } else if (*list == '+') {
1616: return(0);
1617: } else {
1618: while ((*cur == ' ') || (*cur == '\n') || (*cur == '\r'))
1619: cur++;
1620: if (*cur == 0) return(0);
1621: i = 0;
1622: while (*cur != ' ') {
1623: if (i < 10)
1624: attrib[i++] = *cur;
1625: cur++;
1626: if (*cur == 0) return(0);
1627: }
1628: attrib[10] = 0;
1629: while (*cur == ' ') cur++;
1630: if (*cur == 0) return(0);
1631: while ((*cur >= '0') && (*cur <= '9'))
1632: links = (links * 10) + (*cur++ - '0');
1633: while (*cur == ' ') cur++;
1634: if (*cur == 0) return(0);
1635: i = 0;
1636: while (*cur != ' ') {
1637: if (i < 10)
1638: owner[i++] = *cur;
1639: cur++;
1640: if (*cur == 0) return(0);
1641: }
1642: owner[i] = 0;
1643: while (*cur == ' ') cur++;
1644: if (*cur == 0) return(0);
1645: i = 0;
1646: while (*cur != ' ') {
1647: if (i < 10)
1648: group[i++] = *cur;
1649: cur++;
1650: if (*cur == 0) return(0);
1651: }
1652: group[i] = 0;
1653: while (*cur == ' ') cur++;
1654: if (*cur == 0) return(0);
1655: while ((*cur >= '0') && (*cur <= '9'))
1656: size = (size * 10) + (*cur++ - '0');
1657: while (*cur == ' ') cur++;
1658: if (*cur == 0) return(0);
1659: i = 0;
1660: while (*cur != ' ') {
1661: if (i < 3)
1662: month[i++] = *cur;
1663: cur++;
1664: if (*cur == 0) return(0);
1665: }
1666: month[i] = 0;
1667: while (*cur == ' ') cur++;
1668: if (*cur == 0) return(0);
1669: while ((*cur >= '0') && (*cur <= '9'))
1670: day = (day * 10) + (*cur++ - '0');
1671: while (*cur == ' ') cur++;
1672: if (*cur == 0) return(0);
1673: if ((cur[1] == 0) || (cur[2] == 0)) return(0);
1674: if ((cur[1] == ':') || (cur[2] == ':')) {
1675: while ((*cur >= '0') && (*cur <= '9'))
1676: hour = (hour * 10) + (*cur++ - '0');
1677: if (*cur == ':') cur++;
1678: while ((*cur >= '0') && (*cur <= '9'))
1679: minute = (minute * 10) + (*cur++ - '0');
1680: } else {
1681: while ((*cur >= '0') && (*cur <= '9'))
1682: year = (year * 10) + (*cur++ - '0');
1683: }
1684: while (*cur == ' ') cur++;
1685: if (*cur == 0) return(0);
1686: i = 0;
1687: while ((*cur != '\n') && (*cur != '\r')) {
1688: if (i < 150)
1689: filename[i++] = *cur;
1690: cur++;
1691: if (*cur == 0) return(0);
1692: }
1693: filename[i] = 0;
1694: if ((*cur != '\n') && (*cur != '\r'))
1695: return(0);
1696: while ((*cur == '\n') || (*cur == '\r'))
1697: cur++;
1698: }
1699: if (callback != NULL) {
1700: callback(userData, filename, attrib, owner, group, size, links,
1701: year, month, day, hour, minute);
1702: }
1703: return(cur - list);
1704: }
1705:
1706: /**
1707: * xmlNanoFTPList:
1708: * @ctx: an FTP context
1709: * @callback: the user callback
1710: * @userData: the user callback data
1711: * @filename: optional files to list
1712: *
1713: * Do a listing on the server. All files info are passed back
1714: * in the callbacks.
1715: *
1716: * Returns -1 incase of error, 0 otherwise
1717: */
1718:
1719: int
1720: xmlNanoFTPList(void *ctx, ftpListCallback callback, void *userData,
1721: const char *filename) {
1722: xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
1723: char buf[4096 + 1];
1724: int len, res;
1725: int indx = 0, base;
1726: fd_set rfd, efd;
1727: struct timeval tv;
1728:
1729: if (ctxt == NULL) return (-1);
1730: if (filename == NULL) {
1731: if (xmlNanoFTPCwd(ctxt, ctxt->path) < 1)
1732: return(-1);
1733: ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
1734: if (ctxt->dataFd == INVALID_SOCKET)
1735: return(-1);
1736: snprintf(buf, sizeof(buf), "LIST -L\r\n");
1737: } else {
1738: if (filename[0] != '/') {
1739: if (xmlNanoFTPCwd(ctxt, ctxt->path) < 1)
1740: return(-1);
1741: }
1742: ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
1743: if (ctxt->dataFd == INVALID_SOCKET)
1744: return(-1);
1745: snprintf(buf, sizeof(buf), "LIST -L %s\r\n", filename);
1746: }
1747: buf[sizeof(buf) - 1] = 0;
1748: len = strlen(buf);
1749: #ifdef DEBUG_FTP
1750: xmlGenericError(xmlGenericErrorContext, "%s", buf);
1751: #endif
1752: res = send(ctxt->controlFd, buf, len, 0);
1753: if (res < 0) {
1754: __xmlIOErr(XML_FROM_FTP, 0, "send failed");
1755: closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
1756: return(res);
1757: }
1758: res = xmlNanoFTPReadResponse(ctxt);
1759: if (res != 1) {
1760: closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
1761: return(-res);
1762: }
1763:
1764: do {
1765: tv.tv_sec = 1;
1766: tv.tv_usec = 0;
1767: FD_ZERO(&rfd);
1768: FD_SET(ctxt->dataFd, &rfd);
1769: FD_ZERO(&efd);
1770: FD_SET(ctxt->dataFd, &efd);
1771: res = select(ctxt->dataFd + 1, &rfd, NULL, &efd, &tv);
1772: if (res < 0) {
1773: #ifdef DEBUG_FTP
1774: perror("select");
1775: #endif
1776: closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
1777: return(-1);
1778: }
1779: if (res == 0) {
1780: res = xmlNanoFTPCheckResponse(ctxt);
1781: if (res < 0) {
1782: closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
1783: ctxt->dataFd = INVALID_SOCKET;
1784: return(-1);
1785: }
1786: if (res == 2) {
1787: closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
1788: return(0);
1789: }
1790:
1791: continue;
1792: }
1793:
1794: if ((len = recv(ctxt->dataFd, &buf[indx], sizeof(buf) - (indx + 1), 0)) < 0) {
1795: __xmlIOErr(XML_FROM_FTP, 0, "recv");
1796: closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
1797: ctxt->dataFd = INVALID_SOCKET;
1798: return(-1);
1799: }
1800: #ifdef DEBUG_FTP
1801: write(1, &buf[indx], len);
1802: #endif
1803: indx += len;
1804: buf[indx] = 0;
1805: base = 0;
1806: do {
1807: res = xmlNanoFTPParseList(&buf[base], callback, userData);
1808: base += res;
1809: } while (res > 0);
1810:
1811: memmove(&buf[0], &buf[base], indx - base);
1812: indx -= base;
1813: } while (len != 0);
1814: xmlNanoFTPCloseConnection(ctxt);
1815: return(0);
1816: }
1817:
1818: /**
1819: * xmlNanoFTPGetSocket:
1820: * @ctx: an FTP context
1821: * @filename: the file to retrieve (or NULL if path is in context).
1822: *
1823: * Initiate fetch of the given file from the server.
1824: *
1825: * Returns the socket for the data connection, or <0 in case of error
1826: */
1827:
1828:
1829: SOCKET
1830: xmlNanoFTPGetSocket(void *ctx, const char *filename) {
1831: xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
1832: char buf[300];
1833: int res, len;
1834: if (ctx == NULL)
1835: return INVALID_SOCKET;
1836: if ((filename == NULL) && (ctxt->path == NULL))
1837: return INVALID_SOCKET;
1838: ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
1839: if (ctxt->dataFd == INVALID_SOCKET)
1840: return INVALID_SOCKET;
1841:
1842: snprintf(buf, sizeof(buf), "TYPE I\r\n");
1843: len = strlen(buf);
1844: #ifdef DEBUG_FTP
1845: xmlGenericError(xmlGenericErrorContext, "%s", buf);
1846: #endif
1847: res = send(ctxt->controlFd, buf, len, 0);
1848: if (res < 0) {
1849: __xmlIOErr(XML_FROM_FTP, 0, "send failed");
1850: closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
1851: return INVALID_SOCKET;
1852: }
1853: res = xmlNanoFTPReadResponse(ctxt);
1854: if (res != 2) {
1855: closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
1856: return INVALID_SOCKET;
1857: }
1858: if (filename == NULL)
1859: snprintf(buf, sizeof(buf), "RETR %s\r\n", ctxt->path);
1860: else
1861: snprintf(buf, sizeof(buf), "RETR %s\r\n", filename);
1862: buf[sizeof(buf) - 1] = 0;
1863: len = strlen(buf);
1864: #ifdef DEBUG_FTP
1865: xmlGenericError(xmlGenericErrorContext, "%s", buf);
1866: #endif
1867: res = send(ctxt->controlFd, buf, len, 0);
1868: if (res < 0) {
1869: __xmlIOErr(XML_FROM_FTP, 0, "send failed");
1870: closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
1871: return INVALID_SOCKET;
1872: }
1873: res = xmlNanoFTPReadResponse(ctxt);
1874: if (res != 1) {
1875: closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
1876: return INVALID_SOCKET;
1877: }
1878: return(ctxt->dataFd);
1879: }
1880:
1881: /**
1882: * xmlNanoFTPGet:
1883: * @ctx: an FTP context
1884: * @callback: the user callback
1885: * @userData: the user callback data
1886: * @filename: the file to retrieve
1887: *
1888: * Fetch the given file from the server. All data are passed back
1889: * in the callbacks. The last callback has a size of 0 block.
1890: *
1891: * Returns -1 incase of error, 0 otherwise
1892: */
1893:
1894: int
1895: xmlNanoFTPGet(void *ctx, ftpDataCallback callback, void *userData,
1896: const char *filename) {
1897: xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
1898: char buf[4096];
1899: int len = 0, res;
1900: fd_set rfd;
1901: struct timeval tv;
1902:
1903: if (ctxt == NULL) return(-1);
1904: if ((filename == NULL) && (ctxt->path == NULL))
1905: return(-1);
1906: if (callback == NULL)
1907: return(-1);
1908: if (xmlNanoFTPGetSocket(ctxt, filename) == INVALID_SOCKET)
1909: return(-1);
1910:
1911: do {
1912: tv.tv_sec = 1;
1913: tv.tv_usec = 0;
1914: FD_ZERO(&rfd);
1915: FD_SET(ctxt->dataFd, &rfd);
1916: res = select(ctxt->dataFd + 1, &rfd, NULL, NULL, &tv);
1917: if (res < 0) {
1918: #ifdef DEBUG_FTP
1919: perror("select");
1920: #endif
1921: closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
1922: return(-1);
1923: }
1924: if (res == 0) {
1925: res = xmlNanoFTPCheckResponse(ctxt);
1926: if (res < 0) {
1927: closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
1928: ctxt->dataFd = INVALID_SOCKET;
1929: return(-1);
1930: }
1931: if (res == 2) {
1932: closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
1933: return(0);
1934: }
1935:
1936: continue;
1937: }
1938: if ((len = recv(ctxt->dataFd, buf, sizeof(buf), 0)) < 0) {
1939: __xmlIOErr(XML_FROM_FTP, 0, "recv failed");
1940: callback(userData, buf, len);
1941: closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
1942: return(-1);
1943: }
1944: callback(userData, buf, len);
1945: } while (len != 0);
1946:
1947: return(xmlNanoFTPCloseConnection(ctxt));
1948: }
1949:
1950: /**
1951: * xmlNanoFTPRead:
1952: * @ctx: the FTP context
1953: * @dest: a buffer
1954: * @len: the buffer length
1955: *
1956: * This function tries to read @len bytes from the existing FTP connection
1957: * and saves them in @dest. This is a blocking call.
1958: *
1959: * Returns the number of byte read. 0 is an indication of an end of connection.
1960: * -1 indicates a parameter error.
1961: */
1962: int
1963: xmlNanoFTPRead(void *ctx, void *dest, int len) {
1964: xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
1965:
1966: if (ctx == NULL) return(-1);
1967: if (ctxt->dataFd == INVALID_SOCKET) return(0);
1968: if (dest == NULL) return(-1);
1969: if (len <= 0) return(0);
1970:
1971: len = recv(ctxt->dataFd, dest, len, 0);
1972: if (len <= 0) {
1973: if (len < 0)
1974: __xmlIOErr(XML_FROM_FTP, 0, "recv failed");
1975: xmlNanoFTPCloseConnection(ctxt);
1976: }
1977: #ifdef DEBUG_FTP
1978: xmlGenericError(xmlGenericErrorContext, "Recvd %d bytes\n", len);
1979: #endif
1980: return(len);
1981: }
1982:
1983: /**
1984: * xmlNanoFTPOpen:
1985: * @URL: the URL to the resource
1986: *
1987: * Start to fetch the given ftp:// resource
1988: *
1989: * Returns an FTP context, or NULL
1990: */
1991:
1992: void*
1993: xmlNanoFTPOpen(const char *URL) {
1994: xmlNanoFTPCtxtPtr ctxt;
1995: SOCKET sock;
1996:
1997: xmlNanoFTPInit();
1998: if (URL == NULL) return(NULL);
1999: if (strncmp("ftp://", URL, 6)) return(NULL);
2000:
2001: ctxt = (xmlNanoFTPCtxtPtr) xmlNanoFTPNewCtxt(URL);
2002: if (ctxt == NULL) return(NULL);
2003: if (xmlNanoFTPConnect(ctxt) < 0) {
2004: xmlNanoFTPFreeCtxt(ctxt);
2005: return(NULL);
2006: }
2007: sock = xmlNanoFTPGetSocket(ctxt, ctxt->path);
2008: if (sock == INVALID_SOCKET) {
2009: xmlNanoFTPFreeCtxt(ctxt);
2010: return(NULL);
2011: }
2012: return(ctxt);
2013: }
2014:
2015: /**
2016: * xmlNanoFTPClose:
2017: * @ctx: an FTP context
2018: *
2019: * Close the connection and both control and transport
2020: *
2021: * Returns -1 incase of error, 0 otherwise
2022: */
2023:
2024: int
2025: xmlNanoFTPClose(void *ctx) {
2026: xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
2027:
2028: if (ctxt == NULL)
2029: return(-1);
2030:
2031: if (ctxt->dataFd != INVALID_SOCKET) {
2032: closesocket(ctxt->dataFd);
2033: ctxt->dataFd = INVALID_SOCKET;
2034: }
2035: if (ctxt->controlFd != INVALID_SOCKET) {
2036: xmlNanoFTPQuit(ctxt);
2037: closesocket(ctxt->controlFd);
2038: ctxt->controlFd = INVALID_SOCKET;
2039: }
2040: xmlNanoFTPFreeCtxt(ctxt);
2041: return(0);
2042: }
2043:
2044: #ifdef STANDALONE
2045: /************************************************************************
2046: * *
2047: * Basic test in Standalone mode *
2048: * *
2049: ************************************************************************/
2050: static
2051: void ftpList(void *userData, const char *filename, const char* attrib,
2052: const char *owner, const char *group, unsigned long size, int links,
2053: int year, const char *month, int day, int hour, int minute) {
2054: xmlGenericError(xmlGenericErrorContext,
2055: "%s %s %s %ld %s\n", attrib, owner, group, size, filename);
2056: }
2057: static
2058: void ftpData(void *userData, const char *data, int len) {
2059: if (userData == NULL) return;
2060: if (len <= 0) {
2061: fclose((FILE*)userData);
2062: return;
2063: }
2064: fwrite(data, len, 1, (FILE*)userData);
2065: }
2066:
2067: int main(int argc, char **argv) {
2068: void *ctxt;
2069: FILE *output;
2070: char *tstfile = NULL;
2071:
2072: xmlNanoFTPInit();
2073: if (argc > 1) {
2074: ctxt = xmlNanoFTPNewCtxt(argv[1]);
2075: if (xmlNanoFTPConnect(ctxt) < 0) {
2076: xmlGenericError(xmlGenericErrorContext,
2077: "Couldn't connect to %s\n", argv[1]);
2078: exit(1);
2079: }
2080: if (argc > 2)
2081: tstfile = argv[2];
2082: } else
2083: ctxt = xmlNanoFTPConnectTo("localhost", 0);
2084: if (ctxt == NULL) {
2085: xmlGenericError(xmlGenericErrorContext,
2086: "Couldn't connect to localhost\n");
2087: exit(1);
2088: }
2089: xmlNanoFTPList(ctxt, ftpList, NULL, tstfile);
2090: output = fopen("/tmp/tstdata", "w");
2091: if (output != NULL) {
2092: if (xmlNanoFTPGet(ctxt, ftpData, (void *) output, tstfile) < 0)
2093: xmlGenericError(xmlGenericErrorContext,
2094: "Failed to get file\n");
2095:
2096: }
2097: xmlNanoFTPClose(ctxt);
2098: xmlMemoryDump();
2099: exit(0);
2100: }
2101: #endif /* STANDALONE */
2102: #else /* !LIBXML_FTP_ENABLED */
2103: #ifdef STANDALONE
2104: #include <stdio.h>
2105: int main(int argc, char **argv) {
2106: xmlGenericError(xmlGenericErrorContext,
2107: "%s : FTP support not compiled in\n", argv[0]);
2108: return(0);
2109: }
2110: #endif /* STANDALONE */
2111: #endif /* LIBXML_FTP_ENABLED */
2112: #define bottom_nanoftp
2113: #include "elfgcchack.h"
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>