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