wined3d: Pass the correct mask to shader_glsl_add_src_param() in pshader_glsl_texm3x2...
[wine/gsoc_dplay.git] / dlls / wininet / ftp.c
blob841ae3c6d2cbc96548f1e2e2162696fdf3202f9e
1 /*
2 * WININET - Ftp implementation
4 * Copyright 1999 Corel Corporation
5 * Copyright 2004 Mike McCormack for CodeWeavers
6 * Copyright 2004 Kevin Koltzau
8 * Ulrich Czekalla
9 * Noureddine Jemmali
11 * Copyright 2000 Andreas Mohr
12 * Copyright 2002 Jaco Greeff
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "config.h"
30 #include "wine/port.h"
32 #include <errno.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/types.h>
38 #ifdef HAVE_SYS_SOCKET_H
39 # include <sys/socket.h>
40 #endif
41 #ifdef HAVE_UNISTD_H
42 # include <unistd.h>
43 #endif
44 #include <time.h>
45 #include <assert.h>
47 #include "windef.h"
48 #include "winbase.h"
49 #include "wingdi.h"
50 #include "winuser.h"
51 #include "wininet.h"
52 #include "winnls.h"
53 #include "winerror.h"
54 #include "winreg.h"
55 #include "winternl.h"
56 #include "shlwapi.h"
58 #include "wine/debug.h"
59 #include "internet.h"
61 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
63 #define DATA_PACKET_SIZE 0x2000
64 #define szCRLF "\r\n"
65 #define MAX_BACKLOG 5
67 typedef enum {
68 /* FTP commands with arguments. */
69 FTP_CMD_ACCT,
70 FTP_CMD_CWD,
71 FTP_CMD_DELE,
72 FTP_CMD_MKD,
73 FTP_CMD_PASS,
74 FTP_CMD_PORT,
75 FTP_CMD_RETR,
76 FTP_CMD_RMD,
77 FTP_CMD_RNFR,
78 FTP_CMD_RNTO,
79 FTP_CMD_STOR,
80 FTP_CMD_TYPE,
81 FTP_CMD_USER,
82 FTP_CMD_SIZE,
84 /* FTP commands without arguments. */
85 FTP_CMD_ABOR,
86 FTP_CMD_LIST,
87 FTP_CMD_NLST,
88 FTP_CMD_PASV,
89 FTP_CMD_PWD,
90 FTP_CMD_QUIT,
91 } FTP_COMMAND;
93 static const CHAR *szFtpCommands[] = {
94 "ACCT",
95 "CWD",
96 "DELE",
97 "MKD",
98 "PASS",
99 "PORT",
100 "RETR",
101 "RMD",
102 "RNFR",
103 "RNTO",
104 "STOR",
105 "TYPE",
106 "USER",
107 "SIZE",
108 "ABOR",
109 "LIST",
110 "NLST",
111 "PASV",
112 "PWD",
113 "QUIT",
116 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
117 static const WCHAR szNoAccount[] = {'n','o','a','c','c','o','u','n','t','\0'};
119 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr);
120 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr);
121 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr);
122 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
123 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext);
124 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
125 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket);
126 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile);
127 static INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext);
128 static DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
129 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile);
130 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs);
131 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs);
132 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs);
133 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs);
134 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType);
135 static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize);
136 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs);
137 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs);
138 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs);
139 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp);
140 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW fileprop);
141 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
142 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp);
143 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
144 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext);
145 static DWORD FTP_SetResponseError(DWORD dwResponse);
147 /***********************************************************************
148 * FtpPutFileA (WININET.@)
150 * Uploads a file to the FTP server
152 * RETURNS
153 * TRUE on success
154 * FALSE on failure
157 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
158 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
160 LPWSTR lpwzLocalFile;
161 LPWSTR lpwzNewRemoteFile;
162 BOOL ret;
164 lpwzLocalFile = lpszLocalFile?WININET_strdup_AtoW(lpszLocalFile):NULL;
165 lpwzNewRemoteFile = lpszNewRemoteFile?WININET_strdup_AtoW(lpszNewRemoteFile):NULL;
166 ret = FtpPutFileW(hConnect, lpwzLocalFile, lpwzNewRemoteFile,
167 dwFlags, dwContext);
168 HeapFree(GetProcessHeap(), 0, lpwzLocalFile);
169 HeapFree(GetProcessHeap(), 0, lpwzNewRemoteFile);
170 return ret;
173 /***********************************************************************
174 * FtpPutFileW (WININET.@)
176 * Uploads a file to the FTP server
178 * RETURNS
179 * TRUE on success
180 * FALSE on failure
183 static void AsyncFtpPutFileProc(WORKREQUEST *workRequest)
185 struct WORKREQ_FTPPUTFILEW const *req = &workRequest->u.FtpPutFileW;
186 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
188 TRACE("%p\n", lpwfs);
190 FTP_FtpPutFileW(lpwfs, req->lpszLocalFile,
191 req->lpszNewRemoteFile, req->dwFlags, req->dwContext);
193 HeapFree(GetProcessHeap(), 0, req->lpszLocalFile);
194 HeapFree(GetProcessHeap(), 0, req->lpszNewRemoteFile);
197 BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile,
198 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
200 LPWININETFTPSESSIONW lpwfs;
201 LPWININETAPPINFOW hIC = NULL;
202 BOOL r = FALSE;
204 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
205 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
207 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
208 goto lend;
211 hIC = lpwfs->lpAppInfo;
212 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
214 WORKREQUEST workRequest;
215 struct WORKREQ_FTPPUTFILEW *req = &workRequest.u.FtpPutFileW;
217 workRequest.asyncproc = AsyncFtpPutFileProc;
218 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
219 req->lpszLocalFile = WININET_strdupW(lpszLocalFile);
220 req->lpszNewRemoteFile = WININET_strdupW(lpszNewRemoteFile);
221 req->dwFlags = dwFlags;
222 req->dwContext = dwContext;
224 r = INTERNET_AsyncCall(&workRequest);
226 else
228 r = FTP_FtpPutFileW(lpwfs, lpszLocalFile,
229 lpszNewRemoteFile, dwFlags, dwContext);
232 lend:
233 if( lpwfs )
234 WININET_Release( &lpwfs->hdr );
236 return r;
239 /***********************************************************************
240 * FTP_FtpPutFileW (Internal)
242 * Uploads a file to the FTP server
244 * RETURNS
245 * TRUE on success
246 * FALSE on failure
249 BOOL WINAPI FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile,
250 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
252 HANDLE hFile = NULL;
253 BOOL bSuccess = FALSE;
254 LPWININETAPPINFOW hIC = NULL;
255 INT nResCode;
257 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", debugstr_w(lpszLocalFile), debugstr_w(lpszNewRemoteFile));
259 if (!lpszLocalFile || !lpszNewRemoteFile)
261 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
262 return FALSE;
265 assert( WH_HFTPSESSION == lpwfs->hdr.htype);
267 /* Clear any error information */
268 INTERNET_SetLastError(0);
269 hIC = lpwfs->lpAppInfo;
271 /* Open file to be uploaded */
272 if (INVALID_HANDLE_VALUE ==
273 (hFile = CreateFileW(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
275 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND);
276 goto lend;
279 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
281 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
283 INT nDataSocket;
285 /* Get data socket to server */
286 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
288 FTP_SendData(lpwfs, nDataSocket, hFile);
289 closesocket(nDataSocket);
290 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
291 if (nResCode)
293 if (nResCode == 226)
294 bSuccess = TRUE;
295 else
296 FTP_SetResponseError(nResCode);
301 lend:
302 if (lpwfs->lstnSocket != -1)
303 closesocket(lpwfs->lstnSocket);
305 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
307 INTERNET_ASYNC_RESULT iar;
309 iar.dwResult = (DWORD)bSuccess;
310 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
311 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
312 &iar, sizeof(INTERNET_ASYNC_RESULT));
315 if (hFile)
316 CloseHandle(hFile);
318 return bSuccess;
322 /***********************************************************************
323 * FtpSetCurrentDirectoryA (WININET.@)
325 * Change the working directory on the FTP server
327 * RETURNS
328 * TRUE on success
329 * FALSE on failure
332 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
334 LPWSTR lpwzDirectory;
335 BOOL ret;
337 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
338 ret = FtpSetCurrentDirectoryW(hConnect, lpwzDirectory);
339 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
340 return ret;
344 /***********************************************************************
345 * FtpSetCurrentDirectoryW (WININET.@)
347 * Change the working directory on the FTP server
349 * RETURNS
350 * TRUE on success
351 * FALSE on failure
354 static void AsyncFtpSetCurrentDirectoryProc(WORKREQUEST *workRequest)
356 struct WORKREQ_FTPSETCURRENTDIRECTORYW const *req = &workRequest->u.FtpSetCurrentDirectoryW;
357 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
359 TRACE("%p\n", lpwfs);
361 FTP_FtpSetCurrentDirectoryW(lpwfs, req->lpszDirectory);
362 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
365 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
367 LPWININETFTPSESSIONW lpwfs = NULL;
368 LPWININETAPPINFOW hIC = NULL;
369 BOOL r = FALSE;
371 if (!lpszDirectory)
373 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
374 goto lend;
377 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
378 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
380 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
381 goto lend;
384 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
386 hIC = lpwfs->lpAppInfo;
387 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
389 WORKREQUEST workRequest;
390 struct WORKREQ_FTPSETCURRENTDIRECTORYW *req;
392 workRequest.asyncproc = AsyncFtpSetCurrentDirectoryProc;
393 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
394 req = &workRequest.u.FtpSetCurrentDirectoryW;
395 req->lpszDirectory = WININET_strdupW(lpszDirectory);
397 r = INTERNET_AsyncCall(&workRequest);
399 else
401 r = FTP_FtpSetCurrentDirectoryW(lpwfs, lpszDirectory);
404 lend:
405 if( lpwfs )
406 WININET_Release( &lpwfs->hdr );
408 return r;
412 /***********************************************************************
413 * FTP_FtpSetCurrentDirectoryW (Internal)
415 * Change the working directory on the FTP server
417 * RETURNS
418 * TRUE on success
419 * FALSE on failure
422 BOOL WINAPI FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
424 INT nResCode;
425 LPWININETAPPINFOW hIC = NULL;
426 DWORD bSuccess = FALSE;
428 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
430 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
432 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
433 return FALSE;
436 /* Clear any error information */
437 INTERNET_SetLastError(0);
439 hIC = lpwfs->lpAppInfo;
440 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
441 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
442 goto lend;
444 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
446 if (nResCode)
448 if (nResCode == 250)
449 bSuccess = TRUE;
450 else
451 FTP_SetResponseError(nResCode);
454 lend:
455 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
457 INTERNET_ASYNC_RESULT iar;
459 iar.dwResult = (DWORD)bSuccess;
460 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
461 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
462 &iar, sizeof(INTERNET_ASYNC_RESULT));
464 return bSuccess;
468 /***********************************************************************
469 * FtpCreateDirectoryA (WININET.@)
471 * Create new directory on the FTP server
473 * RETURNS
474 * TRUE on success
475 * FALSE on failure
478 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
480 LPWSTR lpwzDirectory;
481 BOOL ret;
483 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
484 ret = FtpCreateDirectoryW(hConnect, lpwzDirectory);
485 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
486 return ret;
490 /***********************************************************************
491 * FtpCreateDirectoryW (WININET.@)
493 * Create new directory on the FTP server
495 * RETURNS
496 * TRUE on success
497 * FALSE on failure
500 static void AsyncFtpCreateDirectoryProc(WORKREQUEST *workRequest)
502 struct WORKREQ_FTPCREATEDIRECTORYW const *req = &workRequest->u.FtpCreateDirectoryW;
503 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
505 TRACE(" %p\n", lpwfs);
507 FTP_FtpCreateDirectoryW(lpwfs, req->lpszDirectory);
508 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
511 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
513 LPWININETFTPSESSIONW lpwfs;
514 LPWININETAPPINFOW hIC = NULL;
515 BOOL r = FALSE;
517 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
518 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
520 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
521 goto lend;
524 hIC = lpwfs->lpAppInfo;
525 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
527 WORKREQUEST workRequest;
528 struct WORKREQ_FTPCREATEDIRECTORYW *req;
530 workRequest.asyncproc = AsyncFtpCreateDirectoryProc;
531 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
532 req = &workRequest.u.FtpCreateDirectoryW;
533 req->lpszDirectory = WININET_strdupW(lpszDirectory);
535 r = INTERNET_AsyncCall(&workRequest);
537 else
539 r = FTP_FtpCreateDirectoryW(lpwfs, lpszDirectory);
541 lend:
542 if( lpwfs )
543 WININET_Release( &lpwfs->hdr );
545 return r;
549 /***********************************************************************
550 * FTP_FtpCreateDirectoryW (Internal)
552 * Create new directory on the FTP server
554 * RETURNS
555 * TRUE on success
556 * FALSE on failure
559 BOOL WINAPI FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
561 INT nResCode;
562 BOOL bSuccess = FALSE;
563 LPWININETAPPINFOW hIC = NULL;
565 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
567 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
569 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
570 return FALSE;
573 /* Clear any error information */
574 INTERNET_SetLastError(0);
576 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
577 goto lend;
579 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
580 if (nResCode)
582 if (nResCode == 257)
583 bSuccess = TRUE;
584 else
585 FTP_SetResponseError(nResCode);
588 lend:
589 hIC = lpwfs->lpAppInfo;
590 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
592 INTERNET_ASYNC_RESULT iar;
594 iar.dwResult = (DWORD)bSuccess;
595 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
596 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
597 &iar, sizeof(INTERNET_ASYNC_RESULT));
600 return bSuccess;
603 /***********************************************************************
604 * FtpFindFirstFileA (WININET.@)
606 * Search the specified directory
608 * RETURNS
609 * HINTERNET on success
610 * NULL on failure
613 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
614 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
616 LPWSTR lpwzSearchFile;
617 WIN32_FIND_DATAW wfd;
618 LPWIN32_FIND_DATAW lpFindFileDataW;
619 HINTERNET ret;
621 lpwzSearchFile = lpszSearchFile?WININET_strdup_AtoW(lpszSearchFile):NULL;
622 lpFindFileDataW = lpFindFileData?&wfd:NULL;
623 ret = FtpFindFirstFileW(hConnect, lpwzSearchFile, lpFindFileDataW, dwFlags, dwContext);
624 HeapFree(GetProcessHeap(), 0, lpwzSearchFile);
626 if(lpFindFileData) {
627 WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData);
629 return ret;
633 /***********************************************************************
634 * FtpFindFirstFileW (WININET.@)
636 * Search the specified directory
638 * RETURNS
639 * HINTERNET on success
640 * NULL on failure
643 static void AsyncFtpFindFirstFileProc(WORKREQUEST *workRequest)
645 struct WORKREQ_FTPFINDFIRSTFILEW const *req = &workRequest->u.FtpFindFirstFileW;
646 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
648 TRACE("%p\n", lpwfs);
650 FTP_FtpFindFirstFileW(lpwfs, req->lpszSearchFile,
651 req->lpFindFileData, req->dwFlags, req->dwContext);
652 HeapFree(GetProcessHeap(), 0, req->lpszSearchFile);
655 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
656 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
658 LPWININETFTPSESSIONW lpwfs;
659 LPWININETAPPINFOW hIC = NULL;
660 HINTERNET r = NULL;
662 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
663 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
665 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
666 goto lend;
669 hIC = lpwfs->lpAppInfo;
670 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
672 WORKREQUEST workRequest;
673 struct WORKREQ_FTPFINDFIRSTFILEW *req;
675 workRequest.asyncproc = AsyncFtpFindFirstFileProc;
676 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
677 req = &workRequest.u.FtpFindFirstFileW;
678 req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : WININET_strdupW(lpszSearchFile);
679 req->lpFindFileData = lpFindFileData;
680 req->dwFlags = dwFlags;
681 req->dwContext= dwContext;
683 INTERNET_AsyncCall(&workRequest);
684 r = NULL;
686 else
688 r = FTP_FtpFindFirstFileW(lpwfs, lpszSearchFile, lpFindFileData,
689 dwFlags, dwContext);
691 lend:
692 if( lpwfs )
693 WININET_Release( &lpwfs->hdr );
695 return r;
699 /***********************************************************************
700 * FTP_FtpFindFirstFileW (Internal)
702 * Search the specified directory
704 * RETURNS
705 * HINTERNET on success
706 * NULL on failure
709 HINTERNET WINAPI FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs,
710 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
712 INT nResCode;
713 LPWININETAPPINFOW hIC = NULL;
714 HINTERNET hFindNext = NULL;
716 TRACE("\n");
718 assert(WH_HFTPSESSION == lpwfs->hdr.htype);
720 /* Clear any error information */
721 INTERNET_SetLastError(0);
723 if (!FTP_InitListenSocket(lpwfs))
724 goto lend;
726 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
727 goto lend;
729 if (!FTP_SendPortOrPasv(lpwfs))
730 goto lend;
732 hIC = lpwfs->lpAppInfo;
733 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, NULL,
734 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
735 goto lend;
737 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
738 if (nResCode)
740 if (nResCode == 125 || nResCode == 150)
742 INT nDataSocket;
744 /* Get data socket to server */
745 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
747 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpszSearchFile, lpFindFileData, dwContext);
748 closesocket(nDataSocket);
749 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
750 if (nResCode != 226 && nResCode != 250)
751 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
754 else
755 FTP_SetResponseError(nResCode);
758 lend:
759 if (lpwfs->lstnSocket != -1)
760 closesocket(lpwfs->lstnSocket);
762 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
764 INTERNET_ASYNC_RESULT iar;
766 if (hFindNext)
768 iar.dwResult = (DWORD)hFindNext;
769 iar.dwError = ERROR_SUCCESS;
770 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
771 &iar, sizeof(INTERNET_ASYNC_RESULT));
774 iar.dwResult = (DWORD)hFindNext;
775 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
776 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
777 &iar, sizeof(INTERNET_ASYNC_RESULT));
780 return hFindNext;
784 /***********************************************************************
785 * FtpGetCurrentDirectoryA (WININET.@)
787 * Retrieves the current directory
789 * RETURNS
790 * TRUE on success
791 * FALSE on failure
794 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
795 LPDWORD lpdwCurrentDirectory)
797 WCHAR *dir = NULL;
798 DWORD len;
799 BOOL ret;
801 if(lpdwCurrentDirectory) {
802 len = *lpdwCurrentDirectory;
803 if(lpszCurrentDirectory)
805 dir = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
806 if (NULL == dir)
808 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
809 return FALSE;
813 ret = FtpGetCurrentDirectoryW(hFtpSession, lpszCurrentDirectory?dir:NULL, lpdwCurrentDirectory?&len:NULL);
814 if(lpdwCurrentDirectory) {
815 *lpdwCurrentDirectory = len;
816 if(lpszCurrentDirectory) {
817 WideCharToMultiByte(CP_ACP, 0, dir, len, lpszCurrentDirectory, *lpdwCurrentDirectory, NULL, NULL);
818 HeapFree(GetProcessHeap(), 0, dir);
821 return ret;
825 /***********************************************************************
826 * FtpGetCurrentDirectoryW (WININET.@)
828 * Retrieves the current directory
830 * RETURNS
831 * TRUE on success
832 * FALSE on failure
835 static void AsyncFtpGetCurrentDirectoryProc(WORKREQUEST *workRequest)
837 struct WORKREQ_FTPGETCURRENTDIRECTORYW const *req = &workRequest->u.FtpGetCurrentDirectoryW;
838 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
840 TRACE("%p\n", lpwfs);
842 FTP_FtpGetCurrentDirectoryW(lpwfs, req->lpszDirectory, req->lpdwDirectory);
845 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
846 LPDWORD lpdwCurrentDirectory)
848 LPWININETFTPSESSIONW lpwfs;
849 LPWININETAPPINFOW hIC = NULL;
850 BOOL r = FALSE;
852 TRACE("len(%d)\n", *lpdwCurrentDirectory);
854 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
855 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
857 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
858 goto lend;
861 hIC = lpwfs->lpAppInfo;
862 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
864 WORKREQUEST workRequest;
865 struct WORKREQ_FTPGETCURRENTDIRECTORYW *req;
867 workRequest.asyncproc = AsyncFtpGetCurrentDirectoryProc;
868 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
869 req = &workRequest.u.FtpGetCurrentDirectoryW;
870 req->lpszDirectory = lpszCurrentDirectory;
871 req->lpdwDirectory = lpdwCurrentDirectory;
873 r = INTERNET_AsyncCall(&workRequest);
875 else
877 r = FTP_FtpGetCurrentDirectoryW(lpwfs, lpszCurrentDirectory,
878 lpdwCurrentDirectory);
881 lend:
882 if( lpwfs )
883 WININET_Release( &lpwfs->hdr );
885 return r;
889 /***********************************************************************
890 * FTP_FtpGetCurrentDirectoryA (Internal)
892 * Retrieves the current directory
894 * RETURNS
895 * TRUE on success
896 * FALSE on failure
899 BOOL WINAPI FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszCurrentDirectory,
900 LPDWORD lpdwCurrentDirectory)
902 INT nResCode;
903 LPWININETAPPINFOW hIC = NULL;
904 DWORD bSuccess = FALSE;
906 TRACE("len(%d)\n", *lpdwCurrentDirectory);
908 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
910 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
911 return FALSE;
914 /* Clear any error information */
915 INTERNET_SetLastError(0);
917 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
919 hIC = lpwfs->lpAppInfo;
920 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
921 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
922 goto lend;
924 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
925 if (nResCode)
927 if (nResCode == 257) /* Extract directory name */
929 DWORD firstpos, lastpos, len;
930 LPWSTR lpszResponseBuffer = WININET_strdup_AtoW(INTERNET_GetResponseBuffer());
932 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
934 if ('"' == lpszResponseBuffer[lastpos])
936 if (!firstpos)
937 firstpos = lastpos;
938 else
939 break;
943 len = lastpos - firstpos - 1;
944 lstrcpynW(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1], *lpdwCurrentDirectory);
945 HeapFree(GetProcessHeap(), 0, lpszResponseBuffer);
946 *lpdwCurrentDirectory = len;
947 bSuccess = TRUE;
949 else
950 FTP_SetResponseError(nResCode);
953 lend:
954 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
956 INTERNET_ASYNC_RESULT iar;
958 iar.dwResult = (DWORD)bSuccess;
959 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
960 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
961 &iar, sizeof(INTERNET_ASYNC_RESULT));
964 return (DWORD) bSuccess;
967 /***********************************************************************
968 * FtpOpenFileA (WININET.@)
970 * Open a remote file for writing or reading
972 * RETURNS
973 * HINTERNET handle on success
974 * NULL on failure
977 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
978 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
979 DWORD dwContext)
981 LPWSTR lpwzFileName;
982 HINTERNET ret;
984 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
985 ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext);
986 HeapFree(GetProcessHeap(), 0, lpwzFileName);
987 return ret;
991 /***********************************************************************
992 * FtpOpenFileW (WININET.@)
994 * Open a remote file for writing or reading
996 * RETURNS
997 * HINTERNET handle on success
998 * NULL on failure
1001 static void AsyncFtpOpenFileProc(WORKREQUEST *workRequest)
1003 struct WORKREQ_FTPOPENFILEW const *req = &workRequest->u.FtpOpenFileW;
1004 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1006 TRACE("%p\n", lpwfs);
1008 FTP_FtpOpenFileW(lpwfs, req->lpszFilename,
1009 req->dwAccess, req->dwFlags, req->dwContext);
1010 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1013 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
1014 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1015 DWORD dwContext)
1017 LPWININETFTPSESSIONW lpwfs;
1018 LPWININETAPPINFOW hIC = NULL;
1019 HINTERNET r = NULL;
1021 TRACE("(%p,%s,0x%08x,0x%08x,0x%08x)\n", hFtpSession,
1022 debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext);
1024 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1025 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1027 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1028 goto lend;
1031 if (lpwfs->download_in_progress != NULL) {
1032 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1033 goto lend;
1035 hIC = lpwfs->lpAppInfo;
1036 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1038 WORKREQUEST workRequest;
1039 struct WORKREQ_FTPOPENFILEW *req;
1041 workRequest.asyncproc = AsyncFtpOpenFileProc;
1042 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1043 req = &workRequest.u.FtpOpenFileW;
1044 req->lpszFilename = WININET_strdupW(lpszFileName);
1045 req->dwAccess = fdwAccess;
1046 req->dwFlags = dwFlags;
1047 req->dwContext = dwContext;
1049 INTERNET_AsyncCall(&workRequest);
1050 r = NULL;
1052 else
1054 r = FTP_FtpOpenFileW(lpwfs, lpszFileName, fdwAccess, dwFlags, dwContext);
1057 lend:
1058 if( lpwfs )
1059 WININET_Release( &lpwfs->hdr );
1061 return r;
1065 /***********************************************************************
1066 * FTP_FtpOpenFileW (Internal)
1068 * Open a remote file for writing or reading
1070 * RETURNS
1071 * HINTERNET handle on success
1072 * NULL on failure
1075 HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs,
1076 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1077 DWORD dwContext)
1079 INT nDataSocket;
1080 BOOL bSuccess = FALSE;
1081 LPWININETFTPFILE lpwh = NULL;
1082 LPWININETAPPINFOW hIC = NULL;
1083 HINTERNET handle = NULL;
1085 TRACE("\n");
1087 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1089 /* Clear any error information */
1090 INTERNET_SetLastError(0);
1092 if (GENERIC_READ == fdwAccess)
1094 /* Set up socket to retrieve data */
1095 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
1097 else if (GENERIC_WRITE == fdwAccess)
1099 /* Set up socket to send data */
1100 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
1103 /* Get data socket to server */
1104 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
1106 lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPFILE));
1107 lpwh->hdr.htype = WH_HFILE;
1108 lpwh->hdr.dwFlags = dwFlags;
1109 lpwh->hdr.dwContext = dwContext;
1110 lpwh->hdr.dwRefCount = 1;
1111 lpwh->hdr.destroy = FTP_CloseFileTransferHandle;
1112 lpwh->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
1113 lpwh->nDataSocket = nDataSocket;
1114 lpwh->session_deleted = FALSE;
1116 WININET_AddRef( &lpwfs->hdr );
1117 lpwh->lpFtpSession = lpwfs;
1119 handle = WININET_AllocHandle( &lpwh->hdr );
1120 if( !handle )
1121 goto lend;
1123 /* Indicate that a download is currently in progress */
1124 lpwfs->download_in_progress = lpwh;
1127 if (lpwfs->lstnSocket != -1)
1128 closesocket(lpwfs->lstnSocket);
1130 hIC = lpwfs->lpAppInfo;
1131 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1133 INTERNET_ASYNC_RESULT iar;
1135 if (lpwh)
1137 iar.dwResult = (DWORD)handle;
1138 iar.dwError = ERROR_SUCCESS;
1139 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
1140 &iar, sizeof(INTERNET_ASYNC_RESULT));
1143 iar.dwResult = (DWORD)bSuccess;
1144 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1145 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1146 &iar, sizeof(INTERNET_ASYNC_RESULT));
1149 lend:
1150 if( lpwh )
1151 WININET_Release( &lpwh->hdr );
1153 return handle;
1157 /***********************************************************************
1158 * FtpGetFileA (WININET.@)
1160 * Retrieve file from the FTP server
1162 * RETURNS
1163 * TRUE on success
1164 * FALSE on failure
1167 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1168 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1169 DWORD dwContext)
1171 LPWSTR lpwzRemoteFile;
1172 LPWSTR lpwzNewFile;
1173 BOOL ret;
1175 lpwzRemoteFile = lpszRemoteFile?WININET_strdup_AtoW(lpszRemoteFile):NULL;
1176 lpwzNewFile = lpszNewFile?WININET_strdup_AtoW(lpszNewFile):NULL;
1177 ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists,
1178 dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1179 HeapFree(GetProcessHeap(), 0, lpwzRemoteFile);
1180 HeapFree(GetProcessHeap(), 0, lpwzNewFile);
1181 return ret;
1185 /***********************************************************************
1186 * FtpGetFileW (WININET.@)
1188 * Retrieve file from the FTP server
1190 * RETURNS
1191 * TRUE on success
1192 * FALSE on failure
1195 static void AsyncFtpGetFileProc(WORKREQUEST *workRequest)
1197 struct WORKREQ_FTPGETFILEW const *req = &workRequest->u.FtpGetFileW;
1198 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1200 TRACE("%p\n", lpwfs);
1202 FTP_FtpGetFileW(lpwfs, req->lpszRemoteFile,
1203 req->lpszNewFile, req->fFailIfExists,
1204 req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext);
1205 HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile);
1206 HeapFree(GetProcessHeap(), 0, req->lpszNewFile);
1209 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1210 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1211 DWORD dwContext)
1213 LPWININETFTPSESSIONW lpwfs;
1214 LPWININETAPPINFOW hIC = NULL;
1215 BOOL r = FALSE;
1217 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet );
1218 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1220 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1221 goto lend;
1224 if (lpwfs->download_in_progress != NULL) {
1225 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1226 goto lend;
1229 hIC = lpwfs->lpAppInfo;
1230 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1232 WORKREQUEST workRequest;
1233 struct WORKREQ_FTPGETFILEW *req;
1235 workRequest.asyncproc = AsyncFtpGetFileProc;
1236 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1237 req = &workRequest.u.FtpGetFileW;
1238 req->lpszRemoteFile = WININET_strdupW(lpszRemoteFile);
1239 req->lpszNewFile = WININET_strdupW(lpszNewFile);
1240 req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1241 req->fFailIfExists = fFailIfExists;
1242 req->dwFlags = dwInternetFlags;
1243 req->dwContext = dwContext;
1245 r = INTERNET_AsyncCall(&workRequest);
1247 else
1249 r = FTP_FtpGetFileW(lpwfs, lpszRemoteFile, lpszNewFile,
1250 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1253 lend:
1254 if( lpwfs )
1255 WININET_Release( &lpwfs->hdr );
1257 return r;
1261 /***********************************************************************
1262 * FTP_FtpGetFileW (Internal)
1264 * Retrieve file from the FTP server
1266 * RETURNS
1267 * TRUE on success
1268 * FALSE on failure
1271 BOOL WINAPI FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1272 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1273 DWORD dwContext)
1275 DWORD nBytes;
1276 BOOL bSuccess = FALSE;
1277 HANDLE hFile;
1278 LPWININETAPPINFOW hIC = NULL;
1280 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile));
1282 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1284 /* Clear any error information */
1285 INTERNET_SetLastError(0);
1287 /* Ensure we can write to lpszNewfile by opening it */
1288 hFile = CreateFileW(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1289 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1290 if (INVALID_HANDLE_VALUE == hFile)
1291 goto lend;
1293 /* Set up socket to retrieve data */
1294 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
1296 if (nBytes > 0)
1298 INT nDataSocket;
1300 /* Get data socket to server */
1301 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1303 INT nResCode;
1305 /* Receive data */
1306 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
1307 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
1308 if (nResCode)
1310 if (nResCode == 226)
1311 bSuccess = TRUE;
1312 else
1313 FTP_SetResponseError(nResCode);
1315 closesocket(nDataSocket);
1319 lend:
1320 if (lpwfs->lstnSocket != -1)
1321 closesocket(lpwfs->lstnSocket);
1323 if (hFile)
1324 CloseHandle(hFile);
1326 hIC = lpwfs->lpAppInfo;
1327 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1329 INTERNET_ASYNC_RESULT iar;
1331 iar.dwResult = (DWORD)bSuccess;
1332 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1333 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1334 &iar, sizeof(INTERNET_ASYNC_RESULT));
1337 return bSuccess;
1340 /***********************************************************************
1341 * FtpGetFileSize (WININET.@)
1343 DWORD WINAPI FtpGetFileSize( HINTERNET hFile, LPDWORD lpdwFileSizeHigh )
1345 FIXME("(%p, %p)\n", hFile, lpdwFileSizeHigh);
1347 if (lpdwFileSizeHigh)
1348 *lpdwFileSizeHigh = 0;
1350 return 0;
1353 /***********************************************************************
1354 * FtpDeleteFileA (WININET.@)
1356 * Delete a file on the ftp server
1358 * RETURNS
1359 * TRUE on success
1360 * FALSE on failure
1363 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1365 LPWSTR lpwzFileName;
1366 BOOL ret;
1368 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1369 ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1370 HeapFree(GetProcessHeap(), 0, lpwzFileName);
1371 return ret;
1374 /***********************************************************************
1375 * FtpDeleteFileW (WININET.@)
1377 * Delete a file on the ftp server
1379 * RETURNS
1380 * TRUE on success
1381 * FALSE on failure
1384 static void AsyncFtpDeleteFileProc(WORKREQUEST *workRequest)
1386 struct WORKREQ_FTPDELETEFILEW const *req = &workRequest->u.FtpDeleteFileW;
1387 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1389 TRACE("%p\n", lpwfs);
1391 FTP_FtpDeleteFileW(lpwfs, req->lpszFilename);
1392 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1395 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1397 LPWININETFTPSESSIONW lpwfs;
1398 LPWININETAPPINFOW hIC = NULL;
1399 BOOL r = FALSE;
1401 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1402 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1404 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1405 goto lend;
1408 hIC = lpwfs->lpAppInfo;
1409 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1411 WORKREQUEST workRequest;
1412 struct WORKREQ_FTPDELETEFILEW *req;
1414 workRequest.asyncproc = AsyncFtpDeleteFileProc;
1415 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1416 req = &workRequest.u.FtpDeleteFileW;
1417 req->lpszFilename = WININET_strdupW(lpszFileName);
1419 r = INTERNET_AsyncCall(&workRequest);
1421 else
1423 r = FTP_FtpDeleteFileW(lpwfs, lpszFileName);
1426 lend:
1427 if( lpwfs )
1428 WININET_Release( &lpwfs->hdr );
1430 return r;
1433 /***********************************************************************
1434 * FTP_FtpDeleteFileW (Internal)
1436 * Delete a file on the ftp server
1438 * RETURNS
1439 * TRUE on success
1440 * FALSE on failure
1443 BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName)
1445 INT nResCode;
1446 BOOL bSuccess = FALSE;
1447 LPWININETAPPINFOW hIC = NULL;
1449 TRACE("%p\n", lpwfs);
1451 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1453 /* Clear any error information */
1454 INTERNET_SetLastError(0);
1456 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1457 goto lend;
1459 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1460 if (nResCode)
1462 if (nResCode == 250)
1463 bSuccess = TRUE;
1464 else
1465 FTP_SetResponseError(nResCode);
1467 lend:
1468 hIC = lpwfs->lpAppInfo;
1469 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1471 INTERNET_ASYNC_RESULT iar;
1473 iar.dwResult = (DWORD)bSuccess;
1474 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1475 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1476 &iar, sizeof(INTERNET_ASYNC_RESULT));
1479 return bSuccess;
1483 /***********************************************************************
1484 * FtpRemoveDirectoryA (WININET.@)
1486 * Remove a directory on the ftp server
1488 * RETURNS
1489 * TRUE on success
1490 * FALSE on failure
1493 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1495 LPWSTR lpwzDirectory;
1496 BOOL ret;
1498 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
1499 ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1500 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
1501 return ret;
1504 /***********************************************************************
1505 * FtpRemoveDirectoryW (WININET.@)
1507 * Remove a directory on the ftp server
1509 * RETURNS
1510 * TRUE on success
1511 * FALSE on failure
1514 static void AsyncFtpRemoveDirectoryProc(WORKREQUEST *workRequest)
1516 struct WORKREQ_FTPREMOVEDIRECTORYW const *req = &workRequest->u.FtpRemoveDirectoryW;
1517 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1519 TRACE("%p\n", lpwfs);
1521 FTP_FtpRemoveDirectoryW(lpwfs, req->lpszDirectory);
1522 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
1525 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1527 LPWININETFTPSESSIONW lpwfs;
1528 LPWININETAPPINFOW hIC = NULL;
1529 BOOL r = FALSE;
1531 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1532 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1534 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1535 goto lend;
1538 hIC = lpwfs->lpAppInfo;
1539 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1541 WORKREQUEST workRequest;
1542 struct WORKREQ_FTPREMOVEDIRECTORYW *req;
1544 workRequest.asyncproc = AsyncFtpRemoveDirectoryProc;
1545 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1546 req = &workRequest.u.FtpRemoveDirectoryW;
1547 req->lpszDirectory = WININET_strdupW(lpszDirectory);
1549 r = INTERNET_AsyncCall(&workRequest);
1551 else
1553 r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory);
1556 lend:
1557 if( lpwfs )
1558 WININET_Release( &lpwfs->hdr );
1560 return r;
1563 /***********************************************************************
1564 * FTP_FtpRemoveDirectoryW (Internal)
1566 * Remove a directory on the ftp server
1568 * RETURNS
1569 * TRUE on success
1570 * FALSE on failure
1573 BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
1575 INT nResCode;
1576 BOOL bSuccess = FALSE;
1577 LPWININETAPPINFOW hIC = NULL;
1579 TRACE("\n");
1581 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1583 /* Clear any error information */
1584 INTERNET_SetLastError(0);
1586 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1587 goto lend;
1589 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1590 if (nResCode)
1592 if (nResCode == 250)
1593 bSuccess = TRUE;
1594 else
1595 FTP_SetResponseError(nResCode);
1598 lend:
1599 hIC = lpwfs->lpAppInfo;
1600 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1602 INTERNET_ASYNC_RESULT iar;
1604 iar.dwResult = (DWORD)bSuccess;
1605 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1606 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1607 &iar, sizeof(INTERNET_ASYNC_RESULT));
1610 return bSuccess;
1614 /***********************************************************************
1615 * FtpRenameFileA (WININET.@)
1617 * Rename a file on the ftp server
1619 * RETURNS
1620 * TRUE on success
1621 * FALSE on failure
1624 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1626 LPWSTR lpwzSrc;
1627 LPWSTR lpwzDest;
1628 BOOL ret;
1630 lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL;
1631 lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL;
1632 ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
1633 HeapFree(GetProcessHeap(), 0, lpwzSrc);
1634 HeapFree(GetProcessHeap(), 0, lpwzDest);
1635 return ret;
1638 /***********************************************************************
1639 * FtpRenameFileW (WININET.@)
1641 * Rename a file on the ftp server
1643 * RETURNS
1644 * TRUE on success
1645 * FALSE on failure
1648 static void AsyncFtpRenameFileProc(WORKREQUEST *workRequest)
1650 struct WORKREQ_FTPRENAMEFILEW const *req = &workRequest->u.FtpRenameFileW;
1651 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1653 TRACE("%p\n", lpwfs);
1655 FTP_FtpRenameFileW(lpwfs, req->lpszSrcFile, req->lpszDestFile);
1656 HeapFree(GetProcessHeap(), 0, req->lpszSrcFile);
1657 HeapFree(GetProcessHeap(), 0, req->lpszDestFile);
1660 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
1662 LPWININETFTPSESSIONW lpwfs;
1663 LPWININETAPPINFOW hIC = NULL;
1664 BOOL r = FALSE;
1666 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1667 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1669 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1670 goto lend;
1673 hIC = lpwfs->lpAppInfo;
1674 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1676 WORKREQUEST workRequest;
1677 struct WORKREQ_FTPRENAMEFILEW *req;
1679 workRequest.asyncproc = AsyncFtpRenameFileProc;
1680 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1681 req = &workRequest.u.FtpRenameFileW;
1682 req->lpszSrcFile = WININET_strdupW(lpszSrc);
1683 req->lpszDestFile = WININET_strdupW(lpszDest);
1685 r = INTERNET_AsyncCall(&workRequest);
1687 else
1689 r = FTP_FtpRenameFileW(lpwfs, lpszSrc, lpszDest);
1692 lend:
1693 if( lpwfs )
1694 WININET_Release( &lpwfs->hdr );
1696 return r;
1699 /***********************************************************************
1700 * FTP_FtpRenameFileW (Internal)
1702 * Rename a file on the ftp server
1704 * RETURNS
1705 * TRUE on success
1706 * FALSE on failure
1709 BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs,
1710 LPCWSTR lpszSrc, LPCWSTR lpszDest)
1712 INT nResCode;
1713 BOOL bSuccess = FALSE;
1714 LPWININETAPPINFOW hIC = NULL;
1716 TRACE("\n");
1718 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1720 /* Clear any error information */
1721 INTERNET_SetLastError(0);
1723 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1724 goto lend;
1726 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1727 if (nResCode == 350)
1729 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1730 goto lend;
1732 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1735 if (nResCode == 250)
1736 bSuccess = TRUE;
1737 else
1738 FTP_SetResponseError(nResCode);
1740 lend:
1741 hIC = lpwfs->lpAppInfo;
1742 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1744 INTERNET_ASYNC_RESULT iar;
1746 iar.dwResult = (DWORD)bSuccess;
1747 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1748 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1749 &iar, sizeof(INTERNET_ASYNC_RESULT));
1752 return bSuccess;
1755 /***********************************************************************
1756 * FtpCommandA (WININET.@)
1758 BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1759 LPCSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1761 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1762 debugstr_a(lpszCommand), dwContext, phFtpCommand);
1764 return TRUE;
1767 /***********************************************************************
1768 * FtpCommandW (WININET.@)
1770 BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1771 LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1773 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1774 debugstr_w(lpszCommand), dwContext, phFtpCommand);
1776 return TRUE;
1779 /***********************************************************************
1780 * FTP_Connect (internal)
1782 * Connect to a ftp server
1784 * RETURNS
1785 * HINTERNET a session handle on success
1786 * NULL on failure
1788 * NOTES:
1790 * Windows uses 'anonymous' as the username, when given a NULL username
1791 * and a NULL password. The password is first looked up in:
1793 * HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\EmailName
1795 * If this entry is not present it uses the current username as the password.
1799 HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
1800 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1801 LPCWSTR lpszPassword, DWORD dwFlags, DWORD dwContext,
1802 DWORD dwInternalFlags)
1804 static const WCHAR szKey[] = {'S','o','f','t','w','a','r','e','\\',
1805 'M','i','c','r','o','s','o','f','t','\\',
1806 'W','i','n','d','o','w','s','\\',
1807 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1808 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
1809 static const WCHAR szValue[] = {'E','m','a','i','l','N','a','m','e',0};
1810 static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'};
1811 static const WCHAR szEmpty[] = {'\0'};
1812 struct sockaddr_in socketAddr;
1813 INT nsocket = -1;
1814 UINT sock_namelen;
1815 BOOL bSuccess = FALSE;
1816 LPWININETFTPSESSIONW lpwfs = NULL;
1817 HINTERNET handle = NULL;
1819 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1820 hIC, debugstr_w(lpszServerName),
1821 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
1823 assert( hIC->hdr.htype == WH_HINIT );
1825 if (NULL == lpszUserName && NULL != lpszPassword)
1827 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1828 goto lerror;
1831 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
1832 if (NULL == lpwfs)
1834 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1835 goto lerror;
1838 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1839 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1841 lpwfs->hdr.htype = WH_HFTPSESSION;
1842 lpwfs->hdr.dwFlags = dwFlags;
1843 lpwfs->hdr.dwContext = dwContext;
1844 lpwfs->hdr.dwInternalFlags = dwInternalFlags;
1845 lpwfs->hdr.dwRefCount = 1;
1846 lpwfs->hdr.destroy = FTP_CloseSessionHandle;
1847 lpwfs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
1848 lpwfs->download_in_progress = NULL;
1850 WININET_AddRef( &hIC->hdr );
1851 lpwfs->lpAppInfo = hIC;
1853 handle = WININET_AllocHandle( &lpwfs->hdr );
1854 if( !handle )
1856 ERR("Failed to alloc handle\n");
1857 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1858 goto lerror;
1861 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1862 if(strchrW(hIC->lpszProxy, ' '))
1863 FIXME("Several proxies not implemented.\n");
1864 if(hIC->lpszProxyBypass)
1865 FIXME("Proxy bypass is ignored.\n");
1867 if ( !lpszUserName) {
1868 HKEY key;
1869 WCHAR szPassword[MAX_PATH];
1870 DWORD len = sizeof(szPassword);
1872 lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
1874 RegOpenKeyW(HKEY_CURRENT_USER, szKey, &key);
1875 if (RegQueryValueExW(key, szValue, NULL, NULL, (LPBYTE)szPassword, &len)) {
1876 /* Nothing in the registry, get the username and use that as the password */
1877 if (!GetUserNameW(szPassword, &len)) {
1878 /* Should never get here, but use an empty password as failsafe */
1879 strcpyW(szPassword, szEmpty);
1882 RegCloseKey(key);
1884 TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword));
1885 lpwfs->lpszPassword = WININET_strdupW(szPassword);
1887 else {
1888 lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
1890 if (lpszPassword)
1891 lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
1892 else
1893 lpwfs->lpszPassword = WININET_strdupW(szEmpty);
1896 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1897 if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
1899 INTERNET_ASYNC_RESULT iar;
1901 iar.dwResult = (DWORD)handle;
1902 iar.dwError = ERROR_SUCCESS;
1904 SendAsyncCallback(&hIC->hdr, dwContext,
1905 INTERNET_STATUS_HANDLE_CREATED, &iar,
1906 sizeof(INTERNET_ASYNC_RESULT));
1909 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1910 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1912 if (!GetAddress(lpszServerName, nServerPort, &socketAddr))
1914 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1915 goto lerror;
1918 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1919 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1921 nsocket = socket(AF_INET,SOCK_STREAM,0);
1922 if (nsocket == -1)
1924 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1925 goto lerror;
1928 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1929 &socketAddr, sizeof(struct sockaddr_in));
1931 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1933 ERR("Unable to connect (%s)\n", strerror(errno));
1934 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1936 else
1938 TRACE("Connected to server\n");
1939 lpwfs->sndSocket = nsocket;
1940 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1941 &socketAddr, sizeof(struct sockaddr_in));
1943 sock_namelen = sizeof(lpwfs->socketAddress);
1944 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1946 if (FTP_ConnectToHost(lpwfs))
1948 TRACE("Successfully logged into server\n");
1949 bSuccess = TRUE;
1953 lerror:
1954 if (!bSuccess && nsocket == -1)
1955 closesocket(nsocket);
1957 if (!bSuccess && lpwfs)
1959 HeapFree(GetProcessHeap(), 0, lpwfs);
1960 WININET_FreeHandle( handle );
1961 handle = NULL;
1962 lpwfs = NULL;
1965 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1967 INTERNET_ASYNC_RESULT iar;
1969 iar.dwResult = (DWORD)lpwfs;
1970 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1971 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1972 &iar, sizeof(INTERNET_ASYNC_RESULT));
1975 return handle;
1979 /***********************************************************************
1980 * FTP_ConnectToHost (internal)
1982 * Connect to a ftp server
1984 * RETURNS
1985 * TRUE on success
1986 * NULL on failure
1989 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
1991 INT nResCode;
1992 BOOL bSuccess = FALSE;
1994 TRACE("\n");
1995 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1997 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1998 goto lend;
2000 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2001 if (nResCode)
2003 /* Login successful... */
2004 if (nResCode == 230)
2005 bSuccess = TRUE;
2006 /* User name okay, need password... */
2007 else if (nResCode == 331)
2008 bSuccess = FTP_SendPassword(lpwfs);
2009 /* Need account for login... */
2010 else if (nResCode == 332)
2011 bSuccess = FTP_SendAccount(lpwfs);
2012 else
2013 FTP_SetResponseError(nResCode);
2016 TRACE("Returning %d\n", bSuccess);
2017 lend:
2018 return bSuccess;
2022 /***********************************************************************
2023 * FTP_SendCommandA (internal)
2025 * Send command to server
2027 * RETURNS
2028 * TRUE on success
2029 * NULL on failure
2032 static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
2033 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
2035 DWORD len;
2036 CHAR *buf;
2037 DWORD nBytesSent = 0;
2038 int nRC = 0;
2039 DWORD dwParamLen;
2041 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
2043 if (lpfnStatusCB)
2045 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
2048 dwParamLen = lpszParam?strlen(lpszParam)+1:0;
2049 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
2050 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
2052 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2053 return FALSE;
2055 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
2056 dwParamLen ? lpszParam : "", szCRLF);
2058 TRACE("Sending (%s) len(%d)\n", buf, len);
2059 while((nBytesSent < len) && (nRC != -1))
2061 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
2062 nBytesSent += nRC;
2065 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
2067 if (lpfnStatusCB)
2069 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_REQUEST_SENT,
2070 &nBytesSent, sizeof(DWORD));
2073 TRACE("Sent %d bytes\n", nBytesSent);
2074 return (nRC != -1);
2077 /***********************************************************************
2078 * FTP_SendCommand (internal)
2080 * Send command to server
2082 * RETURNS
2083 * TRUE on success
2084 * NULL on failure
2087 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
2088 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
2090 BOOL ret;
2091 LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
2092 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
2093 HeapFree(GetProcessHeap(), 0, lpszParamA);
2094 return ret;
2097 /***********************************************************************
2098 * FTP_ReceiveResponse (internal)
2100 * Receive response from server
2102 * RETURNS
2103 * Reply code on success
2104 * 0 on failure
2107 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext)
2109 LPSTR lpszResponse = INTERNET_GetResponseBuffer();
2110 DWORD nRecv;
2111 INT rc = 0;
2112 char firstprefix[5];
2113 BOOL multiline = FALSE;
2114 LPWININETAPPINFOW hIC = NULL;
2116 TRACE("socket(%d)\n", lpwfs->sndSocket);
2118 hIC = lpwfs->lpAppInfo;
2119 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2121 while(1)
2123 if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
2124 goto lerror;
2126 if (nRecv >= 3)
2128 if(!multiline)
2130 if(lpszResponse[3] != '-')
2131 break;
2132 else
2133 { /* Start of multiline repsonse. Loop until we get "nnn " */
2134 multiline = TRUE;
2135 memcpy(firstprefix, lpszResponse, 3);
2136 firstprefix[3] = ' ';
2137 firstprefix[4] = '\0';
2140 else
2142 if(!memcmp(firstprefix, lpszResponse, 4))
2143 break;
2148 if (nRecv >= 3)
2150 rc = atoi(lpszResponse);
2152 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2153 &nRecv, sizeof(DWORD));
2156 lerror:
2157 TRACE("return %d\n", rc);
2158 return rc;
2162 /***********************************************************************
2163 * FTP_SendPassword (internal)
2165 * Send password to ftp server
2167 * RETURNS
2168 * TRUE on success
2169 * NULL on failure
2172 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
2174 INT nResCode;
2175 BOOL bSuccess = FALSE;
2177 TRACE("\n");
2178 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
2179 goto lend;
2181 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2182 if (nResCode)
2184 TRACE("Received reply code %d\n", nResCode);
2185 /* Login successful... */
2186 if (nResCode == 230)
2187 bSuccess = TRUE;
2188 /* Command not implemented, superfluous at the server site... */
2189 /* Need account for login... */
2190 else if (nResCode == 332)
2191 bSuccess = FTP_SendAccount(lpwfs);
2192 else
2193 FTP_SetResponseError(nResCode);
2196 lend:
2197 TRACE("Returning %d\n", bSuccess);
2198 return bSuccess;
2202 /***********************************************************************
2203 * FTP_SendAccount (internal)
2207 * RETURNS
2208 * TRUE on success
2209 * FALSE on failure
2212 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
2214 INT nResCode;
2215 BOOL bSuccess = FALSE;
2217 TRACE("\n");
2218 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
2219 goto lend;
2221 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2222 if (nResCode)
2223 bSuccess = TRUE;
2224 else
2225 FTP_SetResponseError(nResCode);
2227 lend:
2228 return bSuccess;
2232 /***********************************************************************
2233 * FTP_SendStore (internal)
2235 * Send request to upload file to ftp server
2237 * RETURNS
2238 * TRUE on success
2239 * FALSE on failure
2242 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2244 INT nResCode;
2245 BOOL bSuccess = FALSE;
2247 TRACE("\n");
2248 if (!FTP_InitListenSocket(lpwfs))
2249 goto lend;
2251 if (!FTP_SendType(lpwfs, dwType))
2252 goto lend;
2254 if (!FTP_SendPortOrPasv(lpwfs))
2255 goto lend;
2257 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2258 goto lend;
2259 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2260 if (nResCode)
2262 if (nResCode == 150 || nResCode == 125)
2263 bSuccess = TRUE;
2264 else
2265 FTP_SetResponseError(nResCode);
2268 lend:
2269 if (!bSuccess && lpwfs->lstnSocket != -1)
2271 closesocket(lpwfs->lstnSocket);
2272 lpwfs->lstnSocket = -1;
2275 return bSuccess;
2279 /***********************************************************************
2280 * FTP_InitListenSocket (internal)
2282 * Create a socket to listen for server response
2284 * RETURNS
2285 * TRUE on success
2286 * FALSE on failure
2289 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
2291 BOOL bSuccess = FALSE;
2292 socklen_t namelen = sizeof(struct sockaddr_in);
2294 TRACE("\n");
2296 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2297 if (lpwfs->lstnSocket == -1)
2299 TRACE("Unable to create listening socket\n");
2300 goto lend;
2303 /* We obtain our ip addr from the name of the command channel socket */
2304 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2306 /* and get the system to assign us a port */
2307 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
2309 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
2311 TRACE("Unable to bind socket\n");
2312 goto lend;
2315 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2317 TRACE("listen failed\n");
2318 goto lend;
2321 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2322 bSuccess = TRUE;
2324 lend:
2325 if (!bSuccess && lpwfs->lstnSocket == -1)
2327 closesocket(lpwfs->lstnSocket);
2328 lpwfs->lstnSocket = -1;
2331 return bSuccess;
2335 /***********************************************************************
2336 * FTP_SendType (internal)
2338 * Tell server type of data being transferred
2340 * RETURNS
2341 * TRUE on success
2342 * FALSE on failure
2344 * W98SE doesn't cache the type that's currently set
2345 * (i.e. it sends it always),
2346 * so we probably don't want to do that either.
2348 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
2350 INT nResCode;
2351 WCHAR type[] = { 'I','\0' };
2352 BOOL bSuccess = FALSE;
2354 TRACE("\n");
2355 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2356 type[0] = 'A';
2358 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2359 goto lend;
2361 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2362 if (nResCode)
2364 if (nResCode == 2)
2365 bSuccess = TRUE;
2366 else
2367 FTP_SetResponseError(nResCode);
2370 lend:
2371 return bSuccess;
2374 /***********************************************************************
2375 * FTP_GetFileSize (internal)
2377 * Retrieves from the server the size of the given file
2379 * RETURNS
2380 * TRUE on success
2381 * FALSE on failure
2384 static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
2386 INT nResCode;
2387 BOOL bSuccess = FALSE;
2389 TRACE("\n");
2391 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2392 goto lend;
2394 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2395 if (nResCode)
2397 if (nResCode == 213) {
2398 /* Now parses the output to get the actual file size */
2399 int i;
2400 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2402 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2403 if (lpszResponseBuffer[i] == '\0') return FALSE;
2404 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2406 bSuccess = TRUE;
2407 } else {
2408 FTP_SetResponseError(nResCode);
2412 lend:
2413 return bSuccess;
2417 /***********************************************************************
2418 * FTP_SendPort (internal)
2420 * Tell server which port to use
2422 * RETURNS
2423 * TRUE on success
2424 * FALSE on failure
2427 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
2429 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2430 INT nResCode;
2431 WCHAR szIPAddress[64];
2432 BOOL bSuccess = FALSE;
2433 TRACE("\n");
2435 sprintfW(szIPAddress, szIPFormat,
2436 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2437 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2438 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2439 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2440 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2441 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2443 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2444 goto lend;
2446 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2447 if (nResCode)
2449 if (nResCode == 200)
2450 bSuccess = TRUE;
2451 else
2452 FTP_SetResponseError(nResCode);
2455 lend:
2456 return bSuccess;
2460 /***********************************************************************
2461 * FTP_DoPassive (internal)
2463 * Tell server that we want to do passive transfers
2464 * and connect data socket
2466 * RETURNS
2467 * TRUE on success
2468 * FALSE on failure
2471 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
2473 INT nResCode;
2474 BOOL bSuccess = FALSE;
2476 TRACE("\n");
2477 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2478 goto lend;
2480 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2481 if (nResCode)
2483 if (nResCode == 227)
2485 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2486 LPSTR p;
2487 int f[6];
2488 int i;
2489 char *pAddr, *pPort;
2490 INT nsocket = -1;
2491 struct sockaddr_in dataSocketAddress;
2493 p = lpszResponseBuffer+4; /* skip status code */
2495 /* do a very strict check; we can improve that later. */
2497 if (strncmp(p, "Entering Passive Mode", 21))
2499 ERR("unknown response '%.*s', aborting\n", 21, p);
2500 goto lend;
2502 p += 21; /* skip string */
2503 if ((*p++ != ' ') || (*p++ != '('))
2505 ERR("unknown response format, aborting\n");
2506 goto lend;
2509 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2510 &f[4], &f[5]) != 6)
2512 ERR("unknown response address format '%s', aborting\n", p);
2513 goto lend;
2515 for (i=0; i < 6; i++)
2516 f[i] = f[i] & 0xff;
2518 dataSocketAddress = lpwfs->socketAddress;
2519 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2520 pPort = (char *)&(dataSocketAddress.sin_port);
2521 pAddr[0] = f[0];
2522 pAddr[1] = f[1];
2523 pAddr[2] = f[2];
2524 pAddr[3] = f[3];
2525 pPort[0] = f[4];
2526 pPort[1] = f[5];
2528 nsocket = socket(AF_INET,SOCK_STREAM,0);
2529 if (nsocket == -1)
2530 goto lend;
2532 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2534 ERR("can't connect passive FTP data port.\n");
2535 closesocket(nsocket);
2536 goto lend;
2538 lpwfs->pasvSocket = nsocket;
2539 bSuccess = TRUE;
2541 else
2542 FTP_SetResponseError(nResCode);
2545 lend:
2546 return bSuccess;
2550 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
2552 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2554 if (!FTP_DoPassive(lpwfs))
2555 return FALSE;
2557 else
2559 if (!FTP_SendPort(lpwfs))
2560 return FALSE;
2562 return TRUE;
2566 /***********************************************************************
2567 * FTP_GetDataSocket (internal)
2569 * Either accepts an incoming data socket connection from the server
2570 * or just returns the already opened socket after a PASV command
2571 * in case of passive FTP.
2574 * RETURNS
2575 * TRUE on success
2576 * FALSE on failure
2579 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
2581 struct sockaddr_in saddr;
2582 socklen_t addrlen = sizeof(struct sockaddr);
2584 TRACE("\n");
2585 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2587 *nDataSocket = lpwfs->pasvSocket;
2589 else
2591 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2592 closesocket(lpwfs->lstnSocket);
2593 lpwfs->lstnSocket = -1;
2595 return *nDataSocket != -1;
2599 /***********************************************************************
2600 * FTP_SendData (internal)
2602 * Send data to the server
2604 * RETURNS
2605 * TRUE on success
2606 * FALSE on failure
2609 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2611 BY_HANDLE_FILE_INFORMATION fi;
2612 DWORD nBytesRead = 0;
2613 DWORD nBytesSent = 0;
2614 DWORD nTotalSent = 0;
2615 DWORD nBytesToSend, nLen;
2616 int nRC = 1;
2617 time_t s_long_time, e_long_time;
2618 LONG nSeconds;
2619 CHAR *lpszBuffer;
2621 TRACE("\n");
2622 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2623 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2625 /* Get the size of the file. */
2626 GetFileInformationByHandle(hFile, &fi);
2627 time(&s_long_time);
2631 nBytesToSend = nBytesRead - nBytesSent;
2633 if (nBytesToSend <= 0)
2635 /* Read data from file. */
2636 nBytesSent = 0;
2637 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2638 ERR("Failed reading from file\n");
2640 if (nBytesRead > 0)
2641 nBytesToSend = nBytesRead;
2642 else
2643 break;
2646 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2647 DATA_PACKET_SIZE : nBytesToSend;
2648 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2650 if (nRC != -1)
2652 nBytesSent += nRC;
2653 nTotalSent += nRC;
2656 /* Do some computation to display the status. */
2657 time(&e_long_time);
2658 nSeconds = e_long_time - s_long_time;
2659 if( nSeconds / 60 > 0 )
2661 TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n",
2662 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2663 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2665 else
2667 TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n",
2668 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2669 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2671 } while (nRC != -1);
2673 TRACE("file transfer complete!\n");
2675 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2677 return nTotalSent;
2681 /***********************************************************************
2682 * FTP_SendRetrieve (internal)
2684 * Send request to retrieve a file
2686 * RETURNS
2687 * Number of bytes to be received on success
2688 * 0 on failure
2691 static DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2693 INT nResCode;
2694 DWORD nResult = 0;
2696 TRACE("\n");
2697 if (!FTP_InitListenSocket(lpwfs))
2698 goto lend;
2700 if (!FTP_SendType(lpwfs, dwType))
2701 goto lend;
2703 if (!FTP_SendPortOrPasv(lpwfs))
2704 goto lend;
2706 if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2707 goto lend;
2709 TRACE("Waiting to receive %d bytes\n", nResult);
2711 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2712 goto lend;
2714 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2715 if ((nResCode != 125) && (nResCode != 150)) {
2716 /* That means that we got an error getting the file. */
2717 nResult = 0;
2720 lend:
2721 if (0 == nResult && lpwfs->lstnSocket != -1)
2723 closesocket(lpwfs->lstnSocket);
2724 lpwfs->lstnSocket = -1;
2727 return nResult;
2731 /***********************************************************************
2732 * FTP_RetrieveData (internal)
2734 * Retrieve data from server
2736 * RETURNS
2737 * TRUE on success
2738 * FALSE on failure
2741 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2743 DWORD nBytesWritten;
2744 DWORD nBytesReceived = 0;
2745 INT nRC = 0;
2746 CHAR *lpszBuffer;
2748 TRACE("\n");
2750 if (INVALID_HANDLE_VALUE == hFile)
2751 return FALSE;
2753 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2754 if (NULL == lpszBuffer)
2756 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2757 return FALSE;
2760 while (nBytesReceived < nBytes && nRC != -1)
2762 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2763 if (nRC != -1)
2765 /* other side closed socket. */
2766 if (nRC == 0)
2767 goto recv_end;
2768 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2769 nBytesReceived += nRC;
2772 TRACE("%d bytes of %d (%d%%)\r", nBytesReceived, nBytes,
2773 nBytesReceived * 100 / nBytes);
2776 TRACE("Data transfer complete\n");
2777 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2779 recv_end:
2780 return (nRC != -1);
2784 /***********************************************************************
2785 * FTP_CloseSessionHandle (internal)
2787 * Deallocate session handle
2789 * RETURNS
2790 * TRUE on success
2791 * FALSE on failure
2794 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr)
2796 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2798 TRACE("\n");
2800 WININET_Release(&lpwfs->lpAppInfo->hdr);
2802 if (lpwfs->download_in_progress != NULL)
2803 lpwfs->download_in_progress->session_deleted = TRUE;
2805 if (lpwfs->sndSocket != -1)
2806 closesocket(lpwfs->sndSocket);
2808 if (lpwfs->lstnSocket != -1)
2809 closesocket(lpwfs->lstnSocket);
2811 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2812 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2813 HeapFree(GetProcessHeap(), 0, lpwfs);
2817 /***********************************************************************
2818 * FTP_FindNextFileW (Internal)
2820 * Continues a file search from a previous call to FindFirstFile
2822 * RETURNS
2823 * TRUE on success
2824 * FALSE on failure
2827 BOOL WINAPI FTP_FindNextFileW(LPWININETFTPFINDNEXTW lpwh, LPVOID lpvFindData)
2829 BOOL bSuccess = TRUE;
2830 LPWIN32_FIND_DATAW lpFindFileData;
2832 TRACE("index(%d) size(%d)\n", lpwh->index, lpwh->size);
2834 assert (lpwh->hdr.htype == WH_HFTPFINDNEXT);
2836 /* Clear any error information */
2837 INTERNET_SetLastError(0);
2839 lpFindFileData = (LPWIN32_FIND_DATAW) lpvFindData;
2840 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2842 if (lpwh->index >= lpwh->size)
2844 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2845 bSuccess = FALSE;
2846 goto lend;
2849 FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
2850 lpwh->index++;
2852 TRACE("\nName: %s\nSize: %d\n", debugstr_w(lpFindFileData->cFileName), lpFindFileData->nFileSizeLow);
2854 lend:
2856 if (lpwh->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2858 INTERNET_ASYNC_RESULT iar;
2860 iar.dwResult = (DWORD)bSuccess;
2861 iar.dwError = iar.dwError = bSuccess ? ERROR_SUCCESS :
2862 INTERNET_GetLastError();
2864 INTERNET_SendCallback(&lpwh->hdr, lpwh->hdr.dwContext,
2865 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
2866 sizeof(INTERNET_ASYNC_RESULT));
2869 return bSuccess;
2873 /***********************************************************************
2874 * FTP_CloseFindNextHandle (internal)
2876 * Deallocate session handle
2878 * RETURNS
2879 * TRUE on success
2880 * FALSE on failure
2883 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr)
2885 LPWININETFTPFINDNEXTW lpwfn = (LPWININETFTPFINDNEXTW) hdr;
2886 DWORD i;
2888 TRACE("\n");
2890 WININET_Release(&lpwfn->lpFtpSession->hdr);
2892 for (i = 0; i < lpwfn->size; i++)
2894 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2897 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2898 HeapFree(GetProcessHeap(), 0, lpwfn);
2901 /***********************************************************************
2902 * FTP_CloseFileTransferHandle (internal)
2904 * Closes the file transfer handle. This also 'cleans' the data queue of
2905 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2908 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr)
2910 LPWININETFTPFILE lpwh = (LPWININETFTPFILE) hdr;
2911 LPWININETFTPSESSIONW lpwfs = lpwh->lpFtpSession;
2912 INT nResCode;
2914 TRACE("\n");
2916 WININET_Release(&lpwh->lpFtpSession->hdr);
2918 if (!lpwh->session_deleted)
2919 lpwfs->download_in_progress = NULL;
2921 /* This just serves to flush the control socket of any spurrious lines written
2922 to it (like '226 Transfer complete.').
2924 Wonder what to do if the server sends us an error code though...
2926 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2928 if (lpwh->nDataSocket != -1)
2929 closesocket(lpwh->nDataSocket);
2931 HeapFree(GetProcessHeap(), 0, lpwh);
2934 /***********************************************************************
2935 * FTP_ReceiveFileList (internal)
2937 * Read file list from server
2939 * RETURNS
2940 * Handle to file list on success
2941 * NULL on failure
2944 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2945 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext)
2947 DWORD dwSize = 0;
2948 LPFILEPROPERTIESW lpafp = NULL;
2949 LPWININETFTPFINDNEXTW lpwfn = NULL;
2950 HINTERNET handle = 0;
2952 TRACE("(%p,%d,%s,%p,%d)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
2954 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
2956 if(lpFindFileData)
2957 FTP_ConvertFileProp(lpafp, lpFindFileData);
2959 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFTPFINDNEXTW));
2960 if (lpwfn)
2962 lpwfn->hdr.htype = WH_HFTPFINDNEXT;
2963 lpwfn->hdr.dwContext = dwContext;
2964 lpwfn->hdr.dwRefCount = 1;
2965 lpwfn->hdr.destroy = FTP_CloseFindNextHandle;
2966 lpwfn->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
2967 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2968 lpwfn->size = dwSize;
2969 lpwfn->lpafp = lpafp;
2971 WININET_AddRef( &lpwfs->hdr );
2972 lpwfn->lpFtpSession = lpwfs;
2974 handle = WININET_AllocHandle( &lpwfn->hdr );
2978 if( lpwfn )
2979 WININET_Release( &lpwfn->hdr );
2981 TRACE("Matched %d files\n", dwSize);
2982 return handle;
2986 /***********************************************************************
2987 * FTP_ConvertFileProp (internal)
2989 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
2991 * RETURNS
2992 * TRUE on success
2993 * FALSE on failure
2996 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
2998 BOOL bSuccess = FALSE;
3000 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
3002 if (lpafp)
3004 /* Convert 'Unix' time to Windows time */
3005 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
3006 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
3007 lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime;
3008 lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime;
3010 /* Not all fields are filled in */
3011 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
3012 lpFindFileData->nFileSizeLow = lpafp->nSize;
3014 if (lpafp->bIsDirectory)
3015 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
3017 if (lpafp->lpszName)
3018 lstrcpynW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
3020 bSuccess = TRUE;
3023 return bSuccess;
3026 /***********************************************************************
3027 * FTP_ParseNextFile (internal)
3029 * Parse the next line in file listing
3031 * RETURNS
3032 * TRUE on success
3033 * FALSE on failure
3035 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
3037 static const char szSpace[] = " \t";
3038 DWORD nBufLen;
3039 char *pszLine;
3040 char *pszToken;
3041 char *pszTmp;
3042 BOOL found = FALSE;
3043 int i;
3045 lpfp->lpszName = NULL;
3046 do {
3047 if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
3048 return FALSE;
3050 pszToken = strtok(pszLine, szSpace);
3051 /* ls format
3052 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
3054 * For instance:
3055 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
3057 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
3058 if(!FTP_ParsePermission(pszToken, lpfp))
3059 lpfp->bIsDirectory = FALSE;
3060 for(i=0; i<=3; i++) {
3061 if(!(pszToken = strtok(NULL, szSpace)))
3062 break;
3064 if(!pszToken) continue;
3065 if(lpfp->bIsDirectory) {
3066 TRACE("Is directory\n");
3067 lpfp->nSize = 0;
3069 else {
3070 TRACE("Size: %s\n", pszToken);
3071 lpfp->nSize = atol(pszToken);
3074 lpfp->tmLastModified.tm_sec = 0;
3075 lpfp->tmLastModified.tm_min = 0;
3076 lpfp->tmLastModified.tm_hour = 0;
3077 lpfp->tmLastModified.tm_mday = 0;
3078 lpfp->tmLastModified.tm_mon = 0;
3079 lpfp->tmLastModified.tm_year = 0;
3081 /* Determine month */
3082 pszToken = strtok(NULL, szSpace);
3083 if(!pszToken) continue;
3084 if(strlen(pszToken) >= 3) {
3085 pszToken[3] = 0;
3086 if((pszTmp = StrStrIA(szMonths, pszToken)))
3087 lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
3089 /* Determine day */
3090 pszToken = strtok(NULL, szSpace);
3091 if(!pszToken) continue;
3092 lpfp->tmLastModified.tm_mday = atoi(pszToken);
3093 /* Determine time or year */
3094 pszToken = strtok(NULL, szSpace);
3095 if(!pszToken) continue;
3096 if((pszTmp = strchr(pszToken, ':'))) {
3097 struct tm* apTM;
3098 time_t aTime;
3099 *pszTmp = 0;
3100 pszTmp++;
3101 lpfp->tmLastModified.tm_min = atoi(pszTmp);
3102 lpfp->tmLastModified.tm_hour = atoi(pszToken);
3103 time(&aTime);
3104 apTM = localtime(&aTime);
3105 lpfp->tmLastModified.tm_year = apTM->tm_year;
3107 else {
3108 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
3109 lpfp->tmLastModified.tm_hour = 12;
3111 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3112 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3113 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3114 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3116 pszToken = strtok(NULL, szSpace);
3117 if(!pszToken) continue;
3118 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3119 TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
3121 /* NT way of parsing ... :
3123 07-13-03 08:55PM <DIR> sakpatch
3124 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
3126 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
3127 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
3129 sscanf(pszToken, "%d-%d-%d",
3130 &lpfp->tmLastModified.tm_mon,
3131 &lpfp->tmLastModified.tm_mday,
3132 &lpfp->tmLastModified.tm_year);
3134 /* Hacky and bad Y2K protection :-) */
3135 if (lpfp->tmLastModified.tm_year < 70)
3136 lpfp->tmLastModified.tm_year += 100;
3138 pszToken = strtok(NULL, szSpace);
3139 if(!pszToken) continue;
3140 sscanf(pszToken, "%d:%d",
3141 &lpfp->tmLastModified.tm_hour,
3142 &lpfp->tmLastModified.tm_min);
3143 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
3144 lpfp->tmLastModified.tm_hour += 12;
3146 lpfp->tmLastModified.tm_sec = 0;
3148 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3149 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3150 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3151 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3153 pszToken = strtok(NULL, szSpace);
3154 if(!pszToken) continue;
3155 if(!strcasecmp(pszToken, "<DIR>")) {
3156 lpfp->bIsDirectory = TRUE;
3157 lpfp->nSize = 0;
3158 TRACE("Is directory\n");
3160 else {
3161 lpfp->bIsDirectory = FALSE;
3162 lpfp->nSize = atol(pszToken);
3163 TRACE("Size: %d\n", lpfp->nSize);
3166 pszToken = strtok(NULL, szSpace);
3167 if(!pszToken) continue;
3168 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3169 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
3171 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
3172 else if(pszToken[0] == '+') {
3173 FIXME("EPLF Format not implemented\n");
3176 if(lpfp->lpszName) {
3177 if((lpszSearchFile == NULL) ||
3178 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
3179 found = TRUE;
3180 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
3182 else {
3183 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
3184 lpfp->lpszName = NULL;
3187 } while(!found);
3188 return TRUE;
3191 /***********************************************************************
3192 * FTP_ParseDirectory (internal)
3194 * Parse string of directory information
3196 * RETURNS
3197 * TRUE on success
3198 * FALSE on failure
3200 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3201 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
3203 BOOL bSuccess = TRUE;
3204 INT sizeFilePropArray = 500;/*20; */
3205 INT indexFilePropArray = -1;
3207 TRACE("\n");
3209 /* Allocate intial file properties array */
3210 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
3211 if (!*lpafp)
3212 return FALSE;
3214 do {
3215 if (indexFilePropArray+1 >= sizeFilePropArray)
3217 LPFILEPROPERTIESW tmpafp;
3219 sizeFilePropArray *= 2;
3220 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
3221 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
3222 if (NULL == tmpafp)
3224 bSuccess = FALSE;
3225 break;
3228 *lpafp = tmpafp;
3230 indexFilePropArray++;
3231 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
3233 if (bSuccess && indexFilePropArray)
3235 if (indexFilePropArray < sizeFilePropArray - 1)
3237 LPFILEPROPERTIESW tmpafp;
3239 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
3240 sizeof(FILEPROPERTIESW)*indexFilePropArray);
3241 if (NULL == tmpafp)
3242 *lpafp = tmpafp;
3244 *dwfp = indexFilePropArray;
3246 else
3248 HeapFree(GetProcessHeap(), 0, *lpafp);
3249 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3250 bSuccess = FALSE;
3253 return bSuccess;
3257 /***********************************************************************
3258 * FTP_ParsePermission (internal)
3260 * Parse permission string of directory information
3262 * RETURNS
3263 * TRUE on success
3264 * FALSE on failure
3267 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3269 BOOL bSuccess = TRUE;
3270 unsigned short nPermission = 0;
3271 INT nPos = 1;
3272 INT nLast = 9;
3274 TRACE("\n");
3275 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3277 bSuccess = FALSE;
3278 return bSuccess;
3281 lpfp->bIsDirectory = (*lpszPermission == 'd');
3284 switch (nPos)
3286 case 1:
3287 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3288 break;
3289 case 2:
3290 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3291 break;
3292 case 3:
3293 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3294 break;
3295 case 4:
3296 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3297 break;
3298 case 5:
3299 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3300 break;
3301 case 6:
3302 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3303 break;
3304 case 7:
3305 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3306 break;
3307 case 8:
3308 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3309 break;
3310 case 9:
3311 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3312 break;
3314 nPos++;
3315 }while (nPos <= nLast);
3317 lpfp->permissions = nPermission;
3318 return bSuccess;
3322 /***********************************************************************
3323 * FTP_SetResponseError (internal)
3325 * Set the appropriate error code for a given response from the server
3327 * RETURNS
3330 static DWORD FTP_SetResponseError(DWORD dwResponse)
3332 DWORD dwCode = 0;
3334 switch(dwResponse)
3336 case 421: /* Service not available - Server may be shutting down. */
3337 dwCode = ERROR_INTERNET_TIMEOUT;
3338 break;
3340 case 425: /* Cannot open data connection. */
3341 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3342 break;
3344 case 426: /* Connection closed, transer aborted. */
3345 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3346 break;
3348 case 500: /* Syntax error. Command unrecognized. */
3349 case 501: /* Syntax error. Error in parameters or arguments. */
3350 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
3351 break;
3353 case 530: /* Not logged in. Login incorrect. */
3354 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3355 break;
3357 case 550: /* File action not taken. File not found or no access. */
3358 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
3359 break;
3361 case 450: /* File action not taken. File may be busy. */
3362 case 451: /* Action aborted. Server error. */
3363 case 452: /* Action not taken. Insufficient storage space on server. */
3364 case 502: /* Command not implemented. */
3365 case 503: /* Bad sequence of command. */
3366 case 504: /* Command not implemented for that parameter. */
3367 case 532: /* Need account for storing files */
3368 case 551: /* Requested action aborted. Page type unknown */
3369 case 552: /* Action aborted. Exceeded storage allocation */
3370 case 553: /* Action not taken. File name not allowed. */
3372 default:
3373 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
3374 break;
3377 INTERNET_SetLastError(dwCode);
3378 return dwCode;