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 if(lpwfs) 2585 WININET_Release( &lpwfs->hdr ); 2586 return NULL; 2587 } 2588 2589 return lpwfs->hdr.hInternet; 2590 } 2591 2592 2593 /*********************************************************************** 2594 * FTP_ConnectToHost (internal) 2595 * 2596 * Connect to a ftp server 2597 * 2598 * RETURNS 2599 * TRUE on success 2600 * NULL on failure 2601 * 2602 */ 2603 static BOOL FTP_ConnectToHost(ftp_session_t *lpwfs) 2604 { 2605 INT nResCode; 2606 BOOL bSuccess = FALSE; 2607 2608 TRACE("\n"); 2609 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 2610 2611 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0)) 2612 goto lend; 2613 2614 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 2615 if (nResCode) 2616 { 2617 /* Login successful... */ 2618 if (nResCode == 230) 2619 bSuccess = TRUE; 2620 /* User name okay, need password... */ 2621 else if (nResCode == 331) 2622 bSuccess = FTP_SendPassword(lpwfs); 2623 /* Need account for login... */ 2624 else if (nResCode == 332) 2625 bSuccess = FTP_SendAccount(lpwfs); 2626 else 2627 FTP_SetResponseError(nResCode); 2628 } 2629 2630 TRACE("Returning %d\n", bSuccess); 2631 lend: 2632 return bSuccess; 2633 } 2634 2635 /*********************************************************************** 2636 * FTP_GetNextLine (internal) 2637 * 2638 * Parse next line in directory string listing 2639 * 2640 * RETURNS 2641 * Pointer to beginning of next line 2642 * NULL on failure 2643 * 2644 */ 2645 2646 static LPSTR FTP_GetNextLine(INT nSocket, LPDWORD dwLen) 2647 { 2648 struct timeval tv = {RESPONSE_TIMEOUT,0}; 2649 FD_SET set; 2650 INT nRecv = 0; 2651 LPSTR lpszBuffer = INTERNET_GetResponseBuffer(); 2652 2653 TRACE("\n"); 2654 2655 FD_ZERO(&set); 2656 FD_SET(nSocket, &set); 2657 2658 while (nRecv < MAX_REPLY_LEN) 2659 { 2660 if (select(nSocket+1, &set, NULL, NULL, &tv) > 0) 2661 { 2662 if (sock_recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0) 2663 { 2664 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); 2665 return NULL; 2666 } 2667 2668 if (lpszBuffer[nRecv] == '\n') 2669 { 2670 lpszBuffer[nRecv] = '\0'; 2671 *dwLen = nRecv - 1; 2672 TRACE(":%d %s\n", nRecv, lpszBuffer); 2673 return lpszBuffer; 2674 } 2675 if (lpszBuffer[nRecv] != '\r') 2676 nRecv++; 2677 } 2678 else 2679 { 2680 INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT); 2681 return NULL; 2682 } 2683 } 2684 2685 return NULL; 2686 } 2687 2688 /*********************************************************************** 2689 * FTP_SendCommandA (internal) 2690 * 2691 * Send command to server 2692 * 2693 * RETURNS 2694 * TRUE on success 2695 * NULL on failure 2696 * 2697 */ 2698 static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam, 2699 INTERNET_STATUS_CALLBACK lpfnStatusCB, object_header_t *hdr, DWORD_PTR dwContext) 2700 { 2701 DWORD len; 2702 CHAR *buf; 2703 DWORD nBytesSent = 0; 2704 int nRC = 0; 2705 DWORD dwParamLen; 2706 2707 TRACE("%d: (%s) %d\n", ftpCmd, debugstr_a(lpszParam), nSocket); 2708 2709 if (lpfnStatusCB) 2710 { 2711 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0); 2712 } 2713 2714 dwParamLen = lpszParam?strlen(lpszParam)+1:0; 2715 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF); 2716 if (NULL == (buf = heap_alloc(len+1))) 2717 { 2718 INTERNET_SetLastError(ERROR_OUTOFMEMORY); 2719 return FALSE; 2720 } 2721 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "", 2722 dwParamLen ? lpszParam : "", szCRLF); 2723 2724 TRACE("Sending (%s) len(%d)\n", debugstr_a(buf), len); 2725 while((nBytesSent < len) && (nRC != -1)) 2726 { 2727 nRC = sock_send(nSocket, buf+nBytesSent, len - nBytesSent, 0); 2728 nBytesSent += nRC; 2729 } 2730 heap_free(buf); 2731 2732 if (lpfnStatusCB) 2733 { 2734 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_REQUEST_SENT, 2735 &nBytesSent, sizeof(DWORD)); 2736 } 2737 2738 TRACE("Sent %d bytes\n", nBytesSent); 2739 return (nRC != -1); 2740 } 2741 2742 /*********************************************************************** 2743 * FTP_SendCommand (internal) 2744 * 2745 * Send command to server 2746 * 2747 * RETURNS 2748 * TRUE on success 2749 * NULL on failure 2750 * 2751 */ 2752 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam, 2753 INTERNET_STATUS_CALLBACK lpfnStatusCB, object_header_t *hdr, DWORD_PTR dwContext) 2754 { 2755 BOOL ret; 2756 LPSTR lpszParamA = heap_strdupWtoA(lpszParam); 2757 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext); 2758 heap_free(lpszParamA); 2759 return ret; 2760 } 2761 2762 /*********************************************************************** 2763 * FTP_ReceiveResponse (internal) 2764 * 2765 * Receive response from server 2766 * 2767 * RETURNS 2768 * Reply code on success 2769 * 0 on failure 2770 * 2771 */ 2772 INT FTP_ReceiveResponse(ftp_session_t *lpwfs, DWORD_PTR dwContext) 2773 { 2774 LPSTR lpszResponse = INTERNET_GetResponseBuffer(); 2775 DWORD nRecv; 2776 INT rc = 0; 2777 char firstprefix[5]; 2778 BOOL multiline = FALSE; 2779 2780 TRACE("socket(%d)\n", lpwfs->sndSocket); 2781 2782 INTERNET_SendCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); 2783 2784 while(1) 2785 { 2786 if (!FTP_GetNextLine(lpwfs->sndSocket, &nRecv)) 2787 goto lerror; 2788 2789 if (nRecv >= 3) 2790 { 2791 if(!multiline) 2792 { 2793 if(lpszResponse[3] != '-') 2794 break; 2795 else 2796 { /* Start of multiline response. Loop until we get "nnn " */ 2797 multiline = TRUE; 2798 memcpy(firstprefix, lpszResponse, 3); 2799 firstprefix[3] = ' '; 2800 firstprefix[4] = '\0'; 2801 } 2802 } 2803 else 2804 { 2805 if(!memcmp(firstprefix, lpszResponse, 4)) 2806 break; 2807 } 2808 } 2809 } 2810 2811 if (nRecv >= 3) 2812 { 2813 rc = atoi(lpszResponse); 2814 2815 INTERNET_SendCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED, 2816 &nRecv, sizeof(DWORD)); 2817 } 2818 2819 lerror: 2820 TRACE("return %d\n", rc); 2821 return rc; 2822 } 2823 2824 2825 /*********************************************************************** 2826 * FTP_SendPassword (internal) 2827 * 2828 * Send password to ftp server 2829 * 2830 * RETURNS 2831 * TRUE on success 2832 * NULL on failure 2833 * 2834 */ 2835 static BOOL FTP_SendPassword(ftp_session_t *lpwfs) 2836 { 2837 INT nResCode; 2838 BOOL bSuccess = FALSE; 2839 2840 TRACE("\n"); 2841 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0)) 2842 goto lend; 2843 2844 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 2845 if (nResCode) 2846 { 2847 TRACE("Received reply code %d\n", nResCode); 2848 /* Login successful... */ 2849 if (nResCode == 230) 2850 bSuccess = TRUE; 2851 /* Command not implemented, superfluous at the server site... */ 2852 /* Need account for login... */ 2853 else if (nResCode == 332) 2854 bSuccess = FTP_SendAccount(lpwfs); 2855 else 2856 FTP_SetResponseError(nResCode); 2857 } 2858 2859 lend: 2860 TRACE("Returning %d\n", bSuccess); 2861 return bSuccess; 2862 } 2863 2864 2865 /*********************************************************************** 2866 * FTP_SendAccount (internal) 2867 * 2868 * 2869 * 2870 * RETURNS 2871 * TRUE on success 2872 * FALSE on failure 2873 * 2874 */ 2875 static BOOL FTP_SendAccount(ftp_session_t *lpwfs) 2876 { 2877 INT nResCode; 2878 BOOL bSuccess = FALSE; 2879 2880 TRACE("\n"); 2881 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0)) 2882 goto lend; 2883 2884 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 2885 if (nResCode) 2886 bSuccess = TRUE; 2887 else 2888 FTP_SetResponseError(nResCode); 2889 2890 lend: 2891 return bSuccess; 2892 } 2893 2894 2895 /*********************************************************************** 2896 * FTP_SendStore (internal) 2897 * 2898 * Send request to upload file to ftp server 2899 * 2900 * RETURNS 2901 * TRUE on success 2902 * FALSE on failure 2903 * 2904 */ 2905 static BOOL FTP_SendStore(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType) 2906 { 2907 INT nResCode; 2908 BOOL bSuccess = FALSE; 2909 2910 TRACE("\n"); 2911 if (!FTP_InitListenSocket(lpwfs)) 2912 goto lend; 2913 2914 if (!FTP_SendType(lpwfs, dwType)) 2915 goto lend; 2916 2917 if (!FTP_SendPortOrPasv(lpwfs)) 2918 goto lend; 2919 2920 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0)) 2921 goto lend; 2922 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 2923 if (nResCode) 2924 { 2925 if (nResCode == 150 || nResCode == 125) 2926 bSuccess = TRUE; 2927 else 2928 FTP_SetResponseError(nResCode); 2929 } 2930 2931 lend: 2932 if (!bSuccess && lpwfs->lstnSocket != -1) 2933 { 2934 closesocket(lpwfs->lstnSocket); 2935 lpwfs->lstnSocket = -1; 2936 } 2937 2938 return bSuccess; 2939 } 2940 2941 2942 /*********************************************************************** 2943 * FTP_InitListenSocket (internal) 2944 * 2945 * Create a socket to listen for server response 2946 * 2947 * RETURNS 2948 * TRUE on success 2949 * FALSE on failure 2950 * 2951 */ 2952 static BOOL FTP_InitListenSocket(ftp_session_t *lpwfs) 2953 { 2954 BOOL bSuccess = FALSE; 2955 socklen_t namelen = sizeof(lpwfs->lstnSocketAddress); 2956 2957 TRACE("\n"); 2958 2959 init_winsock(); 2960 lpwfs->lstnSocket = socket(AF_INET, SOCK_STREAM, 0); 2961 if (lpwfs->lstnSocket == -1) 2962 { 2963 TRACE("Unable to create listening socket\n"); 2964 goto lend; 2965 } 2966 2967 /* We obtain our ip addr from the name of the command channel socket */ 2968 lpwfs->lstnSocketAddress = lpwfs->socketAddress; 2969 2970 /* and get the system to assign us a port */ 2971 lpwfs->lstnSocketAddress.sin_port = htons(0); 2972 2973 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(lpwfs->lstnSocketAddress)) == -1) 2974 { 2975 TRACE("Unable to bind socket\n"); 2976 goto lend; 2977 } 2978 2979 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1) 2980 { 2981 TRACE("listen failed\n"); 2982 goto lend; 2983 } 2984 2985 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1) 2986 bSuccess = TRUE; 2987 2988 lend: 2989 if (!bSuccess && lpwfs->lstnSocket != -1) 2990 { 2991 closesocket(lpwfs->lstnSocket); 2992 lpwfs->lstnSocket = -1; 2993 } 2994 2995 return bSuccess; 2996 } 2997 2998 2999 /*********************************************************************** 3000 * FTP_SendType (internal) 3001 * 3002 * Tell server type of data being transferred 3003 * 3004 * RETURNS 3005 * TRUE on success 3006 * FALSE on failure 3007 * 3008 * W98SE doesn't cache the type that's currently set 3009 * (i.e. it sends it always), 3010 * so we probably don't want to do that either. 3011 */ 3012 static BOOL FTP_SendType(ftp_session_t *lpwfs, DWORD dwType) 3013 { 3014 INT nResCode; 3015 WCHAR type[] = { 'I','\0' }; 3016 BOOL bSuccess = FALSE; 3017 3018 TRACE("\n"); 3019 if (dwType & INTERNET_FLAG_TRANSFER_ASCII) 3020 type[0] = 'A'; 3021 3022 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0)) 3023 goto lend; 3024 3025 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100; 3026 if (nResCode) 3027 { 3028 if (nResCode == 2) 3029 bSuccess = TRUE; 3030 else 3031 FTP_SetResponseError(nResCode); 3032 } 3033 3034 lend: 3035 return bSuccess; 3036 } 3037 3038 3039 #if 0 /* FIXME: should probably be used for FtpGetFileSize */ 3040 /*********************************************************************** 3041 * FTP_GetFileSize (internal) 3042 * 3043 * Retrieves from the server the size of the given file 3044 * 3045 * RETURNS 3046 * TRUE on success 3047 * FALSE on failure 3048 * 3049 */ 3050 static BOOL FTP_GetFileSize(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize) 3051 { 3052 INT nResCode; 3053 BOOL bSuccess = FALSE; 3054 3055 TRACE("\n"); 3056 3057 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0)) 3058 goto lend; 3059 3060 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 3061 if (nResCode) 3062 { 3063 if (nResCode == 213) { 3064 /* Now parses the output to get the actual file size */ 3065 int i; 3066 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer(); 3067 3068 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ; 3069 if (lpszResponseBuffer[i] == '\0') return FALSE; 3070 *dwSize = atol(&(lpszResponseBuffer[i + 1])); 3071 3072 bSuccess = TRUE; 3073 } else { 3074 FTP_SetResponseError(nResCode); 3075 } 3076 } 3077 3078 lend: 3079 return bSuccess; 3080 } 3081 #endif 3082 3083 3084 /*********************************************************************** 3085 * FTP_SendPort (internal) 3086 * 3087 * Tell server which port to use 3088 * 3089 * RETURNS 3090 * TRUE on success 3091 * FALSE on failure 3092 * 3093 */ 3094 static BOOL FTP_SendPort(ftp_session_t *lpwfs) 3095 { 3096 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'}; 3097 INT nResCode; 3098 WCHAR szIPAddress[64]; 3099 BOOL bSuccess = FALSE; 3100 TRACE("\n"); 3101 3102 sprintfW(szIPAddress, szIPFormat, 3103 lpwfs->lstnSocketAddress.sin_addr.S_un.S_addr&0x000000FF, 3104 (lpwfs->lstnSocketAddress.sin_addr.S_un.S_addr&0x0000FF00)>>8, 3105 (lpwfs->lstnSocketAddress.sin_addr.S_un.S_addr&0x00FF0000)>>16, 3106 (lpwfs->lstnSocketAddress.sin_addr.S_un.S_addr&0xFF000000)>>24, 3107 lpwfs->lstnSocketAddress.sin_port & 0xFF, 3108 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8); 3109 3110 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0)) 3111 goto lend; 3112 3113 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 3114 if (nResCode) 3115 { 3116 if (nResCode == 200) 3117 bSuccess = TRUE; 3118 else 3119 FTP_SetResponseError(nResCode); 3120 } 3121 3122 lend: 3123 return bSuccess; 3124 } 3125 3126 3127 /*********************************************************************** 3128 * FTP_DoPassive (internal) 3129 * 3130 * Tell server that we want to do passive transfers 3131 * and connect data socket 3132 * 3133 * RETURNS 3134 * TRUE on success 3135 * FALSE on failure 3136 * 3137 */ 3138 static BOOL FTP_DoPassive(ftp_session_t *lpwfs) 3139 { 3140 INT nResCode; 3141 BOOL bSuccess = FALSE; 3142 3143 TRACE("\n"); 3144 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0)) 3145 goto lend; 3146 3147 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 3148 if (nResCode) 3149 { 3150 if (nResCode == 227) 3151 { 3152 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer(); 3153 LPSTR p; 3154 int f[6]; 3155 int i; 3156 char *pAddr, *pPort; 3157 INT nsocket = -1; 3158 struct sockaddr_in dataSocketAddress; 3159 3160 p = lpszResponseBuffer+4; /* skip status code */ 3161 while (*p != '\0' && (*p < '0' || *p > '9')) p++; 3162 3163 if (*p == '\0') 3164 { 3165 ERR("no address found in response, aborting\n"); 3166 goto lend; 3167 } 3168 3169 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3], 3170 &f[4], &f[5]) != 6) 3171 { 3172 ERR("unknown response address format '%s', aborting\n", p); 3173 goto lend; 3174 } 3175 for (i=0; i < 6; i++) 3176 f[i] = f[i] & 0xff; 3177 3178 dataSocketAddress = lpwfs->socketAddress; 3179 pAddr = (char *)&(dataSocketAddress.sin_addr.S_un.S_addr); 3180 pPort = (char *)&(dataSocketAddress.sin_port); 3181 pAddr[0] = f[0]; 3182 pAddr[1] = f[1]; 3183 pAddr[2] = f[2]; 3184 pAddr[3] = f[3]; 3185 pPort[0] = f[4]; 3186 pPort[1] = f[5]; 3187 3188 nsocket = socket(AF_INET,SOCK_STREAM,0); 3189 if (nsocket == -1) 3190 goto lend; 3191 3192 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress))) 3193 { 3194 ERR("can't connect passive FTP data port.\n"); 3195 closesocket(nsocket); 3196 goto lend; 3197 } 3198 lpwfs->pasvSocket = nsocket; 3199 bSuccess = TRUE; 3200 } 3201 else 3202 FTP_SetResponseError(nResCode); 3203 } 3204 3205 lend: 3206 return bSuccess; 3207 } 3208 3209 3210 static BOOL FTP_SendPortOrPasv(ftp_session_t *lpwfs) 3211 { 3212 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE) 3213 { 3214 if (!FTP_DoPassive(lpwfs)) 3215 return FALSE; 3216 } 3217 else 3218 { 3219 if (!FTP_SendPort(lpwfs)) 3220 return FALSE; 3221 } 3222 return TRUE; 3223 } 3224 3225 3226 /*********************************************************************** 3227 * FTP_GetDataSocket (internal) 3228 * 3229 * Either accepts an incoming data socket connection from the server 3230 * or just returns the already opened socket after a PASV command 3231 * in case of passive FTP. 3232 * 3233 * 3234 * RETURNS 3235 * TRUE on success 3236 * FALSE on failure 3237 * 3238 */ 3239 static BOOL FTP_GetDataSocket(ftp_session_t *lpwfs, LPINT nDataSocket) 3240 { 3241 struct sockaddr_in saddr; 3242 socklen_t addrlen = sizeof(saddr); 3243 3244 TRACE("\n"); 3245 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE) 3246 { 3247 *nDataSocket = lpwfs->pasvSocket; 3248 lpwfs->pasvSocket = -1; 3249 } 3250 else 3251 { 3252 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen); 3253 closesocket(lpwfs->lstnSocket); 3254 lpwfs->lstnSocket = -1; 3255 } 3256 return *nDataSocket != -1; 3257 } 3258 3259 3260 /*********************************************************************** 3261 * FTP_SendData (internal) 3262 * 3263 * Send data to the server 3264 * 3265 * RETURNS 3266 * TRUE on success 3267 * FALSE on failure 3268 * 3269 */ 3270 static BOOL FTP_SendData(ftp_session_t *lpwfs, INT nDataSocket, HANDLE hFile) 3271 { 3272 BY_HANDLE_FILE_INFORMATION fi; 3273 DWORD nBytesRead = 0; 3274 DWORD nBytesSent = 0; 3275 DWORD nTotalSent = 0; 3276 DWORD nBytesToSend, nLen; 3277 int nRC = 1; 3278 time_t s_long_time, e_long_time; 3279 LONG nSeconds; 3280 CHAR *lpszBuffer; 3281 3282 TRACE("\n"); 3283 lpszBuffer = heap_alloc_zero(sizeof(CHAR)*DATA_PACKET_SIZE); 3284 3285 /* Get the size of the file. */ 3286 GetFileInformationByHandle(hFile, &fi); 3287 time(&s_long_time); 3288 3289 do 3290 { 3291 nBytesToSend = nBytesRead - nBytesSent; 3292 3293 if (nBytesToSend <= 0) 3294 { 3295 /* Read data from file. */ 3296 nBytesSent = 0; 3297 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0)) 3298 ERR("Failed reading from file\n"); 3299 3300 if (nBytesRead > 0) 3301 nBytesToSend = nBytesRead; 3302 else 3303 break; 3304 } 3305 3306 nLen = DATA_PACKET_SIZE < nBytesToSend ? 3307 DATA_PACKET_SIZE : nBytesToSend; 3308 nRC = sock_send(nDataSocket, lpszBuffer, nLen, 0); 3309 3310 if (nRC != -1) 3311 { 3312 nBytesSent += nRC; 3313 nTotalSent += nRC; 3314 } 3315 3316 /* Do some computation to display the status. */ 3317 time(&e_long_time); 3318 nSeconds = e_long_time - s_long_time; 3319 if( nSeconds / 60 > 0 ) 3320 { 3321 TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n", 3322 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60, 3323 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent ); 3324 } 3325 else 3326 { 3327 TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n", 3328 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds, 3329 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent); 3330 } 3331 } while (nRC != -1); 3332 3333 TRACE("file transfer complete!\n"); 3334 3335 heap_free(lpszBuffer); 3336 return nTotalSent; 3337 } 3338 3339 3340 /*********************************************************************** 3341 * FTP_SendRetrieve (internal) 3342 * 3343 * Send request to retrieve a file 3344 * 3345 * RETURNS 3346 * Number of bytes to be received on success 3347 * 0 on failure 3348 * 3349 */ 3350 static BOOL FTP_SendRetrieve(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType) 3351 { 3352 INT nResCode; 3353 BOOL ret; 3354 3355 TRACE("\n"); 3356 if (!(ret = FTP_InitListenSocket(lpwfs))) 3357 goto lend; 3358 3359 if (!(ret = FTP_SendType(lpwfs, dwType))) 3360 goto lend; 3361 3362 if (!(ret = FTP_SendPortOrPasv(lpwfs))) 3363 goto lend; 3364 3365 if (!(ret = FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))) 3366 goto lend; 3367 3368 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 3369 if ((nResCode != 125) && (nResCode != 150)) { 3370 /* That means that we got an error getting the file. */ 3371 FTP_SetResponseError(nResCode); 3372 ret = FALSE; 3373 } 3374 3375 lend: 3376 if (!ret && lpwfs->lstnSocket != -1) 3377 { 3378 closesocket(lpwfs->lstnSocket); 3379 lpwfs->lstnSocket = -1; 3380 } 3381 3382 return ret; 3383 } 3384 3385 3386 /*********************************************************************** 3387 * FTP_RetrieveData (internal) 3388 * 3389 * Retrieve data from server 3390 * 3391 * RETURNS 3392 * TRUE on success 3393 * FALSE on failure 3394 * 3395 */ 3396 static BOOL FTP_RetrieveFileData(ftp_session_t *lpwfs, INT nDataSocket, HANDLE hFile) 3397 { 3398 DWORD nBytesWritten; 3399 INT nRC = 0; 3400 CHAR *lpszBuffer; 3401 3402 TRACE("\n"); 3403 3404 lpszBuffer = heap_alloc_zero(sizeof(CHAR)*DATA_PACKET_SIZE); 3405 if (NULL == lpszBuffer) 3406 { 3407 INTERNET_SetLastError(ERROR_OUTOFMEMORY); 3408 return FALSE; 3409 } 3410 3411 while (nRC != -1) 3412 { 3413 nRC = sock_recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0); 3414 if (nRC != -1) 3415 { 3416 /* other side closed socket. */ 3417 if (nRC == 0) 3418 goto recv_end; 3419 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL); 3420 } 3421 } 3422 3423 TRACE("Data transfer complete\n"); 3424 3425 recv_end: 3426 heap_free(lpszBuffer); 3427 return (nRC != -1); 3428 } 3429 3430 /*********************************************************************** 3431 * FTPFINDNEXT_Destroy (internal) 3432 * 3433 * Deallocate session handle 3434 */ 3435 static void FTPFINDNEXT_Destroy(object_header_t *hdr) 3436 { 3437 LPWININETFTPFINDNEXTW lpwfn = (LPWININETFTPFINDNEXTW) hdr; 3438 DWORD i; 3439 3440 TRACE("\n"); 3441 3442 WININET_Release(&lpwfn->lpFtpSession->hdr); 3443 3444 for (i = 0; i < lpwfn->size; i++) 3445 { 3446 heap_free(lpwfn->lpafp[i].lpszName); 3447 } 3448 heap_free(lpwfn->lpafp); 3449 } 3450 3451 static DWORD FTPFINDNEXT_FindNextFileProc(WININETFTPFINDNEXTW *find, LPVOID data) 3452 { 3453 WIN32_FIND_DATAW *find_data = data; 3454 DWORD res = ERROR_SUCCESS; 3455 3456 TRACE("index(%d) size(%d)\n", find->index, find->size); 3457 3458 ZeroMemory(find_data, sizeof(WIN32_FIND_DATAW)); 3459 3460 if (find->index < find->size) { 3461 FTP_ConvertFileProp(&find->lpafp[find->index], find_data); 3462 find->index++; 3463 3464 TRACE("Name: %s\nSize: %d\n", debugstr_w(find_data->cFileName), find_data->nFileSizeLow); 3465 }else { 3466 res = ERROR_NO_MORE_FILES; 3467 } 3468 3469 if (find->hdr.dwFlags & INTERNET_FLAG_ASYNC) 3470 { 3471 INTERNET_ASYNC_RESULT iar; 3472 3473 iar.dwResult = (res == ERROR_SUCCESS); 3474 iar.dwError = res; 3475 3476 INTERNET_SendCallback(&find->hdr, find->hdr.dwContext, 3477 INTERNET_STATUS_REQUEST_COMPLETE, &iar, 3478 sizeof(INTERNET_ASYNC_RESULT)); 3479 } 3480 3481 return res; 3482 } 3483 3484 typedef struct { 3485 task_header_t hdr; 3486 WIN32_FIND_DATAW *find_data; 3487 } find_next_task_t; 3488 3489 static void FTPFINDNEXT_AsyncFindNextFileProc(task_header_t *hdr) 3490 { 3491 find_next_task_t *task = (find_next_task_t*)hdr; 3492 3493 FTPFINDNEXT_FindNextFileProc((WININETFTPFINDNEXTW*)task->hdr.hdr, task->find_data); 3494 } 3495 3496 static DWORD FTPFINDNEXT_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) 3497 { 3498 switch(option) { 3499 case INTERNET_OPTION_HANDLE_TYPE: 3500 TRACE("INTERNET_OPTION_HANDLE_TYPE\n"); 3501 3502 if (*size < sizeof(ULONG)) 3503 return ERROR_INSUFFICIENT_BUFFER; 3504 3505 *size = sizeof(DWORD); 3506 *(DWORD*)buffer = INTERNET_HANDLE_TYPE_FTP_FIND; 3507 return ERROR_SUCCESS; 3508 } 3509 3510 return INET_QueryOption(hdr, option, buffer, size, unicode); 3511 } 3512 3513 static DWORD FTPFINDNEXT_FindNextFileW(object_header_t *hdr, void *data) 3514 { 3515 WININETFTPFINDNEXTW *find = (WININETFTPFINDNEXTW*)hdr; 3516 3517 if (find->lpFtpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC) 3518 { 3519 find_next_task_t *task; 3520 3521 task = alloc_async_task(&find->hdr, FTPFINDNEXT_AsyncFindNextFileProc, sizeof(*task)); 3522 task->find_data = data; 3523 3524 INTERNET_AsyncCall(&task->hdr); 3525 return ERROR_SUCCESS; 3526 } 3527 3528 return FTPFINDNEXT_FindNextFileProc(find, data); 3529 } 3530 3531 static const object_vtbl_t FTPFINDNEXTVtbl = { 3532 FTPFINDNEXT_Destroy, 3533 NULL, 3534 FTPFINDNEXT_QueryOption, 3535 INET_SetOption, 3536 NULL, 3537 NULL, 3538 NULL, 3539 FTPFINDNEXT_FindNextFileW 3540 }; 3541 3542 /*********************************************************************** 3543 * FTP_ReceiveFileList (internal) 3544 * 3545 * Read file list from server 3546 * 3547 * RETURNS 3548 * Handle to file list on success 3549 * NULL on failure 3550 * 3551 */ 3552 static HINTERNET FTP_ReceiveFileList(ftp_session_t *lpwfs, INT nSocket, LPCWSTR lpszSearchFile, 3553 LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext) 3554 { 3555 DWORD dwSize = 0; 3556 LPFILEPROPERTIESW lpafp = NULL; 3557 LPWININETFTPFINDNEXTW lpwfn = NULL; 3558 3559 TRACE("(%p,%d,%s,%p,%08lx)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext); 3560 3561 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize)) 3562 { 3563 if(lpFindFileData) 3564 FTP_ConvertFileProp(lpafp, lpFindFileData); 3565 3566 lpwfn = alloc_object(&lpwfs->hdr, &FTPFINDNEXTVtbl, sizeof(WININETFTPFINDNEXTW)); 3567 if (lpwfn) 3568 { 3569 lpwfn->hdr.htype = WH_HFTPFINDNEXT; 3570 lpwfn->hdr.dwContext = dwContext; 3571 lpwfn->index = 1; /* Next index is 1 since we return index 0 */ 3572 lpwfn->size = dwSize; 3573 lpwfn->lpafp = lpafp; 3574 3575 WININET_AddRef( &lpwfs->hdr ); 3576 lpwfn->lpFtpSession = lpwfs; 3577 list_add_head( &lpwfs->hdr.children, &lpwfn->hdr.entry ); 3578 } 3579 } 3580 3581 TRACE("Matched %d files\n", dwSize); 3582 return lpwfn ? lpwfn->hdr.hInternet : NULL; 3583 } 3584 3585 3586 /*********************************************************************** 3587 * FTP_ConvertFileProp (internal) 3588 * 3589 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA 3590 * 3591 * RETURNS 3592 * TRUE on success 3593 * FALSE on failure 3594 * 3595 */ 3596 static BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData) 3597 { 3598 BOOL bSuccess = FALSE; 3599 3600 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW)); 3601 3602 if (lpafp) 3603 { 3604 SystemTimeToFileTime( &lpafp->tmLastModified, &lpFindFileData->ftLastAccessTime ); 3605 lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime; 3606 lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime; 3607 3608 /* Not all fields are filled in */ 3609 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */ 3610 lpFindFileData->nFileSizeLow = lpafp->nSize; 3611 3612 if (lpafp->bIsDirectory) 3613 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY; 3614 3615 if (lpafp->lpszName) 3616 lstrcpynW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH); 3617 3618 bSuccess = TRUE; 3619 } 3620 3621 return bSuccess; 3622 } 3623 3624 /*********************************************************************** 3625 * FTP_ParseNextFile (internal) 3626 * 3627 * Parse the next line in file listing 3628 * 3629 * RETURNS 3630 * TRUE on success 3631 * FALSE on failure 3632 */ 3633 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp) 3634 { 3635 static const char szSpace[] = " \t"; 3636 DWORD nBufLen; 3637 char *pszLine; 3638 char *pszToken; 3639 char *pszTmp; 3640 BOOL found = FALSE; 3641 int i; 3642 3643 lpfp->lpszName = NULL; 3644 do { 3645 if(!(pszLine = FTP_GetNextLine(nSocket, &nBufLen))) 3646 return FALSE; 3647 3648 pszToken = strtok(pszLine, szSpace); 3649 /* ls format 3650 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename> 3651 * 3652 * For instance: 3653 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier 3654 */ 3655 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) { 3656 if(!FTP_ParsePermission(pszToken, lpfp)) 3657 lpfp->bIsDirectory = FALSE; 3658 for(i=0; i<=3; i++) { 3659 if(!(pszToken = strtok(NULL, szSpace))) 3660 break; 3661 } 3662 if(!pszToken) continue; 3663 if(lpfp->bIsDirectory) { 3664 TRACE("Is directory\n"); 3665 lpfp->nSize = 0; 3666 } 3667 else { 3668 TRACE("Size: %s\n", pszToken); 3669 lpfp->nSize = atol(pszToken); 3670 } 3671 3672 lpfp->tmLastModified.wSecond = 0; 3673 lpfp->tmLastModified.wMinute = 0; 3674 lpfp->tmLastModified.wHour = 0; 3675 lpfp->tmLastModified.wDay = 0; 3676 lpfp->tmLastModified.wMonth = 0; 3677 lpfp->tmLastModified.wYear = 0; 3678 3679 /* Determine month */ 3680 pszToken = strtok(NULL, szSpace); 3681 if(!pszToken) continue; 3682 if(strlen(pszToken) >= 3) { 3683 pszToken[3] = 0; 3684 if((pszTmp = StrStrIA(szMonths, pszToken))) 3685 lpfp->tmLastModified.wMonth = ((pszTmp - szMonths) / 3)+1; 3686 } 3687 /* Determine day */ 3688 pszToken = strtok(NULL, szSpace); 3689 if(!pszToken) continue; 3690 lpfp->tmLastModified.wDay = atoi(pszToken); 3691 /* Determine time or year */ 3692 pszToken = strtok(NULL, szSpace); 3693 if(!pszToken) continue; 3694 if((pszTmp = strchr(pszToken, ':'))) { 3695 SYSTEMTIME curr_time; 3696 *pszTmp = 0; 3697 pszTmp++; 3698 lpfp->tmLastModified.wMinute = atoi(pszTmp); 3699 lpfp->tmLastModified.wHour = atoi(pszToken); 3700 GetLocalTime( &curr_time ); 3701 lpfp->tmLastModified.wYear = curr_time.wYear; 3702 } 3703 else { 3704 lpfp->tmLastModified.wYear = atoi(pszToken); 3705 lpfp->tmLastModified.wHour = 12; 3706 } 3707 TRACE("Mod time: %02d:%02d:%02d %04d/%02d/%02d\n", 3708 lpfp->tmLastModified.wHour, lpfp->tmLastModified.wMinute, lpfp->tmLastModified.wSecond, 3709 lpfp->tmLastModified.wYear, lpfp->tmLastModified.wMonth, lpfp->tmLastModified.wDay); 3710 3711 pszToken = strtok(NULL, szSpace); 3712 if(!pszToken) continue; 3713 lpfp->lpszName = heap_strdupAtoW(pszToken); 3714 TRACE("File: %s\n", debugstr_w(lpfp->lpszName)); 3715 } 3716 /* NT way of parsing ... : 3717 3718 07-13-03 08:55PM <DIR> sakpatch 3719 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz 3720 */ 3721 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) { 3722 int mon, mday, year, hour, min; 3723 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */ 3724 3725 sscanf(pszToken, "%d-%d-%d", &mon, &mday, &year); 3726 lpfp->tmLastModified.wDay = mday; 3727 lpfp->tmLastModified.wMonth = mon; 3728 lpfp->tmLastModified.wYear = year; 3729 3730 /* Hacky and bad Y2K protection :-) */ 3731 if (lpfp->tmLastModified.wYear < 70) lpfp->tmLastModified.wYear += 2000; 3732 3733 pszToken = strtok(NULL, szSpace); 3734 if(!pszToken) continue; 3735 sscanf(pszToken, "%d:%d", &hour, &min); 3736 lpfp->tmLastModified.wHour = hour; 3737 lpfp->tmLastModified.wMinute = min; 3738 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) { 3739 lpfp->tmLastModified.wHour += 12; 3740 } 3741 lpfp->tmLastModified.wSecond = 0; 3742 3743 TRACE("Mod time: %02d:%02d:%02d %04d/%02d/%02d\n", 3744 lpfp->tmLastModified.wHour, lpfp->tmLastModified.wMinute, lpfp->tmLastModified.wSecond, 3745 lpfp->tmLastModified.wYear, lpfp->tmLastModified.wMonth, lpfp->tmLastModified.wDay); 3746 3747 pszToken = strtok(NULL, szSpace); 3748 if(!pszToken) continue; 3749 if(!strcasecmp(pszToken, "<DIR>")) { 3750 lpfp->bIsDirectory = TRUE; 3751 lpfp->nSize = 0; 3752 TRACE("Is directory\n"); 3753 } 3754 else { 3755 lpfp->bIsDirectory = FALSE; 3756 lpfp->nSize = atol(pszToken); 3757 TRACE("Size: %d\n", lpfp->nSize); 3758 } 3759 3760 pszToken = strtok(NULL, szSpace); 3761 if(!pszToken) continue; 3762 lpfp->lpszName = heap_strdupAtoW(pszToken); 3763 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName)); 3764 } 3765 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */ 3766 else if(pszToken[0] == '+') { 3767 FIXME("EPLF Format not implemented\n"); 3768 } 3769 3770 if(lpfp->lpszName) { 3771 if((lpszSearchFile == NULL) || 3772 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) { 3773 found = TRUE; 3774 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName)); 3775 } 3776 else { 3777 heap_free(lpfp->lpszName); 3778 lpfp->lpszName = NULL; 3779 } 3780 } 3781 } while(!found); 3782 return TRUE; 3783 } 3784 3785 /*********************************************************************** 3786 * FTP_ParseDirectory (internal) 3787 * 3788 * Parse string of directory information 3789 * 3790 * RETURNS 3791 * TRUE on success 3792 * FALSE on failure 3793 */ 3794 static BOOL FTP_ParseDirectory(ftp_session_t *lpwfs, INT nSocket, LPCWSTR lpszSearchFile, 3795 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp) 3796 { 3797 BOOL bSuccess = TRUE; 3798 INT sizeFilePropArray = 500;/*20; */ 3799 INT indexFilePropArray = -1; 3800 3801 TRACE("\n"); 3802 3803 /* Allocate initial file properties array */ 3804 *lpafp = heap_alloc_zero(sizeof(FILEPROPERTIESW)*(sizeFilePropArray)); 3805 if (!*lpafp) 3806 return FALSE; 3807 3808 do { 3809 if (indexFilePropArray+1 >= sizeFilePropArray) 3810 { 3811 LPFILEPROPERTIESW tmpafp; 3812 3813 sizeFilePropArray *= 2; 3814 tmpafp = heap_realloc_zero(*lpafp, sizeof(FILEPROPERTIESW)*sizeFilePropArray); 3815 if (NULL == tmpafp) 3816 { 3817 bSuccess = FALSE; 3818 break; 3819 } 3820 3821 *lpafp = tmpafp; 3822 } 3823 indexFilePropArray++; 3824 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray])); 3825 3826 if (bSuccess && indexFilePropArray) 3827 { 3828 if (indexFilePropArray < sizeFilePropArray - 1) 3829 { 3830 LPFILEPROPERTIESW tmpafp; 3831 3832 tmpafp = heap_realloc(*lpafp, sizeof(FILEPROPERTIESW)*indexFilePropArray); 3833 if (NULL != tmpafp) 3834 *lpafp = tmpafp; 3835 } 3836 *dwfp = indexFilePropArray; 3837 } 3838 else 3839 { 3840 heap_free(*lpafp); 3841 INTERNET_SetLastError(ERROR_NO_MORE_FILES); 3842 bSuccess = FALSE; 3843 } 3844 3845 return bSuccess; 3846 } 3847 3848 3849 /*********************************************************************** 3850 * FTP_ParsePermission (internal) 3851 * 3852 * Parse permission string of directory information 3853 * 3854 * RETURNS 3855 * TRUE on success 3856 * FALSE on failure 3857 * 3858 */ 3859 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp) 3860 { 3861 BOOL bSuccess = TRUE; 3862 unsigned short nPermission = 0; 3863 INT nPos = 1; 3864 INT nLast = 9; 3865 3866 TRACE("\n"); 3867 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l')) 3868 { 3869 bSuccess = FALSE; 3870 return bSuccess; 3871 } 3872 3873 lpfp->bIsDirectory = (*lpszPermission == 'd'); 3874 do 3875 { 3876 switch (nPos) 3877 { 3878 case 1: 3879 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8; 3880 break; 3881 case 2: 3882 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7; 3883 break; 3884 case 3: 3885 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6; 3886 break; 3887 case 4: 3888 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5; 3889 break; 3890 case 5: 3891 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4; 3892 break; 3893 case 6: 3894 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3; 3895 break; 3896 case 7: 3897 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2; 3898 break; 3899 case 8: 3900 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1; 3901 break; 3902 case 9: 3903 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0); 3904 break; 3905 } 3906 nPos++; 3907 }while (nPos <= nLast); 3908 3909 lpfp->permissions = nPermission; 3910 return bSuccess; 3911 } 3912 3913 3914 /*********************************************************************** 3915 * FTP_SetResponseError (internal) 3916 * 3917 * Set the appropriate error code for a given response from the server 3918 * 3919 * RETURNS 3920 * 3921 */ 3922 static DWORD FTP_SetResponseError(DWORD dwResponse) 3923 { 3924 DWORD dwCode = 0; 3925 3926 switch(dwResponse) 3927 { 3928 case 425: /* Cannot open data connection. */ 3929 dwCode = ERROR_INTERNET_CANNOT_CONNECT; 3930 break; 3931 3932 case 426: /* Connection closed, transer aborted. */ 3933 dwCode = ERROR_INTERNET_CONNECTION_ABORTED; 3934 break; 3935 3936 case 530: /* Not logged in. Login incorrect. */ 3937 dwCode = ERROR_INTERNET_LOGIN_FAILURE; 3938 break; 3939 3940 case 421: /* Service not available - Server may be shutting down. */ 3941 case 450: /* File action not taken. File may be busy. */ 3942 case 451: /* Action aborted. Server error. */ 3943 case 452: /* Action not taken. Insufficient storage space on server. */ 3944 case 500: /* Syntax error. Command unrecognized. */ 3945 case 501: /* Syntax error. Error in parameters or arguments. */ 3946 case 502: /* Command not implemented. */ 3947 case 503: /* Bad sequence of commands. */ 3948 case 504: /* Command not implemented for that parameter. */ 3949 case 532: /* Need account for storing files */ 3950 case 550: /* File action not taken. File not found or no access. */ 3951 case 551: /* Requested action aborted. Page type unknown */ 3952 case 552: /* Action aborted. Exceeded storage allocation */ 3953 case 553: /* Action not taken. File name not allowed. */ 3954 3955 default: 3956 dwCode = ERROR_INTERNET_EXTENDED_ERROR; 3957 break; 3958 } 3959 3960 INTERNET_SetLastError(dwCode); 3961 return dwCode; 3962 } 3963