1 #ifdef __REACTOS__ 2 #include "precomp.h" 3 #else 4 /* 5 * WININET - Ftp implementation 6 * 7 * Copyright 1999 Corel Corporation 8 * Copyright 2004 Mike McCormack for CodeWeavers 9 * Copyright 2004 Kevin Koltzau 10 * Copyright 2007 Hans Leidekker 11 * 12 * Ulrich Czekalla 13 * Noureddine Jemmali 14 * 15 * Copyright 2000 Andreas Mohr 16 * Copyright 2002 Jaco Greeff 17 * 18 * This library is free software; you can redistribute it and/or 19 * modify it under the terms of the GNU Lesser General Public 20 * License as published by the Free Software Foundation; either 21 * version 2.1 of the License, or (at your option) any later version. 22 * 23 * This library is distributed in the hope that it will be useful, 24 * but WITHOUT ANY WARRANTY; without even the implied warranty of 25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 26 * Lesser General Public License for more details. 27 * 28 * You should have received a copy of the GNU Lesser General Public 29 * License along with this library; if not, write to the Free Software 30 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 31 */ 32 33 #include "ws2tcpip.h" 34 35 #include <stdarg.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <time.h> 40 #include <assert.h> 41 42 #include "windef.h" 43 #include "winbase.h" 44 #include "wingdi.h" 45 #include "winuser.h" 46 #include "wininet.h" 47 #include "winnls.h" 48 #include "winerror.h" 49 #include "winreg.h" 50 #include "winternl.h" 51 #include "shlwapi.h" 52 53 #include "wine/debug.h" 54 #include "internet.h" 55 #endif /* defined(__REACTOS__) */ 56 57 WINE_DEFAULT_DEBUG_CHANNEL(wininet); 58 59 #define RESPONSE_TIMEOUT 30 60 61 typedef struct _ftp_session_t ftp_session_t; 62 63 typedef struct 64 { 65 object_header_t hdr; 66 ftp_session_t *lpFtpSession; 67 BOOL session_deleted; 68 int nDataSocket; 69 WCHAR *cache_file; 70 HANDLE cache_file_handle; 71 } ftp_file_t; 72 73 struct _ftp_session_t 74 { 75 object_header_t hdr; 76 appinfo_t *lpAppInfo; 77 int sndSocket; 78 int lstnSocket; 79 int pasvSocket; /* data socket connected by us in case of passive FTP */ 80 ftp_file_t *download_in_progress; 81 struct sockaddr_in socketAddress; 82 struct sockaddr_in lstnSocketAddress; 83 LPWSTR servername; 84 INTERNET_PORT serverport; 85 LPWSTR lpszPassword; 86 LPWSTR lpszUserName; 87 }; 88 89 typedef struct 90 { 91 BOOL bIsDirectory; 92 LPWSTR lpszName; 93 DWORD nSize; 94 SYSTEMTIME tmLastModified; 95 unsigned short permissions; 96 } FILEPROPERTIESW, *LPFILEPROPERTIESW; 97 98 typedef struct 99 { 100 object_header_t hdr; 101 ftp_session_t *lpFtpSession; 102 DWORD index; 103 DWORD size; 104 LPFILEPROPERTIESW lpafp; 105 } WININETFTPFINDNEXTW, *LPWININETFTPFINDNEXTW; 106 107 #define DATA_PACKET_SIZE 0x2000 108 #define szCRLF "\r\n" 109 #define MAX_BACKLOG 5 110 111 /* Testing shows that Windows only accepts dwFlags where the last 112 * 3 (yes 3) bits define FTP_TRANSFER_TYPE_UNKNOWN, FTP_TRANSFER_TYPE_ASCII or FTP_TRANSFER_TYPE_BINARY. 113 */ 114 #define FTP_CONDITION_MASK 0x0007 115 116 typedef enum { 117 /* FTP commands with arguments. */ 118 FTP_CMD_ACCT, 119 FTP_CMD_CWD, 120 FTP_CMD_DELE, 121 FTP_CMD_MKD, 122 FTP_CMD_PASS, 123 FTP_CMD_PORT, 124 FTP_CMD_RETR, 125 FTP_CMD_RMD, 126 FTP_CMD_RNFR, 127 FTP_CMD_RNTO, 128 FTP_CMD_STOR, 129 FTP_CMD_TYPE, 130 FTP_CMD_USER, 131 FTP_CMD_SIZE, 132 133 /* FTP commands without arguments. */ 134 FTP_CMD_ABOR, 135 FTP_CMD_LIST, 136 FTP_CMD_NLST, 137 FTP_CMD_PASV, 138 FTP_CMD_PWD, 139 FTP_CMD_QUIT, 140 } FTP_COMMAND; 141 142 static const CHAR *const szFtpCommands[] = { 143 "ACCT", 144 "CWD", 145 "DELE", 146 "MKD", 147 "PASS", 148 "PORT", 149 "RETR", 150 "RMD", 151 "RNFR", 152 "RNTO", 153 "STOR", 154 "TYPE", 155 "USER", 156 "SIZE", 157 "ABOR", 158 "LIST", 159 "NLST", 160 "PASV", 161 "PWD", 162 "QUIT", 163 }; 164 165 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"; 166 167 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam, 168 INTERNET_STATUS_CALLBACK lpfnStatusCB, object_header_t *hdr, DWORD_PTR dwContext); 169 static BOOL FTP_SendStore(ftp_session_t*, LPCWSTR lpszRemoteFile, DWORD dwType); 170 static BOOL FTP_GetDataSocket(ftp_session_t*, LPINT nDataSocket); 171 static BOOL FTP_SendData(ftp_session_t*, INT nDataSocket, HANDLE hFile); 172 static INT FTP_ReceiveResponse(ftp_session_t*, DWORD_PTR dwContext); 173 static BOOL FTP_SendRetrieve(ftp_session_t*, LPCWSTR lpszRemoteFile, DWORD dwType); 174 static BOOL FTP_RetrieveFileData(ftp_session_t*, INT nDataSocket, HANDLE hFile); 175 static BOOL FTP_InitListenSocket(ftp_session_t*); 176 static BOOL FTP_ConnectToHost(ftp_session_t*); 177 static BOOL FTP_SendPassword(ftp_session_t*); 178 static BOOL FTP_SendAccount(ftp_session_t*); 179 static BOOL FTP_SendType(ftp_session_t*, DWORD dwType); 180 static BOOL FTP_SendPort(ftp_session_t*); 181 static BOOL FTP_DoPassive(ftp_session_t*); 182 static BOOL FTP_SendPortOrPasv(ftp_session_t*); 183 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp); 184 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW fileprop); 185 static BOOL FTP_ParseDirectory(ftp_session_t*, INT nSocket, LPCWSTR lpszSearchFile, 186 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp); 187 static HINTERNET FTP_ReceiveFileList(ftp_session_t*, INT nSocket, LPCWSTR lpszSearchFile, 188 LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext); 189 static DWORD FTP_SetResponseError(DWORD dwResponse); 190 static BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData); 191 static BOOL FTP_FtpPutFileW(ftp_session_t*, LPCWSTR lpszLocalFile, 192 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext); 193 static BOOL FTP_FtpSetCurrentDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory); 194 static BOOL FTP_FtpCreateDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory); 195 static HINTERNET FTP_FtpFindFirstFileW(ftp_session_t*, 196 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext); 197 static BOOL FTP_FtpGetCurrentDirectoryW(ftp_session_t*, LPWSTR lpszCurrentDirectory, 198 LPDWORD lpdwCurrentDirectory); 199 static BOOL FTP_FtpRenameFileW(ftp_session_t*, LPCWSTR lpszSrc, LPCWSTR lpszDest); 200 static BOOL FTP_FtpRemoveDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory); 201 static BOOL FTP_FtpDeleteFileW(ftp_session_t*, LPCWSTR lpszFileName); 202 static BOOL FTP_FtpGetFileW(ftp_session_t*, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile, 203 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags, 204 DWORD_PTR dwContext); 205 206 /* A temporary helper until we get rid of INTERNET_GetLastError calls */ 207 static BOOL res_to_le(DWORD res) 208 { 209 if(res != ERROR_SUCCESS) 210 INTERNET_SetLastError(res); 211 return res == ERROR_SUCCESS; 212 } 213 214 /*********************************************************************** 215 * FtpPutFileA (WININET.@) 216 * 217 * Uploads a file to the FTP server 218 * 219 * RETURNS 220 * TRUE on success 221 * FALSE on failure 222 * 223 */ 224 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile, 225 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext) 226 { 227 LPWSTR lpwzLocalFile; 228 LPWSTR lpwzNewRemoteFile; 229 BOOL ret; 230 231 lpwzLocalFile = heap_strdupAtoW(lpszLocalFile); 232 lpwzNewRemoteFile = heap_strdupAtoW(lpszNewRemoteFile); 233 ret = FtpPutFileW(hConnect, lpwzLocalFile, lpwzNewRemoteFile, 234 dwFlags, dwContext); 235 heap_free(lpwzLocalFile); 236 heap_free(lpwzNewRemoteFile); 237 return ret; 238 } 239 240 typedef struct { 241 task_header_t hdr; 242 WCHAR *local_file; 243 WCHAR *remote_file; 244 DWORD flags; 245 DWORD_PTR context; 246 } put_file_task_t; 247 248 static void AsyncFtpPutFileProc(task_header_t *hdr) 249 { 250 put_file_task_t *task = (put_file_task_t*)hdr; 251 ftp_session_t *session = (ftp_session_t*)task->hdr.hdr; 252 253 TRACE("%p\n", session); 254 255 FTP_FtpPutFileW(session, task->local_file, task->remote_file, 256 task->flags, task->context); 257 258 heap_free(task->local_file); 259 heap_free(task->remote_file); 260 } 261 262 /*********************************************************************** 263 * FtpPutFileW (WININET.@) 264 * 265 * Uploads a file to the FTP server 266 * 267 * RETURNS 268 * TRUE on success 269 * FALSE on failure 270 * 271 */ 272 BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile, 273 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext) 274 { 275 ftp_session_t *lpwfs; 276 appinfo_t *hIC = NULL; 277 BOOL r = FALSE; 278 279 if (!lpszLocalFile || !lpszNewRemoteFile) 280 { 281 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 282 return FALSE; 283 } 284 285 lpwfs = (ftp_session_t*) get_handle_object( hConnect ); 286 if (!lpwfs) 287 { 288 INTERNET_SetLastError(ERROR_INVALID_HANDLE); 289 return FALSE; 290 } 291 292 if (WH_HFTPSESSION != lpwfs->hdr.htype) 293 { 294 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); 295 goto lend; 296 } 297 298 if (lpwfs->download_in_progress != NULL) 299 { 300 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); 301 goto lend; 302 } 303 304 if ((dwFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY) 305 { 306 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 307 goto lend; 308 } 309 310 hIC = lpwfs->lpAppInfo; 311 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 312 { 313 put_file_task_t *task = alloc_async_task(&lpwfs->hdr, AsyncFtpPutFileProc, sizeof(*task)); 314 315 task->local_file = heap_strdupW(lpszLocalFile); 316 task->remote_file = heap_strdupW(lpszNewRemoteFile); 317 task->flags = dwFlags; 318 task->context = dwContext; 319 320 r = res_to_le(INTERNET_AsyncCall(&task->hdr)); 321 } 322 else 323 { 324 r = FTP_FtpPutFileW(lpwfs, lpszLocalFile, 325 lpszNewRemoteFile, dwFlags, dwContext); 326 } 327 328 lend: 329 WININET_Release( &lpwfs->hdr ); 330 331 return r; 332 } 333 334 /*********************************************************************** 335 * FTP_FtpPutFileW (Internal) 336 * 337 * Uploads a file to the FTP server 338 * 339 * RETURNS 340 * TRUE on success 341 * FALSE on failure 342 * 343 */ 344 static BOOL FTP_FtpPutFileW(ftp_session_t *lpwfs, LPCWSTR lpszLocalFile, 345 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext) 346 { 347 HANDLE hFile; 348 BOOL bSuccess = FALSE; 349 appinfo_t *hIC = NULL; 350 INT nResCode; 351 352 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", debugstr_w(lpszLocalFile), debugstr_w(lpszNewRemoteFile)); 353 354 /* Clear any error information */ 355 INTERNET_SetLastError(0); 356 357 /* Open file to be uploaded */ 358 if (INVALID_HANDLE_VALUE == 359 (hFile = CreateFileW(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0))) 360 /* Let CreateFile set the appropriate error */ 361 return FALSE; 362 363 hIC = lpwfs->lpAppInfo; 364 365 INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0); 366 367 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags)) 368 { 369 INT nDataSocket; 370 371 /* Get data socket to server */ 372 if (FTP_GetDataSocket(lpwfs, &nDataSocket)) 373 { 374 FTP_SendData(lpwfs, nDataSocket, hFile); 375 closesocket(nDataSocket); 376 nResCode = FTP_ReceiveResponse(lpwfs, dwContext); 377 if (nResCode) 378 { 379 if (nResCode == 226) 380 bSuccess = TRUE; 381 else 382 FTP_SetResponseError(nResCode); 383 } 384 } 385 } 386 387 if (lpwfs->lstnSocket != -1) 388 { 389 closesocket(lpwfs->lstnSocket); 390 lpwfs->lstnSocket = -1; 391 } 392 393 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 394 { 395 INTERNET_ASYNC_RESULT iar; 396 397 iar.dwResult = (DWORD)bSuccess; 398 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); 399 INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, 400 &iar, sizeof(INTERNET_ASYNC_RESULT)); 401 } 402 403 CloseHandle(hFile); 404 405 return bSuccess; 406 } 407 408 409 /*********************************************************************** 410 * FtpSetCurrentDirectoryA (WININET.@) 411 * 412 * Change the working directory on the FTP server 413 * 414 * RETURNS 415 * TRUE on success 416 * FALSE on failure 417 * 418 */ 419 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory) 420 { 421 LPWSTR lpwzDirectory; 422 BOOL ret; 423 424 lpwzDirectory = heap_strdupAtoW(lpszDirectory); 425 ret = FtpSetCurrentDirectoryW(hConnect, lpwzDirectory); 426 heap_free(lpwzDirectory); 427 return ret; 428 } 429 430 typedef struct { 431 task_header_t hdr; 432 WCHAR *directory; 433 } directory_task_t; 434 435 static void AsyncFtpSetCurrentDirectoryProc(task_header_t *hdr) 436 { 437 directory_task_t *task = (directory_task_t*)hdr; 438 ftp_session_t *session = (ftp_session_t*)task->hdr.hdr; 439 440 TRACE("%p\n", session); 441 442 FTP_FtpSetCurrentDirectoryW(session, task->directory); 443 heap_free(task->directory); 444 } 445 446 /*********************************************************************** 447 * FtpSetCurrentDirectoryW (WININET.@) 448 * 449 * Change the working directory on the FTP server 450 * 451 * RETURNS 452 * TRUE on success 453 * FALSE on failure 454 * 455 */ 456 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory) 457 { 458 ftp_session_t *lpwfs = NULL; 459 appinfo_t *hIC = NULL; 460 BOOL r = FALSE; 461 462 if (!lpszDirectory) 463 { 464 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 465 goto lend; 466 } 467 468 lpwfs = (ftp_session_t*) get_handle_object( hConnect ); 469 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) 470 { 471 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); 472 goto lend; 473 } 474 475 if (lpwfs->download_in_progress != NULL) 476 { 477 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); 478 goto lend; 479 } 480 481 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory)); 482 483 hIC = lpwfs->lpAppInfo; 484 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 485 { 486 directory_task_t *task; 487 488 task = alloc_async_task(&lpwfs->hdr, AsyncFtpSetCurrentDirectoryProc, sizeof(*task)); 489 task->directory = heap_strdupW(lpszDirectory); 490 491 r = res_to_le(INTERNET_AsyncCall(&task->hdr)); 492 } 493 else 494 { 495 r = FTP_FtpSetCurrentDirectoryW(lpwfs, lpszDirectory); 496 } 497 498 lend: 499 if( lpwfs ) 500 WININET_Release( &lpwfs->hdr ); 501 502 return r; 503 } 504 505 506 /*********************************************************************** 507 * FTP_FtpSetCurrentDirectoryW (Internal) 508 * 509 * Change the working directory on the FTP server 510 * 511 * RETURNS 512 * TRUE on success 513 * FALSE on failure 514 * 515 */ 516 static BOOL FTP_FtpSetCurrentDirectoryW(ftp_session_t *lpwfs, LPCWSTR lpszDirectory) 517 { 518 INT nResCode; 519 appinfo_t *hIC = NULL; 520 BOOL bSuccess = FALSE; 521 522 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory)); 523 524 /* Clear any error information */ 525 INTERNET_SetLastError(0); 526 527 hIC = lpwfs->lpAppInfo; 528 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory, 529 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext)) 530 goto lend; 531 532 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 533 534 if (nResCode) 535 { 536 if (nResCode == 250) 537 bSuccess = TRUE; 538 else 539 FTP_SetResponseError(nResCode); 540 } 541 542 lend: 543 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 544 { 545 INTERNET_ASYNC_RESULT iar; 546 547 iar.dwResult = bSuccess; 548 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR; 549 INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, 550 &iar, sizeof(INTERNET_ASYNC_RESULT)); 551 } 552 return bSuccess; 553 } 554 555 556 /*********************************************************************** 557 * FtpCreateDirectoryA (WININET.@) 558 * 559 * Create new directory on the FTP server 560 * 561 * RETURNS 562 * TRUE on success 563 * FALSE on failure 564 * 565 */ 566 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory) 567 { 568 LPWSTR lpwzDirectory; 569 BOOL ret; 570 571 lpwzDirectory = heap_strdupAtoW(lpszDirectory); 572 ret = FtpCreateDirectoryW(hConnect, lpwzDirectory); 573 heap_free(lpwzDirectory); 574 return ret; 575 } 576 577 578 static void AsyncFtpCreateDirectoryProc(task_header_t *hdr) 579 { 580 directory_task_t *task = (directory_task_t*)hdr; 581 ftp_session_t *session = (ftp_session_t*)task->hdr.hdr; 582 583 TRACE(" %p\n", session); 584 585 FTP_FtpCreateDirectoryW(session, task->directory); 586 heap_free(task->directory); 587 } 588 589 /*********************************************************************** 590 * FtpCreateDirectoryW (WININET.@) 591 * 592 * Create new directory on the FTP server 593 * 594 * RETURNS 595 * TRUE on success 596 * FALSE on failure 597 * 598 */ 599 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory) 600 { 601 ftp_session_t *lpwfs; 602 appinfo_t *hIC = NULL; 603 BOOL r = FALSE; 604 605 lpwfs = (ftp_session_t*) get_handle_object( hConnect ); 606 if (!lpwfs) 607 { 608 INTERNET_SetLastError(ERROR_INVALID_HANDLE); 609 return FALSE; 610 } 611 612 if (WH_HFTPSESSION != lpwfs->hdr.htype) 613 { 614 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); 615 goto lend; 616 } 617 618 if (lpwfs->download_in_progress != NULL) 619 { 620 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); 621 goto lend; 622 } 623 624 if (!lpszDirectory) 625 { 626 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 627 goto lend; 628 } 629 630 hIC = lpwfs->lpAppInfo; 631 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 632 { 633 directory_task_t *task; 634 635 task = alloc_async_task(&lpwfs->hdr, AsyncFtpCreateDirectoryProc, sizeof(*task)); 636 task->directory = heap_strdupW(lpszDirectory); 637 638 r = res_to_le(INTERNET_AsyncCall(&task->hdr)); 639 } 640 else 641 { 642 r = FTP_FtpCreateDirectoryW(lpwfs, lpszDirectory); 643 } 644 lend: 645 WININET_Release( &lpwfs->hdr ); 646 647 return r; 648 } 649 650 651 /*********************************************************************** 652 * FTP_FtpCreateDirectoryW (Internal) 653 * 654 * Create new directory on the FTP server 655 * 656 * RETURNS 657 * TRUE on success 658 * FALSE on failure 659 * 660 */ 661 static BOOL FTP_FtpCreateDirectoryW(ftp_session_t *lpwfs, LPCWSTR lpszDirectory) 662 { 663 INT nResCode; 664 BOOL bSuccess = FALSE; 665 appinfo_t *hIC = NULL; 666 667 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory)); 668 669 /* Clear any error information */ 670 INTERNET_SetLastError(0); 671 672 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0)) 673 goto lend; 674 675 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 676 if (nResCode) 677 { 678 if (nResCode == 257) 679 bSuccess = TRUE; 680 else 681 FTP_SetResponseError(nResCode); 682 } 683 684 lend: 685 hIC = lpwfs->lpAppInfo; 686 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 687 { 688 INTERNET_ASYNC_RESULT iar; 689 690 iar.dwResult = (DWORD)bSuccess; 691 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); 692 INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, 693 &iar, sizeof(INTERNET_ASYNC_RESULT)); 694 } 695 696 return bSuccess; 697 } 698 699 /*********************************************************************** 700 * FtpFindFirstFileA (WININET.@) 701 * 702 * Search the specified directory 703 * 704 * RETURNS 705 * HINTERNET on success 706 * NULL on failure 707 * 708 */ 709 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect, 710 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext) 711 { 712 LPWSTR lpwzSearchFile; 713 WIN32_FIND_DATAW wfd; 714 LPWIN32_FIND_DATAW lpFindFileDataW; 715 HINTERNET ret; 716 717 lpwzSearchFile = heap_strdupAtoW(lpszSearchFile); 718 lpFindFileDataW = lpFindFileData?&wfd:NULL; 719 ret = FtpFindFirstFileW(hConnect, lpwzSearchFile, lpFindFileDataW, dwFlags, dwContext); 720 heap_free(lpwzSearchFile); 721 722 if (ret && lpFindFileData) 723 WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData); 724 725 return ret; 726 } 727 728 typedef struct { 729 task_header_t hdr; 730 WCHAR *search_file; 731 WIN32_FIND_DATAW *find_file_data; 732 DWORD flags; 733 DWORD_PTR context; 734 } find_first_file_task_t; 735 736 static void AsyncFtpFindFirstFileProc(task_header_t *hdr) 737 { 738 find_first_file_task_t *task = (find_first_file_task_t*)hdr; 739 ftp_session_t *session = (ftp_session_t*)task->hdr.hdr; 740 741 TRACE("%p\n", session); 742 743 FTP_FtpFindFirstFileW(session, task->search_file, task->find_file_data, task->flags, task->context); 744 heap_free(task->search_file); 745 } 746 747 /*********************************************************************** 748 * FtpFindFirstFileW (WININET.@) 749 * 750 * Search the specified directory 751 * 752 * RETURNS 753 * HINTERNET on success 754 * NULL on failure 755 * 756 */ 757 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect, 758 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext) 759 { 760 ftp_session_t *lpwfs; 761 appinfo_t *hIC = NULL; 762 HINTERNET r = NULL; 763 764 lpwfs = (ftp_session_t*) get_handle_object( hConnect ); 765 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) 766 { 767 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); 768 goto lend; 769 } 770 771 if (lpwfs->download_in_progress != NULL) 772 { 773 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); 774 goto lend; 775 } 776 777 hIC = lpwfs->lpAppInfo; 778 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 779 { 780 find_first_file_task_t *task; 781 782 task = alloc_async_task(&lpwfs->hdr, AsyncFtpFindFirstFileProc, sizeof(*task)); 783 task->search_file = heap_strdupW(lpszSearchFile); 784 task->find_file_data = lpFindFileData; 785 task->flags = dwFlags; 786 task->context = dwContext; 787 788 INTERNET_AsyncCall(&task->hdr); 789 r = NULL; 790 } 791 else 792 { 793 r = FTP_FtpFindFirstFileW(lpwfs, lpszSearchFile, lpFindFileData, 794 dwFlags, dwContext); 795 } 796 lend: 797 if( lpwfs ) 798 WININET_Release( &lpwfs->hdr ); 799 800 return r; 801 } 802 803 804 /*********************************************************************** 805 * FTP_FtpFindFirstFileW (Internal) 806 * 807 * Search the specified directory 808 * 809 * RETURNS 810 * HINTERNET on success 811 * NULL on failure 812 * 813 */ 814 static HINTERNET FTP_FtpFindFirstFileW(ftp_session_t *lpwfs, 815 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext) 816 { 817 INT nResCode; 818 appinfo_t *hIC = NULL; 819 HINTERNET hFindNext = NULL; 820 LPWSTR lpszSearchPath = NULL; 821 822 TRACE("\n"); 823 824 /* Clear any error information */ 825 INTERNET_SetLastError(0); 826 827 if (!FTP_InitListenSocket(lpwfs)) 828 goto lend; 829 830 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII)) 831 goto lend; 832 833 if (!FTP_SendPortOrPasv(lpwfs)) 834 goto lend; 835 836 /* split search path into file and path */ 837 if (lpszSearchFile) 838 { 839 LPCWSTR name = lpszSearchFile, p; 840 if ((p = wcsrchr( name, '\\' ))) name = p + 1; 841 if ((p = wcsrchr( name, '/' ))) name = p + 1; 842 if (name != lpszSearchFile) 843 { 844 lpszSearchPath = heap_strndupW(lpszSearchFile, name - lpszSearchFile); 845 lpszSearchFile = name; 846 } 847 } 848 849 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, lpszSearchPath, 850 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext)) 851 goto lend; 852 853 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 854 if (nResCode) 855 { 856 if (nResCode == 125 || nResCode == 150) 857 { 858 INT nDataSocket; 859 860 /* Get data socket to server */ 861 if (FTP_GetDataSocket(lpwfs, &nDataSocket)) 862 { 863 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpszSearchFile, lpFindFileData, dwContext); 864 closesocket(nDataSocket); 865 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 866 if (nResCode != 226 && nResCode != 250) 867 INTERNET_SetLastError(ERROR_NO_MORE_FILES); 868 } 869 } 870 else 871 FTP_SetResponseError(nResCode); 872 } 873 874 lend: 875 heap_free(lpszSearchPath); 876 877 if (lpwfs->lstnSocket != -1) 878 { 879 closesocket(lpwfs->lstnSocket); 880 lpwfs->lstnSocket = -1; 881 } 882 883 hIC = lpwfs->lpAppInfo; 884 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 885 { 886 INTERNET_ASYNC_RESULT iar; 887 888 if (hFindNext) 889 { 890 iar.dwResult = (DWORD_PTR)hFindNext; 891 iar.dwError = ERROR_SUCCESS; 892 INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED, 893 &iar, sizeof(INTERNET_ASYNC_RESULT)); 894 } 895 896 iar.dwResult = (DWORD_PTR)hFindNext; 897 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError(); 898 INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, 899 &iar, sizeof(INTERNET_ASYNC_RESULT)); 900 } 901 902 return hFindNext; 903 } 904 905 906 /*********************************************************************** 907 * FtpGetCurrentDirectoryA (WININET.@) 908 * 909 * Retrieves the current directory 910 * 911 * RETURNS 912 * TRUE on success 913 * FALSE on failure 914 * 915 */ 916 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory, 917 LPDWORD lpdwCurrentDirectory) 918 { 919 WCHAR *dir = NULL; 920 DWORD len; 921 BOOL ret; 922 923 if(lpdwCurrentDirectory) { 924 len = *lpdwCurrentDirectory; 925 if(lpszCurrentDirectory) 926 { 927 dir = heap_alloc(len * sizeof(WCHAR)); 928 if (NULL == dir) 929 { 930 INTERNET_SetLastError(ERROR_OUTOFMEMORY); 931 return FALSE; 932 } 933 } 934 } 935 ret = FtpGetCurrentDirectoryW(hFtpSession, lpszCurrentDirectory?dir:NULL, lpdwCurrentDirectory?&len:NULL); 936 937 if (ret && lpszCurrentDirectory) 938 WideCharToMultiByte(CP_ACP, 0, dir, -1, lpszCurrentDirectory, len, NULL, NULL); 939 940 if (lpdwCurrentDirectory) *lpdwCurrentDirectory = len; 941 heap_free(dir); 942 return ret; 943 } 944 945 typedef struct { 946 task_header_t hdr; 947 WCHAR *directory; 948 DWORD *directory_len; 949 } get_current_dir_task_t; 950 951 static void AsyncFtpGetCurrentDirectoryProc(task_header_t *hdr) 952 { 953 get_current_dir_task_t *task = (get_current_dir_task_t*)hdr; 954 ftp_session_t *session = (ftp_session_t*)task->hdr.hdr; 955 956 TRACE("%p\n", session); 957 958 FTP_FtpGetCurrentDirectoryW(session, task->directory, task->directory_len); 959 } 960 961 /*********************************************************************** 962 * FtpGetCurrentDirectoryW (WININET.@) 963 * 964 * Retrieves the current directory 965 * 966 * RETURNS 967 * TRUE on success 968 * FALSE on failure 969 * 970 */ 971 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory, 972 LPDWORD lpdwCurrentDirectory) 973 { 974 ftp_session_t *lpwfs; 975 appinfo_t *hIC = NULL; 976 BOOL r = FALSE; 977 978 TRACE("%p %p %p\n", hFtpSession, lpszCurrentDirectory, lpdwCurrentDirectory); 979 980 lpwfs = (ftp_session_t*) get_handle_object( hFtpSession ); 981 if (NULL == lpwfs) 982 { 983 INTERNET_SetLastError(ERROR_INVALID_HANDLE); 984 goto lend; 985 } 986 987 if (WH_HFTPSESSION != lpwfs->hdr.htype) 988 { 989 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); 990 goto lend; 991 } 992 993 if (!lpdwCurrentDirectory) 994 { 995 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 996 goto lend; 997 } 998 999 if (lpszCurrentDirectory == NULL) 1000 { 1001 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); 1002 goto lend; 1003 } 1004 1005 if (lpwfs->download_in_progress != NULL) 1006 { 1007 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); 1008 goto lend; 1009 } 1010 1011 hIC = lpwfs->lpAppInfo; 1012 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 1013 { 1014 get_current_dir_task_t *task; 1015 1016 task = alloc_async_task(&lpwfs->hdr, AsyncFtpGetCurrentDirectoryProc, sizeof(*task)); 1017 task->directory = lpszCurrentDirectory; 1018 task->directory_len = lpdwCurrentDirectory; 1019 1020 r = res_to_le(INTERNET_AsyncCall(&task->hdr)); 1021 } 1022 else 1023 { 1024 r = FTP_FtpGetCurrentDirectoryW(lpwfs, lpszCurrentDirectory, 1025 lpdwCurrentDirectory); 1026 } 1027 1028 lend: 1029 if( lpwfs ) 1030 WININET_Release( &lpwfs->hdr ); 1031 1032 return r; 1033 } 1034 1035 1036 /*********************************************************************** 1037 * FTP_FtpGetCurrentDirectoryW (Internal) 1038 * 1039 * Retrieves the current directory 1040 * 1041 * RETURNS 1042 * TRUE on success 1043 * FALSE on failure 1044 * 1045 */ 1046 static BOOL FTP_FtpGetCurrentDirectoryW(ftp_session_t *lpwfs, LPWSTR lpszCurrentDirectory, 1047 LPDWORD lpdwCurrentDirectory) 1048 { 1049 INT nResCode; 1050 appinfo_t *hIC = NULL; 1051 BOOL bSuccess = FALSE; 1052 1053 /* Clear any error information */ 1054 INTERNET_SetLastError(0); 1055 1056 hIC = lpwfs->lpAppInfo; 1057 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL, 1058 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext)) 1059 goto lend; 1060 1061 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 1062 if (nResCode) 1063 { 1064 if (nResCode == 257) /* Extract directory name */ 1065 { 1066 DWORD firstpos, lastpos, len; 1067 LPWSTR lpszResponseBuffer = heap_strdupAtoW(INTERNET_GetResponseBuffer()); 1068 1069 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++) 1070 { 1071 if ('"' == lpszResponseBuffer[lastpos]) 1072 { 1073 if (!firstpos) 1074 firstpos = lastpos; 1075 else 1076 break; 1077 } 1078 } 1079 len = lastpos - firstpos; 1080 if (*lpdwCurrentDirectory >= len) 1081 { 1082 memcpy(lpszCurrentDirectory, &lpszResponseBuffer[firstpos + 1], len * sizeof(WCHAR)); 1083 lpszCurrentDirectory[len - 1] = 0; 1084 *lpdwCurrentDirectory = len; 1085 bSuccess = TRUE; 1086 } 1087 else INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); 1088 1089 heap_free(lpszResponseBuffer); 1090 } 1091 else 1092 FTP_SetResponseError(nResCode); 1093 } 1094 1095 lend: 1096 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 1097 { 1098 INTERNET_ASYNC_RESULT iar; 1099 1100 iar.dwResult = bSuccess; 1101 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR; 1102 INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, 1103 &iar, sizeof(INTERNET_ASYNC_RESULT)); 1104 } 1105 1106 return bSuccess; 1107 } 1108 1109 1110 /*********************************************************************** 1111 * FTPFILE_Destroy(internal) 1112 * 1113 * Closes the file transfer handle. This also 'cleans' the data queue of 1114 * the 'transfer complete' message (this is a bit of a hack though :-/ ) 1115 * 1116 */ 1117 static void FTPFILE_Destroy(object_header_t *hdr) 1118 { 1119 ftp_file_t *lpwh = (ftp_file_t*) hdr; 1120 ftp_session_t *lpwfs = lpwh->lpFtpSession; 1121 INT nResCode; 1122 1123 TRACE("\n"); 1124 1125 if (lpwh->cache_file_handle != INVALID_HANDLE_VALUE) 1126 CloseHandle(lpwh->cache_file_handle); 1127 1128 heap_free(lpwh->cache_file); 1129 1130 if (!lpwh->session_deleted) 1131 lpwfs->download_in_progress = NULL; 1132 1133 if (lpwh->nDataSocket != -1) 1134 closesocket(lpwh->nDataSocket); 1135 1136 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 1137 if (nResCode > 0 && nResCode != 226) WARN("server reports failed transfer\n"); 1138 1139 WININET_Release(&lpwh->lpFtpSession->hdr); 1140 } 1141 1142 static DWORD FTPFILE_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) 1143 { 1144 switch(option) { 1145 case INTERNET_OPTION_HANDLE_TYPE: 1146 TRACE("INTERNET_OPTION_HANDLE_TYPE\n"); 1147 1148 if (*size < sizeof(ULONG)) 1149 return ERROR_INSUFFICIENT_BUFFER; 1150 1151 *size = sizeof(DWORD); 1152 *(DWORD*)buffer = INTERNET_HANDLE_TYPE_FTP_FILE; 1153 return ERROR_SUCCESS; 1154 case INTERNET_OPTION_DATAFILE_NAME: 1155 { 1156 DWORD required; 1157 ftp_file_t *file = (ftp_file_t *)hdr; 1158 1159 TRACE("INTERNET_OPTION_DATAFILE_NAME\n"); 1160 1161 if (!file->cache_file) 1162 { 1163 *size = 0; 1164 return ERROR_INTERNET_ITEM_NOT_FOUND; 1165 } 1166 if (unicode) 1167 { 1168 required = (lstrlenW(file->cache_file) + 1) * sizeof(WCHAR); 1169 if (*size < required) 1170 return ERROR_INSUFFICIENT_BUFFER; 1171 1172 *size = required; 1173 memcpy(buffer, file->cache_file, *size); 1174 return ERROR_SUCCESS; 1175 } 1176 else 1177 { 1178 required = WideCharToMultiByte(CP_ACP, 0, file->cache_file, -1, NULL, 0, NULL, NULL); 1179 if (required > *size) 1180 return ERROR_INSUFFICIENT_BUFFER; 1181 1182 *size = WideCharToMultiByte(CP_ACP, 0, file->cache_file, -1, buffer, *size, NULL, NULL); 1183 return ERROR_SUCCESS; 1184 } 1185 } 1186 } 1187 return INET_QueryOption(hdr, option, buffer, size, unicode); 1188 } 1189 1190 static DWORD FTPFILE_ReadFile(object_header_t *hdr, void *buffer, DWORD size, DWORD *read, 1191 DWORD flags, DWORD_PTR context) 1192 { 1193 ftp_file_t *file = (ftp_file_t*)hdr; 1194 int res; 1195 DWORD error; 1196 1197 if (file->nDataSocket == -1) 1198 return ERROR_INTERNET_DISCONNECTED; 1199 1200 /* FIXME: FTP should use NETCON_ stuff */ 1201 res = sock_recv(file->nDataSocket, buffer, size, MSG_WAITALL); 1202 *read = res>0 ? res : 0; 1203 1204 error = res >= 0 ? ERROR_SUCCESS : INTERNET_ERROR_BASE; /* FIXME */ 1205 if (error == ERROR_SUCCESS && file->cache_file) 1206 { 1207 DWORD bytes_written; 1208 1209 if (!WriteFile(file->cache_file_handle, buffer, *read, &bytes_written, NULL)) 1210 WARN("WriteFile failed: %u\n", GetLastError()); 1211 } 1212 return error; 1213 } 1214 1215 static DWORD FTPFILE_WriteFile(object_header_t *hdr, const void *buffer, DWORD size, DWORD *written) 1216 { 1217 ftp_file_t *lpwh = (ftp_file_t*) hdr; 1218 int res; 1219 1220 res = sock_send(lpwh->nDataSocket, buffer, size, 0); 1221 1222 *written = res>0 ? res : 0; 1223 return res >= 0 ? ERROR_SUCCESS : WSAGetLastError(); 1224 } 1225 1226 static void FTP_ReceiveRequestData(ftp_file_t *file, BOOL first_notif) 1227 { 1228 INTERNET_ASYNC_RESULT iar; 1229 BYTE buffer[4096]; 1230 int available; 1231 1232 TRACE("%p\n", file); 1233 1234 available = sock_recv(file->nDataSocket, buffer, sizeof(buffer), MSG_PEEK); 1235 1236 if(available != -1) { 1237 iar.dwResult = (DWORD_PTR)file->hdr.hInternet; 1238 iar.dwError = first_notif ? 0 : available; 1239 }else { 1240 iar.dwResult = 0; 1241 iar.dwError = INTERNET_GetLastError(); 1242 } 1243 1244 INTERNET_SendCallback(&file->hdr, file->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar, 1245 sizeof(INTERNET_ASYNC_RESULT)); 1246 } 1247 1248 static void FTPFILE_AsyncQueryDataAvailableProc(task_header_t *task) 1249 { 1250 ftp_file_t *file = (ftp_file_t*)task->hdr; 1251 1252 FTP_ReceiveRequestData(file, FALSE); 1253 } 1254 1255 static DWORD FTPFILE_QueryDataAvailable(object_header_t *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx) 1256 { 1257 ftp_file_t *file = (ftp_file_t*) hdr; 1258 ULONG unread = 0; 1259 int retval; 1260 1261 TRACE("(%p %p %x %lx)\n", file, available, flags, ctx); 1262 1263 retval = ioctlsocket(file->nDataSocket, FIONREAD, &unread); 1264 if (!retval) 1265 TRACE("%d bytes of queued, but unread data\n", unread); 1266 1267 *available = unread; 1268 1269 if(!unread) { 1270 BYTE byte; 1271 1272 *available = 0; 1273 1274 retval = sock_recv(file->nDataSocket, &byte, 1, MSG_PEEK); 1275 if(retval > 0) { 1276 task_header_t *task; 1277 1278 task = alloc_async_task(&file->hdr, FTPFILE_AsyncQueryDataAvailableProc, sizeof(*task)); 1279 INTERNET_AsyncCall(task); 1280 1281 return ERROR_IO_PENDING; 1282 } 1283 } 1284 1285 return ERROR_SUCCESS; 1286 } 1287 1288 static DWORD FTPFILE_LockRequestFile(object_header_t *hdr, req_file_t **ret) 1289 { 1290 ftp_file_t *file = (ftp_file_t*)hdr; 1291 FIXME("%p\n", file); 1292 return ERROR_NOT_SUPPORTED; 1293 } 1294 1295 static const object_vtbl_t FTPFILEVtbl = { 1296 FTPFILE_Destroy, 1297 NULL, 1298 FTPFILE_QueryOption, 1299 INET_SetOption, 1300 FTPFILE_ReadFile, 1301 FTPFILE_WriteFile, 1302 FTPFILE_QueryDataAvailable, 1303 NULL, 1304 FTPFILE_LockRequestFile 1305 }; 1306 1307 /*********************************************************************** 1308 * FTP_FtpOpenFileW (Internal) 1309 * 1310 * Open a remote file for writing or reading 1311 * 1312 * RETURNS 1313 * HINTERNET handle on success 1314 * NULL on failure 1315 * 1316 */ 1317 static HINTERNET FTP_FtpOpenFileW(ftp_session_t *lpwfs, 1318 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags, 1319 DWORD_PTR dwContext) 1320 { 1321 INT nDataSocket; 1322 BOOL bSuccess = FALSE; 1323 ftp_file_t *lpwh = NULL; 1324 appinfo_t *hIC = NULL; 1325 1326 TRACE("\n"); 1327 1328 /* Clear any error information */ 1329 INTERNET_SetLastError(0); 1330 1331 if (GENERIC_READ == fdwAccess) 1332 { 1333 /* Set up socket to retrieve data */ 1334 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags); 1335 } 1336 else if (GENERIC_WRITE == fdwAccess) 1337 { 1338 /* Set up socket to send data */ 1339 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags); 1340 } 1341 1342 /* Get data socket to server */ 1343 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket)) 1344 { 1345 lpwh = alloc_object(&lpwfs->hdr, &FTPFILEVtbl, sizeof(ftp_file_t)); 1346 lpwh->hdr.htype = WH_HFILE; 1347 lpwh->hdr.dwFlags = dwFlags; 1348 lpwh->hdr.dwContext = dwContext; 1349 lpwh->nDataSocket = nDataSocket; 1350 lpwh->cache_file = NULL; 1351 lpwh->cache_file_handle = INVALID_HANDLE_VALUE; 1352 lpwh->session_deleted = FALSE; 1353 1354 WININET_AddRef( &lpwfs->hdr ); 1355 lpwh->lpFtpSession = lpwfs; 1356 list_add_head( &lpwfs->hdr.children, &lpwh->hdr.entry ); 1357 1358 /* Indicate that a download is currently in progress */ 1359 lpwfs->download_in_progress = lpwh; 1360 } 1361 1362 if (lpwfs->lstnSocket != -1) 1363 { 1364 closesocket(lpwfs->lstnSocket); 1365 lpwfs->lstnSocket = -1; 1366 } 1367 1368 if (bSuccess && fdwAccess == GENERIC_READ) 1369 { 1370 WCHAR filename[MAX_PATH + 1]; 1371 URL_COMPONENTSW uc; 1372 DWORD len; 1373 1374 memset(&uc, 0, sizeof(uc)); 1375 uc.dwStructSize = sizeof(uc); 1376 uc.nScheme = INTERNET_SCHEME_FTP; 1377 uc.lpszHostName = lpwfs->servername; 1378 uc.nPort = lpwfs->serverport; 1379 uc.lpszUserName = lpwfs->lpszUserName; 1380 uc.lpszUrlPath = heap_strdupW(lpszFileName); 1381 1382 if (!InternetCreateUrlW(&uc, 0, NULL, &len) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) 1383 { 1384 WCHAR *url = heap_alloc(len * sizeof(WCHAR)); 1385 1386 if (url && InternetCreateUrlW(&uc, 0, url, &len) && CreateUrlCacheEntryW(url, 0, NULL, filename, 0)) 1387 { 1388 lpwh->cache_file = heap_strdupW(filename); 1389 lpwh->cache_file_handle = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_READ, 1390 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 1391 if (lpwh->cache_file_handle == INVALID_HANDLE_VALUE) 1392 { 1393 WARN("Could not create cache file: %u\n", GetLastError()); 1394 heap_free(lpwh->cache_file); 1395 lpwh->cache_file = NULL; 1396 } 1397 } 1398 heap_free(url); 1399 } 1400 heap_free(uc.lpszUrlPath); 1401 } 1402 1403 hIC = lpwfs->lpAppInfo; 1404 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 1405 { 1406 INTERNET_ASYNC_RESULT iar; 1407 1408 if (lpwh) 1409 { 1410 iar.dwResult = (DWORD_PTR)lpwh->hdr.hInternet; 1411 iar.dwError = ERROR_SUCCESS; 1412 INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED, 1413 &iar, sizeof(INTERNET_ASYNC_RESULT)); 1414 } 1415 1416 if(bSuccess) { 1417 FTP_ReceiveRequestData(lpwh, TRUE); 1418 }else { 1419 iar.dwResult = 0; 1420 iar.dwError = INTERNET_GetLastError(); 1421 INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, 1422 &iar, sizeof(INTERNET_ASYNC_RESULT)); 1423 } 1424 } 1425 1426 if(!bSuccess) 1427 return FALSE; 1428 1429 return lpwh->hdr.hInternet; 1430 } 1431 1432 1433 /*********************************************************************** 1434 * FtpOpenFileA (WININET.@) 1435 * 1436 * Open a remote file for writing or reading 1437 * 1438 * RETURNS 1439 * HINTERNET handle on success 1440 * NULL on failure 1441 * 1442 */ 1443 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession, 1444 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags, 1445 DWORD_PTR dwContext) 1446 { 1447 LPWSTR lpwzFileName; 1448 HINTERNET ret; 1449 1450 lpwzFileName = heap_strdupAtoW(lpszFileName); 1451 ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext); 1452 heap_free(lpwzFileName); 1453 return ret; 1454 } 1455 1456 typedef struct { 1457 task_header_t hdr; 1458 WCHAR *file_name; 1459 DWORD access; 1460 DWORD flags; 1461 DWORD_PTR context; 1462 } open_file_task_t; 1463 1464 static void AsyncFtpOpenFileProc(task_header_t *hdr) 1465 { 1466 open_file_task_t *task = (open_file_task_t*)hdr; 1467 ftp_session_t *session = (ftp_session_t*)task->hdr.hdr; 1468 1469 TRACE("%p\n", session); 1470 1471 FTP_FtpOpenFileW(session, task->file_name, task->access, task->flags, task->context); 1472 heap_free(task->file_name); 1473 } 1474 1475 /*********************************************************************** 1476 * FtpOpenFileW (WININET.@) 1477 * 1478 * Open a remote file for writing or reading 1479 * 1480 * RETURNS 1481 * HINTERNET handle on success 1482 * NULL on failure 1483 * 1484 */ 1485 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession, 1486 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags, 1487 DWORD_PTR dwContext) 1488 { 1489 ftp_session_t *lpwfs; 1490 appinfo_t *hIC = NULL; 1491 HINTERNET r = NULL; 1492 1493 TRACE("(%p,%s,0x%08x,0x%08x,0x%08lx)\n", hFtpSession, 1494 debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext); 1495 1496 lpwfs = (ftp_session_t*) get_handle_object( hFtpSession ); 1497 if (!lpwfs) 1498 { 1499 INTERNET_SetLastError(ERROR_INVALID_HANDLE); 1500 return FALSE; 1501 } 1502 1503 if (WH_HFTPSESSION != lpwfs->hdr.htype) 1504 { 1505 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); 1506 goto lend; 1507 } 1508 1509 if ((!lpszFileName) || 1510 ((fdwAccess != GENERIC_READ) && (fdwAccess != GENERIC_WRITE)) || 1511 ((dwFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY)) 1512 { 1513 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 1514 goto lend; 1515 } 1516 1517 if (lpwfs->download_in_progress != NULL) 1518 { 1519 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); 1520 goto lend; 1521 } 1522 1523 hIC = lpwfs->lpAppInfo; 1524 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 1525 { 1526 open_file_task_t *task; 1527 1528 task = alloc_async_task(&lpwfs->hdr, AsyncFtpOpenFileProc, sizeof(*task)); 1529 task->file_name = heap_strdupW(lpszFileName); 1530 task->access = fdwAccess; 1531 task->flags = dwFlags; 1532 task->context = dwContext; 1533 1534 INTERNET_AsyncCall(&task->hdr); 1535 r = NULL; 1536 } 1537 else 1538 { 1539 r = FTP_FtpOpenFileW(lpwfs, lpszFileName, fdwAccess, dwFlags, dwContext); 1540 } 1541 1542 lend: 1543 WININET_Release( &lpwfs->hdr ); 1544 1545 return r; 1546 } 1547 1548 1549 /*********************************************************************** 1550 * FtpGetFileA (WININET.@) 1551 * 1552 * Retrieve file from the FTP server 1553 * 1554 * RETURNS 1555 * TRUE on success 1556 * FALSE on failure 1557 * 1558 */ 1559 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile, 1560 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags, 1561 DWORD_PTR dwContext) 1562 { 1563 LPWSTR lpwzRemoteFile; 1564 LPWSTR lpwzNewFile; 1565 BOOL ret; 1566 1567 lpwzRemoteFile = heap_strdupAtoW(lpszRemoteFile); 1568 lpwzNewFile = heap_strdupAtoW(lpszNewFile); 1569 ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists, 1570 dwLocalFlagsAttribute, dwInternetFlags, dwContext); 1571 heap_free(lpwzRemoteFile); 1572 heap_free(lpwzNewFile); 1573 return ret; 1574 } 1575 1576 typedef struct { 1577 task_header_t hdr; 1578 WCHAR *remote_file; 1579 WCHAR *new_file; 1580 BOOL fail_if_exists; 1581 DWORD local_attr; 1582 DWORD flags; 1583 DWORD_PTR context; 1584 } get_file_task_t; 1585 1586 static void AsyncFtpGetFileProc(task_header_t *hdr) 1587 { 1588 get_file_task_t *task = (get_file_task_t*)hdr; 1589 ftp_session_t *session = (ftp_session_t*)task->hdr.hdr; 1590 1591 TRACE("%p\n", session); 1592 1593 FTP_FtpGetFileW(session, task->remote_file, task->new_file, task->fail_if_exists, 1594 task->local_attr, task->flags, task->context); 1595 heap_free(task->remote_file); 1596 heap_free(task->new_file); 1597 } 1598 1599 1600 /*********************************************************************** 1601 * FtpGetFileW (WININET.@) 1602 * 1603 * Retrieve file from the FTP server 1604 * 1605 * RETURNS 1606 * TRUE on success 1607 * FALSE on failure 1608 * 1609 */ 1610 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile, 1611 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags, 1612 DWORD_PTR dwContext) 1613 { 1614 ftp_session_t *lpwfs; 1615 appinfo_t *hIC = NULL; 1616 BOOL r = FALSE; 1617 1618 if (!lpszRemoteFile || !lpszNewFile) 1619 { 1620 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 1621 return FALSE; 1622 } 1623 1624 lpwfs = (ftp_session_t*) get_handle_object( hInternet ); 1625 if (!lpwfs) 1626 { 1627 INTERNET_SetLastError(ERROR_INVALID_HANDLE); 1628 return FALSE; 1629 } 1630 1631 if (WH_HFTPSESSION != lpwfs->hdr.htype) 1632 { 1633 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); 1634 goto lend; 1635 } 1636 1637 if ((dwInternetFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY) 1638 { 1639 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 1640 goto lend; 1641 } 1642 1643 if (lpwfs->download_in_progress != NULL) 1644 { 1645 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); 1646 goto lend; 1647 } 1648 1649 hIC = lpwfs->lpAppInfo; 1650 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 1651 { 1652 get_file_task_t *task; 1653 1654 task = alloc_async_task(&lpwfs->hdr, AsyncFtpGetFileProc, sizeof(*task)); 1655 task->remote_file = heap_strdupW(lpszRemoteFile); 1656 task->new_file = heap_strdupW(lpszNewFile); 1657 task->local_attr = dwLocalFlagsAttribute; 1658 task->fail_if_exists = fFailIfExists; 1659 task->flags = dwInternetFlags; 1660 task->context = dwContext; 1661 1662 r = res_to_le(INTERNET_AsyncCall(&task->hdr)); 1663 } 1664 else 1665 { 1666 r = FTP_FtpGetFileW(lpwfs, lpszRemoteFile, lpszNewFile, 1667 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext); 1668 } 1669 1670 lend: 1671 WININET_Release( &lpwfs->hdr ); 1672 1673 return r; 1674 } 1675 1676 1677 /*********************************************************************** 1678 * FTP_FtpGetFileW (Internal) 1679 * 1680 * Retrieve file from the FTP server 1681 * 1682 * RETURNS 1683 * TRUE on success 1684 * FALSE on failure 1685 * 1686 */ 1687 static BOOL FTP_FtpGetFileW(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile, 1688 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags, 1689 DWORD_PTR dwContext) 1690 { 1691 BOOL bSuccess = FALSE; 1692 HANDLE hFile; 1693 appinfo_t *hIC = NULL; 1694 1695 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile)); 1696 1697 /* Clear any error information */ 1698 INTERNET_SetLastError(0); 1699 1700 /* Ensure we can write to lpszNewfile by opening it */ 1701 hFile = CreateFileW(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ? 1702 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0); 1703 if (INVALID_HANDLE_VALUE == hFile) 1704 return FALSE; 1705 1706 /* Set up socket to retrieve data */ 1707 if (FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags)) 1708 { 1709 INT nDataSocket; 1710 1711 /* Get data socket to server */ 1712 if (FTP_GetDataSocket(lpwfs, &nDataSocket)) 1713 { 1714 INT nResCode; 1715 1716 /* Receive data */ 1717 FTP_RetrieveFileData(lpwfs, nDataSocket, hFile); 1718 closesocket(nDataSocket); 1719 1720 nResCode = FTP_ReceiveResponse(lpwfs, dwContext); 1721 if (nResCode) 1722 { 1723 if (nResCode == 226) 1724 bSuccess = TRUE; 1725 else 1726 FTP_SetResponseError(nResCode); 1727 } 1728 } 1729 } 1730 1731 if (lpwfs->lstnSocket != -1) 1732 { 1733 closesocket(lpwfs->lstnSocket); 1734 lpwfs->lstnSocket = -1; 1735 } 1736 1737 CloseHandle(hFile); 1738 1739 hIC = lpwfs->lpAppInfo; 1740 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 1741 { 1742 INTERNET_ASYNC_RESULT iar; 1743 1744 iar.dwResult = (DWORD)bSuccess; 1745 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); 1746 INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, 1747 &iar, sizeof(INTERNET_ASYNC_RESULT)); 1748 } 1749 1750 if (!bSuccess) DeleteFileW(lpszNewFile); 1751 return bSuccess; 1752 } 1753 1754 /*********************************************************************** 1755 * FtpGetFileSize (WININET.@) 1756 */ 1757 DWORD WINAPI FtpGetFileSize( HINTERNET hFile, LPDWORD lpdwFileSizeHigh ) 1758 { 1759 FIXME("(%p, %p)\n", hFile, lpdwFileSizeHigh); 1760 1761 if (lpdwFileSizeHigh) 1762 *lpdwFileSizeHigh = 0; 1763 1764 return 0; 1765 } 1766 1767 /*********************************************************************** 1768 * FtpDeleteFileA (WININET.@) 1769 * 1770 * Delete a file on the ftp server 1771 * 1772 * RETURNS 1773 * TRUE on success 1774 * FALSE on failure 1775 * 1776 */ 1777 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName) 1778 { 1779 LPWSTR lpwzFileName; 1780 BOOL ret; 1781 1782 lpwzFileName = heap_strdupAtoW(lpszFileName); 1783 ret = FtpDeleteFileW(hFtpSession, lpwzFileName); 1784 heap_free(lpwzFileName); 1785 return ret; 1786 } 1787 1788 typedef struct { 1789 task_header_t hdr; 1790 WCHAR *file_name; 1791 } delete_file_task_t; 1792 1793 static void AsyncFtpDeleteFileProc(task_header_t *hdr) 1794 { 1795 delete_file_task_t *task = (delete_file_task_t*)hdr; 1796 ftp_session_t *session = (ftp_session_t*)task->hdr.hdr; 1797 1798 TRACE("%p\n", session); 1799 1800 FTP_FtpDeleteFileW(session, task->file_name); 1801 heap_free(task->file_name); 1802 } 1803 1804 /*********************************************************************** 1805 * FtpDeleteFileW (WININET.@) 1806 * 1807 * Delete a file on the ftp server 1808 * 1809 * RETURNS 1810 * TRUE on success 1811 * FALSE on failure 1812 * 1813 */ 1814 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName) 1815 { 1816 ftp_session_t *lpwfs; 1817 appinfo_t *hIC = NULL; 1818 BOOL r = FALSE; 1819 1820 lpwfs = (ftp_session_t*) get_handle_object( hFtpSession ); 1821 if (!lpwfs) 1822 { 1823 INTERNET_SetLastError(ERROR_INVALID_HANDLE); 1824 return FALSE; 1825 } 1826 1827 if (WH_HFTPSESSION != lpwfs->hdr.htype) 1828 { 1829 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); 1830 goto lend; 1831 } 1832 1833 if (lpwfs->download_in_progress != NULL) 1834 { 1835 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); 1836 goto lend; 1837 } 1838 1839 if (!lpszFileName) 1840 { 1841 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 1842 goto lend; 1843 } 1844 1845 hIC = lpwfs->lpAppInfo; 1846 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 1847 { 1848 delete_file_task_t *task; 1849 1850 task = alloc_async_task(&lpwfs->hdr, AsyncFtpDeleteFileProc, sizeof(*task)); 1851 task->file_name = heap_strdupW(lpszFileName); 1852 1853 r = res_to_le(INTERNET_AsyncCall(&task->hdr)); 1854 } 1855 else 1856 { 1857 r = FTP_FtpDeleteFileW(lpwfs, lpszFileName); 1858 } 1859 1860 lend: 1861 WININET_Release( &lpwfs->hdr ); 1862 1863 return r; 1864 } 1865 1866 /*********************************************************************** 1867 * FTP_FtpDeleteFileW (Internal) 1868 * 1869 * Delete a file on the ftp server 1870 * 1871 * RETURNS 1872 * TRUE on success 1873 * FALSE on failure 1874 * 1875 */ 1876 BOOL FTP_FtpDeleteFileW(ftp_session_t *lpwfs, LPCWSTR lpszFileName) 1877 { 1878 INT nResCode; 1879 BOOL bSuccess = FALSE; 1880 appinfo_t *hIC = NULL; 1881 1882 TRACE("%p\n", lpwfs); 1883 1884 /* Clear any error information */ 1885 INTERNET_SetLastError(0); 1886 1887 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0)) 1888 goto lend; 1889 1890 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 1891 if (nResCode) 1892 { 1893 if (nResCode == 250) 1894 bSuccess = TRUE; 1895 else 1896 FTP_SetResponseError(nResCode); 1897 } 1898 lend: 1899 hIC = lpwfs->lpAppInfo; 1900 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 1901 { 1902 INTERNET_ASYNC_RESULT iar; 1903 1904 iar.dwResult = (DWORD)bSuccess; 1905 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); 1906 INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, 1907 &iar, sizeof(INTERNET_ASYNC_RESULT)); 1908 } 1909 1910 return bSuccess; 1911 } 1912 1913 1914 /*********************************************************************** 1915 * FtpRemoveDirectoryA (WININET.@) 1916 * 1917 * Remove a directory on the ftp server 1918 * 1919 * RETURNS 1920 * TRUE on success 1921 * FALSE on failure 1922 * 1923 */ 1924 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory) 1925 { 1926 LPWSTR lpwzDirectory; 1927 BOOL ret; 1928 1929 lpwzDirectory = heap_strdupAtoW(lpszDirectory); 1930 ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory); 1931 heap_free(lpwzDirectory); 1932 return ret; 1933 } 1934 1935 static void AsyncFtpRemoveDirectoryProc(task_header_t *hdr) 1936 { 1937 directory_task_t *task = (directory_task_t*)hdr; 1938 ftp_session_t *session = (ftp_session_t*)task->hdr.hdr; 1939 1940 TRACE("%p\n", session); 1941 1942 FTP_FtpRemoveDirectoryW(session, task->directory); 1943 heap_free(task->directory); 1944 } 1945 1946 /*********************************************************************** 1947 * FtpRemoveDirectoryW (WININET.@) 1948 * 1949 * Remove a directory on the ftp server 1950 * 1951 * RETURNS 1952 * TRUE on success 1953 * FALSE on failure 1954 * 1955 */ 1956 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory) 1957 { 1958 ftp_session_t *lpwfs; 1959 appinfo_t *hIC = NULL; 1960 BOOL r = FALSE; 1961 1962 lpwfs = (ftp_session_t*) get_handle_object( hFtpSession ); 1963 if (!lpwfs) 1964 { 1965 INTERNET_SetLastError(ERROR_INVALID_HANDLE); 1966 return FALSE; 1967 } 1968 1969 if (WH_HFTPSESSION != lpwfs->hdr.htype) 1970 { 1971 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); 1972 goto lend; 1973 } 1974 1975 if (lpwfs->download_in_progress != NULL) 1976 { 1977 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); 1978 goto lend; 1979 } 1980 1981 if (!lpszDirectory) 1982 { 1983 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 1984 goto lend; 1985 } 1986 1987 hIC = lpwfs->lpAppInfo; 1988 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 1989 { 1990 directory_task_t *task; 1991 1992 task = alloc_async_task(&lpwfs->hdr, AsyncFtpRemoveDirectoryProc, sizeof(*task)); 1993 task->directory = heap_strdupW(lpszDirectory); 1994 1995 r = res_to_le(INTERNET_AsyncCall(&task->hdr)); 1996 } 1997 else 1998 { 1999 r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory); 2000 } 2001 2002 lend: 2003 WININET_Release( &lpwfs->hdr ); 2004 2005 return r; 2006 } 2007 2008 /*********************************************************************** 2009 * FTP_FtpRemoveDirectoryW (Internal) 2010 * 2011 * Remove a directory on the ftp server 2012 * 2013 * RETURNS 2014 * TRUE on success 2015 * FALSE on failure 2016 * 2017 */ 2018 BOOL FTP_FtpRemoveDirectoryW(ftp_session_t *lpwfs, LPCWSTR lpszDirectory) 2019 { 2020 INT nResCode; 2021 BOOL bSuccess = FALSE; 2022 appinfo_t *hIC = NULL; 2023 2024 TRACE("\n"); 2025 2026 /* Clear any error information */ 2027 INTERNET_SetLastError(0); 2028 2029 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0)) 2030 goto lend; 2031 2032 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 2033 if (nResCode) 2034 { 2035 if (nResCode == 250) 2036 bSuccess = TRUE; 2037 else 2038 FTP_SetResponseError(nResCode); 2039 } 2040 2041 lend: 2042 hIC = lpwfs->lpAppInfo; 2043 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 2044 { 2045 INTERNET_ASYNC_RESULT iar; 2046 2047 iar.dwResult = (DWORD)bSuccess; 2048 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); 2049 INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, 2050 &iar, sizeof(INTERNET_ASYNC_RESULT)); 2051 } 2052 2053 return bSuccess; 2054 } 2055 2056 2057 /*********************************************************************** 2058 * FtpRenameFileA (WININET.@) 2059 * 2060 * Rename a file on the ftp server 2061 * 2062 * RETURNS 2063 * TRUE on success 2064 * FALSE on failure 2065 * 2066 */ 2067 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest) 2068 { 2069 LPWSTR lpwzSrc; 2070 LPWSTR lpwzDest; 2071 BOOL ret; 2072 2073 lpwzSrc = heap_strdupAtoW(lpszSrc); 2074 lpwzDest = heap_strdupAtoW(lpszDest); 2075 ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest); 2076 heap_free(lpwzSrc); 2077 heap_free(lpwzDest); 2078 return ret; 2079 } 2080 2081 typedef struct { 2082 task_header_t hdr; 2083 WCHAR *src_file; 2084 WCHAR *dst_file; 2085 } rename_file_task_t; 2086 2087 static void AsyncFtpRenameFileProc(task_header_t *hdr) 2088 { 2089 rename_file_task_t *task = (rename_file_task_t*)hdr; 2090 ftp_session_t *session = (ftp_session_t*)task->hdr.hdr; 2091 2092 TRACE("%p\n", session); 2093 2094 FTP_FtpRenameFileW(session, task->src_file, task->dst_file); 2095 heap_free(task->src_file); 2096 heap_free(task->dst_file); 2097 } 2098 2099 /*********************************************************************** 2100 * FtpRenameFileW (WININET.@) 2101 * 2102 * Rename a file on the ftp server 2103 * 2104 * RETURNS 2105 * TRUE on success 2106 * FALSE on failure 2107 * 2108 */ 2109 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest) 2110 { 2111 ftp_session_t *lpwfs; 2112 appinfo_t *hIC = NULL; 2113 BOOL r = FALSE; 2114 2115 lpwfs = (ftp_session_t*) get_handle_object( hFtpSession ); 2116 if (!lpwfs) 2117 { 2118 INTERNET_SetLastError(ERROR_INVALID_HANDLE); 2119 return FALSE; 2120 } 2121 2122 if (WH_HFTPSESSION != lpwfs->hdr.htype) 2123 { 2124 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); 2125 goto lend; 2126 } 2127 2128 if (lpwfs->download_in_progress != NULL) 2129 { 2130 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); 2131 goto lend; 2132 } 2133 2134 if (!lpszSrc || !lpszDest) 2135 { 2136 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 2137 goto lend; 2138 } 2139 2140 hIC = lpwfs->lpAppInfo; 2141 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 2142 { 2143 rename_file_task_t *task; 2144 2145 task = alloc_async_task(&lpwfs->hdr, AsyncFtpRenameFileProc, sizeof(*task)); 2146 task->src_file = heap_strdupW(lpszSrc); 2147 task->dst_file = heap_strdupW(lpszDest); 2148 2149 r = res_to_le(INTERNET_AsyncCall(&task->hdr)); 2150 } 2151 else 2152 { 2153 r = FTP_FtpRenameFileW(lpwfs, lpszSrc, lpszDest); 2154 } 2155 2156 lend: 2157 WININET_Release( &lpwfs->hdr ); 2158 2159 return r; 2160 } 2161 2162 /*********************************************************************** 2163 * FTP_FtpRenameFileW (Internal) 2164 * 2165 * Rename a file on the ftp server 2166 * 2167 * RETURNS 2168 * TRUE on success 2169 * FALSE on failure 2170 * 2171 */ 2172 BOOL FTP_FtpRenameFileW(ftp_session_t *lpwfs, LPCWSTR lpszSrc, LPCWSTR lpszDest) 2173 { 2174 INT nResCode; 2175 BOOL bSuccess = FALSE; 2176 appinfo_t *hIC = NULL; 2177 2178 TRACE("\n"); 2179 2180 /* Clear any error information */ 2181 INTERNET_SetLastError(0); 2182 2183 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0)) 2184 goto lend; 2185 2186 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 2187 if (nResCode == 350) 2188 { 2189 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0)) 2190 goto lend; 2191 2192 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 2193 } 2194 2195 if (nResCode == 250) 2196 bSuccess = TRUE; 2197 else 2198 FTP_SetResponseError(nResCode); 2199 2200 lend: 2201 hIC = lpwfs->lpAppInfo; 2202 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 2203 { 2204 INTERNET_ASYNC_RESULT iar; 2205 2206 iar.dwResult = (DWORD)bSuccess; 2207 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); 2208 INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, 2209 &iar, sizeof(INTERNET_ASYNC_RESULT)); 2210 } 2211 2212 return bSuccess; 2213 } 2214 2215 /*********************************************************************** 2216 * FtpCommandA (WININET.@) 2217 */ 2218 BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags, 2219 LPCSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand ) 2220 { 2221 BOOL r; 2222 WCHAR *cmdW; 2223 2224 TRACE("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags, 2225 debugstr_a(lpszCommand), dwContext, phFtpCommand); 2226 2227 if (fExpectResponse) 2228 { 2229 FIXME("data connection not supported\n"); 2230 return FALSE; 2231 } 2232 2233 if (!lpszCommand || !lpszCommand[0]) 2234 { 2235 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 2236 return FALSE; 2237 } 2238 2239 if (!(cmdW = heap_strdupAtoW(lpszCommand))) 2240 { 2241 INTERNET_SetLastError(ERROR_OUTOFMEMORY); 2242 return FALSE; 2243 } 2244 2245 r = FtpCommandW(hConnect, fExpectResponse, dwFlags, cmdW, dwContext, phFtpCommand); 2246 2247 heap_free(cmdW); 2248 return r; 2249 } 2250 2251 /*********************************************************************** 2252 * FtpCommandW (WININET.@) 2253 */ 2254 BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags, 2255 LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand ) 2256 { 2257 BOOL r = FALSE; 2258 ftp_session_t *lpwfs; 2259 LPSTR cmd = NULL; 2260 DWORD len, nBytesSent= 0; 2261 INT nResCode, nRC = 0; 2262 2263 TRACE("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags, 2264 debugstr_w(lpszCommand), dwContext, phFtpCommand); 2265 2266 if (!lpszCommand || !lpszCommand[0]) 2267 { 2268 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 2269 return FALSE; 2270 } 2271 2272 if (fExpectResponse) 2273 { 2274 FIXME("data connection not supported\n"); 2275 return FALSE; 2276 } 2277 2278 lpwfs = (ftp_session_t*) get_handle_object( hConnect ); 2279 if (!lpwfs) 2280 { 2281 INTERNET_SetLastError(ERROR_INVALID_HANDLE); 2282 return FALSE; 2283 } 2284 2285 if (WH_HFTPSESSION != lpwfs->hdr.htype) 2286 { 2287 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); 2288 goto lend; 2289 } 2290 2291 if (lpwfs->download_in_progress != NULL) 2292 { 2293 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); 2294 goto lend; 2295 } 2296 2297 len = WideCharToMultiByte(CP_ACP, 0, lpszCommand, -1, NULL, 0, NULL, NULL) + strlen(szCRLF); 2298 if ((cmd = heap_alloc(len))) 2299 WideCharToMultiByte(CP_ACP, 0, lpszCommand, -1, cmd, len, NULL, NULL); 2300 else 2301 { 2302 INTERNET_SetLastError(ERROR_OUTOFMEMORY); 2303 goto lend; 2304 } 2305 2306 strcat(cmd, szCRLF); 2307 len--; 2308 2309 TRACE("Sending (%s) len(%d)\n", debugstr_a(cmd), len); 2310 while ((nBytesSent < len) && (nRC != -1)) 2311 { 2312 nRC = sock_send(lpwfs->sndSocket, cmd + nBytesSent, len - nBytesSent, 0); 2313 if (nRC != -1) 2314 { 2315 nBytesSent += nRC; 2316 TRACE("Sent %d bytes\n", nRC); 2317 } 2318 } 2319 2320 if (nBytesSent) 2321 { 2322 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 2323 if (nResCode > 0 && nResCode < 400) 2324 r = TRUE; 2325 else 2326 FTP_SetResponseError(nResCode); 2327 } 2328 2329 lend: 2330 WININET_Release( &lpwfs->hdr ); 2331 heap_free( cmd ); 2332 return r; 2333 } 2334 2335 2336 /*********************************************************************** 2337 * FTPSESSION_Destroy (internal) 2338 * 2339 * Deallocate session handle 2340 */ 2341 static void FTPSESSION_Destroy(object_header_t *hdr) 2342 { 2343 ftp_session_t *lpwfs = (ftp_session_t*) hdr; 2344 2345 TRACE("\n"); 2346 2347 WININET_Release(&lpwfs->lpAppInfo->hdr); 2348 2349 heap_free(lpwfs->lpszPassword); 2350 heap_free(lpwfs->lpszUserName); 2351 heap_free(lpwfs->servername); 2352 } 2353 2354 static void FTPSESSION_CloseConnection(object_header_t *hdr) 2355 { 2356 ftp_session_t *lpwfs = (ftp_session_t*) hdr; 2357 2358 TRACE("\n"); 2359 2360 INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, 2361 INTERNET_STATUS_CLOSING_CONNECTION, 0, 0); 2362 2363 if (lpwfs->download_in_progress != NULL) 2364 lpwfs->download_in_progress->session_deleted = TRUE; 2365 2366 if (lpwfs->sndSocket != -1) 2367 closesocket(lpwfs->sndSocket); 2368 2369 if (lpwfs->lstnSocket != -1) 2370 closesocket(lpwfs->lstnSocket); 2371 2372 if (lpwfs->pasvSocket != -1) 2373 closesocket(lpwfs->pasvSocket); 2374 2375 INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, 2376 INTERNET_STATUS_CONNECTION_CLOSED, 0, 0); 2377 } 2378 2379 static DWORD FTPSESSION_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) 2380 { 2381 switch(option) { 2382 case INTERNET_OPTION_HANDLE_TYPE: 2383 TRACE("INTERNET_OPTION_HANDLE_TYPE\n"); 2384 2385 if (*size < sizeof(ULONG)) 2386 return ERROR_INSUFFICIENT_BUFFER; 2387 2388 *size = sizeof(DWORD); 2389 *(DWORD*)buffer = INTERNET_HANDLE_TYPE_CONNECT_FTP; 2390 return ERROR_SUCCESS; 2391 } 2392 2393 return INET_QueryOption(hdr, option, buffer, size, unicode); 2394 } 2395 2396 static const object_vtbl_t FTPSESSIONVtbl = { 2397 FTPSESSION_Destroy, 2398 FTPSESSION_CloseConnection, 2399 FTPSESSION_QueryOption, 2400 INET_SetOption, 2401 NULL, 2402 NULL, 2403 NULL, 2404 NULL 2405 }; 2406 2407 2408 /*********************************************************************** 2409 * FTP_Connect (internal) 2410 * 2411 * Connect to a ftp server 2412 * 2413 * RETURNS 2414 * HINTERNET a session handle on success 2415 * NULL on failure 2416 * 2417 * NOTES: 2418 * 2419 * Windows uses 'anonymous' as the username, when given a NULL username 2420 * and a NULL password. The password is first looked up in: 2421 * 2422 * HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\EmailName 2423 * 2424 * If this entry is not present it uses the current username as the password. 2425 * 2426 */ 2427 2428 HINTERNET FTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName, 2429 INTERNET_PORT nServerPort, LPCWSTR lpszUserName, 2430 LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext, 2431 DWORD dwInternalFlags) 2432 { 2433 struct sockaddr_in socketAddr; 2434 INT nsocket = -1; 2435 socklen_t sock_namelen; 2436 BOOL bSuccess = FALSE; 2437 ftp_session_t *lpwfs = NULL; 2438 char szaddr[INET6_ADDRSTRLEN]; 2439 2440 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n", 2441 hIC, debugstr_w(lpszServerName), 2442 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword)); 2443 2444 assert( hIC->hdr.htype == WH_HINIT ); 2445 2446 if ((!lpszUserName || !*lpszUserName) && lpszPassword && *lpszPassword) 2447 { 2448 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 2449 return NULL; 2450 } 2451 2452 lpwfs = alloc_object(&hIC->hdr, &FTPSESSIONVtbl, sizeof(ftp_session_t)); 2453 if (NULL == lpwfs) 2454 { 2455 INTERNET_SetLastError(ERROR_OUTOFMEMORY); 2456 return NULL; 2457 } 2458 2459 if (nServerPort == INTERNET_INVALID_PORT_NUMBER) 2460 lpwfs->serverport = INTERNET_DEFAULT_FTP_PORT; 2461 else 2462 lpwfs->serverport = nServerPort; 2463 2464 lpwfs->hdr.htype = WH_HFTPSESSION; 2465 lpwfs->hdr.dwFlags = dwFlags; 2466 lpwfs->hdr.dwContext = dwContext; 2467 lpwfs->hdr.dwInternalFlags |= dwInternalFlags; 2468 lpwfs->download_in_progress = NULL; 2469 lpwfs->sndSocket = -1; 2470 lpwfs->lstnSocket = -1; 2471 lpwfs->pasvSocket = -1; 2472 2473 WININET_AddRef( &hIC->hdr ); 2474 lpwfs->lpAppInfo = hIC; 2475 list_add_head( &hIC->hdr.children, &lpwfs->hdr.entry ); 2476 2477 if(hIC->proxy && hIC->accessType == INTERNET_OPEN_TYPE_PROXY) { 2478 if(wcschr(hIC->proxy, ' ')) 2479 FIXME("Several proxies not implemented.\n"); 2480 if(hIC->proxyBypass) 2481 FIXME("Proxy bypass is ignored.\n"); 2482 } 2483 if (!lpszUserName || !lpszUserName[0]) { 2484 HKEY key; 2485 WCHAR szPassword[MAX_PATH]; 2486 DWORD len = sizeof(szPassword); 2487 2488 lpwfs->lpszUserName = heap_strdupW(L"anonymous"); 2489 2490 RegOpenKeyW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", &key); 2491 if (RegQueryValueExW(key, L"EmailName", NULL, NULL, (LPBYTE)szPassword, &len)) { 2492 /* Nothing in the registry, get the username and use that as the password */ 2493 if (!GetUserNameW(szPassword, &len)) { 2494 /* Should never get here, but use an empty password as failsafe */ 2495 lstrcpyW(szPassword, L""); 2496 } 2497 } 2498 RegCloseKey(key); 2499 2500 TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword)); 2501 lpwfs->lpszPassword = heap_strdupW(szPassword); 2502 } 2503 else { 2504 lpwfs->lpszUserName = heap_strdupW(lpszUserName); 2505 lpwfs->lpszPassword = heap_strdupW(lpszPassword ? lpszPassword : L""); 2506 } 2507 lpwfs->servername = heap_strdupW(lpszServerName); 2508 2509 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */ 2510 if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL)) 2511 { 2512 INTERNET_ASYNC_RESULT iar; 2513 2514 iar.dwResult = (DWORD_PTR)lpwfs->hdr.hInternet; 2515 iar.dwError = ERROR_SUCCESS; 2516 2517 INTERNET_SendCallback(&hIC->hdr, dwContext, 2518 INTERNET_STATUS_HANDLE_CREATED, &iar, 2519 sizeof(INTERNET_ASYNC_RESULT)); 2520 } 2521 2522 INTERNET_SendCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME, 2523 (LPWSTR) lpszServerName, (lstrlenW(lpszServerName)+1) * sizeof(WCHAR)); 2524 2525 sock_namelen = sizeof(socketAddr); 2526 if (!GetAddress(lpszServerName, lpwfs->serverport, (struct sockaddr *)&socketAddr, &sock_namelen, szaddr)) 2527 { 2528 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED); 2529 goto lerror; 2530 } 2531 2532 if (socketAddr.sin_family != AF_INET) 2533 { 2534 WARN("unsupported address family %d\n", socketAddr.sin_family); 2535 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT); 2536 goto lerror; 2537 } 2538 2539 INTERNET_SendCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED, 2540 szaddr, strlen(szaddr)+1); 2541 2542 init_winsock(); 2543 nsocket = socket(AF_INET,SOCK_STREAM,0); 2544 if (nsocket == -1) 2545 { 2546 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT); 2547 goto lerror; 2548 } 2549 2550 INTERNET_SendCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER, 2551 szaddr, strlen(szaddr)+1); 2552 2553 if (connect(nsocket, (struct sockaddr *)&socketAddr, sock_namelen) < 0) 2554 { 2555 ERR("Unable to connect (%d)\n", WSAGetLastError()); 2556 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT); 2557 closesocket(nsocket); 2558 } 2559 else 2560 { 2561 TRACE("Connected to server\n"); 2562 lpwfs->sndSocket = nsocket; 2563 INTERNET_SendCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER, 2564 szaddr, strlen(szaddr)+1); 2565 2566 sock_namelen = sizeof(lpwfs->socketAddress); 2567 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen); 2568 2569 if (FTP_ConnectToHost(lpwfs)) 2570 { 2571 TRACE("Successfully logged into server\n"); 2572 bSuccess = TRUE; 2573 } 2574 } 2575 2576 lerror: 2577 if (!bSuccess) 2578 { 2579 WININET_Release(&lpwfs->hdr); 2580 return NULL; 2581 } 2582 2583 return lpwfs->hdr.hInternet; 2584 } 2585 2586 2587 /*********************************************************************** 2588 * FTP_ConnectToHost (internal) 2589 * 2590 * Connect to a ftp server 2591 * 2592 * RETURNS 2593 * TRUE on success 2594 * NULL on failure 2595 * 2596 */ 2597 static BOOL FTP_ConnectToHost(ftp_session_t *lpwfs) 2598 { 2599 INT nResCode; 2600 BOOL bSuccess = FALSE; 2601 2602 TRACE("\n"); 2603 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 2604 2605 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0)) 2606 goto lend; 2607 2608 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 2609 if (nResCode) 2610 { 2611 /* Login successful... */ 2612 if (nResCode == 230) 2613 bSuccess = TRUE; 2614 /* User name okay, need password... */ 2615 else if (nResCode == 331) 2616 bSuccess = FTP_SendPassword(lpwfs); 2617 /* Need account for login... */ 2618 else if (nResCode == 332) 2619 bSuccess = FTP_SendAccount(lpwfs); 2620 else 2621 FTP_SetResponseError(nResCode); 2622 } 2623 2624 TRACE("Returning %d\n", bSuccess); 2625 lend: 2626 return bSuccess; 2627 } 2628 2629 /*********************************************************************** 2630 * FTP_GetNextLine (internal) 2631 * 2632 * Parse next line in directory string listing 2633 * 2634 * RETURNS 2635 * Pointer to beginning of next line 2636 * NULL on failure 2637 * 2638 */ 2639 2640 static LPSTR FTP_GetNextLine(INT nSocket, LPDWORD dwLen) 2641 { 2642 struct timeval tv = {RESPONSE_TIMEOUT,0}; 2643 FD_SET set; 2644 INT nRecv = 0; 2645 LPSTR lpszBuffer = INTERNET_GetResponseBuffer(); 2646 2647 TRACE("\n"); 2648 2649 FD_ZERO(&set); 2650 FD_SET(nSocket, &set); 2651 2652 while (nRecv < MAX_REPLY_LEN) 2653 { 2654 if (select(nSocket+1, &set, NULL, NULL, &tv) > 0) 2655 { 2656 if (sock_recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0) 2657 { 2658 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); 2659 return NULL; 2660 } 2661 2662 if (lpszBuffer[nRecv] == '\n') 2663 { 2664 lpszBuffer[nRecv] = '\0'; 2665 *dwLen = nRecv - 1; 2666 TRACE(":%d %s\n", nRecv, lpszBuffer); 2667 return lpszBuffer; 2668 } 2669 if (lpszBuffer[nRecv] != '\r') 2670 nRecv++; 2671 } 2672 else 2673 { 2674 INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT); 2675 return NULL; 2676 } 2677 } 2678 2679 return NULL; 2680 } 2681 2682 /*********************************************************************** 2683 * FTP_SendCommandA (internal) 2684 * 2685 * Send command to server 2686 * 2687 * RETURNS 2688 * TRUE on success 2689 * NULL on failure 2690 * 2691 */ 2692 static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam, 2693 INTERNET_STATUS_CALLBACK lpfnStatusCB, object_header_t *hdr, DWORD_PTR dwContext) 2694 { 2695 DWORD len; 2696 CHAR *buf; 2697 DWORD nBytesSent = 0; 2698 int nRC = 0; 2699 DWORD dwParamLen; 2700 2701 TRACE("%d: (%s) %d\n", ftpCmd, debugstr_a(lpszParam), nSocket); 2702 2703 if (lpfnStatusCB) 2704 { 2705 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0); 2706 } 2707 2708 dwParamLen = lpszParam?strlen(lpszParam)+1:0; 2709 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF); 2710 if (NULL == (buf = heap_alloc(len+1))) 2711 { 2712 INTERNET_SetLastError(ERROR_OUTOFMEMORY); 2713 return FALSE; 2714 } 2715 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "", 2716 dwParamLen ? lpszParam : "", szCRLF); 2717 2718 TRACE("Sending (%s) len(%d)\n", debugstr_a(buf), len); 2719 while((nBytesSent < len) && (nRC != -1)) 2720 { 2721 nRC = sock_send(nSocket, buf+nBytesSent, len - nBytesSent, 0); 2722 nBytesSent += nRC; 2723 } 2724 heap_free(buf); 2725 2726 if (lpfnStatusCB) 2727 { 2728 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_REQUEST_SENT, 2729 &nBytesSent, sizeof(DWORD)); 2730 } 2731 2732 TRACE("Sent %d bytes\n", nBytesSent); 2733 return (nRC != -1); 2734 } 2735 2736 /*********************************************************************** 2737 * FTP_SendCommand (internal) 2738 * 2739 * Send command to server 2740 * 2741 * RETURNS 2742 * TRUE on success 2743 * NULL on failure 2744 * 2745 */ 2746 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam, 2747 INTERNET_STATUS_CALLBACK lpfnStatusCB, object_header_t *hdr, DWORD_PTR dwContext) 2748 { 2749 BOOL ret; 2750 LPSTR lpszParamA = heap_strdupWtoA(lpszParam); 2751 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext); 2752 heap_free(lpszParamA); 2753 return ret; 2754 } 2755 2756 /*********************************************************************** 2757 * FTP_ReceiveResponse (internal) 2758 * 2759 * Receive response from server 2760 * 2761 * RETURNS 2762 * Reply code on success 2763 * 0 on failure 2764 * 2765 */ 2766 INT FTP_ReceiveResponse(ftp_session_t *lpwfs, DWORD_PTR dwContext) 2767 { 2768 LPSTR lpszResponse = INTERNET_GetResponseBuffer(); 2769 DWORD nRecv; 2770 INT rc = 0; 2771 char firstprefix[5]; 2772 BOOL multiline = FALSE; 2773 2774 TRACE("socket(%d)\n", lpwfs->sndSocket); 2775 2776 INTERNET_SendCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); 2777 2778 while(1) 2779 { 2780 if (!FTP_GetNextLine(lpwfs->sndSocket, &nRecv)) 2781 goto lerror; 2782 2783 if (nRecv >= 3) 2784 { 2785 if(!multiline) 2786 { 2787 if(lpszResponse[3] != '-') 2788 break; 2789 else 2790 { /* Start of multiline response. Loop until we get "nnn " */ 2791 multiline = TRUE; 2792 memcpy(firstprefix, lpszResponse, 3); 2793 firstprefix[3] = ' '; 2794 firstprefix[4] = '\0'; 2795 } 2796 } 2797 else 2798 { 2799 if(!memcmp(firstprefix, lpszResponse, 4)) 2800 break; 2801 } 2802 } 2803 } 2804 2805 if (nRecv >= 3) 2806 { 2807 rc = atoi(lpszResponse); 2808 2809 INTERNET_SendCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED, 2810 &nRecv, sizeof(DWORD)); 2811 } 2812 2813 lerror: 2814 TRACE("return %d\n", rc); 2815 return rc; 2816 } 2817 2818 2819 /*********************************************************************** 2820 * FTP_SendPassword (internal) 2821 * 2822 * Send password to ftp server 2823 * 2824 * RETURNS 2825 * TRUE on success 2826 * NULL on failure 2827 * 2828 */ 2829 static BOOL FTP_SendPassword(ftp_session_t *lpwfs) 2830 { 2831 INT nResCode; 2832 BOOL bSuccess = FALSE; 2833 2834 TRACE("\n"); 2835 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0)) 2836 goto lend; 2837 2838 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 2839 if (nResCode) 2840 { 2841 TRACE("Received reply code %d\n", nResCode); 2842 /* Login successful... */ 2843 if (nResCode == 230) 2844 bSuccess = TRUE; 2845 /* Command not implemented, superfluous at the server site... */ 2846 /* Need account for login... */ 2847 else if (nResCode == 332) 2848 bSuccess = FTP_SendAccount(lpwfs); 2849 else 2850 FTP_SetResponseError(nResCode); 2851 } 2852 2853 lend: 2854 TRACE("Returning %d\n", bSuccess); 2855 return bSuccess; 2856 } 2857 2858 2859 /*********************************************************************** 2860 * FTP_SendAccount (internal) 2861 * 2862 * 2863 * 2864 * RETURNS 2865 * TRUE on success 2866 * FALSE on failure 2867 * 2868 */ 2869 static BOOL FTP_SendAccount(ftp_session_t *lpwfs) 2870 { 2871 INT nResCode; 2872 BOOL bSuccess = FALSE; 2873 2874 TRACE("\n"); 2875 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, L"noaccount", 0, 0, 0)) 2876 goto lend; 2877 2878 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 2879 if (nResCode) 2880 bSuccess = TRUE; 2881 else 2882 FTP_SetResponseError(nResCode); 2883 2884 lend: 2885 return bSuccess; 2886 } 2887 2888 2889 /*********************************************************************** 2890 * FTP_SendStore (internal) 2891 * 2892 * Send request to upload file to ftp server 2893 * 2894 * RETURNS 2895 * TRUE on success 2896 * FALSE on failure 2897 * 2898 */ 2899 static BOOL FTP_SendStore(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType) 2900 { 2901 INT nResCode; 2902 BOOL bSuccess = FALSE; 2903 2904 TRACE("\n"); 2905 if (!FTP_InitListenSocket(lpwfs)) 2906 goto lend; 2907 2908 if (!FTP_SendType(lpwfs, dwType)) 2909 goto lend; 2910 2911 if (!FTP_SendPortOrPasv(lpwfs)) 2912 goto lend; 2913 2914 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0)) 2915 goto lend; 2916 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 2917 if (nResCode) 2918 { 2919 if (nResCode == 150 || nResCode == 125) 2920 bSuccess = TRUE; 2921 else 2922 FTP_SetResponseError(nResCode); 2923 } 2924 2925 lend: 2926 if (!bSuccess && lpwfs->lstnSocket != -1) 2927 { 2928 closesocket(lpwfs->lstnSocket); 2929 lpwfs->lstnSocket = -1; 2930 } 2931 2932 return bSuccess; 2933 } 2934 2935 2936 /*********************************************************************** 2937 * FTP_InitListenSocket (internal) 2938 * 2939 * Create a socket to listen for server response 2940 * 2941 * RETURNS 2942 * TRUE on success 2943 * FALSE on failure 2944 * 2945 */ 2946 static BOOL FTP_InitListenSocket(ftp_session_t *lpwfs) 2947 { 2948 BOOL bSuccess = FALSE; 2949 socklen_t namelen = sizeof(lpwfs->lstnSocketAddress); 2950 2951 TRACE("\n"); 2952 2953 init_winsock(); 2954 lpwfs->lstnSocket = socket(AF_INET, SOCK_STREAM, 0); 2955 if (lpwfs->lstnSocket == -1) 2956 { 2957 TRACE("Unable to create listening socket\n"); 2958 goto lend; 2959 } 2960 2961 /* We obtain our ip addr from the name of the command channel socket */ 2962 lpwfs->lstnSocketAddress = lpwfs->socketAddress; 2963 2964 /* and get the system to assign us a port */ 2965 lpwfs->lstnSocketAddress.sin_port = htons(0); 2966 2967 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(lpwfs->lstnSocketAddress)) == -1) 2968 { 2969 TRACE("Unable to bind socket\n"); 2970 goto lend; 2971 } 2972 2973 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1) 2974 { 2975 TRACE("listen failed\n"); 2976 goto lend; 2977 } 2978 2979 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1) 2980 bSuccess = TRUE; 2981 2982 lend: 2983 if (!bSuccess && lpwfs->lstnSocket != -1) 2984 { 2985 closesocket(lpwfs->lstnSocket); 2986 lpwfs->lstnSocket = -1; 2987 } 2988 2989 return bSuccess; 2990 } 2991 2992 2993 /*********************************************************************** 2994 * FTP_SendType (internal) 2995 * 2996 * Tell server type of data being transferred 2997 * 2998 * RETURNS 2999 * TRUE on success 3000 * FALSE on failure 3001 * 3002 * W98SE doesn't cache the type that's currently set 3003 * (i.e. it sends it always), 3004 * so we probably don't want to do that either. 3005 */ 3006 static BOOL FTP_SendType(ftp_session_t *lpwfs, DWORD dwType) 3007 { 3008 INT nResCode; 3009 WCHAR type[] = L"I"; 3010 BOOL bSuccess = FALSE; 3011 3012 TRACE("\n"); 3013 if (dwType & INTERNET_FLAG_TRANSFER_ASCII) 3014 type[0] = 'A'; 3015 3016 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0)) 3017 goto lend; 3018 3019 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100; 3020 if (nResCode) 3021 { 3022 if (nResCode == 2) 3023 bSuccess = TRUE; 3024 else 3025 FTP_SetResponseError(nResCode); 3026 } 3027 3028 lend: 3029 return bSuccess; 3030 } 3031 3032 3033 #if 0 /* FIXME: should probably be used for FtpGetFileSize */ 3034 /*********************************************************************** 3035 * FTP_GetFileSize (internal) 3036 * 3037 * Retrieves from the server the size of the given file 3038 * 3039 * RETURNS 3040 * TRUE on success 3041 * FALSE on failure 3042 * 3043 */ 3044 static BOOL FTP_GetFileSize(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize) 3045 { 3046 INT nResCode; 3047 BOOL bSuccess = FALSE; 3048 3049 TRACE("\n"); 3050 3051 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0)) 3052 goto lend; 3053 3054 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 3055 if (nResCode) 3056 { 3057 if (nResCode == 213) { 3058 /* Now parses the output to get the actual file size */ 3059 int i; 3060 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer(); 3061 3062 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ; 3063 if (lpszResponseBuffer[i] == '\0') return FALSE; 3064 *dwSize = atol(&(lpszResponseBuffer[i + 1])); 3065 3066 bSuccess = TRUE; 3067 } else { 3068 FTP_SetResponseError(nResCode); 3069 } 3070 } 3071 3072 lend: 3073 return bSuccess; 3074 } 3075 #endif 3076 3077 3078 /*********************************************************************** 3079 * FTP_SendPort (internal) 3080 * 3081 * Tell server which port to use 3082 * 3083 * RETURNS 3084 * TRUE on success 3085 * FALSE on failure 3086 * 3087 */ 3088 static BOOL FTP_SendPort(ftp_session_t *lpwfs) 3089 { 3090 INT nResCode; 3091 WCHAR szIPAddress[64]; 3092 BOOL bSuccess = FALSE; 3093 TRACE("\n"); 3094 3095 swprintf(szIPAddress, ARRAY_SIZE(szIPAddress), L"%d,%d,%d,%d,%d,%d", 3096 lpwfs->lstnSocketAddress.sin_addr.S_un.S_addr&0x000000FF, 3097 (lpwfs->lstnSocketAddress.sin_addr.S_un.S_addr&0x0000FF00)>>8, 3098 (lpwfs->lstnSocketAddress.sin_addr.S_un.S_addr&0x00FF0000)>>16, 3099 (lpwfs->lstnSocketAddress.sin_addr.S_un.S_addr&0xFF000000)>>24, 3100 lpwfs->lstnSocketAddress.sin_port & 0xFF, 3101 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8); 3102 3103 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0)) 3104 goto lend; 3105 3106 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 3107 if (nResCode) 3108 { 3109 if (nResCode == 200) 3110 bSuccess = TRUE; 3111 else 3112 FTP_SetResponseError(nResCode); 3113 } 3114 3115 lend: 3116 return bSuccess; 3117 } 3118 3119 3120 /*********************************************************************** 3121 * FTP_DoPassive (internal) 3122 * 3123 * Tell server that we want to do passive transfers 3124 * and connect data socket 3125 * 3126 * RETURNS 3127 * TRUE on success 3128 * FALSE on failure 3129 * 3130 */ 3131 static BOOL FTP_DoPassive(ftp_session_t *lpwfs) 3132 { 3133 INT nResCode; 3134 BOOL bSuccess = FALSE; 3135 3136 TRACE("\n"); 3137 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0)) 3138 goto lend; 3139 3140 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 3141 if (nResCode) 3142 { 3143 if (nResCode == 227) 3144 { 3145 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer(); 3146 LPSTR p; 3147 int f[6]; 3148 int i; 3149 char *pAddr, *pPort; 3150 INT nsocket = -1; 3151 struct sockaddr_in dataSocketAddress; 3152 3153 p = lpszResponseBuffer+4; /* skip status code */ 3154 while (*p != '\0' && (*p < '0' || *p > '9')) p++; 3155 3156 if (*p == '\0') 3157 { 3158 ERR("no address found in response, aborting\n"); 3159 goto lend; 3160 } 3161 3162 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3], 3163 &f[4], &f[5]) != 6) 3164 { 3165 ERR("unknown response address format '%s', aborting\n", p); 3166 goto lend; 3167 } 3168 for (i=0; i < 6; i++) 3169 f[i] = f[i] & 0xff; 3170 3171 dataSocketAddress = lpwfs->socketAddress; 3172 pAddr = (char *)&(dataSocketAddress.sin_addr.S_un.S_addr); 3173 pPort = (char *)&(dataSocketAddress.sin_port); 3174 pAddr[0] = f[0]; 3175 pAddr[1] = f[1]; 3176 pAddr[2] = f[2]; 3177 pAddr[3] = f[3]; 3178 pPort[0] = f[4]; 3179 pPort[1] = f[5]; 3180 3181 nsocket = socket(AF_INET,SOCK_STREAM,0); 3182 if (nsocket == -1) 3183 goto lend; 3184 3185 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress))) 3186 { 3187 ERR("can't connect passive FTP data port.\n"); 3188 closesocket(nsocket); 3189 goto lend; 3190 } 3191 lpwfs->pasvSocket = nsocket; 3192 bSuccess = TRUE; 3193 } 3194 else 3195 FTP_SetResponseError(nResCode); 3196 } 3197 3198 lend: 3199 return bSuccess; 3200 } 3201 3202 3203 static BOOL FTP_SendPortOrPasv(ftp_session_t *lpwfs) 3204 { 3205 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE) 3206 { 3207 if (!FTP_DoPassive(lpwfs)) 3208 return FALSE; 3209 } 3210 else 3211 { 3212 if (!FTP_SendPort(lpwfs)) 3213 return FALSE; 3214 } 3215 return TRUE; 3216 } 3217 3218 3219 /*********************************************************************** 3220 * FTP_GetDataSocket (internal) 3221 * 3222 * Either accepts an incoming data socket connection from the server 3223 * or just returns the already opened socket after a PASV command 3224 * in case of passive FTP. 3225 * 3226 * 3227 * RETURNS 3228 * TRUE on success 3229 * FALSE on failure 3230 * 3231 */ 3232 static BOOL FTP_GetDataSocket(ftp_session_t *lpwfs, LPINT nDataSocket) 3233 { 3234 struct sockaddr_in saddr; 3235 socklen_t addrlen = sizeof(saddr); 3236 3237 TRACE("\n"); 3238 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE) 3239 { 3240 *nDataSocket = lpwfs->pasvSocket; 3241 lpwfs->pasvSocket = -1; 3242 } 3243 else 3244 { 3245 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen); 3246 closesocket(lpwfs->lstnSocket); 3247 lpwfs->lstnSocket = -1; 3248 } 3249 return *nDataSocket != -1; 3250 } 3251 3252 3253 /*********************************************************************** 3254 * FTP_SendData (internal) 3255 * 3256 * Send data to the server 3257 * 3258 * RETURNS 3259 * TRUE on success 3260 * FALSE on failure 3261 * 3262 */ 3263 static BOOL FTP_SendData(ftp_session_t *lpwfs, INT nDataSocket, HANDLE hFile) 3264 { 3265 BY_HANDLE_FILE_INFORMATION fi; 3266 DWORD nBytesRead = 0; 3267 DWORD nBytesSent = 0; 3268 DWORD nTotalSent = 0; 3269 DWORD nBytesToSend, nLen; 3270 int nRC = 1; 3271 time_t s_long_time, e_long_time; 3272 LONG nSeconds; 3273 CHAR *lpszBuffer; 3274 3275 TRACE("\n"); 3276 lpszBuffer = heap_alloc_zero(sizeof(CHAR)*DATA_PACKET_SIZE); 3277 3278 /* Get the size of the file. */ 3279 GetFileInformationByHandle(hFile, &fi); 3280 time(&s_long_time); 3281 3282 do 3283 { 3284 nBytesToSend = nBytesRead - nBytesSent; 3285 3286 if (nBytesToSend <= 0) 3287 { 3288 /* Read data from file. */ 3289 nBytesSent = 0; 3290 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0)) 3291 ERR("Failed reading from file\n"); 3292 3293 if (nBytesRead > 0) 3294 nBytesToSend = nBytesRead; 3295 else 3296 break; 3297 } 3298 3299 nLen = DATA_PACKET_SIZE < nBytesToSend ? 3300 DATA_PACKET_SIZE : nBytesToSend; 3301 nRC = sock_send(nDataSocket, lpszBuffer, nLen, 0); 3302 3303 if (nRC != -1) 3304 { 3305 nBytesSent += nRC; 3306 nTotalSent += nRC; 3307 } 3308 3309 /* Do some computation to display the status. */ 3310 time(&e_long_time); 3311 nSeconds = e_long_time - s_long_time; 3312 if( nSeconds / 60 > 0 ) 3313 { 3314 TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n", 3315 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60, 3316 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent ); 3317 } 3318 else 3319 { 3320 TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n", 3321 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds, 3322 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent); 3323 } 3324 } while (nRC != -1); 3325 3326 TRACE("file transfer complete!\n"); 3327 3328 heap_free(lpszBuffer); 3329 return nTotalSent; 3330 } 3331 3332 3333 /*********************************************************************** 3334 * FTP_SendRetrieve (internal) 3335 * 3336 * Send request to retrieve a file 3337 * 3338 * RETURNS 3339 * Number of bytes to be received on success 3340 * 0 on failure 3341 * 3342 */ 3343 static BOOL FTP_SendRetrieve(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType) 3344 { 3345 INT nResCode; 3346 BOOL ret; 3347 3348 TRACE("\n"); 3349 if (!(ret = FTP_InitListenSocket(lpwfs))) 3350 goto lend; 3351 3352 if (!(ret = FTP_SendType(lpwfs, dwType))) 3353 goto lend; 3354 3355 if (!(ret = FTP_SendPortOrPasv(lpwfs))) 3356 goto lend; 3357 3358 if (!(ret = FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))) 3359 goto lend; 3360 3361 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 3362 if ((nResCode != 125) && (nResCode != 150)) { 3363 /* That means that we got an error getting the file. */ 3364 FTP_SetResponseError(nResCode); 3365 ret = FALSE; 3366 } 3367 3368 lend: 3369 if (!ret && lpwfs->lstnSocket != -1) 3370 { 3371 closesocket(lpwfs->lstnSocket); 3372 lpwfs->lstnSocket = -1; 3373 } 3374 3375 return ret; 3376 } 3377 3378 3379 /*********************************************************************** 3380 * FTP_RetrieveData (internal) 3381 * 3382 * Retrieve data from server 3383 * 3384 * RETURNS 3385 * TRUE on success 3386 * FALSE on failure 3387 * 3388 */ 3389 static BOOL FTP_RetrieveFileData(ftp_session_t *lpwfs, INT nDataSocket, HANDLE hFile) 3390 { 3391 DWORD nBytesWritten; 3392 INT nRC = 0; 3393 CHAR *lpszBuffer; 3394 3395 TRACE("\n"); 3396 3397 lpszBuffer = heap_alloc_zero(sizeof(CHAR)*DATA_PACKET_SIZE); 3398 if (NULL == lpszBuffer) 3399 { 3400 INTERNET_SetLastError(ERROR_OUTOFMEMORY); 3401 return FALSE; 3402 } 3403 3404 while (nRC != -1) 3405 { 3406 nRC = sock_recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0); 3407 if (nRC != -1) 3408 { 3409 /* other side closed socket. */ 3410 if (nRC == 0) 3411 goto recv_end; 3412 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL); 3413 } 3414 } 3415 3416 TRACE("Data transfer complete\n"); 3417 3418 recv_end: 3419 heap_free(lpszBuffer); 3420 return (nRC != -1); 3421 } 3422 3423 /*********************************************************************** 3424 * FTPFINDNEXT_Destroy (internal) 3425 * 3426 * Deallocate session handle 3427 */ 3428 static void FTPFINDNEXT_Destroy(object_header_t *hdr) 3429 { 3430 LPWININETFTPFINDNEXTW lpwfn = (LPWININETFTPFINDNEXTW) hdr; 3431 DWORD i; 3432 3433 TRACE("\n"); 3434 3435 WININET_Release(&lpwfn->lpFtpSession->hdr); 3436 3437 for (i = 0; i < lpwfn->size; i++) 3438 { 3439 heap_free(lpwfn->lpafp[i].lpszName); 3440 } 3441 heap_free(lpwfn->lpafp); 3442 } 3443 3444 static DWORD FTPFINDNEXT_FindNextFileProc(WININETFTPFINDNEXTW *find, LPVOID data) 3445 { 3446 WIN32_FIND_DATAW *find_data = data; 3447 DWORD res = ERROR_SUCCESS; 3448 3449 TRACE("index(%d) size(%d)\n", find->index, find->size); 3450 3451 ZeroMemory(find_data, sizeof(WIN32_FIND_DATAW)); 3452 3453 if (find->index < find->size) { 3454 FTP_ConvertFileProp(&find->lpafp[find->index], find_data); 3455 find->index++; 3456 3457 TRACE("Name: %s\nSize: %d\n", debugstr_w(find_data->cFileName), find_data->nFileSizeLow); 3458 }else { 3459 res = ERROR_NO_MORE_FILES; 3460 } 3461 3462 if (find->hdr.dwFlags & INTERNET_FLAG_ASYNC) 3463 { 3464 INTERNET_ASYNC_RESULT iar; 3465 3466 iar.dwResult = (res == ERROR_SUCCESS); 3467 iar.dwError = res; 3468 3469 INTERNET_SendCallback(&find->hdr, find->hdr.dwContext, 3470 INTERNET_STATUS_REQUEST_COMPLETE, &iar, 3471 sizeof(INTERNET_ASYNC_RESULT)); 3472 } 3473 3474 return res; 3475 } 3476 3477 typedef struct { 3478 task_header_t hdr; 3479 WIN32_FIND_DATAW *find_data; 3480 } find_next_task_t; 3481 3482 static void FTPFINDNEXT_AsyncFindNextFileProc(task_header_t *hdr) 3483 { 3484 find_next_task_t *task = (find_next_task_t*)hdr; 3485 3486 FTPFINDNEXT_FindNextFileProc((WININETFTPFINDNEXTW*)task->hdr.hdr, task->find_data); 3487 } 3488 3489 static DWORD FTPFINDNEXT_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) 3490 { 3491 switch(option) { 3492 case INTERNET_OPTION_HANDLE_TYPE: 3493 TRACE("INTERNET_OPTION_HANDLE_TYPE\n"); 3494 3495 if (*size < sizeof(ULONG)) 3496 return ERROR_INSUFFICIENT_BUFFER; 3497 3498 *size = sizeof(DWORD); 3499 *(DWORD*)buffer = INTERNET_HANDLE_TYPE_FTP_FIND; 3500 return ERROR_SUCCESS; 3501 } 3502 3503 return INET_QueryOption(hdr, option, buffer, size, unicode); 3504 } 3505 3506 static DWORD FTPFINDNEXT_FindNextFileW(object_header_t *hdr, void *data) 3507 { 3508 WININETFTPFINDNEXTW *find = (WININETFTPFINDNEXTW*)hdr; 3509 3510 if (find->lpFtpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC) 3511 { 3512 find_next_task_t *task; 3513 3514 task = alloc_async_task(&find->hdr, FTPFINDNEXT_AsyncFindNextFileProc, sizeof(*task)); 3515 task->find_data = data; 3516 3517 INTERNET_AsyncCall(&task->hdr); 3518 return ERROR_SUCCESS; 3519 } 3520 3521 return FTPFINDNEXT_FindNextFileProc(find, data); 3522 } 3523 3524 static const object_vtbl_t FTPFINDNEXTVtbl = { 3525 FTPFINDNEXT_Destroy, 3526 NULL, 3527 FTPFINDNEXT_QueryOption, 3528 INET_SetOption, 3529 NULL, 3530 NULL, 3531 NULL, 3532 FTPFINDNEXT_FindNextFileW 3533 }; 3534 3535 /*********************************************************************** 3536 * FTP_ReceiveFileList (internal) 3537 * 3538 * Read file list from server 3539 * 3540 * RETURNS 3541 * Handle to file list on success 3542 * NULL on failure 3543 * 3544 */ 3545 static HINTERNET FTP_ReceiveFileList(ftp_session_t *lpwfs, INT nSocket, LPCWSTR lpszSearchFile, 3546 LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext) 3547 { 3548 DWORD dwSize = 0; 3549 LPFILEPROPERTIESW lpafp = NULL; 3550 LPWININETFTPFINDNEXTW lpwfn = NULL; 3551 3552 TRACE("(%p,%d,%s,%p,%08lx)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext); 3553 3554 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize)) 3555 { 3556 if(lpFindFileData) 3557 FTP_ConvertFileProp(lpafp, lpFindFileData); 3558 3559 lpwfn = alloc_object(&lpwfs->hdr, &FTPFINDNEXTVtbl, sizeof(WININETFTPFINDNEXTW)); 3560 if (lpwfn) 3561 { 3562 lpwfn->hdr.htype = WH_HFTPFINDNEXT; 3563 lpwfn->hdr.dwContext = dwContext; 3564 lpwfn->index = 1; /* Next index is 1 since we return index 0 */ 3565 lpwfn->size = dwSize; 3566 lpwfn->lpafp = lpafp; 3567 3568 WININET_AddRef( &lpwfs->hdr ); 3569 lpwfn->lpFtpSession = lpwfs; 3570 list_add_head( &lpwfs->hdr.children, &lpwfn->hdr.entry ); 3571 } 3572 } 3573 3574 TRACE("Matched %d files\n", dwSize); 3575 return lpwfn ? lpwfn->hdr.hInternet : NULL; 3576 } 3577 3578 3579 /*********************************************************************** 3580 * FTP_ConvertFileProp (internal) 3581 * 3582 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA 3583 * 3584 * RETURNS 3585 * TRUE on success 3586 * FALSE on failure 3587 * 3588 */ 3589 static BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData) 3590 { 3591 BOOL bSuccess = FALSE; 3592 3593 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW)); 3594 3595 if (lpafp) 3596 { 3597 SystemTimeToFileTime( &lpafp->tmLastModified, &lpFindFileData->ftLastAccessTime ); 3598 lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime; 3599 lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime; 3600 3601 /* Not all fields are filled in */ 3602 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */ 3603 lpFindFileData->nFileSizeLow = lpafp->nSize; 3604 3605 if (lpafp->bIsDirectory) 3606 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY; 3607 3608 if (lpafp->lpszName) 3609 lstrcpynW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH); 3610 3611 bSuccess = TRUE; 3612 } 3613 3614 return bSuccess; 3615 } 3616 3617 /*********************************************************************** 3618 * FTP_ParseNextFile (internal) 3619 * 3620 * Parse the next line in file listing 3621 * 3622 * RETURNS 3623 * TRUE on success 3624 * FALSE on failure 3625 */ 3626 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp) 3627 { 3628 static const char szSpace[] = " \t"; 3629 DWORD nBufLen; 3630 char *pszLine; 3631 char *pszToken; 3632 char *pszTmp; 3633 BOOL found = FALSE; 3634 int i; 3635 3636 lpfp->lpszName = NULL; 3637 do { 3638 if(!(pszLine = FTP_GetNextLine(nSocket, &nBufLen))) 3639 return FALSE; 3640 3641 pszToken = strtok(pszLine, szSpace); 3642 /* ls format 3643 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename> 3644 * 3645 * For instance: 3646 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier 3647 */ 3648 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) { 3649 if(!FTP_ParsePermission(pszToken, lpfp)) 3650 lpfp->bIsDirectory = FALSE; 3651 for(i=0; i<=3; i++) { 3652 if(!(pszToken = strtok(NULL, szSpace))) 3653 break; 3654 } 3655 if(!pszToken) continue; 3656 if(lpfp->bIsDirectory) { 3657 TRACE("Is directory\n"); 3658 lpfp->nSize = 0; 3659 } 3660 else { 3661 TRACE("Size: %s\n", pszToken); 3662 lpfp->nSize = atol(pszToken); 3663 } 3664 3665 lpfp->tmLastModified.wSecond = 0; 3666 lpfp->tmLastModified.wMinute = 0; 3667 lpfp->tmLastModified.wHour = 0; 3668 lpfp->tmLastModified.wDay = 0; 3669 lpfp->tmLastModified.wMonth = 0; 3670 lpfp->tmLastModified.wYear = 0; 3671 3672 /* Determine month */ 3673 pszToken = strtok(NULL, szSpace); 3674 if(!pszToken) continue; 3675 if(strlen(pszToken) >= 3) { 3676 pszToken[3] = 0; 3677 if((pszTmp = StrStrIA(szMonths, pszToken))) 3678 lpfp->tmLastModified.wMonth = ((pszTmp - szMonths) / 3)+1; 3679 } 3680 /* Determine day */ 3681 pszToken = strtok(NULL, szSpace); 3682 if(!pszToken) continue; 3683 lpfp->tmLastModified.wDay = atoi(pszToken); 3684 /* Determine time or year */ 3685 pszToken = strtok(NULL, szSpace); 3686 if(!pszToken) continue; 3687 if((pszTmp = strchr(pszToken, ':'))) { 3688 SYSTEMTIME curr_time; 3689 *pszTmp = 0; 3690 pszTmp++; 3691 lpfp->tmLastModified.wMinute = atoi(pszTmp); 3692 lpfp->tmLastModified.wHour = atoi(pszToken); 3693 GetLocalTime( &curr_time ); 3694 lpfp->tmLastModified.wYear = curr_time.wYear; 3695 } 3696 else { 3697 lpfp->tmLastModified.wYear = atoi(pszToken); 3698 lpfp->tmLastModified.wHour = 12; 3699 } 3700 TRACE("Mod time: %02d:%02d:%02d %04d/%02d/%02d\n", 3701 lpfp->tmLastModified.wHour, lpfp->tmLastModified.wMinute, lpfp->tmLastModified.wSecond, 3702 lpfp->tmLastModified.wYear, lpfp->tmLastModified.wMonth, lpfp->tmLastModified.wDay); 3703 3704 pszToken = strtok(NULL, szSpace); 3705 if(!pszToken) continue; 3706 lpfp->lpszName = heap_strdupAtoW(pszToken); 3707 TRACE("File: %s\n", debugstr_w(lpfp->lpszName)); 3708 } 3709 /* NT way of parsing ... : 3710 3711 07-13-03 08:55PM <DIR> sakpatch 3712 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz 3713 */ 3714 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) { 3715 int mon, mday, year, hour, min; 3716 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */ 3717 3718 sscanf(pszToken, "%d-%d-%d", &mon, &mday, &year); 3719 lpfp->tmLastModified.wDay = mday; 3720 lpfp->tmLastModified.wMonth = mon; 3721 lpfp->tmLastModified.wYear = year; 3722 3723 /* Hacky and bad Y2K protection :-) */ 3724 if (lpfp->tmLastModified.wYear < 70) lpfp->tmLastModified.wYear += 2000; 3725 3726 pszToken = strtok(NULL, szSpace); 3727 if(!pszToken) continue; 3728 sscanf(pszToken, "%d:%d", &hour, &min); 3729 lpfp->tmLastModified.wHour = hour; 3730 lpfp->tmLastModified.wMinute = min; 3731 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) { 3732 lpfp->tmLastModified.wHour += 12; 3733 } 3734 lpfp->tmLastModified.wSecond = 0; 3735 3736 TRACE("Mod time: %02d:%02d:%02d %04d/%02d/%02d\n", 3737 lpfp->tmLastModified.wHour, lpfp->tmLastModified.wMinute, lpfp->tmLastModified.wSecond, 3738 lpfp->tmLastModified.wYear, lpfp->tmLastModified.wMonth, lpfp->tmLastModified.wDay); 3739 3740 pszToken = strtok(NULL, szSpace); 3741 if(!pszToken) continue; 3742 if(!stricmp(pszToken, "<DIR>")) { 3743 lpfp->bIsDirectory = TRUE; 3744 lpfp->nSize = 0; 3745 TRACE("Is directory\n"); 3746 } 3747 else { 3748 lpfp->bIsDirectory = FALSE; 3749 lpfp->nSize = atol(pszToken); 3750 TRACE("Size: %d\n", lpfp->nSize); 3751 } 3752 3753 pszToken = strtok(NULL, szSpace); 3754 if(!pszToken) continue; 3755 lpfp->lpszName = heap_strdupAtoW(pszToken); 3756 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName)); 3757 } 3758 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */ 3759 else if(pszToken[0] == '+') { 3760 FIXME("EPLF Format not implemented\n"); 3761 } 3762 3763 if(lpfp->lpszName) { 3764 if((lpszSearchFile == NULL) || 3765 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) { 3766 found = TRUE; 3767 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName)); 3768 } 3769 else { 3770 heap_free(lpfp->lpszName); 3771 lpfp->lpszName = NULL; 3772 } 3773 } 3774 } while(!found); 3775 return TRUE; 3776 } 3777 3778 /*********************************************************************** 3779 * FTP_ParseDirectory (internal) 3780 * 3781 * Parse string of directory information 3782 * 3783 * RETURNS 3784 * TRUE on success 3785 * FALSE on failure 3786 */ 3787 static BOOL FTP_ParseDirectory(ftp_session_t *lpwfs, INT nSocket, LPCWSTR lpszSearchFile, 3788 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp) 3789 { 3790 BOOL bSuccess = TRUE; 3791 INT sizeFilePropArray = 500;/*20; */ 3792 INT indexFilePropArray = -1; 3793 3794 TRACE("\n"); 3795 3796 /* Allocate initial file properties array */ 3797 *lpafp = heap_alloc_zero(sizeof(FILEPROPERTIESW)*(sizeFilePropArray)); 3798 if (!*lpafp) 3799 return FALSE; 3800 3801 do { 3802 if (indexFilePropArray+1 >= sizeFilePropArray) 3803 { 3804 LPFILEPROPERTIESW tmpafp; 3805 3806 sizeFilePropArray *= 2; 3807 tmpafp = heap_realloc_zero(*lpafp, sizeof(FILEPROPERTIESW)*sizeFilePropArray); 3808 if (NULL == tmpafp) 3809 { 3810 bSuccess = FALSE; 3811 break; 3812 } 3813 3814 *lpafp = tmpafp; 3815 } 3816 indexFilePropArray++; 3817 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray])); 3818 3819 if (bSuccess && indexFilePropArray) 3820 { 3821 if (indexFilePropArray < sizeFilePropArray - 1) 3822 { 3823 LPFILEPROPERTIESW tmpafp; 3824 3825 tmpafp = heap_realloc(*lpafp, sizeof(FILEPROPERTIESW)*indexFilePropArray); 3826 if (NULL != tmpafp) 3827 *lpafp = tmpafp; 3828 } 3829 *dwfp = indexFilePropArray; 3830 } 3831 else 3832 { 3833 heap_free(*lpafp); 3834 INTERNET_SetLastError(ERROR_NO_MORE_FILES); 3835 bSuccess = FALSE; 3836 } 3837 3838 return bSuccess; 3839 } 3840 3841 3842 /*********************************************************************** 3843 * FTP_ParsePermission (internal) 3844 * 3845 * Parse permission string of directory information 3846 * 3847 * RETURNS 3848 * TRUE on success 3849 * FALSE on failure 3850 * 3851 */ 3852 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp) 3853 { 3854 BOOL bSuccess = TRUE; 3855 unsigned short nPermission = 0; 3856 INT nPos = 1; 3857 INT nLast = 9; 3858 3859 TRACE("\n"); 3860 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l')) 3861 { 3862 bSuccess = FALSE; 3863 return bSuccess; 3864 } 3865 3866 lpfp->bIsDirectory = (*lpszPermission == 'd'); 3867 do 3868 { 3869 switch (nPos) 3870 { 3871 case 1: 3872 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8; 3873 break; 3874 case 2: 3875 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7; 3876 break; 3877 case 3: 3878 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6; 3879 break; 3880 case 4: 3881 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5; 3882 break; 3883 case 5: 3884 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4; 3885 break; 3886 case 6: 3887 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3; 3888 break; 3889 case 7: 3890 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2; 3891 break; 3892 case 8: 3893 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1; 3894 break; 3895 case 9: 3896 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0); 3897 break; 3898 } 3899 nPos++; 3900 }while (nPos <= nLast); 3901 3902 lpfp->permissions = nPermission; 3903 return bSuccess; 3904 } 3905 3906 3907 /*********************************************************************** 3908 * FTP_SetResponseError (internal) 3909 * 3910 * Set the appropriate error code for a given response from the server 3911 * 3912 * RETURNS 3913 * 3914 */ 3915 static DWORD FTP_SetResponseError(DWORD dwResponse) 3916 { 3917 DWORD dwCode = 0; 3918 3919 switch(dwResponse) 3920 { 3921 case 425: /* Cannot open data connection. */ 3922 dwCode = ERROR_INTERNET_CANNOT_CONNECT; 3923 break; 3924 3925 case 426: /* Connection closed, transfer aborted. */ 3926 dwCode = ERROR_INTERNET_CONNECTION_ABORTED; 3927 break; 3928 3929 case 530: /* Not logged in. Login incorrect. */ 3930 dwCode = ERROR_INTERNET_LOGIN_FAILURE; 3931 break; 3932 3933 case 421: /* Service not available - Server may be shutting down. */ 3934 case 450: /* File action not taken. File may be busy. */ 3935 case 451: /* Action aborted. Server error. */ 3936 case 452: /* Action not taken. Insufficient storage space on server. */ 3937 case 500: /* Syntax error. Command unrecognized. */ 3938 case 501: /* Syntax error. Error in parameters or arguments. */ 3939 case 502: /* Command not implemented. */ 3940 case 503: /* Bad sequence of commands. */ 3941 case 504: /* Command not implemented for that parameter. */ 3942 case 532: /* Need account for storing files */ 3943 case 550: /* File action not taken. File not found or no access. */ 3944 case 551: /* Requested action aborted. Page type unknown */ 3945 case 552: /* Action aborted. Exceeded storage allocation */ 3946 case 553: /* Action not taken. File name not allowed. */ 3947 3948 default: 3949 dwCode = ERROR_INTERNET_EXTENDED_ERROR; 3950 break; 3951 } 3952 3953 INTERNET_SetLastError(dwCode); 3954 return dwCode; 3955 } 3956