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