Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenftp.c
Go to the documentation of this file.
00001 /* 00002 * WININET - Ftp implementation 00003 * 00004 * Copyright 1999 Corel Corporation 00005 * Copyright 2004 Mike McCormack for CodeWeavers 00006 * Copyright 2004 Kevin Koltzau 00007 * Copyright 2007 Hans Leidekker 00008 * 00009 * Ulrich Czekalla 00010 * Noureddine Jemmali 00011 * 00012 * Copyright 2000 Andreas Mohr 00013 * Copyright 2002 Jaco Greeff 00014 * 00015 * This library is free software; you can redistribute it and/or 00016 * modify it under the terms of the GNU Lesser General Public 00017 * License as published by the Free Software Foundation; either 00018 * version 2.1 of the License, or (at your option) any later version. 00019 * 00020 * This library is distributed in the hope that it will be useful, 00021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00023 * Lesser General Public License for more details. 00024 * 00025 * You should have received a copy of the GNU Lesser General Public 00026 * License along with this library; if not, write to the Free Software 00027 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00028 */ 00029 00030 #include "config.h" 00031 #include "wine/port.h" 00032 00033 #if defined(__MINGW32__) || defined (_MSC_VER) 00034 #include <ws2tcpip.h> 00035 #endif 00036 00037 #include <errno.h> 00038 #include <stdarg.h> 00039 #include <stdio.h> 00040 #include <stdlib.h> 00041 #include <string.h> 00042 #include <sys/types.h> 00043 #ifdef HAVE_SYS_SOCKET_H 00044 # include <sys/socket.h> 00045 #endif 00046 #ifdef HAVE_ARPA_INET_H 00047 # include <arpa/inet.h> 00048 #endif 00049 #ifdef HAVE_UNISTD_H 00050 # include <unistd.h> 00051 #endif 00052 #ifdef HAVE_SYS_IOCTL_H 00053 # include <sys/ioctl.h> 00054 #endif 00055 #include <time.h> 00056 #include <assert.h> 00057 00058 #include "windef.h" 00059 #include "winbase.h" 00060 #include "wingdi.h" 00061 #include "winuser.h" 00062 #include "wininet.h" 00063 #include "winnls.h" 00064 #include "winerror.h" 00065 #include "winreg.h" 00066 #include "winternl.h" 00067 #include "shlwapi.h" 00068 00069 #include "wine/debug.h" 00070 #include "internet.h" 00071 00072 WINE_DEFAULT_DEBUG_CHANNEL(wininet); 00073 00074 typedef struct _ftp_session_t ftp_session_t; 00075 00076 typedef struct 00077 { 00078 object_header_t hdr; 00079 ftp_session_t *lpFtpSession; 00080 BOOL session_deleted; 00081 int nDataSocket; 00082 WCHAR *cache_file; 00083 HANDLE cache_file_handle; 00084 } ftp_file_t; 00085 00086 struct _ftp_session_t 00087 { 00088 object_header_t hdr; 00089 appinfo_t *lpAppInfo; 00090 int sndSocket; 00091 int lstnSocket; 00092 int pasvSocket; /* data socket connected by us in case of passive FTP */ 00093 ftp_file_t *download_in_progress; 00094 struct sockaddr_in socketAddress; 00095 struct sockaddr_in lstnSocketAddress; 00096 LPWSTR servername; 00097 INTERNET_PORT serverport; 00098 LPWSTR lpszPassword; 00099 LPWSTR lpszUserName; 00100 }; 00101 00102 typedef struct 00103 { 00104 BOOL bIsDirectory; 00105 LPWSTR lpszName; 00106 DWORD nSize; 00107 SYSTEMTIME tmLastModified; 00108 unsigned short permissions; 00109 } FILEPROPERTIESW, *LPFILEPROPERTIESW; 00110 00111 typedef struct 00112 { 00113 object_header_t hdr; 00114 ftp_session_t *lpFtpSession; 00115 DWORD index; 00116 DWORD size; 00117 LPFILEPROPERTIESW lpafp; 00118 } WININETFTPFINDNEXTW, *LPWININETFTPFINDNEXTW; 00119 00120 #define DATA_PACKET_SIZE 0x2000 00121 #define szCRLF "\r\n" 00122 #define MAX_BACKLOG 5 00123 00124 /* Testing shows that Windows only accepts dwFlags where the last 00125 * 3 (yes 3) bits define FTP_TRANSFER_TYPE_UNKNOWN, FTP_TRANSFER_TYPE_ASCII or FTP_TRANSFER_TYPE_BINARY. 00126 */ 00127 #define FTP_CONDITION_MASK 0x0007 00128 00129 typedef enum { 00130 /* FTP commands with arguments. */ 00131 FTP_CMD_ACCT, 00132 FTP_CMD_CWD, 00133 FTP_CMD_DELE, 00134 FTP_CMD_MKD, 00135 FTP_CMD_PASS, 00136 FTP_CMD_PORT, 00137 FTP_CMD_RETR, 00138 FTP_CMD_RMD, 00139 FTP_CMD_RNFR, 00140 FTP_CMD_RNTO, 00141 FTP_CMD_STOR, 00142 FTP_CMD_TYPE, 00143 FTP_CMD_USER, 00144 FTP_CMD_SIZE, 00145 00146 /* FTP commands without arguments. */ 00147 FTP_CMD_ABOR, 00148 FTP_CMD_LIST, 00149 FTP_CMD_NLST, 00150 FTP_CMD_PASV, 00151 FTP_CMD_PWD, 00152 FTP_CMD_QUIT, 00153 } FTP_COMMAND; 00154 00155 static const CHAR *const szFtpCommands[] = { 00156 "ACCT", 00157 "CWD", 00158 "DELE", 00159 "MKD", 00160 "PASS", 00161 "PORT", 00162 "RETR", 00163 "RMD", 00164 "RNFR", 00165 "RNTO", 00166 "STOR", 00167 "TYPE", 00168 "USER", 00169 "SIZE", 00170 "ABOR", 00171 "LIST", 00172 "NLST", 00173 "PASV", 00174 "PWD", 00175 "QUIT", 00176 }; 00177 00178 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"; 00179 static const WCHAR szNoAccount[] = {'n','o','a','c','c','o','u','n','t','\0'}; 00180 00181 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam, 00182 INTERNET_STATUS_CALLBACK lpfnStatusCB, object_header_t *hdr, DWORD_PTR dwContext); 00183 static BOOL FTP_SendStore(ftp_session_t*, LPCWSTR lpszRemoteFile, DWORD dwType); 00184 static BOOL FTP_GetDataSocket(ftp_session_t*, LPINT nDataSocket); 00185 static BOOL FTP_SendData(ftp_session_t*, INT nDataSocket, HANDLE hFile); 00186 static INT FTP_ReceiveResponse(ftp_session_t*, DWORD_PTR dwContext); 00187 static BOOL FTP_SendRetrieve(ftp_session_t*, LPCWSTR lpszRemoteFile, DWORD dwType); 00188 static BOOL FTP_RetrieveFileData(ftp_session_t*, INT nDataSocket, HANDLE hFile); 00189 static BOOL FTP_InitListenSocket(ftp_session_t*); 00190 static BOOL FTP_ConnectToHost(ftp_session_t*); 00191 static BOOL FTP_SendPassword(ftp_session_t*); 00192 static BOOL FTP_SendAccount(ftp_session_t*); 00193 static BOOL FTP_SendType(ftp_session_t*, DWORD dwType); 00194 static BOOL FTP_SendPort(ftp_session_t*); 00195 static BOOL FTP_DoPassive(ftp_session_t*); 00196 static BOOL FTP_SendPortOrPasv(ftp_session_t*); 00197 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp); 00198 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW fileprop); 00199 static BOOL FTP_ParseDirectory(ftp_session_t*, INT nSocket, LPCWSTR lpszSearchFile, 00200 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp); 00201 static HINTERNET FTP_ReceiveFileList(ftp_session_t*, INT nSocket, LPCWSTR lpszSearchFile, 00202 LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext); 00203 static DWORD FTP_SetResponseError(DWORD dwResponse); 00204 static BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData); 00205 static BOOL FTP_FtpPutFileW(ftp_session_t*, LPCWSTR lpszLocalFile, 00206 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext); 00207 static BOOL FTP_FtpSetCurrentDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory); 00208 static BOOL FTP_FtpCreateDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory); 00209 static HINTERNET FTP_FtpFindFirstFileW(ftp_session_t*, 00210 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext); 00211 static BOOL FTP_FtpGetCurrentDirectoryW(ftp_session_t*, LPWSTR lpszCurrentDirectory, 00212 LPDWORD lpdwCurrentDirectory); 00213 static BOOL FTP_FtpRenameFileW(ftp_session_t*, LPCWSTR lpszSrc, LPCWSTR lpszDest); 00214 static BOOL FTP_FtpRemoveDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory); 00215 static BOOL FTP_FtpDeleteFileW(ftp_session_t*, LPCWSTR lpszFileName); 00216 static BOOL FTP_FtpGetFileW(ftp_session_t*, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile, 00217 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags, 00218 DWORD_PTR dwContext); 00219 00220 /* A temporary helper until we get rid of INTERNET_GetLastError calls */ 00221 static BOOL res_to_le(DWORD res) 00222 { 00223 if(res != ERROR_SUCCESS) 00224 INTERNET_SetLastError(res); 00225 return res == ERROR_SUCCESS; 00226 } 00227 00228 /*********************************************************************** 00229 * FtpPutFileA (WININET.@) 00230 * 00231 * Uploads a file to the FTP server 00232 * 00233 * RETURNS 00234 * TRUE on success 00235 * FALSE on failure 00236 * 00237 */ 00238 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile, 00239 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext) 00240 { 00241 LPWSTR lpwzLocalFile; 00242 LPWSTR lpwzNewRemoteFile; 00243 BOOL ret; 00244 00245 lpwzLocalFile = heap_strdupAtoW(lpszLocalFile); 00246 lpwzNewRemoteFile = heap_strdupAtoW(lpszNewRemoteFile); 00247 ret = FtpPutFileW(hConnect, lpwzLocalFile, lpwzNewRemoteFile, 00248 dwFlags, dwContext); 00249 HeapFree(GetProcessHeap(), 0, lpwzLocalFile); 00250 HeapFree(GetProcessHeap(), 0, lpwzNewRemoteFile); 00251 return ret; 00252 } 00253 00254 static void AsyncFtpPutFileProc(WORKREQUEST *workRequest) 00255 { 00256 struct WORKREQ_FTPPUTFILEW const *req = &workRequest->u.FtpPutFileW; 00257 ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; 00258 00259 TRACE("%p\n", lpwfs); 00260 00261 FTP_FtpPutFileW(lpwfs, req->lpszLocalFile, 00262 req->lpszNewRemoteFile, req->dwFlags, req->dwContext); 00263 00264 HeapFree(GetProcessHeap(), 0, req->lpszLocalFile); 00265 HeapFree(GetProcessHeap(), 0, req->lpszNewRemoteFile); 00266 } 00267 00268 /*********************************************************************** 00269 * FtpPutFileW (WININET.@) 00270 * 00271 * Uploads a file to the FTP server 00272 * 00273 * RETURNS 00274 * TRUE on success 00275 * FALSE on failure 00276 * 00277 */ 00278 BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile, 00279 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext) 00280 { 00281 ftp_session_t *lpwfs; 00282 appinfo_t *hIC = NULL; 00283 BOOL r = FALSE; 00284 00285 if (!lpszLocalFile || !lpszNewRemoteFile) 00286 { 00287 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 00288 return FALSE; 00289 } 00290 00291 lpwfs = (ftp_session_t*) get_handle_object( hConnect ); 00292 if (!lpwfs) 00293 { 00294 INTERNET_SetLastError(ERROR_INVALID_HANDLE); 00295 return FALSE; 00296 } 00297 00298 if (WH_HFTPSESSION != lpwfs->hdr.htype) 00299 { 00300 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); 00301 goto lend; 00302 } 00303 00304 if (lpwfs->download_in_progress != NULL) 00305 { 00306 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); 00307 goto lend; 00308 } 00309 00310 if ((dwFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY) 00311 { 00312 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 00313 goto lend; 00314 } 00315 00316 hIC = lpwfs->lpAppInfo; 00317 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 00318 { 00319 WORKREQUEST workRequest; 00320 struct WORKREQ_FTPPUTFILEW *req = &workRequest.u.FtpPutFileW; 00321 00322 workRequest.asyncproc = AsyncFtpPutFileProc; 00323 workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); 00324 req->lpszLocalFile = heap_strdupW(lpszLocalFile); 00325 req->lpszNewRemoteFile = heap_strdupW(lpszNewRemoteFile); 00326 req->dwFlags = dwFlags; 00327 req->dwContext = dwContext; 00328 00329 r = res_to_le(INTERNET_AsyncCall(&workRequest)); 00330 } 00331 else 00332 { 00333 r = FTP_FtpPutFileW(lpwfs, lpszLocalFile, 00334 lpszNewRemoteFile, dwFlags, dwContext); 00335 } 00336 00337 lend: 00338 WININET_Release( &lpwfs->hdr ); 00339 00340 return r; 00341 } 00342 00343 /*********************************************************************** 00344 * FTP_FtpPutFileW (Internal) 00345 * 00346 * Uploads a file to the FTP server 00347 * 00348 * RETURNS 00349 * TRUE on success 00350 * FALSE on failure 00351 * 00352 */ 00353 static BOOL FTP_FtpPutFileW(ftp_session_t *lpwfs, LPCWSTR lpszLocalFile, 00354 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext) 00355 { 00356 HANDLE hFile; 00357 BOOL bSuccess = FALSE; 00358 appinfo_t *hIC = NULL; 00359 INT nResCode; 00360 00361 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", debugstr_w(lpszLocalFile), debugstr_w(lpszNewRemoteFile)); 00362 00363 /* Clear any error information */ 00364 INTERNET_SetLastError(0); 00365 00366 /* Open file to be uploaded */ 00367 if (INVALID_HANDLE_VALUE == 00368 (hFile = CreateFileW(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0))) 00369 /* Let CreateFile set the appropriate error */ 00370 return FALSE; 00371 00372 hIC = lpwfs->lpAppInfo; 00373 00374 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0); 00375 00376 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags)) 00377 { 00378 INT nDataSocket; 00379 00380 /* Get data socket to server */ 00381 if (FTP_GetDataSocket(lpwfs, &nDataSocket)) 00382 { 00383 FTP_SendData(lpwfs, nDataSocket, hFile); 00384 closesocket(nDataSocket); 00385 nResCode = FTP_ReceiveResponse(lpwfs, dwContext); 00386 if (nResCode) 00387 { 00388 if (nResCode == 226) 00389 bSuccess = TRUE; 00390 else 00391 FTP_SetResponseError(nResCode); 00392 } 00393 } 00394 } 00395 00396 if (lpwfs->lstnSocket != -1) 00397 { 00398 closesocket(lpwfs->lstnSocket); 00399 lpwfs->lstnSocket = -1; 00400 } 00401 00402 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 00403 { 00404 INTERNET_ASYNC_RESULT iar; 00405 00406 iar.dwResult = (DWORD)bSuccess; 00407 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); 00408 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, 00409 &iar, sizeof(INTERNET_ASYNC_RESULT)); 00410 } 00411 00412 CloseHandle(hFile); 00413 00414 return bSuccess; 00415 } 00416 00417 00418 /*********************************************************************** 00419 * FtpSetCurrentDirectoryA (WININET.@) 00420 * 00421 * Change the working directory on the FTP server 00422 * 00423 * RETURNS 00424 * TRUE on success 00425 * FALSE on failure 00426 * 00427 */ 00428 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory) 00429 { 00430 LPWSTR lpwzDirectory; 00431 BOOL ret; 00432 00433 lpwzDirectory = heap_strdupAtoW(lpszDirectory); 00434 ret = FtpSetCurrentDirectoryW(hConnect, lpwzDirectory); 00435 HeapFree(GetProcessHeap(), 0, lpwzDirectory); 00436 return ret; 00437 } 00438 00439 00440 static void AsyncFtpSetCurrentDirectoryProc(WORKREQUEST *workRequest) 00441 { 00442 struct WORKREQ_FTPSETCURRENTDIRECTORYW const *req = &workRequest->u.FtpSetCurrentDirectoryW; 00443 ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; 00444 00445 TRACE("%p\n", lpwfs); 00446 00447 FTP_FtpSetCurrentDirectoryW(lpwfs, req->lpszDirectory); 00448 HeapFree(GetProcessHeap(), 0, req->lpszDirectory); 00449 } 00450 00451 /*********************************************************************** 00452 * FtpSetCurrentDirectoryW (WININET.@) 00453 * 00454 * Change the working directory on the FTP server 00455 * 00456 * RETURNS 00457 * TRUE on success 00458 * FALSE on failure 00459 * 00460 */ 00461 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory) 00462 { 00463 ftp_session_t *lpwfs = NULL; 00464 appinfo_t *hIC = NULL; 00465 BOOL r = FALSE; 00466 00467 if (!lpszDirectory) 00468 { 00469 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 00470 goto lend; 00471 } 00472 00473 lpwfs = (ftp_session_t*) get_handle_object( hConnect ); 00474 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) 00475 { 00476 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); 00477 goto lend; 00478 } 00479 00480 if (lpwfs->download_in_progress != NULL) 00481 { 00482 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); 00483 goto lend; 00484 } 00485 00486 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory)); 00487 00488 hIC = lpwfs->lpAppInfo; 00489 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 00490 { 00491 WORKREQUEST workRequest; 00492 struct WORKREQ_FTPSETCURRENTDIRECTORYW *req; 00493 00494 workRequest.asyncproc = AsyncFtpSetCurrentDirectoryProc; 00495 workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); 00496 req = &workRequest.u.FtpSetCurrentDirectoryW; 00497 req->lpszDirectory = heap_strdupW(lpszDirectory); 00498 00499 r = res_to_le(INTERNET_AsyncCall(&workRequest)); 00500 } 00501 else 00502 { 00503 r = FTP_FtpSetCurrentDirectoryW(lpwfs, lpszDirectory); 00504 } 00505 00506 lend: 00507 if( lpwfs ) 00508 WININET_Release( &lpwfs->hdr ); 00509 00510 return r; 00511 } 00512 00513 00514 /*********************************************************************** 00515 * FTP_FtpSetCurrentDirectoryW (Internal) 00516 * 00517 * Change the working directory on the FTP server 00518 * 00519 * RETURNS 00520 * TRUE on success 00521 * FALSE on failure 00522 * 00523 */ 00524 static BOOL FTP_FtpSetCurrentDirectoryW(ftp_session_t *lpwfs, LPCWSTR lpszDirectory) 00525 { 00526 INT nResCode; 00527 appinfo_t *hIC = NULL; 00528 DWORD bSuccess = FALSE; 00529 00530 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory)); 00531 00532 /* Clear any error information */ 00533 INTERNET_SetLastError(0); 00534 00535 hIC = lpwfs->lpAppInfo; 00536 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory, 00537 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext)) 00538 goto lend; 00539 00540 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 00541 00542 if (nResCode) 00543 { 00544 if (nResCode == 250) 00545 bSuccess = TRUE; 00546 else 00547 FTP_SetResponseError(nResCode); 00548 } 00549 00550 lend: 00551 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 00552 { 00553 INTERNET_ASYNC_RESULT iar; 00554 00555 iar.dwResult = bSuccess; 00556 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR; 00557 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, 00558 &iar, sizeof(INTERNET_ASYNC_RESULT)); 00559 } 00560 return bSuccess; 00561 } 00562 00563 00564 /*********************************************************************** 00565 * FtpCreateDirectoryA (WININET.@) 00566 * 00567 * Create new directory on the FTP server 00568 * 00569 * RETURNS 00570 * TRUE on success 00571 * FALSE on failure 00572 * 00573 */ 00574 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory) 00575 { 00576 LPWSTR lpwzDirectory; 00577 BOOL ret; 00578 00579 lpwzDirectory = heap_strdupAtoW(lpszDirectory); 00580 ret = FtpCreateDirectoryW(hConnect, lpwzDirectory); 00581 HeapFree(GetProcessHeap(), 0, lpwzDirectory); 00582 return ret; 00583 } 00584 00585 00586 static void AsyncFtpCreateDirectoryProc(WORKREQUEST *workRequest) 00587 { 00588 struct WORKREQ_FTPCREATEDIRECTORYW const *req = &workRequest->u.FtpCreateDirectoryW; 00589 ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; 00590 00591 TRACE(" %p\n", lpwfs); 00592 00593 FTP_FtpCreateDirectoryW(lpwfs, req->lpszDirectory); 00594 HeapFree(GetProcessHeap(), 0, req->lpszDirectory); 00595 } 00596 00597 /*********************************************************************** 00598 * FtpCreateDirectoryW (WININET.@) 00599 * 00600 * Create new directory on the FTP server 00601 * 00602 * RETURNS 00603 * TRUE on success 00604 * FALSE on failure 00605 * 00606 */ 00607 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory) 00608 { 00609 ftp_session_t *lpwfs; 00610 appinfo_t *hIC = NULL; 00611 BOOL r = FALSE; 00612 00613 lpwfs = (ftp_session_t*) get_handle_object( hConnect ); 00614 if (!lpwfs) 00615 { 00616 INTERNET_SetLastError(ERROR_INVALID_HANDLE); 00617 return FALSE; 00618 } 00619 00620 if (WH_HFTPSESSION != lpwfs->hdr.htype) 00621 { 00622 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); 00623 goto lend; 00624 } 00625 00626 if (lpwfs->download_in_progress != NULL) 00627 { 00628 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); 00629 goto lend; 00630 } 00631 00632 if (!lpszDirectory) 00633 { 00634 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 00635 goto lend; 00636 } 00637 00638 hIC = lpwfs->lpAppInfo; 00639 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 00640 { 00641 WORKREQUEST workRequest; 00642 struct WORKREQ_FTPCREATEDIRECTORYW *req; 00643 00644 workRequest.asyncproc = AsyncFtpCreateDirectoryProc; 00645 workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); 00646 req = &workRequest.u.FtpCreateDirectoryW; 00647 req->lpszDirectory = heap_strdupW(lpszDirectory); 00648 00649 r = res_to_le(INTERNET_AsyncCall(&workRequest)); 00650 } 00651 else 00652 { 00653 r = FTP_FtpCreateDirectoryW(lpwfs, lpszDirectory); 00654 } 00655 lend: 00656 WININET_Release( &lpwfs->hdr ); 00657 00658 return r; 00659 } 00660 00661 00662 /*********************************************************************** 00663 * FTP_FtpCreateDirectoryW (Internal) 00664 * 00665 * Create new directory on the FTP server 00666 * 00667 * RETURNS 00668 * TRUE on success 00669 * FALSE on failure 00670 * 00671 */ 00672 static BOOL FTP_FtpCreateDirectoryW(ftp_session_t *lpwfs, LPCWSTR lpszDirectory) 00673 { 00674 INT nResCode; 00675 BOOL bSuccess = FALSE; 00676 appinfo_t *hIC = NULL; 00677 00678 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory)); 00679 00680 /* Clear any error information */ 00681 INTERNET_SetLastError(0); 00682 00683 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0)) 00684 goto lend; 00685 00686 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 00687 if (nResCode) 00688 { 00689 if (nResCode == 257) 00690 bSuccess = TRUE; 00691 else 00692 FTP_SetResponseError(nResCode); 00693 } 00694 00695 lend: 00696 hIC = lpwfs->lpAppInfo; 00697 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 00698 { 00699 INTERNET_ASYNC_RESULT iar; 00700 00701 iar.dwResult = (DWORD)bSuccess; 00702 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); 00703 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, 00704 &iar, sizeof(INTERNET_ASYNC_RESULT)); 00705 } 00706 00707 return bSuccess; 00708 } 00709 00710 /*********************************************************************** 00711 * FtpFindFirstFileA (WININET.@) 00712 * 00713 * Search the specified directory 00714 * 00715 * RETURNS 00716 * HINTERNET on success 00717 * NULL on failure 00718 * 00719 */ 00720 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect, 00721 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext) 00722 { 00723 LPWSTR lpwzSearchFile; 00724 WIN32_FIND_DATAW wfd; 00725 LPWIN32_FIND_DATAW lpFindFileDataW; 00726 HINTERNET ret; 00727 00728 lpwzSearchFile = heap_strdupAtoW(lpszSearchFile); 00729 lpFindFileDataW = lpFindFileData?&wfd:NULL; 00730 ret = FtpFindFirstFileW(hConnect, lpwzSearchFile, lpFindFileDataW, dwFlags, dwContext); 00731 HeapFree(GetProcessHeap(), 0, lpwzSearchFile); 00732 00733 if (ret && lpFindFileData) 00734 WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData); 00735 00736 return ret; 00737 } 00738 00739 00740 static void AsyncFtpFindFirstFileProc(WORKREQUEST *workRequest) 00741 { 00742 struct WORKREQ_FTPFINDFIRSTFILEW const *req = &workRequest->u.FtpFindFirstFileW; 00743 ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; 00744 00745 TRACE("%p\n", lpwfs); 00746 00747 FTP_FtpFindFirstFileW(lpwfs, req->lpszSearchFile, 00748 req->lpFindFileData, req->dwFlags, req->dwContext); 00749 HeapFree(GetProcessHeap(), 0, req->lpszSearchFile); 00750 } 00751 00752 /*********************************************************************** 00753 * FtpFindFirstFileW (WININET.@) 00754 * 00755 * Search the specified directory 00756 * 00757 * RETURNS 00758 * HINTERNET on success 00759 * NULL on failure 00760 * 00761 */ 00762 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect, 00763 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext) 00764 { 00765 ftp_session_t *lpwfs; 00766 appinfo_t *hIC = NULL; 00767 HINTERNET r = NULL; 00768 00769 lpwfs = (ftp_session_t*) get_handle_object( hConnect ); 00770 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) 00771 { 00772 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); 00773 goto lend; 00774 } 00775 00776 if (lpwfs->download_in_progress != NULL) 00777 { 00778 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); 00779 goto lend; 00780 } 00781 00782 hIC = lpwfs->lpAppInfo; 00783 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 00784 { 00785 WORKREQUEST workRequest; 00786 struct WORKREQ_FTPFINDFIRSTFILEW *req; 00787 00788 workRequest.asyncproc = AsyncFtpFindFirstFileProc; 00789 workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); 00790 req = &workRequest.u.FtpFindFirstFileW; 00791 req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : heap_strdupW(lpszSearchFile); 00792 req->lpFindFileData = lpFindFileData; 00793 req->dwFlags = dwFlags; 00794 req->dwContext= dwContext; 00795 00796 INTERNET_AsyncCall(&workRequest); 00797 r = NULL; 00798 } 00799 else 00800 { 00801 r = FTP_FtpFindFirstFileW(lpwfs, lpszSearchFile, lpFindFileData, 00802 dwFlags, dwContext); 00803 } 00804 lend: 00805 if( lpwfs ) 00806 WININET_Release( &lpwfs->hdr ); 00807 00808 return r; 00809 } 00810 00811 00812 /*********************************************************************** 00813 * FTP_FtpFindFirstFileW (Internal) 00814 * 00815 * Search the specified directory 00816 * 00817 * RETURNS 00818 * HINTERNET on success 00819 * NULL on failure 00820 * 00821 */ 00822 static HINTERNET FTP_FtpFindFirstFileW(ftp_session_t *lpwfs, 00823 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext) 00824 { 00825 INT nResCode; 00826 appinfo_t *hIC = NULL; 00827 HINTERNET hFindNext = NULL; 00828 00829 TRACE("\n"); 00830 00831 /* Clear any error information */ 00832 INTERNET_SetLastError(0); 00833 00834 if (!FTP_InitListenSocket(lpwfs)) 00835 goto lend; 00836 00837 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII)) 00838 goto lend; 00839 00840 if (!FTP_SendPortOrPasv(lpwfs)) 00841 goto lend; 00842 00843 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, NULL, 00844 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext)) 00845 goto lend; 00846 00847 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 00848 if (nResCode) 00849 { 00850 if (nResCode == 125 || nResCode == 150) 00851 { 00852 INT nDataSocket; 00853 00854 /* Get data socket to server */ 00855 if (FTP_GetDataSocket(lpwfs, &nDataSocket)) 00856 { 00857 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpszSearchFile, lpFindFileData, dwContext); 00858 closesocket(nDataSocket); 00859 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 00860 if (nResCode != 226 && nResCode != 250) 00861 INTERNET_SetLastError(ERROR_NO_MORE_FILES); 00862 } 00863 } 00864 else 00865 FTP_SetResponseError(nResCode); 00866 } 00867 00868 lend: 00869 if (lpwfs->lstnSocket != -1) 00870 { 00871 closesocket(lpwfs->lstnSocket); 00872 lpwfs->lstnSocket = -1; 00873 } 00874 00875 hIC = lpwfs->lpAppInfo; 00876 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 00877 { 00878 INTERNET_ASYNC_RESULT iar; 00879 00880 if (hFindNext) 00881 { 00882 iar.dwResult = (DWORD_PTR)hFindNext; 00883 iar.dwError = ERROR_SUCCESS; 00884 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED, 00885 &iar, sizeof(INTERNET_ASYNC_RESULT)); 00886 } 00887 00888 iar.dwResult = (DWORD_PTR)hFindNext; 00889 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError(); 00890 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, 00891 &iar, sizeof(INTERNET_ASYNC_RESULT)); 00892 } 00893 00894 return hFindNext; 00895 } 00896 00897 00898 /*********************************************************************** 00899 * FtpGetCurrentDirectoryA (WININET.@) 00900 * 00901 * Retrieves the current directory 00902 * 00903 * RETURNS 00904 * TRUE on success 00905 * FALSE on failure 00906 * 00907 */ 00908 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory, 00909 LPDWORD lpdwCurrentDirectory) 00910 { 00911 WCHAR *dir = NULL; 00912 DWORD len; 00913 BOOL ret; 00914 00915 if(lpdwCurrentDirectory) { 00916 len = *lpdwCurrentDirectory; 00917 if(lpszCurrentDirectory) 00918 { 00919 dir = heap_alloc(len * sizeof(WCHAR)); 00920 if (NULL == dir) 00921 { 00922 INTERNET_SetLastError(ERROR_OUTOFMEMORY); 00923 return FALSE; 00924 } 00925 } 00926 } 00927 ret = FtpGetCurrentDirectoryW(hFtpSession, lpszCurrentDirectory?dir:NULL, lpdwCurrentDirectory?&len:NULL); 00928 00929 if (ret && lpszCurrentDirectory) 00930 WideCharToMultiByte(CP_ACP, 0, dir, -1, lpszCurrentDirectory, len, NULL, NULL); 00931 00932 if (lpdwCurrentDirectory) *lpdwCurrentDirectory = len; 00933 HeapFree(GetProcessHeap(), 0, dir); 00934 return ret; 00935 } 00936 00937 00938 static void AsyncFtpGetCurrentDirectoryProc(WORKREQUEST *workRequest) 00939 { 00940 struct WORKREQ_FTPGETCURRENTDIRECTORYW const *req = &workRequest->u.FtpGetCurrentDirectoryW; 00941 ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; 00942 00943 TRACE("%p\n", lpwfs); 00944 00945 FTP_FtpGetCurrentDirectoryW(lpwfs, req->lpszDirectory, req->lpdwDirectory); 00946 } 00947 00948 /*********************************************************************** 00949 * FtpGetCurrentDirectoryW (WININET.@) 00950 * 00951 * Retrieves the current directory 00952 * 00953 * RETURNS 00954 * TRUE on success 00955 * FALSE on failure 00956 * 00957 */ 00958 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory, 00959 LPDWORD lpdwCurrentDirectory) 00960 { 00961 ftp_session_t *lpwfs; 00962 appinfo_t *hIC = NULL; 00963 BOOL r = FALSE; 00964 00965 TRACE("%p %p %p\n", hFtpSession, lpszCurrentDirectory, lpdwCurrentDirectory); 00966 00967 lpwfs = (ftp_session_t*) get_handle_object( hFtpSession ); 00968 if (NULL == lpwfs) 00969 { 00970 INTERNET_SetLastError(ERROR_INVALID_HANDLE); 00971 goto lend; 00972 } 00973 00974 if (WH_HFTPSESSION != lpwfs->hdr.htype) 00975 { 00976 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); 00977 goto lend; 00978 } 00979 00980 if (!lpdwCurrentDirectory) 00981 { 00982 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 00983 goto lend; 00984 } 00985 00986 if (lpszCurrentDirectory == NULL) 00987 { 00988 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); 00989 goto lend; 00990 } 00991 00992 if (lpwfs->download_in_progress != NULL) 00993 { 00994 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); 00995 goto lend; 00996 } 00997 00998 hIC = lpwfs->lpAppInfo; 00999 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 01000 { 01001 WORKREQUEST workRequest; 01002 struct WORKREQ_FTPGETCURRENTDIRECTORYW *req; 01003 01004 workRequest.asyncproc = AsyncFtpGetCurrentDirectoryProc; 01005 workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); 01006 req = &workRequest.u.FtpGetCurrentDirectoryW; 01007 req->lpszDirectory = lpszCurrentDirectory; 01008 req->lpdwDirectory = lpdwCurrentDirectory; 01009 01010 r = res_to_le(INTERNET_AsyncCall(&workRequest)); 01011 } 01012 else 01013 { 01014 r = FTP_FtpGetCurrentDirectoryW(lpwfs, lpszCurrentDirectory, 01015 lpdwCurrentDirectory); 01016 } 01017 01018 lend: 01019 if( lpwfs ) 01020 WININET_Release( &lpwfs->hdr ); 01021 01022 return r; 01023 } 01024 01025 01026 /*********************************************************************** 01027 * FTP_FtpGetCurrentDirectoryW (Internal) 01028 * 01029 * Retrieves the current directory 01030 * 01031 * RETURNS 01032 * TRUE on success 01033 * FALSE on failure 01034 * 01035 */ 01036 static BOOL FTP_FtpGetCurrentDirectoryW(ftp_session_t *lpwfs, LPWSTR lpszCurrentDirectory, 01037 LPDWORD lpdwCurrentDirectory) 01038 { 01039 INT nResCode; 01040 appinfo_t *hIC = NULL; 01041 DWORD bSuccess = FALSE; 01042 01043 /* Clear any error information */ 01044 INTERNET_SetLastError(0); 01045 01046 hIC = lpwfs->lpAppInfo; 01047 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL, 01048 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext)) 01049 goto lend; 01050 01051 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 01052 if (nResCode) 01053 { 01054 if (nResCode == 257) /* Extract directory name */ 01055 { 01056 DWORD firstpos, lastpos, len; 01057 LPWSTR lpszResponseBuffer = heap_strdupAtoW(INTERNET_GetResponseBuffer()); 01058 01059 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++) 01060 { 01061 if ('"' == lpszResponseBuffer[lastpos]) 01062 { 01063 if (!firstpos) 01064 firstpos = lastpos; 01065 else 01066 break; 01067 } 01068 } 01069 len = lastpos - firstpos; 01070 if (*lpdwCurrentDirectory >= len) 01071 { 01072 memcpy(lpszCurrentDirectory, &lpszResponseBuffer[firstpos + 1], len * sizeof(WCHAR)); 01073 lpszCurrentDirectory[len - 1] = 0; 01074 *lpdwCurrentDirectory = len; 01075 bSuccess = TRUE; 01076 } 01077 else INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); 01078 01079 HeapFree(GetProcessHeap(), 0, lpszResponseBuffer); 01080 } 01081 else 01082 FTP_SetResponseError(nResCode); 01083 } 01084 01085 lend: 01086 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 01087 { 01088 INTERNET_ASYNC_RESULT iar; 01089 01090 iar.dwResult = bSuccess; 01091 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR; 01092 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, 01093 &iar, sizeof(INTERNET_ASYNC_RESULT)); 01094 } 01095 01096 return bSuccess; 01097 } 01098 01099 01100 /*********************************************************************** 01101 * FTPFILE_Destroy(internal) 01102 * 01103 * Closes the file transfer handle. This also 'cleans' the data queue of 01104 * the 'transfer complete' message (this is a bit of a hack though :-/ ) 01105 * 01106 */ 01107 static void FTPFILE_Destroy(object_header_t *hdr) 01108 { 01109 ftp_file_t *lpwh = (ftp_file_t*) hdr; 01110 ftp_session_t *lpwfs = lpwh->lpFtpSession; 01111 INT nResCode; 01112 01113 TRACE("\n"); 01114 01115 if (lpwh->cache_file_handle != INVALID_HANDLE_VALUE) 01116 CloseHandle(lpwh->cache_file_handle); 01117 01118 HeapFree(GetProcessHeap(), 0, lpwh->cache_file); 01119 01120 if (!lpwh->session_deleted) 01121 lpwfs->download_in_progress = NULL; 01122 01123 if (lpwh->nDataSocket != -1) 01124 closesocket(lpwh->nDataSocket); 01125 01126 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 01127 if (nResCode > 0 && nResCode != 226) WARN("server reports failed transfer\n"); 01128 01129 WININET_Release(&lpwh->lpFtpSession->hdr); 01130 } 01131 01132 static DWORD FTPFILE_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) 01133 { 01134 switch(option) { 01135 case INTERNET_OPTION_HANDLE_TYPE: 01136 TRACE("INTERNET_OPTION_HANDLE_TYPE\n"); 01137 01138 if (*size < sizeof(ULONG)) 01139 return ERROR_INSUFFICIENT_BUFFER; 01140 01141 *size = sizeof(DWORD); 01142 *(DWORD*)buffer = INTERNET_HANDLE_TYPE_FTP_FILE; 01143 return ERROR_SUCCESS; 01144 case INTERNET_OPTION_DATAFILE_NAME: 01145 { 01146 DWORD required; 01147 ftp_file_t *file = (ftp_file_t *)hdr; 01148 01149 TRACE("INTERNET_OPTION_DATAFILE_NAME\n"); 01150 01151 if (!file->cache_file) 01152 { 01153 *size = 0; 01154 return ERROR_INTERNET_ITEM_NOT_FOUND; 01155 } 01156 if (unicode) 01157 { 01158 required = (lstrlenW(file->cache_file) + 1) * sizeof(WCHAR); 01159 if (*size < required) 01160 return ERROR_INSUFFICIENT_BUFFER; 01161 01162 *size = required; 01163 memcpy(buffer, file->cache_file, *size); 01164 return ERROR_SUCCESS; 01165 } 01166 else 01167 { 01168 required = WideCharToMultiByte(CP_ACP, 0, file->cache_file, -1, NULL, 0, NULL, NULL); 01169 if (required > *size) 01170 return ERROR_INSUFFICIENT_BUFFER; 01171 01172 *size = WideCharToMultiByte(CP_ACP, 0, file->cache_file, -1, buffer, *size, NULL, NULL); 01173 return ERROR_SUCCESS; 01174 } 01175 } 01176 } 01177 return INET_QueryOption(hdr, option, buffer, size, unicode); 01178 } 01179 01180 static DWORD FTPFILE_ReadFile(object_header_t *hdr, void *buffer, DWORD size, DWORD *read) 01181 { 01182 ftp_file_t *file = (ftp_file_t*)hdr; 01183 int res; 01184 DWORD error; 01185 01186 if (file->nDataSocket == -1) 01187 return ERROR_INTERNET_DISCONNECTED; 01188 01189 /* FIXME: FTP should use NETCON_ stuff */ 01190 res = recv(file->nDataSocket, buffer, size, MSG_WAITALL); 01191 *read = res>0 ? res : 0; 01192 01193 error = res >= 0 ? ERROR_SUCCESS : INTERNET_ERROR_BASE; /* FIXME */ 01194 if (error == ERROR_SUCCESS && file->cache_file) 01195 { 01196 DWORD bytes_written; 01197 01198 if (!WriteFile(file->cache_file_handle, buffer, *read, &bytes_written, NULL)) 01199 WARN("WriteFile failed: %u\n", GetLastError()); 01200 } 01201 return error; 01202 } 01203 01204 static DWORD FTPFILE_ReadFileExA(object_header_t *hdr, INTERNET_BUFFERSA *buffers, 01205 DWORD flags, DWORD_PTR context) 01206 { 01207 return FTPFILE_ReadFile(hdr, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength); 01208 } 01209 01210 static DWORD FTPFILE_ReadFileExW(object_header_t *hdr, INTERNET_BUFFERSW *buffers, 01211 DWORD flags, DWORD_PTR context) 01212 { 01213 return FTPFILE_ReadFile(hdr, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength); 01214 } 01215 01216 static DWORD FTPFILE_WriteFile(object_header_t *hdr, const void *buffer, DWORD size, DWORD *written) 01217 { 01218 ftp_file_t *lpwh = (ftp_file_t*) hdr; 01219 int res; 01220 01221 res = send(lpwh->nDataSocket, buffer, size, 0); 01222 01223 *written = res>0 ? res : 0; 01224 return res >= 0 ? ERROR_SUCCESS : sock_get_error(errno); 01225 } 01226 01227 static void FTP_ReceiveRequestData(ftp_file_t *file, BOOL first_notif) 01228 { 01229 INTERNET_ASYNC_RESULT iar; 01230 BYTE buffer[4096]; 01231 int available; 01232 01233 TRACE("%p\n", file); 01234 01235 available = recv(file->nDataSocket, buffer, sizeof(buffer), MSG_PEEK); 01236 01237 if(available != -1) { 01238 iar.dwResult = (DWORD_PTR)file->hdr.hInternet; 01239 iar.dwError = first_notif ? 0 : available; 01240 }else { 01241 iar.dwResult = 0; 01242 iar.dwError = INTERNET_GetLastError(); 01243 } 01244 01245 INTERNET_SendCallback(&file->hdr, file->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar, 01246 sizeof(INTERNET_ASYNC_RESULT)); 01247 } 01248 01249 static void FTPFILE_AsyncQueryDataAvailableProc(WORKREQUEST *workRequest) 01250 { 01251 ftp_file_t *file = (ftp_file_t*)workRequest->hdr; 01252 01253 FTP_ReceiveRequestData(file, FALSE); 01254 } 01255 01256 static DWORD FTPFILE_QueryDataAvailable(object_header_t *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx) 01257 { 01258 ftp_file_t *file = (ftp_file_t*) hdr; 01259 int retval, unread = 0; 01260 01261 TRACE("(%p %p %x %lx)\n", file, available, flags, ctx); 01262 01263 #ifdef FIONREAD 01264 retval = ioctlsocket(file->nDataSocket, FIONREAD, &unread); 01265 if (!retval) 01266 TRACE("%d bytes of queued, but unread data\n", unread); 01267 #else 01268 FIXME("FIONREAD not available\n"); 01269 #endif 01270 01271 *available = unread; 01272 01273 if(!unread) { 01274 BYTE byte; 01275 01276 *available = 0; 01277 01278 retval = recv(file->nDataSocket, &byte, 1, MSG_PEEK); 01279 if(retval > 0) { 01280 WORKREQUEST workRequest; 01281 01282 *available = 0; 01283 workRequest.asyncproc = FTPFILE_AsyncQueryDataAvailableProc; 01284 workRequest.hdr = WININET_AddRef( &file->hdr ); 01285 01286 INTERNET_AsyncCall(&workRequest); 01287 01288 return ERROR_IO_PENDING; 01289 } 01290 } 01291 01292 return ERROR_SUCCESS; 01293 } 01294 01295 01296 static const object_vtbl_t FTPFILEVtbl = { 01297 FTPFILE_Destroy, 01298 NULL, 01299 FTPFILE_QueryOption, 01300 NULL, 01301 FTPFILE_ReadFile, 01302 FTPFILE_ReadFileExA, 01303 FTPFILE_ReadFileExW, 01304 FTPFILE_WriteFile, 01305 FTPFILE_QueryDataAvailable, 01306 NULL 01307 }; 01308 01309 /*********************************************************************** 01310 * FTP_FtpOpenFileW (Internal) 01311 * 01312 * Open a remote file for writing or reading 01313 * 01314 * RETURNS 01315 * HINTERNET handle on success 01316 * NULL on failure 01317 * 01318 */ 01319 static HINTERNET FTP_FtpOpenFileW(ftp_session_t *lpwfs, 01320 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags, 01321 DWORD_PTR dwContext) 01322 { 01323 INT nDataSocket; 01324 BOOL bSuccess = FALSE; 01325 ftp_file_t *lpwh = NULL; 01326 appinfo_t *hIC = NULL; 01327 01328 TRACE("\n"); 01329 01330 /* Clear any error information */ 01331 INTERNET_SetLastError(0); 01332 01333 if (GENERIC_READ == fdwAccess) 01334 { 01335 /* Set up socket to retrieve data */ 01336 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags); 01337 } 01338 else if (GENERIC_WRITE == fdwAccess) 01339 { 01340 /* Set up socket to send data */ 01341 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags); 01342 } 01343 01344 /* Get data socket to server */ 01345 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket)) 01346 { 01347 lpwh = alloc_object(&lpwfs->hdr, &FTPFILEVtbl, sizeof(ftp_file_t)); 01348 lpwh->hdr.htype = WH_HFILE; 01349 lpwh->hdr.dwFlags = dwFlags; 01350 lpwh->hdr.dwContext = dwContext; 01351 lpwh->nDataSocket = nDataSocket; 01352 lpwh->cache_file = NULL; 01353 lpwh->cache_file_handle = INVALID_HANDLE_VALUE; 01354 lpwh->session_deleted = FALSE; 01355 01356 WININET_AddRef( &lpwfs->hdr ); 01357 lpwh->lpFtpSession = lpwfs; 01358 list_add_head( &lpwfs->hdr.children, &lpwh->hdr.entry ); 01359 01360 /* Indicate that a download is currently in progress */ 01361 lpwfs->download_in_progress = lpwh; 01362 } 01363 01364 if (lpwfs->lstnSocket != -1) 01365 { 01366 closesocket(lpwfs->lstnSocket); 01367 lpwfs->lstnSocket = -1; 01368 } 01369 01370 if (bSuccess && fdwAccess == GENERIC_READ) 01371 { 01372 WCHAR filename[MAX_PATH + 1]; 01373 URL_COMPONENTSW uc; 01374 DWORD len; 01375 01376 memset(&uc, 0, sizeof(uc)); 01377 uc.dwStructSize = sizeof(uc); 01378 uc.nScheme = INTERNET_SCHEME_FTP; 01379 uc.lpszHostName = lpwfs->servername; 01380 uc.nPort = lpwfs->serverport; 01381 uc.lpszUserName = lpwfs->lpszUserName; 01382 uc.lpszUrlPath = heap_strdupW(lpszFileName); 01383 01384 if (!InternetCreateUrlW(&uc, 0, NULL, &len) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) 01385 { 01386 WCHAR *url = heap_alloc(len * sizeof(WCHAR)); 01387 01388 if (url && InternetCreateUrlW(&uc, 0, url, &len) && CreateUrlCacheEntryW(url, 0, NULL, filename, 0)) 01389 { 01390 lpwh->cache_file = heap_strdupW(filename); 01391 lpwh->cache_file_handle = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_READ, 01392 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 01393 if (lpwh->cache_file_handle == INVALID_HANDLE_VALUE) 01394 { 01395 WARN("Could not create cache file: %u\n", GetLastError()); 01396 HeapFree(GetProcessHeap(), 0, lpwh->cache_file); 01397 lpwh->cache_file = NULL; 01398 } 01399 } 01400 HeapFree(GetProcessHeap(), 0, url); 01401 } 01402 HeapFree(GetProcessHeap(), 0, uc.lpszUrlPath); 01403 } 01404 01405 hIC = lpwfs->lpAppInfo; 01406 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 01407 { 01408 INTERNET_ASYNC_RESULT iar; 01409 01410 if (lpwh) 01411 { 01412 iar.dwResult = (DWORD_PTR)lpwh->hdr.hInternet; 01413 iar.dwError = ERROR_SUCCESS; 01414 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED, 01415 &iar, sizeof(INTERNET_ASYNC_RESULT)); 01416 } 01417 01418 if(bSuccess) { 01419 FTP_ReceiveRequestData(lpwh, TRUE); 01420 }else { 01421 iar.dwResult = 0; 01422 iar.dwError = INTERNET_GetLastError(); 01423 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, 01424 &iar, sizeof(INTERNET_ASYNC_RESULT)); 01425 } 01426 } 01427 01428 if(!bSuccess) { 01429 if(lpwh) 01430 WININET_Release( &lpwh->hdr ); 01431 return FALSE; 01432 } 01433 01434 return lpwh->hdr.hInternet; 01435 } 01436 01437 01438 /*********************************************************************** 01439 * FtpOpenFileA (WININET.@) 01440 * 01441 * Open a remote file for writing or reading 01442 * 01443 * RETURNS 01444 * HINTERNET handle on success 01445 * NULL on failure 01446 * 01447 */ 01448 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession, 01449 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags, 01450 DWORD_PTR dwContext) 01451 { 01452 LPWSTR lpwzFileName; 01453 HINTERNET ret; 01454 01455 lpwzFileName = heap_strdupAtoW(lpszFileName); 01456 ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext); 01457 HeapFree(GetProcessHeap(), 0, lpwzFileName); 01458 return ret; 01459 } 01460 01461 01462 static void AsyncFtpOpenFileProc(WORKREQUEST *workRequest) 01463 { 01464 struct WORKREQ_FTPOPENFILEW const *req = &workRequest->u.FtpOpenFileW; 01465 ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; 01466 01467 TRACE("%p\n", lpwfs); 01468 01469 FTP_FtpOpenFileW(lpwfs, req->lpszFilename, 01470 req->dwAccess, req->dwFlags, req->dwContext); 01471 HeapFree(GetProcessHeap(), 0, req->lpszFilename); 01472 } 01473 01474 /*********************************************************************** 01475 * FtpOpenFileW (WININET.@) 01476 * 01477 * Open a remote file for writing or reading 01478 * 01479 * RETURNS 01480 * HINTERNET handle on success 01481 * NULL on failure 01482 * 01483 */ 01484 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession, 01485 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags, 01486 DWORD_PTR dwContext) 01487 { 01488 ftp_session_t *lpwfs; 01489 appinfo_t *hIC = NULL; 01490 HINTERNET r = NULL; 01491 01492 TRACE("(%p,%s,0x%08x,0x%08x,0x%08lx)\n", hFtpSession, 01493 debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext); 01494 01495 lpwfs = (ftp_session_t*) get_handle_object( hFtpSession ); 01496 if (!lpwfs) 01497 { 01498 INTERNET_SetLastError(ERROR_INVALID_HANDLE); 01499 return FALSE; 01500 } 01501 01502 if (WH_HFTPSESSION != lpwfs->hdr.htype) 01503 { 01504 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); 01505 goto lend; 01506 } 01507 01508 if ((!lpszFileName) || 01509 ((fdwAccess != GENERIC_READ) && (fdwAccess != GENERIC_WRITE)) || 01510 ((dwFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY)) 01511 { 01512 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 01513 goto lend; 01514 } 01515 01516 if (lpwfs->download_in_progress != NULL) 01517 { 01518 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); 01519 goto lend; 01520 } 01521 01522 hIC = lpwfs->lpAppInfo; 01523 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 01524 { 01525 WORKREQUEST workRequest; 01526 struct WORKREQ_FTPOPENFILEW *req; 01527 01528 workRequest.asyncproc = AsyncFtpOpenFileProc; 01529 workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); 01530 req = &workRequest.u.FtpOpenFileW; 01531 req->lpszFilename = heap_strdupW(lpszFileName); 01532 req->dwAccess = fdwAccess; 01533 req->dwFlags = dwFlags; 01534 req->dwContext = dwContext; 01535 01536 INTERNET_AsyncCall(&workRequest); 01537 r = NULL; 01538 } 01539 else 01540 { 01541 r = FTP_FtpOpenFileW(lpwfs, lpszFileName, fdwAccess, dwFlags, dwContext); 01542 } 01543 01544 lend: 01545 WININET_Release( &lpwfs->hdr ); 01546 01547 return r; 01548 } 01549 01550 01551 /*********************************************************************** 01552 * FtpGetFileA (WININET.@) 01553 * 01554 * Retrieve file from the FTP server 01555 * 01556 * RETURNS 01557 * TRUE on success 01558 * FALSE on failure 01559 * 01560 */ 01561 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile, 01562 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags, 01563 DWORD_PTR dwContext) 01564 { 01565 LPWSTR lpwzRemoteFile; 01566 LPWSTR lpwzNewFile; 01567 BOOL ret; 01568 01569 lpwzRemoteFile = heap_strdupAtoW(lpszRemoteFile); 01570 lpwzNewFile = heap_strdupAtoW(lpszNewFile); 01571 ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists, 01572 dwLocalFlagsAttribute, dwInternetFlags, dwContext); 01573 HeapFree(GetProcessHeap(), 0, lpwzRemoteFile); 01574 HeapFree(GetProcessHeap(), 0, lpwzNewFile); 01575 return ret; 01576 } 01577 01578 01579 static void AsyncFtpGetFileProc(WORKREQUEST *workRequest) 01580 { 01581 struct WORKREQ_FTPGETFILEW const *req = &workRequest->u.FtpGetFileW; 01582 ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; 01583 01584 TRACE("%p\n", lpwfs); 01585 01586 FTP_FtpGetFileW(lpwfs, req->lpszRemoteFile, 01587 req->lpszNewFile, req->fFailIfExists, 01588 req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext); 01589 HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile); 01590 HeapFree(GetProcessHeap(), 0, req->lpszNewFile); 01591 } 01592 01593 01594 /*********************************************************************** 01595 * FtpGetFileW (WININET.@) 01596 * 01597 * Retrieve file from the FTP server 01598 * 01599 * RETURNS 01600 * TRUE on success 01601 * FALSE on failure 01602 * 01603 */ 01604 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile, 01605 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags, 01606 DWORD_PTR dwContext) 01607 { 01608 ftp_session_t *lpwfs; 01609 appinfo_t *hIC = NULL; 01610 BOOL r = FALSE; 01611 01612 if (!lpszRemoteFile || !lpszNewFile) 01613 { 01614 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 01615 return FALSE; 01616 } 01617 01618 lpwfs = (ftp_session_t*) get_handle_object( hInternet ); 01619 if (!lpwfs) 01620 { 01621 INTERNET_SetLastError(ERROR_INVALID_HANDLE); 01622 return FALSE; 01623 } 01624 01625 if (WH_HFTPSESSION != lpwfs->hdr.htype) 01626 { 01627 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); 01628 goto lend; 01629 } 01630 01631 if ((dwInternetFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY) 01632 { 01633 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 01634 goto lend; 01635 } 01636 01637 if (lpwfs->download_in_progress != NULL) 01638 { 01639 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); 01640 goto lend; 01641 } 01642 01643 hIC = lpwfs->lpAppInfo; 01644 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 01645 { 01646 WORKREQUEST workRequest; 01647 struct WORKREQ_FTPGETFILEW *req; 01648 01649 workRequest.asyncproc = AsyncFtpGetFileProc; 01650 workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); 01651 req = &workRequest.u.FtpGetFileW; 01652 req->lpszRemoteFile = heap_strdupW(lpszRemoteFile); 01653 req->lpszNewFile = heap_strdupW(lpszNewFile); 01654 req->dwLocalFlagsAttribute = dwLocalFlagsAttribute; 01655 req->fFailIfExists = fFailIfExists; 01656 req->dwFlags = dwInternetFlags; 01657 req->dwContext = dwContext; 01658 01659 r = res_to_le(INTERNET_AsyncCall(&workRequest)); 01660 } 01661 else 01662 { 01663 r = FTP_FtpGetFileW(lpwfs, lpszRemoteFile, lpszNewFile, 01664 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext); 01665 } 01666 01667 lend: 01668 WININET_Release( &lpwfs->hdr ); 01669 01670 return r; 01671 } 01672 01673 01674 /*********************************************************************** 01675 * FTP_FtpGetFileW (Internal) 01676 * 01677 * Retrieve file from the FTP server 01678 * 01679 * RETURNS 01680 * TRUE on success 01681 * FALSE on failure 01682 * 01683 */ 01684 static BOOL FTP_FtpGetFileW(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile, 01685 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags, 01686 DWORD_PTR dwContext) 01687 { 01688 BOOL bSuccess = FALSE; 01689 HANDLE hFile; 01690 appinfo_t *hIC = NULL; 01691 01692 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile)); 01693 01694 /* Clear any error information */ 01695 INTERNET_SetLastError(0); 01696 01697 /* Ensure we can write to lpszNewfile by opening it */ 01698 hFile = CreateFileW(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ? 01699 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0); 01700 if (INVALID_HANDLE_VALUE == hFile) 01701 return FALSE; 01702 01703 /* Set up socket to retrieve data */ 01704 if (FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags)) 01705 { 01706 INT nDataSocket; 01707 01708 /* Get data socket to server */ 01709 if (FTP_GetDataSocket(lpwfs, &nDataSocket)) 01710 { 01711 INT nResCode; 01712 01713 /* Receive data */ 01714 FTP_RetrieveFileData(lpwfs, nDataSocket, hFile); 01715 closesocket(nDataSocket); 01716 01717 nResCode = FTP_ReceiveResponse(lpwfs, dwContext); 01718 if (nResCode) 01719 { 01720 if (nResCode == 226) 01721 bSuccess = TRUE; 01722 else 01723 FTP_SetResponseError(nResCode); 01724 } 01725 } 01726 } 01727 01728 if (lpwfs->lstnSocket != -1) 01729 { 01730 closesocket(lpwfs->lstnSocket); 01731 lpwfs->lstnSocket = -1; 01732 } 01733 01734 CloseHandle(hFile); 01735 01736 hIC = lpwfs->lpAppInfo; 01737 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 01738 { 01739 INTERNET_ASYNC_RESULT iar; 01740 01741 iar.dwResult = (DWORD)bSuccess; 01742 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); 01743 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, 01744 &iar, sizeof(INTERNET_ASYNC_RESULT)); 01745 } 01746 01747 if (!bSuccess) DeleteFileW(lpszNewFile); 01748 return bSuccess; 01749 } 01750 01751 /*********************************************************************** 01752 * FtpGetFileSize (WININET.@) 01753 */ 01754 DWORD WINAPI FtpGetFileSize( HINTERNET hFile, LPDWORD lpdwFileSizeHigh ) 01755 { 01756 FIXME("(%p, %p)\n", hFile, lpdwFileSizeHigh); 01757 01758 if (lpdwFileSizeHigh) 01759 *lpdwFileSizeHigh = 0; 01760 01761 return 0; 01762 } 01763 01764 /*********************************************************************** 01765 * FtpDeleteFileA (WININET.@) 01766 * 01767 * Delete a file on the ftp server 01768 * 01769 * RETURNS 01770 * TRUE on success 01771 * FALSE on failure 01772 * 01773 */ 01774 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName) 01775 { 01776 LPWSTR lpwzFileName; 01777 BOOL ret; 01778 01779 lpwzFileName = heap_strdupAtoW(lpszFileName); 01780 ret = FtpDeleteFileW(hFtpSession, lpwzFileName); 01781 HeapFree(GetProcessHeap(), 0, lpwzFileName); 01782 return ret; 01783 } 01784 01785 static void AsyncFtpDeleteFileProc(WORKREQUEST *workRequest) 01786 { 01787 struct WORKREQ_FTPDELETEFILEW const *req = &workRequest->u.FtpDeleteFileW; 01788 ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; 01789 01790 TRACE("%p\n", lpwfs); 01791 01792 FTP_FtpDeleteFileW(lpwfs, req->lpszFilename); 01793 HeapFree(GetProcessHeap(), 0, req->lpszFilename); 01794 } 01795 01796 /*********************************************************************** 01797 * FtpDeleteFileW (WININET.@) 01798 * 01799 * Delete a file on the ftp server 01800 * 01801 * RETURNS 01802 * TRUE on success 01803 * FALSE on failure 01804 * 01805 */ 01806 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName) 01807 { 01808 ftp_session_t *lpwfs; 01809 appinfo_t *hIC = NULL; 01810 BOOL r = FALSE; 01811 01812 lpwfs = (ftp_session_t*) get_handle_object( hFtpSession ); 01813 if (!lpwfs) 01814 { 01815 INTERNET_SetLastError(ERROR_INVALID_HANDLE); 01816 return FALSE; 01817 } 01818 01819 if (WH_HFTPSESSION != lpwfs->hdr.htype) 01820 { 01821 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); 01822 goto lend; 01823 } 01824 01825 if (lpwfs->download_in_progress != NULL) 01826 { 01827 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); 01828 goto lend; 01829 } 01830 01831 if (!lpszFileName) 01832 { 01833 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 01834 goto lend; 01835 } 01836 01837 hIC = lpwfs->lpAppInfo; 01838 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 01839 { 01840 WORKREQUEST workRequest; 01841 struct WORKREQ_FTPDELETEFILEW *req; 01842 01843 workRequest.asyncproc = AsyncFtpDeleteFileProc; 01844 workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); 01845 req = &workRequest.u.FtpDeleteFileW; 01846 req->lpszFilename = heap_strdupW(lpszFileName); 01847 01848 r = res_to_le(INTERNET_AsyncCall(&workRequest)); 01849 } 01850 else 01851 { 01852 r = FTP_FtpDeleteFileW(lpwfs, lpszFileName); 01853 } 01854 01855 lend: 01856 WININET_Release( &lpwfs->hdr ); 01857 01858 return r; 01859 } 01860 01861 /*********************************************************************** 01862 * FTP_FtpDeleteFileW (Internal) 01863 * 01864 * Delete a file on the ftp server 01865 * 01866 * RETURNS 01867 * TRUE on success 01868 * FALSE on failure 01869 * 01870 */ 01871 BOOL FTP_FtpDeleteFileW(ftp_session_t *lpwfs, LPCWSTR lpszFileName) 01872 { 01873 INT nResCode; 01874 BOOL bSuccess = FALSE; 01875 appinfo_t *hIC = NULL; 01876 01877 TRACE("%p\n", lpwfs); 01878 01879 /* Clear any error information */ 01880 INTERNET_SetLastError(0); 01881 01882 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0)) 01883 goto lend; 01884 01885 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 01886 if (nResCode) 01887 { 01888 if (nResCode == 250) 01889 bSuccess = TRUE; 01890 else 01891 FTP_SetResponseError(nResCode); 01892 } 01893 lend: 01894 hIC = lpwfs->lpAppInfo; 01895 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 01896 { 01897 INTERNET_ASYNC_RESULT iar; 01898 01899 iar.dwResult = (DWORD)bSuccess; 01900 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); 01901 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, 01902 &iar, sizeof(INTERNET_ASYNC_RESULT)); 01903 } 01904 01905 return bSuccess; 01906 } 01907 01908 01909 /*********************************************************************** 01910 * FtpRemoveDirectoryA (WININET.@) 01911 * 01912 * Remove a directory on the ftp server 01913 * 01914 * RETURNS 01915 * TRUE on success 01916 * FALSE on failure 01917 * 01918 */ 01919 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory) 01920 { 01921 LPWSTR lpwzDirectory; 01922 BOOL ret; 01923 01924 lpwzDirectory = heap_strdupAtoW(lpszDirectory); 01925 ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory); 01926 HeapFree(GetProcessHeap(), 0, lpwzDirectory); 01927 return ret; 01928 } 01929 01930 static void AsyncFtpRemoveDirectoryProc(WORKREQUEST *workRequest) 01931 { 01932 struct WORKREQ_FTPREMOVEDIRECTORYW const *req = &workRequest->u.FtpRemoveDirectoryW; 01933 ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; 01934 01935 TRACE("%p\n", lpwfs); 01936 01937 FTP_FtpRemoveDirectoryW(lpwfs, req->lpszDirectory); 01938 HeapFree(GetProcessHeap(), 0, req->lpszDirectory); 01939 } 01940 01941 /*********************************************************************** 01942 * FtpRemoveDirectoryW (WININET.@) 01943 * 01944 * Remove a directory on the ftp server 01945 * 01946 * RETURNS 01947 * TRUE on success 01948 * FALSE on failure 01949 * 01950 */ 01951 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory) 01952 { 01953 ftp_session_t *lpwfs; 01954 appinfo_t *hIC = NULL; 01955 BOOL r = FALSE; 01956 01957 lpwfs = (ftp_session_t*) get_handle_object( hFtpSession ); 01958 if (!lpwfs) 01959 { 01960 INTERNET_SetLastError(ERROR_INVALID_HANDLE); 01961 return FALSE; 01962 } 01963 01964 if (WH_HFTPSESSION != lpwfs->hdr.htype) 01965 { 01966 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); 01967 goto lend; 01968 } 01969 01970 if (lpwfs->download_in_progress != NULL) 01971 { 01972 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); 01973 goto lend; 01974 } 01975 01976 if (!lpszDirectory) 01977 { 01978 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 01979 goto lend; 01980 } 01981 01982 hIC = lpwfs->lpAppInfo; 01983 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 01984 { 01985 WORKREQUEST workRequest; 01986 struct WORKREQ_FTPREMOVEDIRECTORYW *req; 01987 01988 workRequest.asyncproc = AsyncFtpRemoveDirectoryProc; 01989 workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); 01990 req = &workRequest.u.FtpRemoveDirectoryW; 01991 req->lpszDirectory = heap_strdupW(lpszDirectory); 01992 01993 r = res_to_le(INTERNET_AsyncCall(&workRequest)); 01994 } 01995 else 01996 { 01997 r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory); 01998 } 01999 02000 lend: 02001 WININET_Release( &lpwfs->hdr ); 02002 02003 return r; 02004 } 02005 02006 /*********************************************************************** 02007 * FTP_FtpRemoveDirectoryW (Internal) 02008 * 02009 * Remove a directory on the ftp server 02010 * 02011 * RETURNS 02012 * TRUE on success 02013 * FALSE on failure 02014 * 02015 */ 02016 BOOL FTP_FtpRemoveDirectoryW(ftp_session_t *lpwfs, LPCWSTR lpszDirectory) 02017 { 02018 INT nResCode; 02019 BOOL bSuccess = FALSE; 02020 appinfo_t *hIC = NULL; 02021 02022 TRACE("\n"); 02023 02024 /* Clear any error information */ 02025 INTERNET_SetLastError(0); 02026 02027 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0)) 02028 goto lend; 02029 02030 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 02031 if (nResCode) 02032 { 02033 if (nResCode == 250) 02034 bSuccess = TRUE; 02035 else 02036 FTP_SetResponseError(nResCode); 02037 } 02038 02039 lend: 02040 hIC = lpwfs->lpAppInfo; 02041 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 02042 { 02043 INTERNET_ASYNC_RESULT iar; 02044 02045 iar.dwResult = (DWORD)bSuccess; 02046 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); 02047 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, 02048 &iar, sizeof(INTERNET_ASYNC_RESULT)); 02049 } 02050 02051 return bSuccess; 02052 } 02053 02054 02055 /*********************************************************************** 02056 * FtpRenameFileA (WININET.@) 02057 * 02058 * Rename a file on the ftp server 02059 * 02060 * RETURNS 02061 * TRUE on success 02062 * FALSE on failure 02063 * 02064 */ 02065 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest) 02066 { 02067 LPWSTR lpwzSrc; 02068 LPWSTR lpwzDest; 02069 BOOL ret; 02070 02071 lpwzSrc = heap_strdupAtoW(lpszSrc); 02072 lpwzDest = heap_strdupAtoW(lpszDest); 02073 ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest); 02074 HeapFree(GetProcessHeap(), 0, lpwzSrc); 02075 HeapFree(GetProcessHeap(), 0, lpwzDest); 02076 return ret; 02077 } 02078 02079 static void AsyncFtpRenameFileProc(WORKREQUEST *workRequest) 02080 { 02081 struct WORKREQ_FTPRENAMEFILEW const *req = &workRequest->u.FtpRenameFileW; 02082 ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; 02083 02084 TRACE("%p\n", lpwfs); 02085 02086 FTP_FtpRenameFileW(lpwfs, req->lpszSrcFile, req->lpszDestFile); 02087 HeapFree(GetProcessHeap(), 0, req->lpszSrcFile); 02088 HeapFree(GetProcessHeap(), 0, req->lpszDestFile); 02089 } 02090 02091 /*********************************************************************** 02092 * FtpRenameFileW (WININET.@) 02093 * 02094 * Rename a file on the ftp server 02095 * 02096 * RETURNS 02097 * TRUE on success 02098 * FALSE on failure 02099 * 02100 */ 02101 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest) 02102 { 02103 ftp_session_t *lpwfs; 02104 appinfo_t *hIC = NULL; 02105 BOOL r = FALSE; 02106 02107 lpwfs = (ftp_session_t*) get_handle_object( hFtpSession ); 02108 if (!lpwfs) 02109 { 02110 INTERNET_SetLastError(ERROR_INVALID_HANDLE); 02111 return FALSE; 02112 } 02113 02114 if (WH_HFTPSESSION != lpwfs->hdr.htype) 02115 { 02116 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); 02117 goto lend; 02118 } 02119 02120 if (lpwfs->download_in_progress != NULL) 02121 { 02122 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); 02123 goto lend; 02124 } 02125 02126 if (!lpszSrc || !lpszDest) 02127 { 02128 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 02129 goto lend; 02130 } 02131 02132 hIC = lpwfs->lpAppInfo; 02133 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 02134 { 02135 WORKREQUEST workRequest; 02136 struct WORKREQ_FTPRENAMEFILEW *req; 02137 02138 workRequest.asyncproc = AsyncFtpRenameFileProc; 02139 workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); 02140 req = &workRequest.u.FtpRenameFileW; 02141 req->lpszSrcFile = heap_strdupW(lpszSrc); 02142 req->lpszDestFile = heap_strdupW(lpszDest); 02143 02144 r = res_to_le(INTERNET_AsyncCall(&workRequest)); 02145 } 02146 else 02147 { 02148 r = FTP_FtpRenameFileW(lpwfs, lpszSrc, lpszDest); 02149 } 02150 02151 lend: 02152 WININET_Release( &lpwfs->hdr ); 02153 02154 return r; 02155 } 02156 02157 /*********************************************************************** 02158 * FTP_FtpRenameFileW (Internal) 02159 * 02160 * Rename a file on the ftp server 02161 * 02162 * RETURNS 02163 * TRUE on success 02164 * FALSE on failure 02165 * 02166 */ 02167 BOOL FTP_FtpRenameFileW(ftp_session_t *lpwfs, LPCWSTR lpszSrc, LPCWSTR lpszDest) 02168 { 02169 INT nResCode; 02170 BOOL bSuccess = FALSE; 02171 appinfo_t *hIC = NULL; 02172 02173 TRACE("\n"); 02174 02175 /* Clear any error information */ 02176 INTERNET_SetLastError(0); 02177 02178 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0)) 02179 goto lend; 02180 02181 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 02182 if (nResCode == 350) 02183 { 02184 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0)) 02185 goto lend; 02186 02187 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 02188 } 02189 02190 if (nResCode == 250) 02191 bSuccess = TRUE; 02192 else 02193 FTP_SetResponseError(nResCode); 02194 02195 lend: 02196 hIC = lpwfs->lpAppInfo; 02197 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) 02198 { 02199 INTERNET_ASYNC_RESULT iar; 02200 02201 iar.dwResult = (DWORD)bSuccess; 02202 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); 02203 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, 02204 &iar, sizeof(INTERNET_ASYNC_RESULT)); 02205 } 02206 02207 return bSuccess; 02208 } 02209 02210 /*********************************************************************** 02211 * FtpCommandA (WININET.@) 02212 */ 02213 BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags, 02214 LPCSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand ) 02215 { 02216 BOOL r; 02217 WCHAR *cmdW; 02218 02219 TRACE("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags, 02220 debugstr_a(lpszCommand), dwContext, phFtpCommand); 02221 02222 if (fExpectResponse) 02223 { 02224 FIXME("data connection not supported\n"); 02225 return FALSE; 02226 } 02227 02228 if (!lpszCommand || !lpszCommand[0]) 02229 { 02230 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 02231 return FALSE; 02232 } 02233 02234 if (!(cmdW = heap_strdupAtoW(lpszCommand))) 02235 { 02236 INTERNET_SetLastError(ERROR_OUTOFMEMORY); 02237 return FALSE; 02238 } 02239 02240 r = FtpCommandW(hConnect, fExpectResponse, dwFlags, cmdW, dwContext, phFtpCommand); 02241 02242 HeapFree(GetProcessHeap(), 0, cmdW); 02243 return r; 02244 } 02245 02246 /*********************************************************************** 02247 * FtpCommandW (WININET.@) 02248 */ 02249 BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags, 02250 LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand ) 02251 { 02252 BOOL r = FALSE; 02253 ftp_session_t *lpwfs; 02254 LPSTR cmd = NULL; 02255 DWORD len, nBytesSent= 0; 02256 INT nResCode, nRC = 0; 02257 02258 TRACE("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags, 02259 debugstr_w(lpszCommand), dwContext, phFtpCommand); 02260 02261 if (!lpszCommand || !lpszCommand[0]) 02262 { 02263 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 02264 return FALSE; 02265 } 02266 02267 if (fExpectResponse) 02268 { 02269 FIXME("data connection not supported\n"); 02270 return FALSE; 02271 } 02272 02273 lpwfs = (ftp_session_t*) get_handle_object( hConnect ); 02274 if (!lpwfs) 02275 { 02276 INTERNET_SetLastError(ERROR_INVALID_HANDLE); 02277 return FALSE; 02278 } 02279 02280 if (WH_HFTPSESSION != lpwfs->hdr.htype) 02281 { 02282 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); 02283 goto lend; 02284 } 02285 02286 if (lpwfs->download_in_progress != NULL) 02287 { 02288 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); 02289 goto lend; 02290 } 02291 02292 len = WideCharToMultiByte(CP_ACP, 0, lpszCommand, -1, NULL, 0, NULL, NULL) + strlen(szCRLF); 02293 if ((cmd = heap_alloc(len))) 02294 WideCharToMultiByte(CP_ACP, 0, lpszCommand, -1, cmd, len, NULL, NULL); 02295 else 02296 { 02297 INTERNET_SetLastError(ERROR_OUTOFMEMORY); 02298 goto lend; 02299 } 02300 02301 strcat(cmd, szCRLF); 02302 len--; 02303 02304 TRACE("Sending (%s) len(%d)\n", cmd, len); 02305 while ((nBytesSent < len) && (nRC != -1)) 02306 { 02307 nRC = send(lpwfs->sndSocket, cmd + nBytesSent, len - nBytesSent, 0); 02308 if (nRC != -1) 02309 { 02310 nBytesSent += nRC; 02311 TRACE("Sent %d bytes\n", nRC); 02312 } 02313 } 02314 02315 if (nBytesSent) 02316 { 02317 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 02318 if (nResCode > 0 && nResCode < 400) 02319 r = TRUE; 02320 else 02321 FTP_SetResponseError(nResCode); 02322 } 02323 02324 lend: 02325 WININET_Release( &lpwfs->hdr ); 02326 HeapFree(GetProcessHeap(), 0, cmd); 02327 return r; 02328 } 02329 02330 02331 /*********************************************************************** 02332 * FTPSESSION_Destroy (internal) 02333 * 02334 * Deallocate session handle 02335 */ 02336 static void FTPSESSION_Destroy(object_header_t *hdr) 02337 { 02338 ftp_session_t *lpwfs = (ftp_session_t*) hdr; 02339 02340 TRACE("\n"); 02341 02342 WININET_Release(&lpwfs->lpAppInfo->hdr); 02343 02344 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword); 02345 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName); 02346 HeapFree(GetProcessHeap(), 0, lpwfs->servername); 02347 } 02348 02349 static void FTPSESSION_CloseConnection(object_header_t *hdr) 02350 { 02351 ftp_session_t *lpwfs = (ftp_session_t*) hdr; 02352 02353 TRACE("\n"); 02354 02355 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, 02356 INTERNET_STATUS_CLOSING_CONNECTION, 0, 0); 02357 02358 if (lpwfs->download_in_progress != NULL) 02359 lpwfs->download_in_progress->session_deleted = TRUE; 02360 02361 if (lpwfs->sndSocket != -1) 02362 closesocket(lpwfs->sndSocket); 02363 02364 if (lpwfs->lstnSocket != -1) 02365 closesocket(lpwfs->lstnSocket); 02366 02367 if (lpwfs->pasvSocket != -1) 02368 closesocket(lpwfs->pasvSocket); 02369 02370 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, 02371 INTERNET_STATUS_CONNECTION_CLOSED, 0, 0); 02372 } 02373 02374 static DWORD FTPSESSION_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) 02375 { 02376 switch(option) { 02377 case INTERNET_OPTION_HANDLE_TYPE: 02378 TRACE("INTERNET_OPTION_HANDLE_TYPE\n"); 02379 02380 if (*size < sizeof(ULONG)) 02381 return ERROR_INSUFFICIENT_BUFFER; 02382 02383 *size = sizeof(DWORD); 02384 *(DWORD*)buffer = INTERNET_HANDLE_TYPE_CONNECT_FTP; 02385 return ERROR_SUCCESS; 02386 } 02387 02388 return INET_QueryOption(hdr, option, buffer, size, unicode); 02389 } 02390 02391 static const object_vtbl_t FTPSESSIONVtbl = { 02392 FTPSESSION_Destroy, 02393 FTPSESSION_CloseConnection, 02394 FTPSESSION_QueryOption, 02395 NULL, 02396 NULL, 02397 NULL, 02398 NULL, 02399 NULL, 02400 NULL 02401 }; 02402 02403 02404 /*********************************************************************** 02405 * FTP_Connect (internal) 02406 * 02407 * Connect to a ftp server 02408 * 02409 * RETURNS 02410 * HINTERNET a session handle on success 02411 * NULL on failure 02412 * 02413 * NOTES: 02414 * 02415 * Windows uses 'anonymous' as the username, when given a NULL username 02416 * and a NULL password. The password is first looked up in: 02417 * 02418 * HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\EmailName 02419 * 02420 * If this entry is not present it uses the current username as the password. 02421 * 02422 */ 02423 02424 HINTERNET FTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName, 02425 INTERNET_PORT nServerPort, LPCWSTR lpszUserName, 02426 LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext, 02427 DWORD dwInternalFlags) 02428 { 02429 static const WCHAR szKey[] = {'S','o','f','t','w','a','r','e','\\', 02430 'M','i','c','r','o','s','o','f','t','\\', 02431 'W','i','n','d','o','w','s','\\', 02432 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', 02433 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0}; 02434 static const WCHAR szValue[] = {'E','m','a','i','l','N','a','m','e',0}; 02435 static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'}; 02436 static const WCHAR szEmpty[] = {'\0'}; 02437 struct sockaddr_in socketAddr; 02438 INT nsocket = -1; 02439 UINT sock_namelen; 02440 BOOL bSuccess = FALSE; 02441 ftp_session_t *lpwfs = NULL; 02442 char szaddr[INET_ADDRSTRLEN]; 02443 02444 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n", 02445 hIC, debugstr_w(lpszServerName), 02446 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword)); 02447 02448 assert( hIC->hdr.htype == WH_HINIT ); 02449 02450 if ((!lpszUserName || !*lpszUserName) && lpszPassword && *lpszPassword) 02451 { 02452 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 02453 return NULL; 02454 } 02455 02456 lpwfs = alloc_object(&hIC->hdr, &FTPSESSIONVtbl, sizeof(ftp_session_t)); 02457 if (NULL == lpwfs) 02458 { 02459 INTERNET_SetLastError(ERROR_OUTOFMEMORY); 02460 return NULL; 02461 } 02462 02463 if (nServerPort == INTERNET_INVALID_PORT_NUMBER) 02464 lpwfs->serverport = INTERNET_DEFAULT_FTP_PORT; 02465 else 02466 lpwfs->serverport = nServerPort; 02467 02468 lpwfs->hdr.htype = WH_HFTPSESSION; 02469 lpwfs->hdr.dwFlags = dwFlags; 02470 lpwfs->hdr.dwContext = dwContext; 02471 lpwfs->hdr.dwInternalFlags |= dwInternalFlags; 02472 lpwfs->download_in_progress = NULL; 02473 lpwfs->sndSocket = -1; 02474 lpwfs->lstnSocket = -1; 02475 lpwfs->pasvSocket = -1; 02476 02477 WININET_AddRef( &hIC->hdr ); 02478 lpwfs->lpAppInfo = hIC; 02479 list_add_head( &hIC->hdr.children, &lpwfs->hdr.entry ); 02480 02481 if(hIC->proxy && hIC->accessType == INTERNET_OPEN_TYPE_PROXY) { 02482 if(strchrW(hIC->proxy, ' ')) 02483 FIXME("Several proxies not implemented.\n"); 02484 if(hIC->proxyBypass) 02485 FIXME("Proxy bypass is ignored.\n"); 02486 } 02487 if (!lpszUserName || !strlenW(lpszUserName)) { 02488 HKEY key; 02489 WCHAR szPassword[MAX_PATH]; 02490 DWORD len = sizeof(szPassword); 02491 02492 lpwfs->lpszUserName = heap_strdupW(szDefaultUsername); 02493 02494 RegOpenKeyW(HKEY_CURRENT_USER, szKey, &key); 02495 if (RegQueryValueExW(key, szValue, NULL, NULL, (LPBYTE)szPassword, &len)) { 02496 /* Nothing in the registry, get the username and use that as the password */ 02497 if (!GetUserNameW(szPassword, &len)) { 02498 /* Should never get here, but use an empty password as failsafe */ 02499 strcpyW(szPassword, szEmpty); 02500 } 02501 } 02502 RegCloseKey(key); 02503 02504 TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword)); 02505 lpwfs->lpszPassword = heap_strdupW(szPassword); 02506 } 02507 else { 02508 lpwfs->lpszUserName = heap_strdupW(lpszUserName); 02509 lpwfs->lpszPassword = heap_strdupW(lpszPassword ? lpszPassword : szEmpty); 02510 } 02511 lpwfs->servername = heap_strdupW(lpszServerName); 02512 02513 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */ 02514 if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL)) 02515 { 02516 INTERNET_ASYNC_RESULT iar; 02517 02518 iar.dwResult = (DWORD_PTR)lpwfs->hdr.hInternet; 02519 iar.dwError = ERROR_SUCCESS; 02520 02521 SendAsyncCallback(&hIC->hdr, dwContext, 02522 INTERNET_STATUS_HANDLE_CREATED, &iar, 02523 sizeof(INTERNET_ASYNC_RESULT)); 02524 } 02525 02526 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME, 02527 (LPWSTR) lpszServerName, (strlenW(lpszServerName)+1) * sizeof(WCHAR)); 02528 02529 sock_namelen = sizeof(socketAddr); 02530 if (!GetAddress(lpszServerName, lpwfs->serverport, (struct sockaddr *)&socketAddr, &sock_namelen)) 02531 { 02532 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED); 02533 goto lerror; 02534 } 02535 02536 if (socketAddr.sin_family != AF_INET) 02537 { 02538 WARN("unsupported address family %d\n", socketAddr.sin_family); 02539 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT); 02540 goto lerror; 02541 } 02542 02543 inet_ntop(socketAddr.sin_family, &socketAddr.sin_addr, szaddr, sizeof(szaddr)); 02544 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED, 02545 szaddr, strlen(szaddr)+1); 02546 02547 nsocket = socket(AF_INET,SOCK_STREAM,0); 02548 if (nsocket == -1) 02549 { 02550 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT); 02551 goto lerror; 02552 } 02553 02554 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER, 02555 szaddr, strlen(szaddr)+1); 02556 02557 if (connect(nsocket, (struct sockaddr *)&socketAddr, sock_namelen) < 0) 02558 { 02559 ERR("Unable to connect (%s)\n", strerror(errno)); 02560 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT); 02561 closesocket(nsocket); 02562 } 02563 else 02564 { 02565 TRACE("Connected to server\n"); 02566 lpwfs->sndSocket = nsocket; 02567 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER, 02568 szaddr, strlen(szaddr)+1); 02569 02570 sock_namelen = sizeof(lpwfs->socketAddress); 02571 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen); 02572 02573 if (FTP_ConnectToHost(lpwfs)) 02574 { 02575 TRACE("Successfully logged into server\n"); 02576 bSuccess = TRUE; 02577 } 02578 } 02579 02580 lerror: 02581 if (!bSuccess) 02582 { 02583 if(lpwfs) 02584 WININET_Release( &lpwfs->hdr ); 02585 return NULL; 02586 } 02587 02588 return lpwfs->hdr.hInternet; 02589 } 02590 02591 02592 /*********************************************************************** 02593 * FTP_ConnectToHost (internal) 02594 * 02595 * Connect to a ftp server 02596 * 02597 * RETURNS 02598 * TRUE on success 02599 * NULL on failure 02600 * 02601 */ 02602 static BOOL FTP_ConnectToHost(ftp_session_t *lpwfs) 02603 { 02604 INT nResCode; 02605 BOOL bSuccess = FALSE; 02606 02607 TRACE("\n"); 02608 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 02609 02610 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0)) 02611 goto lend; 02612 02613 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 02614 if (nResCode) 02615 { 02616 /* Login successful... */ 02617 if (nResCode == 230) 02618 bSuccess = TRUE; 02619 /* User name okay, need password... */ 02620 else if (nResCode == 331) 02621 bSuccess = FTP_SendPassword(lpwfs); 02622 /* Need account for login... */ 02623 else if (nResCode == 332) 02624 bSuccess = FTP_SendAccount(lpwfs); 02625 else 02626 FTP_SetResponseError(nResCode); 02627 } 02628 02629 TRACE("Returning %d\n", bSuccess); 02630 lend: 02631 return bSuccess; 02632 } 02633 02634 02635 /*********************************************************************** 02636 * FTP_SendCommandA (internal) 02637 * 02638 * Send command to server 02639 * 02640 * RETURNS 02641 * TRUE on success 02642 * NULL on failure 02643 * 02644 */ 02645 static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam, 02646 INTERNET_STATUS_CALLBACK lpfnStatusCB, object_header_t *hdr, DWORD_PTR dwContext) 02647 { 02648 DWORD len; 02649 CHAR *buf; 02650 DWORD nBytesSent = 0; 02651 int nRC = 0; 02652 DWORD dwParamLen; 02653 02654 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket); 02655 02656 if (lpfnStatusCB) 02657 { 02658 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0); 02659 } 02660 02661 dwParamLen = lpszParam?strlen(lpszParam)+1:0; 02662 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF); 02663 if (NULL == (buf = heap_alloc(len+1))) 02664 { 02665 INTERNET_SetLastError(ERROR_OUTOFMEMORY); 02666 return FALSE; 02667 } 02668 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "", 02669 dwParamLen ? lpszParam : "", szCRLF); 02670 02671 TRACE("Sending (%s) len(%d)\n", buf, len); 02672 while((nBytesSent < len) && (nRC != -1)) 02673 { 02674 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0); 02675 nBytesSent += nRC; 02676 } 02677 02678 HeapFree(GetProcessHeap(), 0, (LPVOID)buf); 02679 02680 if (lpfnStatusCB) 02681 { 02682 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_REQUEST_SENT, 02683 &nBytesSent, sizeof(DWORD)); 02684 } 02685 02686 TRACE("Sent %d bytes\n", nBytesSent); 02687 return (nRC != -1); 02688 } 02689 02690 /*********************************************************************** 02691 * FTP_SendCommand (internal) 02692 * 02693 * Send command to server 02694 * 02695 * RETURNS 02696 * TRUE on success 02697 * NULL on failure 02698 * 02699 */ 02700 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam, 02701 INTERNET_STATUS_CALLBACK lpfnStatusCB, object_header_t *hdr, DWORD_PTR dwContext) 02702 { 02703 BOOL ret; 02704 LPSTR lpszParamA = heap_strdupWtoA(lpszParam); 02705 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext); 02706 HeapFree(GetProcessHeap(), 0, lpszParamA); 02707 return ret; 02708 } 02709 02710 /*********************************************************************** 02711 * FTP_ReceiveResponse (internal) 02712 * 02713 * Receive response from server 02714 * 02715 * RETURNS 02716 * Reply code on success 02717 * 0 on failure 02718 * 02719 */ 02720 INT FTP_ReceiveResponse(ftp_session_t *lpwfs, DWORD_PTR dwContext) 02721 { 02722 LPSTR lpszResponse = INTERNET_GetResponseBuffer(); 02723 DWORD nRecv; 02724 INT rc = 0; 02725 char firstprefix[5]; 02726 BOOL multiline = FALSE; 02727 02728 TRACE("socket(%d)\n", lpwfs->sndSocket); 02729 02730 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); 02731 02732 while(1) 02733 { 02734 if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv)) 02735 goto lerror; 02736 02737 if (nRecv >= 3) 02738 { 02739 if(!multiline) 02740 { 02741 if(lpszResponse[3] != '-') 02742 break; 02743 else 02744 { /* Start of multiline response. Loop until we get "nnn " */ 02745 multiline = TRUE; 02746 memcpy(firstprefix, lpszResponse, 3); 02747 firstprefix[3] = ' '; 02748 firstprefix[4] = '\0'; 02749 } 02750 } 02751 else 02752 { 02753 if(!memcmp(firstprefix, lpszResponse, 4)) 02754 break; 02755 } 02756 } 02757 } 02758 02759 if (nRecv >= 3) 02760 { 02761 rc = atoi(lpszResponse); 02762 02763 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED, 02764 &nRecv, sizeof(DWORD)); 02765 } 02766 02767 lerror: 02768 TRACE("return %d\n", rc); 02769 return rc; 02770 } 02771 02772 02773 /*********************************************************************** 02774 * FTP_SendPassword (internal) 02775 * 02776 * Send password to ftp server 02777 * 02778 * RETURNS 02779 * TRUE on success 02780 * NULL on failure 02781 * 02782 */ 02783 static BOOL FTP_SendPassword(ftp_session_t *lpwfs) 02784 { 02785 INT nResCode; 02786 BOOL bSuccess = FALSE; 02787 02788 TRACE("\n"); 02789 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0)) 02790 goto lend; 02791 02792 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 02793 if (nResCode) 02794 { 02795 TRACE("Received reply code %d\n", nResCode); 02796 /* Login successful... */ 02797 if (nResCode == 230) 02798 bSuccess = TRUE; 02799 /* Command not implemented, superfluous at the server site... */ 02800 /* Need account for login... */ 02801 else if (nResCode == 332) 02802 bSuccess = FTP_SendAccount(lpwfs); 02803 else 02804 FTP_SetResponseError(nResCode); 02805 } 02806 02807 lend: 02808 TRACE("Returning %d\n", bSuccess); 02809 return bSuccess; 02810 } 02811 02812 02813 /*********************************************************************** 02814 * FTP_SendAccount (internal) 02815 * 02816 * 02817 * 02818 * RETURNS 02819 * TRUE on success 02820 * FALSE on failure 02821 * 02822 */ 02823 static BOOL FTP_SendAccount(ftp_session_t *lpwfs) 02824 { 02825 INT nResCode; 02826 BOOL bSuccess = FALSE; 02827 02828 TRACE("\n"); 02829 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0)) 02830 goto lend; 02831 02832 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 02833 if (nResCode) 02834 bSuccess = TRUE; 02835 else 02836 FTP_SetResponseError(nResCode); 02837 02838 lend: 02839 return bSuccess; 02840 } 02841 02842 02843 /*********************************************************************** 02844 * FTP_SendStore (internal) 02845 * 02846 * Send request to upload file to ftp server 02847 * 02848 * RETURNS 02849 * TRUE on success 02850 * FALSE on failure 02851 * 02852 */ 02853 static BOOL FTP_SendStore(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType) 02854 { 02855 INT nResCode; 02856 BOOL bSuccess = FALSE; 02857 02858 TRACE("\n"); 02859 if (!FTP_InitListenSocket(lpwfs)) 02860 goto lend; 02861 02862 if (!FTP_SendType(lpwfs, dwType)) 02863 goto lend; 02864 02865 if (!FTP_SendPortOrPasv(lpwfs)) 02866 goto lend; 02867 02868 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0)) 02869 goto lend; 02870 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 02871 if (nResCode) 02872 { 02873 if (nResCode == 150 || nResCode == 125) 02874 bSuccess = TRUE; 02875 else 02876 FTP_SetResponseError(nResCode); 02877 } 02878 02879 lend: 02880 if (!bSuccess && lpwfs->lstnSocket != -1) 02881 { 02882 closesocket(lpwfs->lstnSocket); 02883 lpwfs->lstnSocket = -1; 02884 } 02885 02886 return bSuccess; 02887 } 02888 02889 02890 /*********************************************************************** 02891 * FTP_InitListenSocket (internal) 02892 * 02893 * Create a socket to listen for server response 02894 * 02895 * RETURNS 02896 * TRUE on success 02897 * FALSE on failure 02898 * 02899 */ 02900 static BOOL FTP_InitListenSocket(ftp_session_t *lpwfs) 02901 { 02902 BOOL bSuccess = FALSE; 02903 socklen_t namelen = sizeof(lpwfs->lstnSocketAddress); 02904 02905 TRACE("\n"); 02906 02907 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0); 02908 if (lpwfs->lstnSocket == -1) 02909 { 02910 TRACE("Unable to create listening socket\n"); 02911 goto lend; 02912 } 02913 02914 /* We obtain our ip addr from the name of the command channel socket */ 02915 lpwfs->lstnSocketAddress = lpwfs->socketAddress; 02916 02917 /* and get the system to assign us a port */ 02918 lpwfs->lstnSocketAddress.sin_port = htons(0); 02919 02920 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(lpwfs->lstnSocketAddress)) == -1) 02921 { 02922 TRACE("Unable to bind socket\n"); 02923 goto lend; 02924 } 02925 02926 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1) 02927 { 02928 TRACE("listen failed\n"); 02929 goto lend; 02930 } 02931 02932 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1) 02933 bSuccess = TRUE; 02934 02935 lend: 02936 if (!bSuccess && lpwfs->lstnSocket != -1) 02937 { 02938 closesocket(lpwfs->lstnSocket); 02939 lpwfs->lstnSocket = -1; 02940 } 02941 02942 return bSuccess; 02943 } 02944 02945 02946 /*********************************************************************** 02947 * FTP_SendType (internal) 02948 * 02949 * Tell server type of data being transferred 02950 * 02951 * RETURNS 02952 * TRUE on success 02953 * FALSE on failure 02954 * 02955 * W98SE doesn't cache the type that's currently set 02956 * (i.e. it sends it always), 02957 * so we probably don't want to do that either. 02958 */ 02959 static BOOL FTP_SendType(ftp_session_t *lpwfs, DWORD dwType) 02960 { 02961 INT nResCode; 02962 WCHAR type[] = { 'I','\0' }; 02963 BOOL bSuccess = FALSE; 02964 02965 TRACE("\n"); 02966 if (dwType & INTERNET_FLAG_TRANSFER_ASCII) 02967 type[0] = 'A'; 02968 02969 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0)) 02970 goto lend; 02971 02972 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100; 02973 if (nResCode) 02974 { 02975 if (nResCode == 2) 02976 bSuccess = TRUE; 02977 else 02978 FTP_SetResponseError(nResCode); 02979 } 02980 02981 lend: 02982 return bSuccess; 02983 } 02984 02985 02986 #if 0 /* FIXME: should probably be used for FtpGetFileSize */ 02987 /*********************************************************************** 02988 * FTP_GetFileSize (internal) 02989 * 02990 * Retrieves from the server the size of the given file 02991 * 02992 * RETURNS 02993 * TRUE on success 02994 * FALSE on failure 02995 * 02996 */ 02997 static BOOL FTP_GetFileSize(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize) 02998 { 02999 INT nResCode; 03000 BOOL bSuccess = FALSE; 03001 03002 TRACE("\n"); 03003 03004 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0)) 03005 goto lend; 03006 03007 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 03008 if (nResCode) 03009 { 03010 if (nResCode == 213) { 03011 /* Now parses the output to get the actual file size */ 03012 int i; 03013 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer(); 03014 03015 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ; 03016 if (lpszResponseBuffer[i] == '\0') return FALSE; 03017 *dwSize = atol(&(lpszResponseBuffer[i + 1])); 03018 03019 bSuccess = TRUE; 03020 } else { 03021 FTP_SetResponseError(nResCode); 03022 } 03023 } 03024 03025 lend: 03026 return bSuccess; 03027 } 03028 #endif 03029 03030 03031 /*********************************************************************** 03032 * FTP_SendPort (internal) 03033 * 03034 * Tell server which port to use 03035 * 03036 * RETURNS 03037 * TRUE on success 03038 * FALSE on failure 03039 * 03040 */ 03041 static BOOL FTP_SendPort(ftp_session_t *lpwfs) 03042 { 03043 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'}; 03044 INT nResCode; 03045 WCHAR szIPAddress[64]; 03046 BOOL bSuccess = FALSE; 03047 TRACE("\n"); 03048 03049 sprintfW(szIPAddress, szIPFormat, 03050 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF, 03051 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8, 03052 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16, 03053 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24, 03054 lpwfs->lstnSocketAddress.sin_port & 0xFF, 03055 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8); 03056 03057 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0)) 03058 goto lend; 03059 03060 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 03061 if (nResCode) 03062 { 03063 if (nResCode == 200) 03064 bSuccess = TRUE; 03065 else 03066 FTP_SetResponseError(nResCode); 03067 } 03068 03069 lend: 03070 return bSuccess; 03071 } 03072 03073 03074 /*********************************************************************** 03075 * FTP_DoPassive (internal) 03076 * 03077 * Tell server that we want to do passive transfers 03078 * and connect data socket 03079 * 03080 * RETURNS 03081 * TRUE on success 03082 * FALSE on failure 03083 * 03084 */ 03085 static BOOL FTP_DoPassive(ftp_session_t *lpwfs) 03086 { 03087 INT nResCode; 03088 BOOL bSuccess = FALSE; 03089 03090 TRACE("\n"); 03091 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0)) 03092 goto lend; 03093 03094 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 03095 if (nResCode) 03096 { 03097 if (nResCode == 227) 03098 { 03099 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer(); 03100 LPSTR p; 03101 int f[6]; 03102 int i; 03103 char *pAddr, *pPort; 03104 INT nsocket = -1; 03105 struct sockaddr_in dataSocketAddress; 03106 03107 p = lpszResponseBuffer+4; /* skip status code */ 03108 while (*p != '\0' && (*p < '0' || *p > '9')) p++; 03109 03110 if (*p == '\0') 03111 { 03112 ERR("no address found in response, aborting\n"); 03113 goto lend; 03114 } 03115 03116 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3], 03117 &f[4], &f[5]) != 6) 03118 { 03119 ERR("unknown response address format '%s', aborting\n", p); 03120 goto lend; 03121 } 03122 for (i=0; i < 6; i++) 03123 f[i] = f[i] & 0xff; 03124 03125 dataSocketAddress = lpwfs->socketAddress; 03126 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr); 03127 pPort = (char *)&(dataSocketAddress.sin_port); 03128 pAddr[0] = f[0]; 03129 pAddr[1] = f[1]; 03130 pAddr[2] = f[2]; 03131 pAddr[3] = f[3]; 03132 pPort[0] = f[4]; 03133 pPort[1] = f[5]; 03134 03135 nsocket = socket(AF_INET,SOCK_STREAM,0); 03136 if (nsocket == -1) 03137 goto lend; 03138 03139 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress))) 03140 { 03141 ERR("can't connect passive FTP data port.\n"); 03142 closesocket(nsocket); 03143 goto lend; 03144 } 03145 lpwfs->pasvSocket = nsocket; 03146 bSuccess = TRUE; 03147 } 03148 else 03149 FTP_SetResponseError(nResCode); 03150 } 03151 03152 lend: 03153 return bSuccess; 03154 } 03155 03156 03157 static BOOL FTP_SendPortOrPasv(ftp_session_t *lpwfs) 03158 { 03159 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE) 03160 { 03161 if (!FTP_DoPassive(lpwfs)) 03162 return FALSE; 03163 } 03164 else 03165 { 03166 if (!FTP_SendPort(lpwfs)) 03167 return FALSE; 03168 } 03169 return TRUE; 03170 } 03171 03172 03173 /*********************************************************************** 03174 * FTP_GetDataSocket (internal) 03175 * 03176 * Either accepts an incoming data socket connection from the server 03177 * or just returns the already opened socket after a PASV command 03178 * in case of passive FTP. 03179 * 03180 * 03181 * RETURNS 03182 * TRUE on success 03183 * FALSE on failure 03184 * 03185 */ 03186 static BOOL FTP_GetDataSocket(ftp_session_t *lpwfs, LPINT nDataSocket) 03187 { 03188 struct sockaddr_in saddr; 03189 socklen_t addrlen = sizeof(struct sockaddr); 03190 03191 TRACE("\n"); 03192 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE) 03193 { 03194 *nDataSocket = lpwfs->pasvSocket; 03195 lpwfs->pasvSocket = -1; 03196 } 03197 else 03198 { 03199 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen); 03200 closesocket(lpwfs->lstnSocket); 03201 lpwfs->lstnSocket = -1; 03202 } 03203 return *nDataSocket != -1; 03204 } 03205 03206 03207 /*********************************************************************** 03208 * FTP_SendData (internal) 03209 * 03210 * Send data to the server 03211 * 03212 * RETURNS 03213 * TRUE on success 03214 * FALSE on failure 03215 * 03216 */ 03217 static BOOL FTP_SendData(ftp_session_t *lpwfs, INT nDataSocket, HANDLE hFile) 03218 { 03219 BY_HANDLE_FILE_INFORMATION fi; 03220 DWORD nBytesRead = 0; 03221 DWORD nBytesSent = 0; 03222 DWORD nTotalSent = 0; 03223 DWORD nBytesToSend, nLen; 03224 int nRC = 1; 03225 time_t s_long_time, e_long_time; 03226 LONG nSeconds; 03227 CHAR *lpszBuffer; 03228 03229 TRACE("\n"); 03230 lpszBuffer = heap_alloc_zero(sizeof(CHAR)*DATA_PACKET_SIZE); 03231 03232 /* Get the size of the file. */ 03233 GetFileInformationByHandle(hFile, &fi); 03234 time(&s_long_time); 03235 03236 do 03237 { 03238 nBytesToSend = nBytesRead - nBytesSent; 03239 03240 if (nBytesToSend <= 0) 03241 { 03242 /* Read data from file. */ 03243 nBytesSent = 0; 03244 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0)) 03245 ERR("Failed reading from file\n"); 03246 03247 if (nBytesRead > 0) 03248 nBytesToSend = nBytesRead; 03249 else 03250 break; 03251 } 03252 03253 nLen = DATA_PACKET_SIZE < nBytesToSend ? 03254 DATA_PACKET_SIZE : nBytesToSend; 03255 nRC = send(nDataSocket, lpszBuffer, nLen, 0); 03256 03257 if (nRC != -1) 03258 { 03259 nBytesSent += nRC; 03260 nTotalSent += nRC; 03261 } 03262 03263 /* Do some computation to display the status. */ 03264 time(&e_long_time); 03265 nSeconds = e_long_time - s_long_time; 03266 if( nSeconds / 60 > 0 ) 03267 { 03268 TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n", 03269 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60, 03270 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent ); 03271 } 03272 else 03273 { 03274 TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n", 03275 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds, 03276 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent); 03277 } 03278 } while (nRC != -1); 03279 03280 TRACE("file transfer complete!\n"); 03281 03282 HeapFree(GetProcessHeap(), 0, lpszBuffer); 03283 03284 return nTotalSent; 03285 } 03286 03287 03288 /*********************************************************************** 03289 * FTP_SendRetrieve (internal) 03290 * 03291 * Send request to retrieve a file 03292 * 03293 * RETURNS 03294 * Number of bytes to be received on success 03295 * 0 on failure 03296 * 03297 */ 03298 static BOOL FTP_SendRetrieve(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType) 03299 { 03300 INT nResCode; 03301 BOOL ret; 03302 03303 TRACE("\n"); 03304 if (!(ret = FTP_InitListenSocket(lpwfs))) 03305 goto lend; 03306 03307 if (!(ret = FTP_SendType(lpwfs, dwType))) 03308 goto lend; 03309 03310 if (!(ret = FTP_SendPortOrPasv(lpwfs))) 03311 goto lend; 03312 03313 if (!(ret = FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))) 03314 goto lend; 03315 03316 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); 03317 if ((nResCode != 125) && (nResCode != 150)) { 03318 /* That means that we got an error getting the file. */ 03319 FTP_SetResponseError(nResCode); 03320 ret = FALSE; 03321 } 03322 03323 lend: 03324 if (!ret && lpwfs->lstnSocket != -1) 03325 { 03326 closesocket(lpwfs->lstnSocket); 03327 lpwfs->lstnSocket = -1; 03328 } 03329 03330 return ret; 03331 } 03332 03333 03334 /*********************************************************************** 03335 * FTP_RetrieveData (internal) 03336 * 03337 * Retrieve data from server 03338 * 03339 * RETURNS 03340 * TRUE on success 03341 * FALSE on failure 03342 * 03343 */ 03344 static BOOL FTP_RetrieveFileData(ftp_session_t *lpwfs, INT nDataSocket, HANDLE hFile) 03345 { 03346 DWORD nBytesWritten; 03347 INT nRC = 0; 03348 CHAR *lpszBuffer; 03349 03350 TRACE("\n"); 03351 03352 lpszBuffer = heap_alloc_zero(sizeof(CHAR)*DATA_PACKET_SIZE); 03353 if (NULL == lpszBuffer) 03354 { 03355 INTERNET_SetLastError(ERROR_OUTOFMEMORY); 03356 return FALSE; 03357 } 03358 03359 while (nRC != -1) 03360 { 03361 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0); 03362 if (nRC != -1) 03363 { 03364 /* other side closed socket. */ 03365 if (nRC == 0) 03366 goto recv_end; 03367 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL); 03368 } 03369 } 03370 03371 TRACE("Data transfer complete\n"); 03372 03373 recv_end: 03374 HeapFree(GetProcessHeap(), 0, lpszBuffer); 03375 03376 return (nRC != -1); 03377 } 03378 03379 /*********************************************************************** 03380 * FTPFINDNEXT_Destroy (internal) 03381 * 03382 * Deallocate session handle 03383 */ 03384 static void FTPFINDNEXT_Destroy(object_header_t *hdr) 03385 { 03386 LPWININETFTPFINDNEXTW lpwfn = (LPWININETFTPFINDNEXTW) hdr; 03387 DWORD i; 03388 03389 TRACE("\n"); 03390 03391 WININET_Release(&lpwfn->lpFtpSession->hdr); 03392 03393 for (i = 0; i < lpwfn->size; i++) 03394 { 03395 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName); 03396 } 03397 03398 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp); 03399 } 03400 03401 static DWORD FTPFINDNEXT_FindNextFileProc(WININETFTPFINDNEXTW *find, LPVOID data) 03402 { 03403 WIN32_FIND_DATAW *find_data = data; 03404 DWORD res = ERROR_SUCCESS; 03405 03406 TRACE("index(%d) size(%d)\n", find->index, find->size); 03407 03408 ZeroMemory(find_data, sizeof(WIN32_FIND_DATAW)); 03409 03410 if (find->index < find->size) { 03411 FTP_ConvertFileProp(&find->lpafp[find->index], find_data); 03412 find->index++; 03413 03414 TRACE("Name: %s\nSize: %d\n", debugstr_w(find_data->cFileName), find_data->nFileSizeLow); 03415 }else { 03416 res = ERROR_NO_MORE_FILES; 03417 } 03418 03419 if (find->hdr.dwFlags & INTERNET_FLAG_ASYNC) 03420 { 03421 INTERNET_ASYNC_RESULT iar; 03422 03423 iar.dwResult = (res == ERROR_SUCCESS); 03424 iar.dwError = res; 03425 03426 INTERNET_SendCallback(&find->hdr, find->hdr.dwContext, 03427 INTERNET_STATUS_REQUEST_COMPLETE, &iar, 03428 sizeof(INTERNET_ASYNC_RESULT)); 03429 } 03430 03431 return res; 03432 } 03433 03434 static void FTPFINDNEXT_AsyncFindNextFileProc(WORKREQUEST *workRequest) 03435 { 03436 struct WORKREQ_FTPFINDNEXTW *req = &workRequest->u.FtpFindNextW; 03437 03438 FTPFINDNEXT_FindNextFileProc((WININETFTPFINDNEXTW*)workRequest->hdr, req->lpFindFileData); 03439 } 03440 03441 static DWORD FTPFINDNEXT_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) 03442 { 03443 switch(option) { 03444 case INTERNET_OPTION_HANDLE_TYPE: 03445 TRACE("INTERNET_OPTION_HANDLE_TYPE\n"); 03446 03447 if (*size < sizeof(ULONG)) 03448 return ERROR_INSUFFICIENT_BUFFER; 03449 03450 *size = sizeof(DWORD); 03451 *(DWORD*)buffer = INTERNET_HANDLE_TYPE_FTP_FIND; 03452 return ERROR_SUCCESS; 03453 } 03454 03455 return INET_QueryOption(hdr, option, buffer, size, unicode); 03456 } 03457 03458 static DWORD FTPFINDNEXT_FindNextFileW(object_header_t *hdr, void *data) 03459 { 03460 WININETFTPFINDNEXTW *find = (WININETFTPFINDNEXTW*)hdr; 03461 03462 if (find->lpFtpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC) 03463 { 03464 WORKREQUEST workRequest; 03465 struct WORKREQ_FTPFINDNEXTW *req; 03466 03467 workRequest.asyncproc = FTPFINDNEXT_AsyncFindNextFileProc; 03468 workRequest.hdr = WININET_AddRef( &find->hdr ); 03469 req = &workRequest.u.FtpFindNextW; 03470 req->lpFindFileData = data; 03471 03472 INTERNET_AsyncCall(&workRequest); 03473 03474 return ERROR_SUCCESS; 03475 } 03476 03477 return FTPFINDNEXT_FindNextFileProc(find, data); 03478 } 03479 03480 static const object_vtbl_t FTPFINDNEXTVtbl = { 03481 FTPFINDNEXT_Destroy, 03482 NULL, 03483 FTPFINDNEXT_QueryOption, 03484 NULL, 03485 NULL, 03486 NULL, 03487 NULL, 03488 NULL, 03489 NULL, 03490 FTPFINDNEXT_FindNextFileW 03491 }; 03492 03493 /*********************************************************************** 03494 * FTP_ReceiveFileList (internal) 03495 * 03496 * Read file list from server 03497 * 03498 * RETURNS 03499 * Handle to file list on success 03500 * NULL on failure 03501 * 03502 */ 03503 static HINTERNET FTP_ReceiveFileList(ftp_session_t *lpwfs, INT nSocket, LPCWSTR lpszSearchFile, 03504 LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext) 03505 { 03506 DWORD dwSize = 0; 03507 LPFILEPROPERTIESW lpafp = NULL; 03508 LPWININETFTPFINDNEXTW lpwfn = NULL; 03509 03510 TRACE("(%p,%d,%s,%p,%08lx)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext); 03511 03512 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize)) 03513 { 03514 if(lpFindFileData) 03515 FTP_ConvertFileProp(lpafp, lpFindFileData); 03516 03517 lpwfn = alloc_object(&lpwfs->hdr, &FTPFINDNEXTVtbl, sizeof(WININETFTPFINDNEXTW)); 03518 if (lpwfn) 03519 { 03520 lpwfn->hdr.htype = WH_HFTPFINDNEXT; 03521 lpwfn->hdr.dwContext = dwContext; 03522 lpwfn->index = 1; /* Next index is 1 since we return index 0 */ 03523 lpwfn->size = dwSize; 03524 lpwfn->lpafp = lpafp; 03525 03526 WININET_AddRef( &lpwfs->hdr ); 03527 lpwfn->lpFtpSession = lpwfs; 03528 list_add_head( &lpwfs->hdr.children, &lpwfn->hdr.entry ); 03529 } 03530 } 03531 03532 TRACE("Matched %d files\n", dwSize); 03533 return lpwfn ? lpwfn->hdr.hInternet : NULL; 03534 } 03535 03536 03537 /*********************************************************************** 03538 * FTP_ConvertFileProp (internal) 03539 * 03540 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA 03541 * 03542 * RETURNS 03543 * TRUE on success 03544 * FALSE on failure 03545 * 03546 */ 03547 static BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData) 03548 { 03549 BOOL bSuccess = FALSE; 03550 03551 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW)); 03552 03553 if (lpafp) 03554 { 03555 SystemTimeToFileTime( &lpafp->tmLastModified, &lpFindFileData->ftLastAccessTime ); 03556 lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime; 03557 lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime; 03558 03559 /* Not all fields are filled in */ 03560 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */ 03561 lpFindFileData->nFileSizeLow = lpafp->nSize; 03562 03563 if (lpafp->bIsDirectory) 03564 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY; 03565 03566 if (lpafp->lpszName) 03567 lstrcpynW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH); 03568 03569 bSuccess = TRUE; 03570 } 03571 03572 return bSuccess; 03573 } 03574 03575 /*********************************************************************** 03576 * FTP_ParseNextFile (internal) 03577 * 03578 * Parse the next line in file listing 03579 * 03580 * RETURNS 03581 * TRUE on success 03582 * FALSE on failure 03583 */ 03584 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp) 03585 { 03586 static const char szSpace[] = " \t"; 03587 DWORD nBufLen; 03588 char *pszLine; 03589 char *pszToken; 03590 char *pszTmp; 03591 BOOL found = FALSE; 03592 int i; 03593 03594 lpfp->lpszName = NULL; 03595 do { 03596 if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen))) 03597 return FALSE; 03598 03599 pszToken = strtok(pszLine, szSpace); 03600 /* ls format 03601 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename> 03602 * 03603 * For instance: 03604 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier 03605 */ 03606 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) { 03607 if(!FTP_ParsePermission(pszToken, lpfp)) 03608 lpfp->bIsDirectory = FALSE; 03609 for(i=0; i<=3; i++) { 03610 if(!(pszToken = strtok(NULL, szSpace))) 03611 break; 03612 } 03613 if(!pszToken) continue; 03614 if(lpfp->bIsDirectory) { 03615 TRACE("Is directory\n"); 03616 lpfp->nSize = 0; 03617 } 03618 else { 03619 TRACE("Size: %s\n", pszToken); 03620 lpfp->nSize = atol(pszToken); 03621 } 03622 03623 lpfp->tmLastModified.wSecond = 0; 03624 lpfp->tmLastModified.wMinute = 0; 03625 lpfp->tmLastModified.wHour = 0; 03626 lpfp->tmLastModified.wDay = 0; 03627 lpfp->tmLastModified.wMonth = 0; 03628 lpfp->tmLastModified.wYear = 0; 03629 03630 /* Determine month */ 03631 pszToken = strtok(NULL, szSpace); 03632 if(!pszToken) continue; 03633 if(strlen(pszToken) >= 3) { 03634 pszToken[3] = 0; 03635 if((pszTmp = StrStrIA(szMonths, pszToken))) 03636 lpfp->tmLastModified.wMonth = ((pszTmp - szMonths) / 3)+1; 03637 } 03638 /* Determine day */ 03639 pszToken = strtok(NULL, szSpace); 03640 if(!pszToken) continue; 03641 lpfp->tmLastModified.wDay = atoi(pszToken); 03642 /* Determine time or year */ 03643 pszToken = strtok(NULL, szSpace); 03644 if(!pszToken) continue; 03645 if((pszTmp = strchr(pszToken, ':'))) { 03646 SYSTEMTIME curr_time; 03647 *pszTmp = 0; 03648 pszTmp++; 03649 lpfp->tmLastModified.wMinute = atoi(pszTmp); 03650 lpfp->tmLastModified.wHour = atoi(pszToken); 03651 GetLocalTime( &curr_time ); 03652 lpfp->tmLastModified.wYear = curr_time.wYear; 03653 } 03654 else { 03655 lpfp->tmLastModified.wYear = atoi(pszToken); 03656 lpfp->tmLastModified.wHour = 12; 03657 } 03658 TRACE("Mod time: %02d:%02d:%02d %04d/%02d/%02d\n", 03659 lpfp->tmLastModified.wHour, lpfp->tmLastModified.wMinute, lpfp->tmLastModified.wSecond, 03660 lpfp->tmLastModified.wYear, lpfp->tmLastModified.wMonth, lpfp->tmLastModified.wDay); 03661 03662 pszToken = strtok(NULL, szSpace); 03663 if(!pszToken) continue; 03664 lpfp->lpszName = heap_strdupAtoW(pszToken); 03665 TRACE("File: %s\n", debugstr_w(lpfp->lpszName)); 03666 } 03667 /* NT way of parsing ... : 03668 03669 07-13-03 08:55PM <DIR> sakpatch 03670 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz 03671 */ 03672 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) { 03673 int mon, mday, year, hour, min; 03674 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */ 03675 03676 sscanf(pszToken, "%d-%d-%d", &mon, &mday, &year); 03677 lpfp->tmLastModified.wDay = mday; 03678 lpfp->tmLastModified.wMonth = mon; 03679 lpfp->tmLastModified.wYear = year; 03680 03681 /* Hacky and bad Y2K protection :-) */ 03682 if (lpfp->tmLastModified.wYear < 70) lpfp->tmLastModified.wYear += 2000; 03683 03684 pszToken = strtok(NULL, szSpace); 03685 if(!pszToken) continue; 03686 sscanf(pszToken, "%d:%d", &hour, &min); 03687 lpfp->tmLastModified.wHour = hour; 03688 lpfp->tmLastModified.wMinute = min; 03689 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) { 03690 lpfp->tmLastModified.wHour += 12; 03691 } 03692 lpfp->tmLastModified.wSecond = 0; 03693 03694 TRACE("Mod time: %02d:%02d:%02d %04d/%02d/%02d\n", 03695 lpfp->tmLastModified.wHour, lpfp->tmLastModified.wMinute, lpfp->tmLastModified.wSecond, 03696 lpfp->tmLastModified.wYear, lpfp->tmLastModified.wMonth, lpfp->tmLastModified.wDay); 03697 03698 pszToken = strtok(NULL, szSpace); 03699 if(!pszToken) continue; 03700 if(!strcasecmp(pszToken, "<DIR>")) { 03701 lpfp->bIsDirectory = TRUE; 03702 lpfp->nSize = 0; 03703 TRACE("Is directory\n"); 03704 } 03705 else { 03706 lpfp->bIsDirectory = FALSE; 03707 lpfp->nSize = atol(pszToken); 03708 TRACE("Size: %d\n", lpfp->nSize); 03709 } 03710 03711 pszToken = strtok(NULL, szSpace); 03712 if(!pszToken) continue; 03713 lpfp->lpszName = heap_strdupAtoW(pszToken); 03714 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName)); 03715 } 03716 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */ 03717 else if(pszToken[0] == '+') { 03718 FIXME("EPLF Format not implemented\n"); 03719 } 03720 03721 if(lpfp->lpszName) { 03722 if((lpszSearchFile == NULL) || 03723 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) { 03724 found = TRUE; 03725 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName)); 03726 } 03727 else { 03728 HeapFree(GetProcessHeap(), 0, lpfp->lpszName); 03729 lpfp->lpszName = NULL; 03730 } 03731 } 03732 } while(!found); 03733 return TRUE; 03734 } 03735 03736 /*********************************************************************** 03737 * FTP_ParseDirectory (internal) 03738 * 03739 * Parse string of directory information 03740 * 03741 * RETURNS 03742 * TRUE on success 03743 * FALSE on failure 03744 */ 03745 static BOOL FTP_ParseDirectory(ftp_session_t *lpwfs, INT nSocket, LPCWSTR lpszSearchFile, 03746 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp) 03747 { 03748 BOOL bSuccess = TRUE; 03749 INT sizeFilePropArray = 500;/*20; */ 03750 INT indexFilePropArray = -1; 03751 03752 TRACE("\n"); 03753 03754 /* Allocate initial file properties array */ 03755 *lpafp = heap_alloc_zero(sizeof(FILEPROPERTIESW)*(sizeFilePropArray)); 03756 if (!*lpafp) 03757 return FALSE; 03758 03759 do { 03760 if (indexFilePropArray+1 >= sizeFilePropArray) 03761 { 03762 LPFILEPROPERTIESW tmpafp; 03763 03764 sizeFilePropArray *= 2; 03765 tmpafp = heap_realloc_zero(*lpafp, sizeof(FILEPROPERTIESW)*sizeFilePropArray); 03766 if (NULL == tmpafp) 03767 { 03768 bSuccess = FALSE; 03769 break; 03770 } 03771 03772 *lpafp = tmpafp; 03773 } 03774 indexFilePropArray++; 03775 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray])); 03776 03777 if (bSuccess && indexFilePropArray) 03778 { 03779 if (indexFilePropArray < sizeFilePropArray - 1) 03780 { 03781 LPFILEPROPERTIESW tmpafp; 03782 03783 tmpafp = heap_realloc(*lpafp, sizeof(FILEPROPERTIESW)*indexFilePropArray); 03784 if (NULL != tmpafp) 03785 *lpafp = tmpafp; 03786 } 03787 *dwfp = indexFilePropArray; 03788 } 03789 else 03790 { 03791 HeapFree(GetProcessHeap(), 0, *lpafp); 03792 INTERNET_SetLastError(ERROR_NO_MORE_FILES); 03793 bSuccess = FALSE; 03794 } 03795 03796 return bSuccess; 03797 } 03798 03799 03800 /*********************************************************************** 03801 * FTP_ParsePermission (internal) 03802 * 03803 * Parse permission string of directory information 03804 * 03805 * RETURNS 03806 * TRUE on success 03807 * FALSE on failure 03808 * 03809 */ 03810 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp) 03811 { 03812 BOOL bSuccess = TRUE; 03813 unsigned short nPermission = 0; 03814 INT nPos = 1; 03815 INT nLast = 9; 03816 03817 TRACE("\n"); 03818 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l')) 03819 { 03820 bSuccess = FALSE; 03821 return bSuccess; 03822 } 03823 03824 lpfp->bIsDirectory = (*lpszPermission == 'd'); 03825 do 03826 { 03827 switch (nPos) 03828 { 03829 case 1: 03830 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8; 03831 break; 03832 case 2: 03833 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7; 03834 break; 03835 case 3: 03836 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6; 03837 break; 03838 case 4: 03839 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5; 03840 break; 03841 case 5: 03842 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4; 03843 break; 03844 case 6: 03845 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3; 03846 break; 03847 case 7: 03848 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2; 03849 break; 03850 case 8: 03851 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1; 03852 break; 03853 case 9: 03854 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0); 03855 break; 03856 } 03857 nPos++; 03858 }while (nPos <= nLast); 03859 03860 lpfp->permissions = nPermission; 03861 return bSuccess; 03862 } 03863 03864 03865 /*********************************************************************** 03866 * FTP_SetResponseError (internal) 03867 * 03868 * Set the appropriate error code for a given response from the server 03869 * 03870 * RETURNS 03871 * 03872 */ 03873 static DWORD FTP_SetResponseError(DWORD dwResponse) 03874 { 03875 DWORD dwCode = 0; 03876 03877 switch(dwResponse) 03878 { 03879 case 425: /* Cannot open data connection. */ 03880 dwCode = ERROR_INTERNET_CANNOT_CONNECT; 03881 break; 03882 03883 case 426: /* Connection closed, transer aborted. */ 03884 dwCode = ERROR_INTERNET_CONNECTION_ABORTED; 03885 break; 03886 03887 case 530: /* Not logged in. Login incorrect. */ 03888 dwCode = ERROR_INTERNET_LOGIN_FAILURE; 03889 break; 03890 03891 case 421: /* Service not available - Server may be shutting down. */ 03892 case 450: /* File action not taken. File may be busy. */ 03893 case 451: /* Action aborted. Server error. */ 03894 case 452: /* Action not taken. Insufficient storage space on server. */ 03895 case 500: /* Syntax error. Command unrecognized. */ 03896 case 501: /* Syntax error. Error in parameters or arguments. */ 03897 case 502: /* Command not implemented. */ 03898 case 503: /* Bad sequence of commands. */ 03899 case 504: /* Command not implemented for that parameter. */ 03900 case 532: /* Need account for storing files */ 03901 case 550: /* File action not taken. File not found or no access. */ 03902 case 551: /* Requested action aborted. Page type unknown */ 03903 case 552: /* Action aborted. Exceeded storage allocation */ 03904 case 553: /* Action not taken. File name not allowed. */ 03905 03906 default: 03907 dwCode = ERROR_INTERNET_EXTENDED_ERROR; 03908 break; 03909 } 03910 03911 INTERNET_SetLastError(dwCode); 03912 return dwCode; 03913 } Generated on Sat May 26 2012 04:16:09 for ReactOS by
1.7.6.1
|