blob: a2ecc40876097b147e3bf8d213bbc3ed61556324 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
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
Daniel Veillardcbaf3992001-12-31 16:16:02 +000015#else /* TESTING */
Daniel Veillardf3afa7d2001-06-09 13:52:58 +000016#define NEED_SOCKETS
Daniel Veillardcbaf3992001-12-31 16:16:02 +000017#endif /* TESTING */
Owen Taylor3473f882001-02-23 17:55:21 +000018
Daniel Veillard34ce8be2002-03-18 19:37:11 +000019#define IN_LIBXML
Daniel Veillard5e2dace2001-07-18 19:30:27 +000020#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000021
22#ifdef LIBXML_FTP_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000023#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
Daniel Veillard75eb1ad2003-07-07 14:42:44 +000055#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
Owen Taylor3473f882001-02-23 17:55:21 +000061#ifdef HAVE_STRINGS_H
62#include <strings.h>
63#endif
64
65#include <libxml/xmlmemory.h>
Daniel Veillardd0463562001-10-13 09:15:48 +000066#include <libxml/parser.h>
Owen Taylor3473f882001-02-23 17:55:21 +000067#include <libxml/xmlerror.h>
Daniel Veillardcacbe5d2003-01-10 16:09:51 +000068#include <libxml/uri.h>
Daniel Veillardd0463562001-10-13 09:15:48 +000069#include <libxml/nanoftp.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000070#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000071
72/* #define DEBUG_FTP 1 */
73#ifdef STANDALONE
74#ifndef DEBUG_FTP
75#define DEBUG_FTP 1
76#endif
77#endif
78
Daniel Veillard1638a472003-08-14 01:23:25 +000079
80#ifdef __MINGW32__
81#define _WINSOCKAPI_
82#include <wsockcompat.h>
83#include <winsock2.h>
84#undef SOCKLEN_T
85#define SOCKLEN_T unsigned int
86#endif
87
88
Owen Taylor3473f882001-02-23 17:55:21 +000089/**
90 * A couple portability macros
91 */
92#ifndef _WINSOCKAPI_
Daniel Veillarda9cce9c2003-09-29 13:20:24 +000093#ifndef __BEOS__
Owen Taylor3473f882001-02-23 17:55:21 +000094#define closesocket(s) close(s)
Daniel Veillarda9cce9c2003-09-29 13:20:24 +000095#endif
Owen Taylor3473f882001-02-23 17:55:21 +000096#define SOCKET int
97#endif
Daniel Veillardacf7ff02001-10-29 20:21:47 +000098#if defined(VMS) || defined(__VMS)
99#define SOCKLEN_T unsigned int
100#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000101
Daniel Veillard89f7f272003-09-29 13:29:09 +0000102#ifdef __BEOS__
103#ifndef PF_INET
104#define PF_INET AF_INET
105#endif
106#endif
107
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000108
Owen Taylor3473f882001-02-23 17:55:21 +0000109#define FTP_COMMAND_OK 200
110#define FTP_SYNTAX_ERROR 500
111#define FTP_GET_PASSWD 331
112#define FTP_BUF_SIZE 512
113
William M. Brack030a7a12004-02-10 12:48:57 +0000114#define XML_NANO_MAX_URLBUF 4096
115
Owen Taylor3473f882001-02-23 17:55:21 +0000116typedef struct xmlNanoFTPCtxt {
117 char *protocol; /* the protocol name */
118 char *hostname; /* the host name */
119 int port; /* the port */
120 char *path; /* the path within the URL */
121 char *user; /* user string */
122 char *passwd; /* passwd string */
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000123#ifdef SUPPORT_IP6
124 struct sockaddr_storage ftpAddr; /* this is large enough to hold IPv6 address*/
125#else
Owen Taylor3473f882001-02-23 17:55:21 +0000126 struct sockaddr_in ftpAddr; /* the socket address struct */
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000127#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000128 int passive; /* currently we support only passive !!! */
129 SOCKET controlFd; /* the file descriptor for the control socket */
130 SOCKET dataFd; /* the file descriptor for the data socket */
131 int state; /* WRITE / READ / CLOSED */
132 int returnValue; /* the protocol return value */
133 /* buffer for data received from the control connection */
134 char controlBuf[FTP_BUF_SIZE + 1];
135 int controlBufIndex;
136 int controlBufUsed;
137 int controlBufAnswer;
138} xmlNanoFTPCtxt, *xmlNanoFTPCtxtPtr;
139
140static int initialized = 0;
141static char *proxy = NULL; /* the proxy name if any */
142static int proxyPort = 0; /* the proxy port if any */
143static char *proxyUser = NULL; /* user for proxy authentication */
144static char *proxyPasswd = NULL;/* passwd for proxy authentication */
145static int proxyType = 0; /* uses TYPE or a@b ? */
146
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000147#ifdef SUPPORT_IP6
Daniel Veillard2db8c122003-07-08 12:16:59 +0000148static
149int have_ipv6(void) {
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000150 int s;
151
152 s = socket (AF_INET6, SOCK_STREAM, 0);
153 if (s != -1) {
154 close (s);
155 return (1);
156 }
157 return (0);
158}
159#endif
160
Owen Taylor3473f882001-02-23 17:55:21 +0000161/**
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000162 * xmlFTPErrMemory:
163 * @extra: extra informations
164 *
165 * Handle an out of memory condition
166 */
167static void
168xmlFTPErrMemory(const char *extra)
169{
170 __xmlSimpleError(XML_FROM_FTP, XML_ERR_NO_MEMORY, NULL, NULL, extra);
171}
172
173/**
Owen Taylor3473f882001-02-23 17:55:21 +0000174 * xmlNanoFTPInit:
175 *
176 * Initialize the FTP protocol layer.
177 * Currently it just checks for proxy informations,
178 * and get the hostname
179 */
180
181void
182xmlNanoFTPInit(void) {
183 const char *env;
184#ifdef _WINSOCKAPI_
185 WSADATA wsaData;
186#endif
187
188 if (initialized)
189 return;
190
191#ifdef _WINSOCKAPI_
192 if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
193 return;
194#endif
195
Owen Taylor3473f882001-02-23 17:55:21 +0000196 proxyPort = 21;
197 env = getenv("no_proxy");
198 if (env != NULL)
199 return;
200 env = getenv("ftp_proxy");
201 if (env != NULL) {
202 xmlNanoFTPScanProxy(env);
203 } else {
204 env = getenv("FTP_PROXY");
205 if (env != NULL) {
206 xmlNanoFTPScanProxy(env);
207 }
208 }
209 env = getenv("ftp_proxy_user");
210 if (env != NULL) {
211 proxyUser = xmlMemStrdup(env);
212 }
213 env = getenv("ftp_proxy_password");
214 if (env != NULL) {
215 proxyPasswd = xmlMemStrdup(env);
216 }
217 initialized = 1;
218}
219
220/**
Daniel Veillarde356c282001-03-10 12:32:04 +0000221 * xmlNanoFTPCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +0000222 *
223 * Cleanup the FTP protocol layer. This cleanup proxy informations.
224 */
225
226void
227xmlNanoFTPCleanup(void) {
228 if (proxy != NULL) {
229 xmlFree(proxy);
230 proxy = NULL;
231 }
232 if (proxyUser != NULL) {
233 xmlFree(proxyUser);
234 proxyUser = NULL;
235 }
236 if (proxyPasswd != NULL) {
237 xmlFree(proxyPasswd);
238 proxyPasswd = NULL;
239 }
Owen Taylor3473f882001-02-23 17:55:21 +0000240#ifdef _WINSOCKAPI_
241 if (initialized)
242 WSACleanup();
243#endif
244 initialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000245}
246
247/**
248 * xmlNanoFTPProxy:
249 * @host: the proxy host name
250 * @port: the proxy port
251 * @user: the proxy user name
252 * @passwd: the proxy password
253 * @type: the type of proxy 1 for using SITE, 2 for USER a@b
254 *
255 * Setup the FTP proxy informations.
256 * This can also be done by using ftp_proxy ftp_proxy_user and
257 * ftp_proxy_password environment variables.
258 */
259
260void
261xmlNanoFTPProxy(const char *host, int port, const char *user,
262 const char *passwd, int type) {
263 if (proxy != NULL)
264 xmlFree(proxy);
265 if (proxyUser != NULL)
266 xmlFree(proxyUser);
267 if (proxyPasswd != NULL)
268 xmlFree(proxyPasswd);
269 if (host)
270 proxy = xmlMemStrdup(host);
271 if (user)
272 proxyUser = xmlMemStrdup(user);
273 if (passwd)
274 proxyPasswd = xmlMemStrdup(passwd);
275 proxyPort = port;
276 proxyType = type;
277}
278
279/**
280 * xmlNanoFTPScanURL:
281 * @ctx: an FTP context
282 * @URL: The URL used to initialize the context
283 *
284 * (Re)Initialize an FTP context by parsing the URL and finding
285 * the protocol host port and path it indicates.
286 */
287
288static void
289xmlNanoFTPScanURL(void *ctx, const char *URL) {
290 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
291 const char *cur = URL;
William M. Brack030a7a12004-02-10 12:48:57 +0000292 char buf[XML_NANO_MAX_URLBUF];
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000293 int indx = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000294 int port = 0;
295
296 if (ctxt->protocol != NULL) {
297 xmlFree(ctxt->protocol);
298 ctxt->protocol = NULL;
299 }
300 if (ctxt->hostname != NULL) {
301 xmlFree(ctxt->hostname);
302 ctxt->hostname = NULL;
303 }
304 if (ctxt->path != NULL) {
305 xmlFree(ctxt->path);
306 ctxt->path = NULL;
307 }
308 if (URL == NULL) return;
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000309 buf[indx] = 0;
William M. Brack030a7a12004-02-10 12:48:57 +0000310 while ((*cur != 0) && (indx < XML_NANO_MAX_URLBUF - 1)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000311 if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000312 buf[indx] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000313 ctxt->protocol = xmlMemStrdup(buf);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000314 indx = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000315 cur += 3;
316 break;
317 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000318 buf[indx++] = *cur++;
Owen Taylor3473f882001-02-23 17:55:21 +0000319 }
320 if (*cur == 0) return;
321
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000322 buf[indx] = 0;
Daniel Veillardc69e0b12001-11-20 08:35:07 +0000323 /* allow user@ and user:pass@ forms */
324 {
325 const char *p = strchr(cur, '@');
326 if(p) {
William M. Brack030a7a12004-02-10 12:48:57 +0000327 while(indx < XML_NANO_MAX_URLBUF-1) {
Daniel Veillardc69e0b12001-11-20 08:35:07 +0000328 if(cur[0] == ':' || cur[0] == '@') break;
329 buf[indx++] = *cur++;
330 }
331 buf[indx] = 0;
332 ctxt->user = xmlMemStrdup(buf);
333 indx = 0;
334 if(cur[0] == ':') {
335 cur++;
William M. Brack030a7a12004-02-10 12:48:57 +0000336 while(indx < XML_NANO_MAX_URLBUF-1) {
Daniel Veillardc69e0b12001-11-20 08:35:07 +0000337 if(cur[0] == '@') break;
338 buf[indx++] = *cur++;
339 }
340 buf[indx] = 0;
341 ctxt->passwd = xmlMemStrdup(buf);
342 indx = 0;
343 }
344 cur = p+1;
345 }
346 }
347
William M. Brack030a7a12004-02-10 12:48:57 +0000348 while (indx < XML_NANO_MAX_URLBUF - 1) {
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000349 if ((strchr (cur, '[') && !strchr (cur, ']')) ||
350 (!strchr (cur, '[') && strchr (cur, ']'))) {
351 xmlGenericError (xmlGenericErrorContext, "\nxmlNanoFTPScanURL: %s",
352 "Syntax Error\n");
353 return;
354 }
355
356 if (cur[0] == '[') {
357 cur++;
358 while (cur[0] != ']')
359 buf[indx++] = *cur++;
360
361 if (!strchr (buf, ':')) {
362 xmlGenericError (xmlGenericErrorContext, "\nxmlNanoFTPScanURL: %s",
363 "Use [IPv6]/IPv4 format\n");
364 return;
365 }
366
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000367 buf[indx] = 0;
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000368 ctxt->hostname = xmlMemStrdup (buf);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000369 indx = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000370 cur += 1;
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000371 if (cur[0] == ':') {
Owen Taylor3473f882001-02-23 17:55:21 +0000372 cur++;
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000373 while (*cur >= '0' && *cur <= '9') {
374 port *= 10;
375 port += *cur - '0';
376 cur++;
377 }
378
379 if (port != 0) ctxt->port = port;
380 while ((cur[0] != '/') && (*cur != 0))
381 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +0000382 }
Owen Taylor3473f882001-02-23 17:55:21 +0000383 break;
384 }
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000385 else { /* address is an IPv4 one*/
386 if (cur[0] == ':') {
387 buf[indx] = 0;
388 ctxt->hostname = xmlMemStrdup (buf);
389 indx = 0;
390 cur += 1;
391 while ((*cur >= '0') && (*cur <= '9')) {
392 port *= 10;
393 port += *cur - '0';
394 cur++;
395 }
396 if (port != 0) ctxt->port = port;
397 while ((cur[0] != '/') && (*cur != 0))
398 cur++;
399 break;
400 }
401 if ((*cur == '/') || (*cur == 0)) {
402 buf[indx] = 0;
403 ctxt->hostname = xmlMemStrdup (buf);
404 indx = 0;
405 break;
406 }
Owen Taylor3473f882001-02-23 17:55:21 +0000407 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000408 buf[indx++] = *cur++;
Owen Taylor3473f882001-02-23 17:55:21 +0000409 }
410 if (*cur == 0)
411 ctxt->path = xmlMemStrdup("/");
412 else {
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000413 indx = 0;
414 buf[indx] = 0;
William M. Brack030a7a12004-02-10 12:48:57 +0000415 while ((*cur != 0) && (indx < XML_NANO_MAX_URLBUF-1))
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000416 buf[indx++] = *cur++;
417 buf[indx] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000418 ctxt->path = xmlMemStrdup(buf);
419 }
420}
421
422/**
423 * xmlNanoFTPUpdateURL:
424 * @ctx: an FTP context
425 * @URL: The URL used to update the context
426 *
427 * Update an FTP context by parsing the URL and finding
428 * new path it indicates. If there is an error in the
429 * protocol, hostname, port or other information, the
430 * error is raised. It indicates a new connection has to
431 * be established.
432 *
433 * Returns 0 if Ok, -1 in case of error (other host).
434 */
435
436int
437xmlNanoFTPUpdateURL(void *ctx, const char *URL) {
438 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
439 const char *cur = URL;
William M. Brack030a7a12004-02-10 12:48:57 +0000440 char buf[XML_NANO_MAX_URLBUF];
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000441 int indx = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000442 int port = 0;
443
444 if (URL == NULL)
445 return(-1);
446 if (ctxt == NULL)
447 return(-1);
448 if (ctxt->protocol == NULL)
449 return(-1);
450 if (ctxt->hostname == NULL)
451 return(-1);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000452 buf[indx] = 0;
William M. Brack030a7a12004-02-10 12:48:57 +0000453 while ((*cur != 0) && (indx < XML_NANO_MAX_URLBUF-1)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000454 if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000455 buf[indx] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000456 if (strcmp(ctxt->protocol, buf))
457 return(-1);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000458 indx = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000459 cur += 3;
460 break;
461 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000462 buf[indx++] = *cur++;
Owen Taylor3473f882001-02-23 17:55:21 +0000463 }
464 if (*cur == 0)
465 return(-1);
466
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000467 buf[indx] = 0;
William M. Brack030a7a12004-02-10 12:48:57 +0000468 while (indx < XML_NANO_MAX_URLBUF-1) {
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000469 if ((strchr (cur, '[') && !strchr (cur, ']')) ||
470 (!strchr (cur, '[') && strchr (cur, ']'))) {
471 xmlGenericError (xmlGenericErrorContext, "\nxmlNanoFTPUpdateURL: %s",
472 "Syntax Error\n");
473 return (-1);
474 }
475
476 if (cur[0] == '[') {
477 cur++;
William M. Brack030a7a12004-02-10 12:48:57 +0000478 while ((cur[0] != ']') && (indx < XML_NANO_MAX_URLBUF-1))
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000479 buf[indx++] = *cur++;
480
481 if (!strchr (buf, ':')) {
482 xmlGenericError (xmlGenericErrorContext, "\nxmlNanoFTPUpdateURL: %s",
483 "Use [IPv6]/IPv4 format\n");
484 return (-1);
485 }
486
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000487 buf[indx] = 0;
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000488 if (strcmp (ctxt->hostname, buf))
489 return (-1);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000490 indx = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000491 cur += 1;
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000492 if (cur[0] == ':') {
Owen Taylor3473f882001-02-23 17:55:21 +0000493 cur++;
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000494 while (*cur >= '0' && *cur <= '9') {
495 port *= 10;
496 port += *cur - '0';
497 cur++;
498 }
499
500 if (port != ctxt->port)
501 return (-1);
502 while ((cur[0] != '/') && (*cur != 0))
503 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +0000504 }
Owen Taylor3473f882001-02-23 17:55:21 +0000505 break;
506 }
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000507 else {
508 if (cur[0] == ':') {
509 buf[indx] = 0;
510 if (strcmp (ctxt->hostname, buf))
511 return (-1);
512 indx = 0;
513 cur += 1;
514 while ((*cur >= '0') && (*cur <= '9')) {
515 port *= 10;
516 port += *cur - '0';
517 cur++;
518 }
519 if (port != ctxt->port)
520 return (-1);
521 while ((cur[0] != '/') && (*cur != 0))
522 cur++;
523 break;
524 }
525 if ((*cur == '/') || (*cur == 0)) {
526 buf[indx] = 0;
527 if (strcmp (ctxt->hostname, buf))
528 return (-1);
529 indx = 0;
530 break;
531 }
Owen Taylor3473f882001-02-23 17:55:21 +0000532 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000533 buf[indx++] = *cur++;
Owen Taylor3473f882001-02-23 17:55:21 +0000534 }
535 if (ctxt->path != NULL) {
536 xmlFree(ctxt->path);
537 ctxt->path = NULL;
538 }
539
540 if (*cur == 0)
541 ctxt->path = xmlMemStrdup("/");
542 else {
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000543 indx = 0;
544 buf[indx] = 0;
William M. Brack030a7a12004-02-10 12:48:57 +0000545 while ((*cur != 0) && (indx < XML_NANO_MAX_URLBUF-1))
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000546 buf[indx++] = *cur++;
547 buf[indx] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000548 ctxt->path = xmlMemStrdup(buf);
549 }
550 return(0);
551}
552
553/**
554 * xmlNanoFTPScanProxy:
555 * @URL: The proxy URL used to initialize the proxy context
556 *
557 * (Re)Initialize the FTP Proxy context by parsing the URL and finding
558 * the protocol host port it indicates.
559 * Should be like ftp://myproxy/ or ftp://myproxy:3128/
560 * A NULL URL cleans up proxy informations.
561 */
562
563void
564xmlNanoFTPScanProxy(const char *URL) {
565 const char *cur = URL;
William M. Brack030a7a12004-02-10 12:48:57 +0000566 char buf[XML_NANO_MAX_URLBUF];
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000567 int indx = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000568 int port = 0;
569
570 if (proxy != NULL) {
571 xmlFree(proxy);
572 proxy = NULL;
573 }
574 if (proxyPort != 0) {
575 proxyPort = 0;
576 }
577#ifdef DEBUG_FTP
578 if (URL == NULL)
579 xmlGenericError(xmlGenericErrorContext, "Removing FTP proxy info\n");
580 else
581 xmlGenericError(xmlGenericErrorContext, "Using FTP proxy %s\n", URL);
582#endif
583 if (URL == NULL) return;
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000584 buf[indx] = 0;
William M. Brack030a7a12004-02-10 12:48:57 +0000585 while ((*cur != 0) && (indx < XML_NANO_MAX_URLBUF-1)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000586 if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000587 buf[indx] = 0;
588 indx = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000589 cur += 3;
590 break;
591 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000592 buf[indx++] = *cur++;
Owen Taylor3473f882001-02-23 17:55:21 +0000593 }
594 if (*cur == 0) return;
595
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000596 buf[indx] = 0;
William M. Brack030a7a12004-02-10 12:48:57 +0000597 while (indx < XML_NANO_MAX_URLBUF-1) {
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000598 if ((strchr (cur, '[') && !strchr (cur, ']')) ||
599 (!strchr (cur, '[') && strchr (cur, ']'))) {
600 xmlGenericError (xmlGenericErrorContext, "\nxmlNanoFTPScanProxy: %s",
601 "Syntax error\n");
602 return;
603 }
604
605 if (cur[0] == '[') {
606 cur++;
607 while (cur[0] != ']')
608 buf[indx++] = *cur++;
609 if (!strchr (buf, ':')) {
610 xmlGenericError (xmlGenericErrorContext, "\nxmlNanoFTPScanProxy: %s",
611 "Use [IPv6]/IPv4 format\n");
612 return;
613 }
614
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000615 buf[indx] = 0;
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000616 proxy = xmlMemStrdup (buf);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000617 indx = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000618 cur += 1;
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000619 if (cur[0] == ':') {
Owen Taylor3473f882001-02-23 17:55:21 +0000620 cur++;
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000621 while (*cur >= '0' && *cur <= '9') {
622 port *= 10;
623 port += *cur - '0';
624 cur++;
625 }
626
627 if (port != 0) proxyPort = port;
628 while ((cur[0] != '/') && (*cur != 0))
629 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +0000630 }
Owen Taylor3473f882001-02-23 17:55:21 +0000631 break;
632 }
Daniel Veillardde2a67b2003-06-21 14:20:04 +0000633 else {
634 if (cur[0] == ':') {
635 buf[indx] = 0;
636 proxy = xmlMemStrdup (buf);
637 indx = 0;
638 cur += 1;
639 while ((*cur >= '0') && (*cur <= '9')) {
640 port *= 10;
641 port += *cur - '0';
642 cur++;
643 }
644 if (port != 0) proxyPort = port;
645 while ((cur[0] != '/') && (*cur != 0))
646 cur++;
647 break;
648 }
649 if ((*cur == '/') || (*cur == 0)) {
650 buf[indx] = 0;
651 proxy = xmlMemStrdup (buf);
652 indx = 0;
653 break;
654 }
Owen Taylor3473f882001-02-23 17:55:21 +0000655 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000656 buf[indx++] = *cur++;
Owen Taylor3473f882001-02-23 17:55:21 +0000657 }
658}
659
660/**
661 * xmlNanoFTPNewCtxt:
662 * @URL: The URL used to initialize the context
663 *
664 * Allocate and initialize a new FTP context.
665 *
666 * Returns an FTP context or NULL in case of error.
667 */
668
669void*
670xmlNanoFTPNewCtxt(const char *URL) {
671 xmlNanoFTPCtxtPtr ret;
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000672 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +0000673
674 ret = (xmlNanoFTPCtxtPtr) xmlMalloc(sizeof(xmlNanoFTPCtxt));
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000675 if (ret == NULL) {
676 xmlFTPErrMemory("allocating FTP context");
677 return(NULL);
678 }
Owen Taylor3473f882001-02-23 17:55:21 +0000679
680 memset(ret, 0, sizeof(xmlNanoFTPCtxt));
681 ret->port = 21;
682 ret->passive = 1;
683 ret->returnValue = 0;
684 ret->controlBufIndex = 0;
685 ret->controlBufUsed = 0;
Daniel Veillardc69e0b12001-11-20 08:35:07 +0000686 ret->controlFd = -1;
Owen Taylor3473f882001-02-23 17:55:21 +0000687
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000688 unescaped = xmlURIUnescapeString(URL, 0, NULL);
689 if (unescaped != NULL)
690 xmlNanoFTPScanURL(ret, unescaped);
691 else if (URL != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +0000692 xmlNanoFTPScanURL(ret, URL);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000693 xmlFree(unescaped);
Owen Taylor3473f882001-02-23 17:55:21 +0000694
695 return(ret);
696}
697
698/**
699 * xmlNanoFTPFreeCtxt:
700 * @ctx: an FTP context
701 *
702 * Frees the context after closing the connection.
703 */
704
705void
706xmlNanoFTPFreeCtxt(void * ctx) {
707 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
708 if (ctxt == NULL) return;
709 if (ctxt->hostname != NULL) xmlFree(ctxt->hostname);
710 if (ctxt->protocol != NULL) xmlFree(ctxt->protocol);
711 if (ctxt->path != NULL) xmlFree(ctxt->path);
712 ctxt->passive = 1;
713 if (ctxt->controlFd >= 0) closesocket(ctxt->controlFd);
714 ctxt->controlFd = -1;
715 ctxt->controlBufIndex = -1;
716 ctxt->controlBufUsed = -1;
717 xmlFree(ctxt);
718}
719
720/**
721 * xmlNanoFTPParseResponse:
Owen Taylor3473f882001-02-23 17:55:21 +0000722 * @buf: the buffer containing the response
723 * @len: the buffer length
724 *
725 * Parsing of the server answer, we just extract the code.
726 *
727 * returns 0 for errors
728 * +XXX for last line of response
729 * -XXX for response to be continued
730 */
731static int
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000732xmlNanoFTPParseResponse(char *buf, int len) {
Owen Taylor3473f882001-02-23 17:55:21 +0000733 int val = 0;
734
735 if (len < 3) return(-1);
736 if ((*buf >= '0') && (*buf <= '9'))
737 val = val * 10 + (*buf - '0');
738 else
739 return(0);
740 buf++;
741 if ((*buf >= '0') && (*buf <= '9'))
742 val = val * 10 + (*buf - '0');
743 else
744 return(0);
745 buf++;
746 if ((*buf >= '0') && (*buf <= '9'))
747 val = val * 10 + (*buf - '0');
748 else
749 return(0);
750 buf++;
751 if (*buf == '-')
752 return(-val);
753 return(val);
754}
755
756/**
757 * xmlNanoFTPGetMore:
758 * @ctx: an FTP context
759 *
760 * Read more information from the FTP control connection
761 * Returns the number of bytes read, < 0 indicates an error
762 */
763static int
764xmlNanoFTPGetMore(void *ctx) {
765 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
766 int len;
767 int size;
768
769 if ((ctxt->controlBufIndex < 0) || (ctxt->controlBufIndex > FTP_BUF_SIZE)) {
770#ifdef DEBUG_FTP
771 xmlGenericError(xmlGenericErrorContext,
772 "xmlNanoFTPGetMore : controlBufIndex = %d\n",
773 ctxt->controlBufIndex);
774#endif
775 return(-1);
776 }
777
778 if ((ctxt->controlBufUsed < 0) || (ctxt->controlBufUsed > FTP_BUF_SIZE)) {
779#ifdef DEBUG_FTP
780 xmlGenericError(xmlGenericErrorContext,
781 "xmlNanoFTPGetMore : controlBufUsed = %d\n",
782 ctxt->controlBufUsed);
783#endif
784 return(-1);
785 }
786 if (ctxt->controlBufIndex > ctxt->controlBufUsed) {
787#ifdef DEBUG_FTP
788 xmlGenericError(xmlGenericErrorContext,
789 "xmlNanoFTPGetMore : controlBufIndex > controlBufUsed %d > %d\n",
790 ctxt->controlBufIndex, ctxt->controlBufUsed);
791#endif
792 return(-1);
793 }
794
795 /*
796 * First pack the control buffer
797 */
798 if (ctxt->controlBufIndex > 0) {
799 memmove(&ctxt->controlBuf[0], &ctxt->controlBuf[ctxt->controlBufIndex],
800 ctxt->controlBufUsed - ctxt->controlBufIndex);
801 ctxt->controlBufUsed -= ctxt->controlBufIndex;
802 ctxt->controlBufIndex = 0;
803 }
804 size = FTP_BUF_SIZE - ctxt->controlBufUsed;
805 if (size == 0) {
806#ifdef DEBUG_FTP
807 xmlGenericError(xmlGenericErrorContext,
808 "xmlNanoFTPGetMore : buffer full %d \n", ctxt->controlBufUsed);
809#endif
810 return(0);
811 }
812
813 /*
Daniel Veillard60087f32001-10-10 09:45:09 +0000814 * Read the amount left on the control connection
Owen Taylor3473f882001-02-23 17:55:21 +0000815 */
816 if ((len = recv(ctxt->controlFd, &ctxt->controlBuf[ctxt->controlBufIndex],
817 size, 0)) < 0) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000818 __xmlIOErr(XML_FROM_FTP, 0, "recv failed");
Owen Taylor3473f882001-02-23 17:55:21 +0000819 closesocket(ctxt->controlFd); ctxt->controlFd = -1;
820 ctxt->controlFd = -1;
821 return(-1);
822 }
823#ifdef DEBUG_FTP
824 xmlGenericError(xmlGenericErrorContext,
825 "xmlNanoFTPGetMore : read %d [%d - %d]\n", len,
826 ctxt->controlBufUsed, ctxt->controlBufUsed + len);
827#endif
828 ctxt->controlBufUsed += len;
829 ctxt->controlBuf[ctxt->controlBufUsed] = 0;
830
831 return(len);
832}
833
834/**
835 * xmlNanoFTPReadResponse:
836 * @ctx: an FTP context
837 *
838 * Read the response from the FTP server after a command.
839 * Returns the code number
840 */
841static int
842xmlNanoFTPReadResponse(void *ctx) {
843 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
844 char *ptr, *end;
845 int len;
846 int res = -1, cur = -1;
847
848get_more:
849 /*
850 * Assumes everything up to controlBuf[controlBufIndex] has been read
851 * and analyzed.
852 */
853 len = xmlNanoFTPGetMore(ctx);
854 if (len < 0) {
855 return(-1);
856 }
857 if ((ctxt->controlBufUsed == 0) && (len == 0)) {
858 return(-1);
859 }
860 ptr = &ctxt->controlBuf[ctxt->controlBufIndex];
861 end = &ctxt->controlBuf[ctxt->controlBufUsed];
862
863#ifdef DEBUG_FTP
864 xmlGenericError(xmlGenericErrorContext,
865 "\n<<<\n%s\n--\n", ptr);
866#endif
867 while (ptr < end) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000868 cur = xmlNanoFTPParseResponse(ptr, end - ptr);
Owen Taylor3473f882001-02-23 17:55:21 +0000869 if (cur > 0) {
870 /*
871 * Successfully scanned the control code, scratch
872 * till the end of the line, but keep the index to be
873 * able to analyze the result if needed.
874 */
875 res = cur;
876 ptr += 3;
877 ctxt->controlBufAnswer = ptr - ctxt->controlBuf;
878 while ((ptr < end) && (*ptr != '\n')) ptr++;
879 if (*ptr == '\n') ptr++;
880 if (*ptr == '\r') ptr++;
881 break;
882 }
883 while ((ptr < end) && (*ptr != '\n')) ptr++;
884 if (ptr >= end) {
885 ctxt->controlBufIndex = ctxt->controlBufUsed;
886 goto get_more;
887 }
888 if (*ptr != '\r') ptr++;
889 }
890
891 if (res < 0) goto get_more;
892 ctxt->controlBufIndex = ptr - ctxt->controlBuf;
893#ifdef DEBUG_FTP
894 ptr = &ctxt->controlBuf[ctxt->controlBufIndex];
895 xmlGenericError(xmlGenericErrorContext, "\n---\n%s\n--\n", ptr);
896#endif
897
898#ifdef DEBUG_FTP
899 xmlGenericError(xmlGenericErrorContext, "Got %d\n", res);
900#endif
901 return(res / 100);
902}
903
904/**
905 * xmlNanoFTPGetResponse:
906 * @ctx: an FTP context
907 *
908 * Get the response from the FTP server after a command.
909 * Returns the code number
910 */
911
912int
913xmlNanoFTPGetResponse(void *ctx) {
914 int res;
915
916 res = xmlNanoFTPReadResponse(ctx);
917
918 return(res);
919}
920
921/**
922 * xmlNanoFTPCheckResponse:
923 * @ctx: an FTP context
924 *
925 * Check if there is a response from the FTP server after a command.
926 * Returns the code number, or 0
927 */
928
929int
930xmlNanoFTPCheckResponse(void *ctx) {
931 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
932 fd_set rfd;
933 struct timeval tv;
934
935 tv.tv_sec = 0;
936 tv.tv_usec = 0;
937 FD_ZERO(&rfd);
938 FD_SET(ctxt->controlFd, &rfd);
939 switch(select(ctxt->controlFd + 1, &rfd, NULL, NULL, &tv)) {
940 case 0:
941 return(0);
942 case -1:
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000943 __xmlIOErr(XML_FROM_FTP, 0, "select");
Owen Taylor3473f882001-02-23 17:55:21 +0000944 return(-1);
945
946 }
947
948 return(xmlNanoFTPReadResponse(ctx));
949}
950
951/**
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000952 * Send the user authentication
Owen Taylor3473f882001-02-23 17:55:21 +0000953 */
954
955static int
956xmlNanoFTPSendUser(void *ctx) {
957 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
958 char buf[200];
959 int len;
960 int res;
961
962 if (ctxt->user == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000963 snprintf(buf, sizeof(buf), "USER anonymous\r\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000964 else
Owen Taylor3473f882001-02-23 17:55:21 +0000965 snprintf(buf, sizeof(buf), "USER %s\r\n", ctxt->user);
Owen Taylor3473f882001-02-23 17:55:21 +0000966 buf[sizeof(buf) - 1] = 0;
967 len = strlen(buf);
968#ifdef DEBUG_FTP
Daniel Veillard635ef722001-10-29 11:48:19 +0000969 xmlGenericError(xmlGenericErrorContext, "%s", buf);
Owen Taylor3473f882001-02-23 17:55:21 +0000970#endif
971 res = send(ctxt->controlFd, buf, len, 0);
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000972 if (res < 0) {
973 __xmlIOErr(XML_FROM_FTP, 0, "send failed");
974 return(res);
975 }
Owen Taylor3473f882001-02-23 17:55:21 +0000976 return(0);
977}
978
979/**
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000980 * Send the password authentication
Owen Taylor3473f882001-02-23 17:55:21 +0000981 */
982
983static int
984xmlNanoFTPSendPasswd(void *ctx) {
985 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
986 char buf[200];
987 int len;
988 int res;
989
990 if (ctxt->passwd == NULL)
Daniel Veillard9ae1eba2001-10-19 09:48:35 +0000991 snprintf(buf, sizeof(buf), "PASS anonymous@\r\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000992 else
Owen Taylor3473f882001-02-23 17:55:21 +0000993 snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd);
Owen Taylor3473f882001-02-23 17:55:21 +0000994 buf[sizeof(buf) - 1] = 0;
995 len = strlen(buf);
996#ifdef DEBUG_FTP
Daniel Veillard635ef722001-10-29 11:48:19 +0000997 xmlGenericError(xmlGenericErrorContext, "%s", buf);
Owen Taylor3473f882001-02-23 17:55:21 +0000998#endif
999 res = send(ctxt->controlFd, buf, len, 0);
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001000 if (res < 0) {
1001 __xmlIOErr(XML_FROM_FTP, 0, "send failed");
1002 return(res);
1003 }
Owen Taylor3473f882001-02-23 17:55:21 +00001004 return(0);
1005}
1006
1007/**
1008 * xmlNanoFTPQuit:
1009 * @ctx: an FTP context
1010 *
1011 * Send a QUIT command to the server
1012 *
1013 * Returns -1 in case of error, 0 otherwise
1014 */
1015
1016
1017int
1018xmlNanoFTPQuit(void *ctx) {
1019 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
1020 char buf[200];
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001021 int len, res;
Owen Taylor3473f882001-02-23 17:55:21 +00001022
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001023 snprintf(buf, sizeof(buf), "QUIT\r\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001024 len = strlen(buf);
1025#ifdef DEBUG_FTP
Daniel Veillard635ef722001-10-29 11:48:19 +00001026 xmlGenericError(xmlGenericErrorContext, "%s", buf); /* Just to be consistent, even though we know it can't have a % in it */
Owen Taylor3473f882001-02-23 17:55:21 +00001027#endif
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001028 res = send(ctxt->controlFd, buf, len, 0);
1029 if (res < 0) {
1030 __xmlIOErr(XML_FROM_FTP, 0, "send failed");
1031 return(res);
1032 }
Owen Taylor3473f882001-02-23 17:55:21 +00001033 return(0);
1034}
1035
1036/**
1037 * xmlNanoFTPConnect:
1038 * @ctx: an FTP context
1039 *
1040 * Tries to open a control connection
1041 *
1042 * Returns -1 in case of error, 0 otherwise
1043 */
1044
1045int
1046xmlNanoFTPConnect(void *ctx) {
1047 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
1048 struct hostent *hp;
1049 int port;
1050 int res;
Daniel Veillard2db8c122003-07-08 12:16:59 +00001051 int addrlen = sizeof (struct sockaddr_in);
Owen Taylor3473f882001-02-23 17:55:21 +00001052
1053 if (ctxt == NULL)
1054 return(-1);
1055 if (ctxt->hostname == NULL)
1056 return(-1);
1057
1058 /*
1059 * do the blocking DNS query.
1060 */
Owen Taylor3473f882001-02-23 17:55:21 +00001061 if (proxy) {
1062 port = proxyPort;
1063 } else {
1064 port = ctxt->port;
1065 }
1066 if (port == 0)
1067 port = 21;
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001068
1069 memset (&ctxt->ftpAddr, 0, sizeof(ctxt->ftpAddr));
1070
1071#ifdef SUPPORT_IP6
1072 if (have_ipv6 ()) {
Daniel Veillard2db8c122003-07-08 12:16:59 +00001073 struct addrinfo hints, *tmp, *result;
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001074
1075 result = NULL;
1076 memset (&hints, 0, sizeof(hints));
1077 hints.ai_socktype = SOCK_STREAM;
1078
1079 if (proxy) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001080 if (getaddrinfo (proxy, NULL, &hints, &result) != 0) {
1081 __xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed");
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001082 return (-1);
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001083 }
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001084 }
1085 else
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001086 if (getaddrinfo (ctxt->hostname, NULL, &hints, &result) != 0) {
1087 __xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed");
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001088 return (-1);
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001089 }
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001090
Daniel Veillard2db8c122003-07-08 12:16:59 +00001091 for (tmp = result; tmp; tmp = tmp->ai_next)
1092 if (tmp->ai_family == AF_INET || tmp->ai_family == AF_INET6)
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001093 break;
1094
Daniel Veillard3dc93a42003-07-10 14:04:33 +00001095 if (!tmp) {
1096 if (result)
1097 freeaddrinfo (result);
1098 return (-1);
1099 }
1100 else {
Daniel Veillard2db8c122003-07-08 12:16:59 +00001101 if (tmp->ai_family == AF_INET6) {
1102 memcpy (&ctxt->ftpAddr, tmp->ai_addr, tmp->ai_addrlen);
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001103 ((struct sockaddr_in6 *) &ctxt->ftpAddr)->sin6_port = htons (port);
1104 ctxt->controlFd = socket (AF_INET6, SOCK_STREAM, 0);
1105 }
1106 else {
Daniel Veillard2db8c122003-07-08 12:16:59 +00001107 memcpy (&ctxt->ftpAddr, tmp->ai_addr, tmp->ai_addrlen);
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001108 ((struct sockaddr_in *) &ctxt->ftpAddr)->sin_port = htons (port);
1109 ctxt->controlFd = socket (AF_INET, SOCK_STREAM, 0);
1110 }
Daniel Veillard2db8c122003-07-08 12:16:59 +00001111 addrlen = tmp->ai_addrlen;
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001112 freeaddrinfo (result);
1113 }
1114 }
1115 else
1116#endif
1117 {
1118 if (proxy)
1119 hp = gethostbyname (proxy);
1120 else
1121 hp = gethostbyname (ctxt->hostname);
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001122 if (hp == NULL) {
1123 __xmlIOErr(XML_FROM_FTP, 0, "gethostbyname failed");
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001124 return (-1);
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001125 }
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001126
1127 /*
1128 * Prepare the socket
1129 */
1130 ((struct sockaddr_in *)&ctxt->ftpAddr)->sin_family = AF_INET;
1131 memcpy (&((struct sockaddr_in *)&ctxt->ftpAddr)->sin_addr,
1132 hp->h_addr_list[0], hp->h_length);
1133 ((struct sockaddr_in *)&ctxt->ftpAddr)->sin_port = htons (port);
1134 ctxt->controlFd = socket (AF_INET, SOCK_STREAM, 0);
1135 addrlen = sizeof (struct sockaddr_in);
1136 }
1137
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001138 if (ctxt->controlFd < 0) {
1139 __xmlIOErr(XML_FROM_FTP, 0, "socket failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001140 return(-1);
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001141 }
Owen Taylor3473f882001-02-23 17:55:21 +00001142
1143 /*
1144 * Do the connect.
1145 */
1146 if (connect(ctxt->controlFd, (struct sockaddr *) &ctxt->ftpAddr,
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001147 addrlen) < 0) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001148 __xmlIOErr(XML_FROM_FTP, 0, "Failed to create a connection");
Owen Taylor3473f882001-02-23 17:55:21 +00001149 closesocket(ctxt->controlFd); ctxt->controlFd = -1;
1150 ctxt->controlFd = -1;
1151 return(-1);
1152 }
1153
1154 /*
1155 * Wait for the HELLO from the server.
1156 */
1157 res = xmlNanoFTPGetResponse(ctxt);
1158 if (res != 2) {
1159 closesocket(ctxt->controlFd); ctxt->controlFd = -1;
1160 ctxt->controlFd = -1;
1161 return(-1);
1162 }
1163
1164 /*
1165 * State diagram for the login operation on the FTP server
1166 *
1167 * Reference: RFC 959
1168 *
1169 * 1
1170 * +---+ USER +---+------------->+---+
1171 * | B |---------->| W | 2 ---->| E |
1172 * +---+ +---+------ | -->+---+
1173 * | | | | |
1174 * 3 | | 4,5 | | |
1175 * -------------- ----- | | |
1176 * | | | | |
1177 * | | | | |
1178 * | --------- |
1179 * | 1| | | |
1180 * V | | | |
1181 * +---+ PASS +---+ 2 | ------>+---+
1182 * | |---------->| W |------------->| S |
1183 * +---+ +---+ ---------->+---+
1184 * | | | | |
1185 * 3 | |4,5| | |
1186 * -------------- -------- |
1187 * | | | | |
1188 * | | | | |
1189 * | -----------
1190 * | 1,3| | | |
1191 * V | 2| | |
1192 * +---+ ACCT +---+-- | ----->+---+
1193 * | |---------->| W | 4,5 -------->| F |
1194 * +---+ +---+------------->+---+
1195 *
1196 * Of course in case of using a proxy this get really nasty and is not
1197 * standardized at all :-(
1198 */
1199 if (proxy) {
1200 int len;
1201 char buf[400];
1202
1203 if (proxyUser != NULL) {
1204 /*
1205 * We need proxy auth
1206 */
Owen Taylor3473f882001-02-23 17:55:21 +00001207 snprintf(buf, sizeof(buf), "USER %s\r\n", proxyUser);
Owen Taylor3473f882001-02-23 17:55:21 +00001208 buf[sizeof(buf) - 1] = 0;
1209 len = strlen(buf);
1210#ifdef DEBUG_FTP
Daniel Veillard635ef722001-10-29 11:48:19 +00001211 xmlGenericError(xmlGenericErrorContext, "%s", buf);
Owen Taylor3473f882001-02-23 17:55:21 +00001212#endif
1213 res = send(ctxt->controlFd, buf, len, 0);
1214 if (res < 0) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001215 __xmlIOErr(XML_FROM_FTP, 0, "send failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001216 closesocket(ctxt->controlFd);
1217 ctxt->controlFd = -1;
1218 return(res);
1219 }
1220 res = xmlNanoFTPGetResponse(ctxt);
1221 switch (res) {
1222 case 2:
1223 if (proxyPasswd == NULL)
1224 break;
1225 case 3:
1226 if (proxyPasswd != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00001227 snprintf(buf, sizeof(buf), "PASS %s\r\n", proxyPasswd);
Owen Taylor3473f882001-02-23 17:55:21 +00001228 else
Daniel Veillard9ae1eba2001-10-19 09:48:35 +00001229 snprintf(buf, sizeof(buf), "PASS anonymous@\r\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001230 buf[sizeof(buf) - 1] = 0;
1231 len = strlen(buf);
1232#ifdef DEBUG_FTP
Daniel Veillard635ef722001-10-29 11:48:19 +00001233 xmlGenericError(xmlGenericErrorContext, "%s", buf);
Owen Taylor3473f882001-02-23 17:55:21 +00001234#endif
1235 res = send(ctxt->controlFd, buf, len, 0);
1236 if (res < 0) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001237 __xmlIOErr(XML_FROM_FTP, 0, "send failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001238 closesocket(ctxt->controlFd);
1239 ctxt->controlFd = -1;
1240 return(res);
1241 }
1242 res = xmlNanoFTPGetResponse(ctxt);
1243 if (res > 3) {
1244 closesocket(ctxt->controlFd);
1245 ctxt->controlFd = -1;
1246 return(-1);
1247 }
1248 break;
1249 case 1:
1250 break;
1251 case 4:
1252 case 5:
1253 case -1:
1254 default:
1255 closesocket(ctxt->controlFd);
1256 ctxt->controlFd = -1;
1257 return(-1);
1258 }
1259 }
1260
1261 /*
1262 * We assume we don't need more authentication to the proxy
1263 * and that it succeeded :-\
1264 */
1265 switch (proxyType) {
1266 case 0:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001267 /* we will try in sequence */
Owen Taylor3473f882001-02-23 17:55:21 +00001268 case 1:
1269 /* Using SITE command */
Owen Taylor3473f882001-02-23 17:55:21 +00001270 snprintf(buf, sizeof(buf), "SITE %s\r\n", ctxt->hostname);
Owen Taylor3473f882001-02-23 17:55:21 +00001271 buf[sizeof(buf) - 1] = 0;
1272 len = strlen(buf);
1273#ifdef DEBUG_FTP
Daniel Veillard635ef722001-10-29 11:48:19 +00001274 xmlGenericError(xmlGenericErrorContext, "%s", buf);
Owen Taylor3473f882001-02-23 17:55:21 +00001275#endif
1276 res = send(ctxt->controlFd, buf, len, 0);
1277 if (res < 0) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001278 __xmlIOErr(XML_FROM_FTP, 0, "send failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001279 closesocket(ctxt->controlFd); ctxt->controlFd = -1;
1280 ctxt->controlFd = -1;
1281 return(res);
1282 }
1283 res = xmlNanoFTPGetResponse(ctxt);
1284 if (res == 2) {
1285 /* we assume it worked :-\ 1 is error for SITE command */
1286 proxyType = 1;
1287 break;
1288 }
1289 if (proxyType == 1) {
1290 closesocket(ctxt->controlFd); ctxt->controlFd = -1;
1291 ctxt->controlFd = -1;
1292 return(-1);
1293 }
1294 case 2:
1295 /* USER user@host command */
1296 if (ctxt->user == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00001297 snprintf(buf, sizeof(buf), "USER anonymous@%s\r\n",
1298 ctxt->hostname);
Owen Taylor3473f882001-02-23 17:55:21 +00001299 else
Owen Taylor3473f882001-02-23 17:55:21 +00001300 snprintf(buf, sizeof(buf), "USER %s@%s\r\n",
1301 ctxt->user, ctxt->hostname);
Owen Taylor3473f882001-02-23 17:55:21 +00001302 buf[sizeof(buf) - 1] = 0;
1303 len = strlen(buf);
1304#ifdef DEBUG_FTP
Daniel Veillard635ef722001-10-29 11:48:19 +00001305 xmlGenericError(xmlGenericErrorContext, "%s", buf);
Owen Taylor3473f882001-02-23 17:55:21 +00001306#endif
1307 res = send(ctxt->controlFd, buf, len, 0);
1308 if (res < 0) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001309 __xmlIOErr(XML_FROM_FTP, 0, "send failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001310 closesocket(ctxt->controlFd); ctxt->controlFd = -1;
1311 ctxt->controlFd = -1;
1312 return(res);
1313 }
1314 res = xmlNanoFTPGetResponse(ctxt);
1315 if ((res == 1) || (res == 2)) {
1316 /* we assume it worked :-\ */
1317 proxyType = 2;
1318 return(0);
1319 }
1320 if (ctxt->passwd == NULL)
Daniel Veillard9ae1eba2001-10-19 09:48:35 +00001321 snprintf(buf, sizeof(buf), "PASS anonymous@\r\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001322 else
Owen Taylor3473f882001-02-23 17:55:21 +00001323 snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd);
Owen Taylor3473f882001-02-23 17:55:21 +00001324 buf[sizeof(buf) - 1] = 0;
1325 len = strlen(buf);
1326#ifdef DEBUG_FTP
Daniel Veillard635ef722001-10-29 11:48:19 +00001327 xmlGenericError(xmlGenericErrorContext, "%s", buf);
Owen Taylor3473f882001-02-23 17:55:21 +00001328#endif
1329 res = send(ctxt->controlFd, buf, len, 0);
1330 if (res < 0) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001331 __xmlIOErr(XML_FROM_FTP, 0, "send failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001332 closesocket(ctxt->controlFd); ctxt->controlFd = -1;
1333 ctxt->controlFd = -1;
1334 return(res);
1335 }
1336 res = xmlNanoFTPGetResponse(ctxt);
1337 if ((res == 1) || (res == 2)) {
1338 /* we assume it worked :-\ */
1339 proxyType = 2;
1340 return(0);
1341 }
1342 if (proxyType == 2) {
1343 closesocket(ctxt->controlFd); ctxt->controlFd = -1;
1344 ctxt->controlFd = -1;
1345 return(-1);
1346 }
1347 case 3:
1348 /*
1349 * If you need support for other Proxy authentication scheme
1350 * send the code or at least the sequence in use.
1351 */
1352 default:
1353 closesocket(ctxt->controlFd); ctxt->controlFd = -1;
1354 ctxt->controlFd = -1;
1355 return(-1);
1356 }
1357 }
1358 /*
1359 * Non-proxy handling.
1360 */
1361 res = xmlNanoFTPSendUser(ctxt);
1362 if (res < 0) {
1363 closesocket(ctxt->controlFd); ctxt->controlFd = -1;
1364 ctxt->controlFd = -1;
1365 return(-1);
1366 }
1367 res = xmlNanoFTPGetResponse(ctxt);
1368 switch (res) {
1369 case 2:
1370 return(0);
1371 case 3:
1372 break;
1373 case 1:
1374 case 4:
1375 case 5:
1376 case -1:
1377 default:
1378 closesocket(ctxt->controlFd); ctxt->controlFd = -1;
1379 ctxt->controlFd = -1;
1380 return(-1);
1381 }
1382 res = xmlNanoFTPSendPasswd(ctxt);
1383 if (res < 0) {
1384 closesocket(ctxt->controlFd); ctxt->controlFd = -1;
1385 ctxt->controlFd = -1;
1386 return(-1);
1387 }
1388 res = xmlNanoFTPGetResponse(ctxt);
1389 switch (res) {
1390 case 2:
1391 break;
1392 case 3:
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001393 __xmlIOErr(XML_FROM_FTP, XML_FTP_ACCNT,
1394 "FTP server asking for ACCNT on anonymous\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001395 case 1:
1396 case 4:
1397 case 5:
1398 case -1:
1399 default:
1400 closesocket(ctxt->controlFd); ctxt->controlFd = -1;
1401 ctxt->controlFd = -1;
1402 return(-1);
1403 }
1404
1405 return(0);
1406}
1407
1408/**
1409 * xmlNanoFTPConnectTo:
1410 * @server: an FTP server name
1411 * @port: the port (use 21 if 0)
1412 *
1413 * Tries to open a control connection to the given server/port
1414 *
1415 * Returns an fTP context or NULL if it failed
1416 */
1417
1418void*
1419xmlNanoFTPConnectTo(const char *server, int port) {
1420 xmlNanoFTPCtxtPtr ctxt;
1421 int res;
1422
1423 xmlNanoFTPInit();
1424 if (server == NULL)
1425 return(NULL);
1426 ctxt = (xmlNanoFTPCtxtPtr) xmlNanoFTPNewCtxt(NULL);
1427 ctxt->hostname = xmlMemStrdup(server);
1428 if (port != 0)
1429 ctxt->port = port;
1430 res = xmlNanoFTPConnect(ctxt);
1431 if (res < 0) {
1432 xmlNanoFTPFreeCtxt(ctxt);
1433 return(NULL);
1434 }
1435 return(ctxt);
1436}
1437
1438/**
1439 * xmlNanoFTPCwd:
1440 * @ctx: an FTP context
1441 * @directory: a directory on the server
1442 *
1443 * Tries to change the remote directory
1444 *
1445 * Returns -1 incase of error, 1 if CWD worked, 0 if it failed
1446 */
1447
1448int
1449xmlNanoFTPCwd(void *ctx, char *directory) {
1450 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
1451 char buf[400];
1452 int len;
1453 int res;
1454
1455 /*
1456 * Expected response code for CWD:
1457 *
1458 * CWD
1459 * 250
1460 * 500, 501, 502, 421, 530, 550
1461 */
Owen Taylor3473f882001-02-23 17:55:21 +00001462 snprintf(buf, sizeof(buf), "CWD %s\r\n", directory);
Owen Taylor3473f882001-02-23 17:55:21 +00001463 buf[sizeof(buf) - 1] = 0;
1464 len = strlen(buf);
1465#ifdef DEBUG_FTP
Daniel Veillard635ef722001-10-29 11:48:19 +00001466 xmlGenericError(xmlGenericErrorContext, "%s", buf);
Owen Taylor3473f882001-02-23 17:55:21 +00001467#endif
1468 res = send(ctxt->controlFd, buf, len, 0);
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001469 if (res < 0) {
1470 __xmlIOErr(XML_FROM_FTP, 0, "send failed");
1471 return(res);
1472 }
Owen Taylor3473f882001-02-23 17:55:21 +00001473 res = xmlNanoFTPGetResponse(ctxt);
1474 if (res == 4) {
1475 return(-1);
1476 }
1477 if (res == 2) return(1);
1478 if (res == 5) {
1479 return(0);
1480 }
1481 return(0);
1482}
1483
1484/**
Daniel Veillard6c73cb82003-03-05 16:45:40 +00001485 * xmlNanoFTPDele:
1486 * @ctx: an FTP context
1487 * @file: a file or directory on the server
1488 *
1489 * Tries to delete an item (file or directory) from server
1490 *
1491 * Returns -1 incase of error, 1 if DELE worked, 0 if it failed
1492 */
1493
1494int
1495xmlNanoFTPDele(void *ctx, char *file) {
1496 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
1497 char buf[400];
1498 int len;
1499 int res;
1500
1501 /*
1502 * Expected response code for DELE:
1503 *
1504 * DELE
1505 * 250
1506 * 450, 550
1507 * 500, 501, 502, 421, 530
1508 */
1509
1510 snprintf(buf, sizeof(buf), "DELE %s\r\n", file);
1511 buf[sizeof(buf) - 1] = 0;
1512 len = strlen(buf);
1513#ifdef DEBUG_FTP
1514 xmlGenericError(xmlGenericErrorContext, "%s", buf);
1515#endif
1516 res = send(ctxt->controlFd, buf, len, 0);
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001517 if (res < 0) {
1518 __xmlIOErr(XML_FROM_FTP, 0, "send failed");
1519 return(res);
1520 }
Daniel Veillard6c73cb82003-03-05 16:45:40 +00001521 res = xmlNanoFTPGetResponse(ctxt);
1522 if (res == 4) {
1523 return(-1);
1524 }
1525 if (res == 2) return(1);
1526 if (res == 5) {
1527 return(0);
1528 }
1529 return(0);
1530}
1531/**
Owen Taylor3473f882001-02-23 17:55:21 +00001532 * xmlNanoFTPGetConnection:
1533 * @ctx: an FTP context
1534 *
1535 * Try to open a data connection to the server. Currently only
1536 * passive mode is supported.
1537 *
1538 * Returns -1 incase of error, 0 otherwise
1539 */
1540
1541int
1542xmlNanoFTPGetConnection(void *ctx) {
1543 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
1544 char buf[200], *cur;
1545 int len, i;
1546 int res;
1547 unsigned char ad[6], *adp, *portp;
1548 unsigned int temp[6];
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001549#ifdef SUPPORT_IP6
1550 struct sockaddr_storage dataAddr;
1551#else
Owen Taylor3473f882001-02-23 17:55:21 +00001552 struct sockaddr_in dataAddr;
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001553#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001554 SOCKLEN_T dataAddrLen;
1555
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001556 memset (&dataAddr, 0, sizeof(dataAddr));
1557#ifdef SUPPORT_IP6
1558 if ((ctxt->ftpAddr).ss_family == AF_INET6) {
1559 ctxt->dataFd = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP);
1560 ((struct sockaddr_in6 *)&dataAddr)->sin6_family = AF_INET6;
1561 dataAddrLen = sizeof(struct sockaddr_in6);
1562 } else
1563#endif
1564 {
1565 ctxt->dataFd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
1566 ((struct sockaddr_in *)&dataAddr)->sin_family = AF_INET;
1567 dataAddrLen = sizeof (struct sockaddr_in);
Owen Taylor3473f882001-02-23 17:55:21 +00001568 }
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001569
1570 if (ctxt->dataFd < 0) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001571 __xmlIOErr(XML_FROM_FTP, 0, "socket failed");
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001572 return (-1);
1573 }
Owen Taylor3473f882001-02-23 17:55:21 +00001574
1575 if (ctxt->passive) {
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001576#ifdef SUPPORT_IP6
1577 if ((ctxt->ftpAddr).ss_family == AF_INET6)
1578 snprintf (buf, sizeof(buf), "EPSV\r\n");
1579 else
1580#endif
1581 snprintf (buf, sizeof(buf), "PASV\r\n");
1582 len = strlen (buf);
Owen Taylor3473f882001-02-23 17:55:21 +00001583#ifdef DEBUG_FTP
Daniel Veillard635ef722001-10-29 11:48:19 +00001584 xmlGenericError(xmlGenericErrorContext, "%s", buf);
Owen Taylor3473f882001-02-23 17:55:21 +00001585#endif
1586 res = send(ctxt->controlFd, buf, len, 0);
1587 if (res < 0) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001588 __xmlIOErr(XML_FROM_FTP, 0, "send failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001589 closesocket(ctxt->dataFd); ctxt->dataFd = -1;
1590 return(res);
1591 }
1592 res = xmlNanoFTPReadResponse(ctx);
1593 if (res != 2) {
1594 if (res == 5) {
1595 closesocket(ctxt->dataFd); ctxt->dataFd = -1;
1596 return(-1);
1597 } else {
1598 /*
1599 * retry with an active connection
1600 */
1601 closesocket(ctxt->dataFd); ctxt->dataFd = -1;
1602 ctxt->passive = 0;
1603 }
1604 }
1605 cur = &ctxt->controlBuf[ctxt->controlBufAnswer];
1606 while (((*cur < '0') || (*cur > '9')) && *cur != '\0') cur++;
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001607#ifdef SUPPORT_IP6
1608 if ((ctxt->ftpAddr).ss_family == AF_INET6) {
1609 if (sscanf (cur, "%u", &temp[0]) != 1) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001610 __xmlIOErr(XML_FROM_FTP, XML_FTP_EPSV_ANSWER,
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001611 "Invalid answer to EPSV\n");
1612 if (ctxt->dataFd != -1) {
1613 closesocket (ctxt->dataFd); ctxt->dataFd = -1;
1614 }
1615 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001616 }
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001617 memcpy (&((struct sockaddr_in6 *)&dataAddr)->sin6_addr, &((struct sockaddr_in6 *)&ctxt->ftpAddr)->sin6_addr, sizeof(struct in6_addr));
1618 ((struct sockaddr_in6 *)&dataAddr)->sin6_port = htons (temp[0]);
Owen Taylor3473f882001-02-23 17:55:21 +00001619 }
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001620 else
1621#endif
1622 {
1623 if (sscanf (cur, "%u,%u,%u,%u,%u,%u", &temp[0], &temp[1], &temp[2],
1624 &temp[3], &temp[4], &temp[5]) != 6) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001625 __xmlIOErr(XML_FROM_FTP, XML_FTP_PASV_ANSWER,
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001626 "Invalid answer to PASV\n");
1627 if (ctxt->dataFd != -1) {
1628 closesocket (ctxt->dataFd); ctxt->dataFd = -1;
1629 }
1630 return (-1);
1631 }
1632 for (i=0; i<6; i++) ad[i] = (unsigned char) (temp[i] & 0xff);
1633 memcpy (&((struct sockaddr_in *)&dataAddr)->sin_addr, &ad[0], 4);
1634 memcpy (&((struct sockaddr_in *)&dataAddr)->sin_port, &ad[4], 2);
1635 }
1636
Owen Taylor3473f882001-02-23 17:55:21 +00001637 if (connect(ctxt->dataFd, (struct sockaddr *) &dataAddr, dataAddrLen) < 0) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001638 __xmlIOErr(XML_FROM_FTP, 0, "Failed to create a data connection");
Owen Taylor3473f882001-02-23 17:55:21 +00001639 closesocket(ctxt->dataFd); ctxt->dataFd = -1;
1640 return (-1);
1641 }
1642 } else {
1643 getsockname(ctxt->dataFd, (struct sockaddr *) &dataAddr, &dataAddrLen);
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001644#ifdef SUPPORT_IP6
1645 if ((ctxt->ftpAddr).ss_family == AF_INET6)
1646 ((struct sockaddr_in6 *)&dataAddr)->sin6_port = 0;
1647 else
1648#endif
1649 ((struct sockaddr_in *)&dataAddr)->sin_port = 0;
1650
Owen Taylor3473f882001-02-23 17:55:21 +00001651 if (bind(ctxt->dataFd, (struct sockaddr *) &dataAddr, dataAddrLen) < 0) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001652 __xmlIOErr(XML_FROM_FTP, 0, "bind failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001653 closesocket(ctxt->dataFd); ctxt->dataFd = -1;
1654 return (-1);
1655 }
1656 getsockname(ctxt->dataFd, (struct sockaddr *) &dataAddr, &dataAddrLen);
1657
1658 if (listen(ctxt->dataFd, 1) < 0) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001659 __xmlIOErr(XML_FROM_FTP, 0, "listen failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001660 closesocket(ctxt->dataFd); ctxt->dataFd = -1;
1661 return (-1);
1662 }
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001663#ifdef SUPPORT_IP6
1664 if ((ctxt->ftpAddr).ss_family == AF_INET6) {
1665 char buf6[INET6_ADDRSTRLEN];
1666 inet_ntop (AF_INET6, &((struct sockaddr_in6 *)&dataAddr)->sin6_addr,
1667 buf6, INET6_ADDRSTRLEN);
Daniel Veillard2db8c122003-07-08 12:16:59 +00001668 adp = (unsigned char *) buf6;
Daniel Veillardde2a67b2003-06-21 14:20:04 +00001669 portp = (unsigned char *) &((struct sockaddr_in6 *)&dataAddr)->sin6_port;
1670 snprintf (buf, sizeof(buf), "EPRT |2|%s|%s|\r\n", adp, portp);
1671 } else
1672#endif
1673 {
1674 adp = (unsigned char *) &((struct sockaddr_in *)&dataAddr)->sin_addr;
1675 portp = (unsigned char *) &((struct sockaddr_in *)&dataAddr)->sin_port;
1676 snprintf (buf, sizeof(buf), "PORT %d,%d,%d,%d,%d,%d\r\n",
1677 adp[0] & 0xff, adp[1] & 0xff, adp[2] & 0xff, adp[3] & 0xff,
1678 portp[0] & 0xff, portp[1] & 0xff);
1679 }
1680
Owen Taylor3473f882001-02-23 17:55:21 +00001681 buf[sizeof(buf) - 1] = 0;
1682 len = strlen(buf);
1683#ifdef DEBUG_FTP
Daniel Veillard635ef722001-10-29 11:48:19 +00001684 xmlGenericError(xmlGenericErrorContext, "%s", buf);
Owen Taylor3473f882001-02-23 17:55:21 +00001685#endif
1686
1687 res = send(ctxt->controlFd, buf, len, 0);
1688 if (res < 0) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001689 __xmlIOErr(XML_FROM_FTP, 0, "send failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001690 closesocket(ctxt->dataFd); ctxt->dataFd = -1;
1691 return(res);
1692 }
1693 res = xmlNanoFTPGetResponse(ctxt);
1694 if (res != 2) {
1695 closesocket(ctxt->dataFd); ctxt->dataFd = -1;
1696 return(-1);
1697 }
1698 }
1699 return(ctxt->dataFd);
1700
1701}
1702
1703/**
1704 * xmlNanoFTPCloseConnection:
1705 * @ctx: an FTP context
1706 *
1707 * Close the data connection from the server
1708 *
1709 * Returns -1 incase of error, 0 otherwise
1710 */
1711
1712int
1713xmlNanoFTPCloseConnection(void *ctx) {
1714 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
1715 int res;
1716 fd_set rfd, efd;
1717 struct timeval tv;
1718
1719 closesocket(ctxt->dataFd); ctxt->dataFd = -1;
1720 tv.tv_sec = 15;
1721 tv.tv_usec = 0;
1722 FD_ZERO(&rfd);
1723 FD_SET(ctxt->controlFd, &rfd);
1724 FD_ZERO(&efd);
1725 FD_SET(ctxt->controlFd, &efd);
1726 res = select(ctxt->controlFd + 1, &rfd, NULL, &efd, &tv);
1727 if (res < 0) {
1728#ifdef DEBUG_FTP
1729 perror("select");
1730#endif
1731 closesocket(ctxt->controlFd); ctxt->controlFd = -1;
1732 return(-1);
1733 }
1734 if (res == 0) {
1735#ifdef DEBUG_FTP
1736 xmlGenericError(xmlGenericErrorContext,
1737 "xmlNanoFTPCloseConnection: timeout\n");
1738#endif
1739 closesocket(ctxt->controlFd); ctxt->controlFd = -1;
1740 } else {
1741 res = xmlNanoFTPGetResponse(ctxt);
1742 if (res != 2) {
1743 closesocket(ctxt->controlFd); ctxt->controlFd = -1;
1744 return(-1);
1745 }
1746 }
1747 return(0);
1748}
1749
1750/**
1751 * xmlNanoFTPParseList:
1752 * @list: some data listing received from the server
1753 * @callback: the user callback
1754 * @userData: the user callback data
1755 *
1756 * Parse at most one entry from the listing.
1757 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001758 * Returns -1 incase of error, the length of data parsed otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00001759 */
1760
1761static int
1762xmlNanoFTPParseList(const char *list, ftpListCallback callback, void *userData) {
1763 const char *cur = list;
1764 char filename[151];
1765 char attrib[11];
1766 char owner[11];
1767 char group[11];
1768 char month[4];
1769 int year = 0;
1770 int minute = 0;
1771 int hour = 0;
1772 int day = 0;
1773 unsigned long size = 0;
1774 int links = 0;
1775 int i;
1776
1777 if (!strncmp(cur, "total", 5)) {
1778 cur += 5;
1779 while (*cur == ' ') cur++;
1780 while ((*cur >= '0') && (*cur <= '9'))
1781 links = (links * 10) + (*cur++ - '0');
1782 while ((*cur == ' ') || (*cur == '\n') || (*cur == '\r'))
1783 cur++;
1784 return(cur - list);
1785 } else if (*list == '+') {
1786 return(0);
1787 } else {
1788 while ((*cur == ' ') || (*cur == '\n') || (*cur == '\r'))
1789 cur++;
1790 if (*cur == 0) return(0);
1791 i = 0;
1792 while (*cur != ' ') {
1793 if (i < 10)
1794 attrib[i++] = *cur;
1795 cur++;
1796 if (*cur == 0) return(0);
1797 }
1798 attrib[10] = 0;
1799 while (*cur == ' ') cur++;
1800 if (*cur == 0) return(0);
1801 while ((*cur >= '0') && (*cur <= '9'))
1802 links = (links * 10) + (*cur++ - '0');
1803 while (*cur == ' ') cur++;
1804 if (*cur == 0) return(0);
1805 i = 0;
1806 while (*cur != ' ') {
1807 if (i < 10)
1808 owner[i++] = *cur;
1809 cur++;
1810 if (*cur == 0) return(0);
1811 }
1812 owner[i] = 0;
1813 while (*cur == ' ') cur++;
1814 if (*cur == 0) return(0);
1815 i = 0;
1816 while (*cur != ' ') {
1817 if (i < 10)
1818 group[i++] = *cur;
1819 cur++;
1820 if (*cur == 0) return(0);
1821 }
1822 group[i] = 0;
1823 while (*cur == ' ') cur++;
1824 if (*cur == 0) return(0);
1825 while ((*cur >= '0') && (*cur <= '9'))
1826 size = (size * 10) + (*cur++ - '0');
1827 while (*cur == ' ') cur++;
1828 if (*cur == 0) return(0);
1829 i = 0;
1830 while (*cur != ' ') {
1831 if (i < 3)
1832 month[i++] = *cur;
1833 cur++;
1834 if (*cur == 0) return(0);
1835 }
1836 month[i] = 0;
1837 while (*cur == ' ') cur++;
1838 if (*cur == 0) return(0);
1839 while ((*cur >= '0') && (*cur <= '9'))
1840 day = (day * 10) + (*cur++ - '0');
1841 while (*cur == ' ') cur++;
1842 if (*cur == 0) return(0);
1843 if ((cur[1] == 0) || (cur[2] == 0)) return(0);
1844 if ((cur[1] == ':') || (cur[2] == ':')) {
1845 while ((*cur >= '0') && (*cur <= '9'))
1846 hour = (hour * 10) + (*cur++ - '0');
1847 if (*cur == ':') cur++;
1848 while ((*cur >= '0') && (*cur <= '9'))
1849 minute = (minute * 10) + (*cur++ - '0');
1850 } else {
1851 while ((*cur >= '0') && (*cur <= '9'))
1852 year = (year * 10) + (*cur++ - '0');
1853 }
1854 while (*cur == ' ') cur++;
1855 if (*cur == 0) return(0);
1856 i = 0;
1857 while ((*cur != '\n') && (*cur != '\r')) {
1858 if (i < 150)
1859 filename[i++] = *cur;
1860 cur++;
1861 if (*cur == 0) return(0);
1862 }
1863 filename[i] = 0;
1864 if ((*cur != '\n') && (*cur != '\r'))
1865 return(0);
1866 while ((*cur == '\n') || (*cur == '\r'))
1867 cur++;
1868 }
1869 if (callback != NULL) {
1870 callback(userData, filename, attrib, owner, group, size, links,
1871 year, month, day, hour, minute);
1872 }
1873 return(cur - list);
1874}
1875
1876/**
1877 * xmlNanoFTPList:
1878 * @ctx: an FTP context
1879 * @callback: the user callback
1880 * @userData: the user callback data
1881 * @filename: optional files to list
1882 *
1883 * Do a listing on the server. All files info are passed back
1884 * in the callbacks.
1885 *
1886 * Returns -1 incase of error, 0 otherwise
1887 */
1888
1889int
1890xmlNanoFTPList(void *ctx, ftpListCallback callback, void *userData,
1891 char *filename) {
1892 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
1893 char buf[4096 + 1];
1894 int len, res;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001895 int indx = 0, base;
Owen Taylor3473f882001-02-23 17:55:21 +00001896 fd_set rfd, efd;
1897 struct timeval tv;
1898
1899 if (filename == NULL) {
1900 if (xmlNanoFTPCwd(ctxt, ctxt->path) < 1)
1901 return(-1);
1902 ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
1903 if (ctxt->dataFd == -1)
1904 return(-1);
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001905 snprintf(buf, sizeof(buf), "LIST -L\r\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001906 } else {
1907 if (filename[0] != '/') {
1908 if (xmlNanoFTPCwd(ctxt, ctxt->path) < 1)
1909 return(-1);
1910 }
1911 ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
1912 if (ctxt->dataFd == -1)
1913 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001914 snprintf(buf, sizeof(buf), "LIST -L %s\r\n", filename);
Owen Taylor3473f882001-02-23 17:55:21 +00001915 }
1916 buf[sizeof(buf) - 1] = 0;
1917 len = strlen(buf);
1918#ifdef DEBUG_FTP
Daniel Veillard635ef722001-10-29 11:48:19 +00001919 xmlGenericError(xmlGenericErrorContext, "%s", buf);
Owen Taylor3473f882001-02-23 17:55:21 +00001920#endif
1921 res = send(ctxt->controlFd, buf, len, 0);
1922 if (res < 0) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001923 __xmlIOErr(XML_FROM_FTP, 0, "send failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001924 closesocket(ctxt->dataFd); ctxt->dataFd = -1;
1925 return(res);
1926 }
1927 res = xmlNanoFTPReadResponse(ctxt);
1928 if (res != 1) {
1929 closesocket(ctxt->dataFd); ctxt->dataFd = -1;
1930 return(-res);
1931 }
1932
1933 do {
1934 tv.tv_sec = 1;
1935 tv.tv_usec = 0;
1936 FD_ZERO(&rfd);
1937 FD_SET(ctxt->dataFd, &rfd);
1938 FD_ZERO(&efd);
1939 FD_SET(ctxt->dataFd, &efd);
1940 res = select(ctxt->dataFd + 1, &rfd, NULL, &efd, &tv);
1941 if (res < 0) {
1942#ifdef DEBUG_FTP
1943 perror("select");
1944#endif
1945 closesocket(ctxt->dataFd); ctxt->dataFd = -1;
1946 return(-1);
1947 }
1948 if (res == 0) {
1949 res = xmlNanoFTPCheckResponse(ctxt);
1950 if (res < 0) {
1951 closesocket(ctxt->dataFd); ctxt->dataFd = -1;
1952 ctxt->dataFd = -1;
1953 return(-1);
1954 }
1955 if (res == 2) {
1956 closesocket(ctxt->dataFd); ctxt->dataFd = -1;
1957 return(0);
1958 }
1959
1960 continue;
1961 }
1962
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001963 if ((len = recv(ctxt->dataFd, &buf[indx], sizeof(buf) - (indx + 1), 0)) < 0) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00001964 __xmlIOErr(XML_FROM_FTP, 0, "recv");
Owen Taylor3473f882001-02-23 17:55:21 +00001965 closesocket(ctxt->dataFd); ctxt->dataFd = -1;
1966 ctxt->dataFd = -1;
1967 return(-1);
1968 }
1969#ifdef DEBUG_FTP
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001970 write(1, &buf[indx], len);
Owen Taylor3473f882001-02-23 17:55:21 +00001971#endif
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001972 indx += len;
1973 buf[indx] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001974 base = 0;
1975 do {
1976 res = xmlNanoFTPParseList(&buf[base], callback, userData);
1977 base += res;
1978 } while (res > 0);
1979
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001980 memmove(&buf[0], &buf[base], indx - base);
1981 indx -= base;
Owen Taylor3473f882001-02-23 17:55:21 +00001982 } while (len != 0);
1983 xmlNanoFTPCloseConnection(ctxt);
1984 return(0);
1985}
1986
1987/**
1988 * xmlNanoFTPGetSocket:
1989 * @ctx: an FTP context
1990 * @filename: the file to retrieve (or NULL if path is in context).
1991 *
1992 * Initiate fetch of the given file from the server.
1993 *
1994 * Returns the socket for the data connection, or <0 in case of error
1995 */
1996
1997
1998int
1999xmlNanoFTPGetSocket(void *ctx, const char *filename) {
2000 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
2001 char buf[300];
2002 int res, len;
2003 if ((filename == NULL) && (ctxt->path == NULL))
2004 return(-1);
2005 ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
2006 if (ctxt->dataFd == -1)
2007 return(-1);
2008
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002009 snprintf(buf, sizeof(buf), "TYPE I\r\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002010 len = strlen(buf);
2011#ifdef DEBUG_FTP
Daniel Veillard635ef722001-10-29 11:48:19 +00002012 xmlGenericError(xmlGenericErrorContext, "%s", buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002013#endif
2014 res = send(ctxt->controlFd, buf, len, 0);
2015 if (res < 0) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00002016 __xmlIOErr(XML_FROM_FTP, 0, "send failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002017 closesocket(ctxt->dataFd); ctxt->dataFd = -1;
2018 return(res);
2019 }
2020 res = xmlNanoFTPReadResponse(ctxt);
2021 if (res != 2) {
2022 closesocket(ctxt->dataFd); ctxt->dataFd = -1;
2023 return(-res);
2024 }
2025 if (filename == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00002026 snprintf(buf, sizeof(buf), "RETR %s\r\n", ctxt->path);
Owen Taylor3473f882001-02-23 17:55:21 +00002027 else
Owen Taylor3473f882001-02-23 17:55:21 +00002028 snprintf(buf, sizeof(buf), "RETR %s\r\n", filename);
Owen Taylor3473f882001-02-23 17:55:21 +00002029 buf[sizeof(buf) - 1] = 0;
2030 len = strlen(buf);
2031#ifdef DEBUG_FTP
Daniel Veillard635ef722001-10-29 11:48:19 +00002032 xmlGenericError(xmlGenericErrorContext, "%s", buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002033#endif
2034 res = send(ctxt->controlFd, buf, len, 0);
2035 if (res < 0) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00002036 __xmlIOErr(XML_FROM_FTP, 0, "send failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002037 closesocket(ctxt->dataFd); ctxt->dataFd = -1;
2038 return(res);
2039 }
2040 res = xmlNanoFTPReadResponse(ctxt);
2041 if (res != 1) {
2042 closesocket(ctxt->dataFd); ctxt->dataFd = -1;
2043 return(-res);
2044 }
2045 return(ctxt->dataFd);
2046}
2047
2048/**
2049 * xmlNanoFTPGet:
2050 * @ctx: an FTP context
2051 * @callback: the user callback
2052 * @userData: the user callback data
2053 * @filename: the file to retrieve
2054 *
2055 * Fetch the given file from the server. All data are passed back
2056 * in the callbacks. The last callback has a size of 0 block.
2057 *
2058 * Returns -1 incase of error, 0 otherwise
2059 */
2060
2061int
2062xmlNanoFTPGet(void *ctx, ftpDataCallback callback, void *userData,
2063 const char *filename) {
2064 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
2065 char buf[4096];
2066 int len = 0, res;
2067 fd_set rfd;
2068 struct timeval tv;
2069
2070 if ((filename == NULL) && (ctxt->path == NULL))
2071 return(-1);
2072 if (callback == NULL)
2073 return(-1);
2074 if (xmlNanoFTPGetSocket(ctxt, filename) < 0)
2075 return(-1);
2076
2077 do {
2078 tv.tv_sec = 1;
2079 tv.tv_usec = 0;
2080 FD_ZERO(&rfd);
2081 FD_SET(ctxt->dataFd, &rfd);
2082 res = select(ctxt->dataFd + 1, &rfd, NULL, NULL, &tv);
2083 if (res < 0) {
2084#ifdef DEBUG_FTP
2085 perror("select");
2086#endif
2087 closesocket(ctxt->dataFd); ctxt->dataFd = -1;
2088 return(-1);
2089 }
2090 if (res == 0) {
2091 res = xmlNanoFTPCheckResponse(ctxt);
2092 if (res < 0) {
2093 closesocket(ctxt->dataFd); ctxt->dataFd = -1;
2094 ctxt->dataFd = -1;
2095 return(-1);
2096 }
2097 if (res == 2) {
2098 closesocket(ctxt->dataFd); ctxt->dataFd = -1;
2099 return(0);
2100 }
2101
2102 continue;
2103 }
2104 if ((len = recv(ctxt->dataFd, buf, sizeof(buf), 0)) < 0) {
Daniel Veillard2b0f8792003-10-10 19:36:36 +00002105 __xmlIOErr(XML_FROM_FTP, 0, "recv failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002106 callback(userData, buf, len);
2107 closesocket(ctxt->dataFd); ctxt->dataFd = -1;
2108 return(-1);
2109 }
2110 callback(userData, buf, len);
2111 } while (len != 0);
2112
2113 return(xmlNanoFTPCloseConnection(ctxt));
2114}
2115
2116/**
2117 * xmlNanoFTPRead:
2118 * @ctx: the FTP context
2119 * @dest: a buffer
2120 * @len: the buffer length
2121 *
2122 * This function tries to read @len bytes from the existing FTP connection
2123 * and saves them in @dest. This is a blocking call.
2124 *
2125 * Returns the number of byte read. 0 is an indication of an end of connection.
2126 * -1 indicates a parameter error.
2127 */
2128int
2129xmlNanoFTPRead(void *ctx, void *dest, int len) {
2130 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
2131
2132 if (ctx == NULL) return(-1);
2133 if (ctxt->dataFd < 0) return(0);
2134 if (dest == NULL) return(-1);
2135 if (len <= 0) return(0);
2136
2137 len = recv(ctxt->dataFd, dest, len, 0);
Daniel Veillard2b0f8792003-10-10 19:36:36 +00002138 if (len <= 0) {
2139 __xmlIOErr(XML_FROM_FTP, 0, "recv failed");
2140 xmlNanoFTPCloseConnection(ctxt);
2141 }
Owen Taylor3473f882001-02-23 17:55:21 +00002142#ifdef DEBUG_FTP
2143 xmlGenericError(xmlGenericErrorContext, "Recvd %d bytes\n", len);
2144#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002145 return(len);
2146}
2147
2148/**
2149 * xmlNanoFTPOpen:
2150 * @URL: the URL to the resource
2151 *
2152 * Start to fetch the given ftp:// resource
2153 *
2154 * Returns an FTP context, or NULL
2155 */
2156
2157void*
2158xmlNanoFTPOpen(const char *URL) {
2159 xmlNanoFTPCtxtPtr ctxt;
2160 int sock;
2161
2162 xmlNanoFTPInit();
2163 if (URL == NULL) return(NULL);
2164 if (strncmp("ftp://", URL, 6)) return(NULL);
2165
2166 ctxt = (xmlNanoFTPCtxtPtr) xmlNanoFTPNewCtxt(URL);
2167 if (ctxt == NULL) return(NULL);
2168 if (xmlNanoFTPConnect(ctxt) < 0) {
2169 xmlNanoFTPFreeCtxt(ctxt);
2170 return(NULL);
2171 }
2172 sock = xmlNanoFTPGetSocket(ctxt, ctxt->path);
2173 if (sock < 0) {
2174 xmlNanoFTPFreeCtxt(ctxt);
2175 return(NULL);
2176 }
2177 return(ctxt);
2178}
2179
2180/**
2181 * xmlNanoFTPClose:
2182 * @ctx: an FTP context
2183 *
2184 * Close the connection and both control and transport
2185 *
2186 * Returns -1 incase of error, 0 otherwise
2187 */
2188
2189int
2190xmlNanoFTPClose(void *ctx) {
2191 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
2192
2193 if (ctxt == NULL)
2194 return(-1);
2195
2196 if (ctxt->dataFd >= 0) {
2197 closesocket(ctxt->dataFd);
2198 ctxt->dataFd = -1;
2199 }
2200 if (ctxt->controlFd >= 0) {
2201 xmlNanoFTPQuit(ctxt);
2202 closesocket(ctxt->controlFd);
2203 ctxt->controlFd = -1;
2204 }
2205 xmlNanoFTPFreeCtxt(ctxt);
2206 return(0);
2207}
2208
2209#ifdef STANDALONE
2210/************************************************************************
2211 * *
2212 * Basic test in Standalone mode *
2213 * *
2214 ************************************************************************/
Daniel Veillard01c13b52002-12-10 15:19:08 +00002215static
Owen Taylor3473f882001-02-23 17:55:21 +00002216void ftpList(void *userData, const char *filename, const char* attrib,
2217 const char *owner, const char *group, unsigned long size, int links,
2218 int year, const char *month, int day, int hour, int minute) {
2219 xmlGenericError(xmlGenericErrorContext,
2220 "%s %s %s %ld %s\n", attrib, owner, group, size, filename);
2221}
Daniel Veillard01c13b52002-12-10 15:19:08 +00002222static
Owen Taylor3473f882001-02-23 17:55:21 +00002223void ftpData(void *userData, const char *data, int len) {
2224 if (userData == NULL) return;
2225 if (len <= 0) {
Daniel Veillard82cb3192003-10-29 13:39:15 +00002226 fclose((FILE*)userData);
Owen Taylor3473f882001-02-23 17:55:21 +00002227 return;
2228 }
Daniel Veillard82cb3192003-10-29 13:39:15 +00002229 fwrite(data, len, 1, (FILE*)userData);
Owen Taylor3473f882001-02-23 17:55:21 +00002230}
2231
2232int main(int argc, char **argv) {
2233 void *ctxt;
2234 FILE *output;
2235 char *tstfile = NULL;
2236
2237 xmlNanoFTPInit();
2238 if (argc > 1) {
2239 ctxt = xmlNanoFTPNewCtxt(argv[1]);
2240 if (xmlNanoFTPConnect(ctxt) < 0) {
2241 xmlGenericError(xmlGenericErrorContext,
2242 "Couldn't connect to %s\n", argv[1]);
2243 exit(1);
2244 }
2245 if (argc > 2)
2246 tstfile = argv[2];
2247 } else
2248 ctxt = xmlNanoFTPConnectTo("localhost", 0);
2249 if (ctxt == NULL) {
2250 xmlGenericError(xmlGenericErrorContext,
2251 "Couldn't connect to localhost\n");
2252 exit(1);
2253 }
2254 xmlNanoFTPList(ctxt, ftpList, NULL, tstfile);
2255 output = fopen("/tmp/tstdata", "w");
2256 if (output != NULL) {
2257 if (xmlNanoFTPGet(ctxt, ftpData, (void *) output, tstfile) < 0)
2258 xmlGenericError(xmlGenericErrorContext,
2259 "Failed to get file\n");
2260
2261 }
2262 xmlNanoFTPClose(ctxt);
2263 xmlMemoryDump();
2264 exit(0);
2265}
2266#endif /* STANDALONE */
2267#else /* !LIBXML_FTP_ENABLED */
2268#ifdef STANDALONE
2269#include <stdio.h>
2270int main(int argc, char **argv) {
2271 xmlGenericError(xmlGenericErrorContext,
2272 "%s : FTP support not compiled in\n", argv[0]);
2273 return(0);
2274}
2275#endif /* STANDALONE */
2276#endif /* LIBXML_FTP_ENABLED */