push c2887f06509c427775b8fc5c2594c0b3bac35d14
[wine/hacks.git] / dlls / wininet / ftp.c
blobce60fa0c6d75c6fa6d3b82ab0a82957f2568f8a3
1 /*
2 * WININET - Ftp implementation
4 * Copyright 1999 Corel Corporation
5 * Copyright 2004 Mike McCormack for CodeWeavers
6 * Copyright 2004 Kevin Koltzau
7 * Copyright 2007 Hans Leidekker
9 * Ulrich Czekalla
10 * Noureddine Jemmali
12 * Copyright 2000 Andreas Mohr
13 * Copyright 2002 Jaco Greeff
15 * This library is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU Lesser General Public
17 * License as published by the Free Software Foundation; either
18 * version 2.1 of the License, or (at your option) any later version.
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "config.h"
31 #include "wine/port.h"
33 #include <errno.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/types.h>
39 #ifdef HAVE_SYS_SOCKET_H
40 # include <sys/socket.h>
41 #endif
42 #ifdef HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif
45 #include <time.h>
46 #include <assert.h>
48 #include "windef.h"
49 #include "winbase.h"
50 #include "wingdi.h"
51 #include "winuser.h"
52 #include "wininet.h"
53 #include "winnls.h"
54 #include "winerror.h"
55 #include "winreg.h"
56 #include "winternl.h"
57 #include "shlwapi.h"
59 #include "wine/debug.h"
60 #include "internet.h"
62 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
64 #define DATA_PACKET_SIZE 0x2000
65 #define szCRLF "\r\n"
66 #define MAX_BACKLOG 5
68 /* Testing shows that Windows only accepts dwFlags where the last
69 * 3 (yes 3) bits define FTP_TRANSFER_TYPE_UNKNOWN, FTP_TRANSFER_TYPE_ASCII or FTP_TRANSFER_TYPE_BINARY.
71 #define FTP_CONDITION_MASK 0x0007
73 typedef enum {
74 /* FTP commands with arguments. */
75 FTP_CMD_ACCT,
76 FTP_CMD_CWD,
77 FTP_CMD_DELE,
78 FTP_CMD_MKD,
79 FTP_CMD_PASS,
80 FTP_CMD_PORT,
81 FTP_CMD_RETR,
82 FTP_CMD_RMD,
83 FTP_CMD_RNFR,
84 FTP_CMD_RNTO,
85 FTP_CMD_STOR,
86 FTP_CMD_TYPE,
87 FTP_CMD_USER,
88 FTP_CMD_SIZE,
90 /* FTP commands without arguments. */
91 FTP_CMD_ABOR,
92 FTP_CMD_LIST,
93 FTP_CMD_NLST,
94 FTP_CMD_PASV,
95 FTP_CMD_PWD,
96 FTP_CMD_QUIT,
97 } FTP_COMMAND;
99 static const CHAR *const szFtpCommands[] = {
100 "ACCT",
101 "CWD",
102 "DELE",
103 "MKD",
104 "PASS",
105 "PORT",
106 "RETR",
107 "RMD",
108 "RNFR",
109 "RNTO",
110 "STOR",
111 "TYPE",
112 "USER",
113 "SIZE",
114 "ABOR",
115 "LIST",
116 "NLST",
117 "PASV",
118 "PWD",
119 "QUIT",
122 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
123 static const WCHAR szNoAccount[] = {'n','o','a','c','c','o','u','n','t','\0'};
125 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr);
126 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr);
127 static void FTP_CloseConnection(LPWININETHANDLEHEADER hdr);
128 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr);
129 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
130 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext);
131 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
132 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket);
133 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile);
134 static INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD_PTR dwContext);
135 static BOOL FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
136 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile);
137 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs);
138 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs);
139 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs);
140 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs);
141 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType);
142 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs);
143 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs);
144 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs);
145 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp);
146 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW fileprop);
147 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
148 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp);
149 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
150 LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext);
151 static DWORD FTP_SetResponseError(DWORD dwResponse);
153 /***********************************************************************
154 * FtpPutFileA (WININET.@)
156 * Uploads a file to the FTP server
158 * RETURNS
159 * TRUE on success
160 * FALSE on failure
163 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
164 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext)
166 LPWSTR lpwzLocalFile;
167 LPWSTR lpwzNewRemoteFile;
168 BOOL ret;
170 lpwzLocalFile = lpszLocalFile?WININET_strdup_AtoW(lpszLocalFile):NULL;
171 lpwzNewRemoteFile = lpszNewRemoteFile?WININET_strdup_AtoW(lpszNewRemoteFile):NULL;
172 ret = FtpPutFileW(hConnect, lpwzLocalFile, lpwzNewRemoteFile,
173 dwFlags, dwContext);
174 HeapFree(GetProcessHeap(), 0, lpwzLocalFile);
175 HeapFree(GetProcessHeap(), 0, lpwzNewRemoteFile);
176 return ret;
179 static void AsyncFtpPutFileProc(WORKREQUEST *workRequest)
181 struct WORKREQ_FTPPUTFILEW const *req = &workRequest->u.FtpPutFileW;
182 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
184 TRACE("%p\n", lpwfs);
186 FTP_FtpPutFileW(lpwfs, req->lpszLocalFile,
187 req->lpszNewRemoteFile, req->dwFlags, req->dwContext);
189 HeapFree(GetProcessHeap(), 0, req->lpszLocalFile);
190 HeapFree(GetProcessHeap(), 0, req->lpszNewRemoteFile);
193 /***********************************************************************
194 * FtpPutFileW (WININET.@)
196 * Uploads a file to the FTP server
198 * RETURNS
199 * TRUE on success
200 * FALSE on failure
203 BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile,
204 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext)
206 LPWININETFTPSESSIONW lpwfs;
207 LPWININETAPPINFOW hIC = NULL;
208 BOOL r = FALSE;
210 if (!lpszLocalFile || !lpszNewRemoteFile)
212 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
213 return FALSE;
216 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
217 if (!lpwfs)
219 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
220 return FALSE;
223 if (WH_HFTPSESSION != lpwfs->hdr.htype)
225 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
226 goto lend;
229 if (lpwfs->download_in_progress != NULL)
231 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
232 goto lend;
235 if ((dwFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY)
237 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
238 goto lend;
241 hIC = lpwfs->lpAppInfo;
242 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
244 WORKREQUEST workRequest;
245 struct WORKREQ_FTPPUTFILEW *req = &workRequest.u.FtpPutFileW;
247 workRequest.asyncproc = AsyncFtpPutFileProc;
248 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
249 req->lpszLocalFile = WININET_strdupW(lpszLocalFile);
250 req->lpszNewRemoteFile = WININET_strdupW(lpszNewRemoteFile);
251 req->dwFlags = dwFlags;
252 req->dwContext = dwContext;
254 r = INTERNET_AsyncCall(&workRequest);
256 else
258 r = FTP_FtpPutFileW(lpwfs, lpszLocalFile,
259 lpszNewRemoteFile, dwFlags, dwContext);
262 lend:
263 WININET_Release( &lpwfs->hdr );
265 return r;
268 /***********************************************************************
269 * FTP_FtpPutFileW (Internal)
271 * Uploads a file to the FTP server
273 * RETURNS
274 * TRUE on success
275 * FALSE on failure
278 BOOL WINAPI FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile,
279 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext)
281 HANDLE hFile;
282 BOOL bSuccess = FALSE;
283 LPWININETAPPINFOW hIC = NULL;
284 INT nResCode;
286 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", debugstr_w(lpszLocalFile), debugstr_w(lpszNewRemoteFile));
288 /* Clear any error information */
289 INTERNET_SetLastError(0);
291 /* Open file to be uploaded */
292 if (INVALID_HANDLE_VALUE ==
293 (hFile = CreateFileW(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
294 /* Let CreateFile set the appropriate error */
295 return FALSE;
297 hIC = lpwfs->lpAppInfo;
299 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
301 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
303 INT nDataSocket;
305 /* Get data socket to server */
306 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
308 FTP_SendData(lpwfs, nDataSocket, hFile);
309 closesocket(nDataSocket);
310 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
311 if (nResCode)
313 if (nResCode == 226)
314 bSuccess = TRUE;
315 else
316 FTP_SetResponseError(nResCode);
321 if (lpwfs->lstnSocket != -1)
322 closesocket(lpwfs->lstnSocket);
324 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
326 INTERNET_ASYNC_RESULT iar;
328 iar.dwResult = (DWORD)bSuccess;
329 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
330 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
331 &iar, sizeof(INTERNET_ASYNC_RESULT));
334 CloseHandle(hFile);
336 return bSuccess;
340 /***********************************************************************
341 * FtpSetCurrentDirectoryA (WININET.@)
343 * Change the working directory on the FTP server
345 * RETURNS
346 * TRUE on success
347 * FALSE on failure
350 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
352 LPWSTR lpwzDirectory;
353 BOOL ret;
355 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
356 ret = FtpSetCurrentDirectoryW(hConnect, lpwzDirectory);
357 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
358 return ret;
362 static void AsyncFtpSetCurrentDirectoryProc(WORKREQUEST *workRequest)
364 struct WORKREQ_FTPSETCURRENTDIRECTORYW const *req = &workRequest->u.FtpSetCurrentDirectoryW;
365 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
367 TRACE("%p\n", lpwfs);
369 FTP_FtpSetCurrentDirectoryW(lpwfs, req->lpszDirectory);
370 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
373 /***********************************************************************
374 * FtpSetCurrentDirectoryW (WININET.@)
376 * Change the working directory on the FTP server
378 * RETURNS
379 * TRUE on success
380 * FALSE on failure
383 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
385 LPWININETFTPSESSIONW lpwfs = NULL;
386 LPWININETAPPINFOW hIC = NULL;
387 BOOL r = FALSE;
389 if (!lpszDirectory)
391 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
392 goto lend;
395 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
396 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
398 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
399 goto lend;
402 if (lpwfs->download_in_progress != NULL)
404 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
405 goto lend;
408 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
410 hIC = lpwfs->lpAppInfo;
411 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
413 WORKREQUEST workRequest;
414 struct WORKREQ_FTPSETCURRENTDIRECTORYW *req;
416 workRequest.asyncproc = AsyncFtpSetCurrentDirectoryProc;
417 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
418 req = &workRequest.u.FtpSetCurrentDirectoryW;
419 req->lpszDirectory = WININET_strdupW(lpszDirectory);
421 r = INTERNET_AsyncCall(&workRequest);
423 else
425 r = FTP_FtpSetCurrentDirectoryW(lpwfs, lpszDirectory);
428 lend:
429 if( lpwfs )
430 WININET_Release( &lpwfs->hdr );
432 return r;
436 /***********************************************************************
437 * FTP_FtpSetCurrentDirectoryW (Internal)
439 * Change the working directory on the FTP server
441 * RETURNS
442 * TRUE on success
443 * FALSE on failure
446 BOOL WINAPI FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
448 INT nResCode;
449 LPWININETAPPINFOW hIC = NULL;
450 DWORD bSuccess = FALSE;
452 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
454 /* Clear any error information */
455 INTERNET_SetLastError(0);
457 hIC = lpwfs->lpAppInfo;
458 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
459 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
460 goto lend;
462 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
464 if (nResCode)
466 if (nResCode == 250)
467 bSuccess = TRUE;
468 else
469 FTP_SetResponseError(nResCode);
472 lend:
473 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
475 INTERNET_ASYNC_RESULT iar;
477 iar.dwResult = (DWORD)bSuccess;
478 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
479 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
480 &iar, sizeof(INTERNET_ASYNC_RESULT));
482 return bSuccess;
486 /***********************************************************************
487 * FtpCreateDirectoryA (WININET.@)
489 * Create new directory on the FTP server
491 * RETURNS
492 * TRUE on success
493 * FALSE on failure
496 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
498 LPWSTR lpwzDirectory;
499 BOOL ret;
501 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
502 ret = FtpCreateDirectoryW(hConnect, lpwzDirectory);
503 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
504 return ret;
508 static void AsyncFtpCreateDirectoryProc(WORKREQUEST *workRequest)
510 struct WORKREQ_FTPCREATEDIRECTORYW const *req = &workRequest->u.FtpCreateDirectoryW;
511 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
513 TRACE(" %p\n", lpwfs);
515 FTP_FtpCreateDirectoryW(lpwfs, req->lpszDirectory);
516 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
519 /***********************************************************************
520 * FtpCreateDirectoryW (WININET.@)
522 * Create new directory on the FTP server
524 * RETURNS
525 * TRUE on success
526 * FALSE on failure
529 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
531 LPWININETFTPSESSIONW lpwfs;
532 LPWININETAPPINFOW hIC = NULL;
533 BOOL r = FALSE;
535 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
536 if (!lpwfs)
538 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
539 return FALSE;
542 if (WH_HFTPSESSION != lpwfs->hdr.htype)
544 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
545 goto lend;
548 if (lpwfs->download_in_progress != NULL)
550 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
551 goto lend;
554 if (!lpszDirectory)
556 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
557 goto lend;
560 hIC = lpwfs->lpAppInfo;
561 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
563 WORKREQUEST workRequest;
564 struct WORKREQ_FTPCREATEDIRECTORYW *req;
566 workRequest.asyncproc = AsyncFtpCreateDirectoryProc;
567 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
568 req = &workRequest.u.FtpCreateDirectoryW;
569 req->lpszDirectory = WININET_strdupW(lpszDirectory);
571 r = INTERNET_AsyncCall(&workRequest);
573 else
575 r = FTP_FtpCreateDirectoryW(lpwfs, lpszDirectory);
577 lend:
578 WININET_Release( &lpwfs->hdr );
580 return r;
584 /***********************************************************************
585 * FTP_FtpCreateDirectoryW (Internal)
587 * Create new directory on the FTP server
589 * RETURNS
590 * TRUE on success
591 * FALSE on failure
594 BOOL WINAPI FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
596 INT nResCode;
597 BOOL bSuccess = FALSE;
598 LPWININETAPPINFOW hIC = NULL;
600 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
602 /* Clear any error information */
603 INTERNET_SetLastError(0);
605 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
606 goto lend;
608 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
609 if (nResCode)
611 if (nResCode == 257)
612 bSuccess = TRUE;
613 else
614 FTP_SetResponseError(nResCode);
617 lend:
618 hIC = lpwfs->lpAppInfo;
619 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
621 INTERNET_ASYNC_RESULT iar;
623 iar.dwResult = (DWORD)bSuccess;
624 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
625 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
626 &iar, sizeof(INTERNET_ASYNC_RESULT));
629 return bSuccess;
632 /***********************************************************************
633 * FtpFindFirstFileA (WININET.@)
635 * Search the specified directory
637 * RETURNS
638 * HINTERNET on success
639 * NULL on failure
642 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
643 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext)
645 LPWSTR lpwzSearchFile;
646 WIN32_FIND_DATAW wfd;
647 LPWIN32_FIND_DATAW lpFindFileDataW;
648 HINTERNET ret;
650 lpwzSearchFile = lpszSearchFile?WININET_strdup_AtoW(lpszSearchFile):NULL;
651 lpFindFileDataW = lpFindFileData?&wfd:NULL;
652 ret = FtpFindFirstFileW(hConnect, lpwzSearchFile, lpFindFileDataW, dwFlags, dwContext);
653 HeapFree(GetProcessHeap(), 0, lpwzSearchFile);
655 if(lpFindFileData) {
656 WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData);
658 return ret;
662 static void AsyncFtpFindFirstFileProc(WORKREQUEST *workRequest)
664 struct WORKREQ_FTPFINDFIRSTFILEW const *req = &workRequest->u.FtpFindFirstFileW;
665 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
667 TRACE("%p\n", lpwfs);
669 FTP_FtpFindFirstFileW(lpwfs, req->lpszSearchFile,
670 req->lpFindFileData, req->dwFlags, req->dwContext);
671 HeapFree(GetProcessHeap(), 0, req->lpszSearchFile);
674 /***********************************************************************
675 * FtpFindFirstFileW (WININET.@)
677 * Search the specified directory
679 * RETURNS
680 * HINTERNET on success
681 * NULL on failure
684 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
685 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext)
687 LPWININETFTPSESSIONW lpwfs;
688 LPWININETAPPINFOW hIC = NULL;
689 HINTERNET r = NULL;
691 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
692 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
694 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
695 goto lend;
698 if (lpwfs->download_in_progress != NULL)
700 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
701 goto lend;
704 hIC = lpwfs->lpAppInfo;
705 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
707 WORKREQUEST workRequest;
708 struct WORKREQ_FTPFINDFIRSTFILEW *req;
710 workRequest.asyncproc = AsyncFtpFindFirstFileProc;
711 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
712 req = &workRequest.u.FtpFindFirstFileW;
713 req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : WININET_strdupW(lpszSearchFile);
714 req->lpFindFileData = lpFindFileData;
715 req->dwFlags = dwFlags;
716 req->dwContext= dwContext;
718 INTERNET_AsyncCall(&workRequest);
719 r = NULL;
721 else
723 r = FTP_FtpFindFirstFileW(lpwfs, lpszSearchFile, lpFindFileData,
724 dwFlags, dwContext);
726 lend:
727 if( lpwfs )
728 WININET_Release( &lpwfs->hdr );
730 return r;
734 /***********************************************************************
735 * FTP_FtpFindFirstFileW (Internal)
737 * Search the specified directory
739 * RETURNS
740 * HINTERNET on success
741 * NULL on failure
744 HINTERNET WINAPI FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs,
745 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext)
747 INT nResCode;
748 LPWININETAPPINFOW hIC = NULL;
749 HINTERNET hFindNext = NULL;
751 TRACE("\n");
753 /* Clear any error information */
754 INTERNET_SetLastError(0);
756 if (!FTP_InitListenSocket(lpwfs))
757 goto lend;
759 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
760 goto lend;
762 if (!FTP_SendPortOrPasv(lpwfs))
763 goto lend;
765 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, NULL,
766 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
767 goto lend;
769 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
770 if (nResCode)
772 if (nResCode == 125 || nResCode == 150)
774 INT nDataSocket;
776 /* Get data socket to server */
777 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
779 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpszSearchFile, lpFindFileData, dwContext);
780 closesocket(nDataSocket);
781 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
782 if (nResCode != 226 && nResCode != 250)
783 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
786 else
787 FTP_SetResponseError(nResCode);
790 lend:
791 if (lpwfs->lstnSocket != -1)
792 closesocket(lpwfs->lstnSocket);
794 hIC = lpwfs->lpAppInfo;
795 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
797 INTERNET_ASYNC_RESULT iar;
799 if (hFindNext)
801 iar.dwResult = (DWORD)hFindNext;
802 iar.dwError = ERROR_SUCCESS;
803 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
804 &iar, sizeof(INTERNET_ASYNC_RESULT));
807 iar.dwResult = (DWORD)hFindNext;
808 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
809 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
810 &iar, sizeof(INTERNET_ASYNC_RESULT));
813 return hFindNext;
817 /***********************************************************************
818 * FtpGetCurrentDirectoryA (WININET.@)
820 * Retrieves the current directory
822 * RETURNS
823 * TRUE on success
824 * FALSE on failure
827 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
828 LPDWORD lpdwCurrentDirectory)
830 WCHAR *dir = NULL;
831 DWORD len;
832 BOOL ret;
834 if(lpdwCurrentDirectory) {
835 len = *lpdwCurrentDirectory;
836 if(lpszCurrentDirectory)
838 dir = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
839 if (NULL == dir)
841 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
842 return FALSE;
846 ret = FtpGetCurrentDirectoryW(hFtpSession, lpszCurrentDirectory?dir:NULL, lpdwCurrentDirectory?&len:NULL);
847 if(lpdwCurrentDirectory) {
848 *lpdwCurrentDirectory = len;
849 if(lpszCurrentDirectory) {
850 WideCharToMultiByte(CP_ACP, 0, dir, len, lpszCurrentDirectory, *lpdwCurrentDirectory, NULL, NULL);
851 HeapFree(GetProcessHeap(), 0, dir);
854 return ret;
858 static void AsyncFtpGetCurrentDirectoryProc(WORKREQUEST *workRequest)
860 struct WORKREQ_FTPGETCURRENTDIRECTORYW const *req = &workRequest->u.FtpGetCurrentDirectoryW;
861 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
863 TRACE("%p\n", lpwfs);
865 FTP_FtpGetCurrentDirectoryW(lpwfs, req->lpszDirectory, req->lpdwDirectory);
868 /***********************************************************************
869 * FtpGetCurrentDirectoryW (WININET.@)
871 * Retrieves the current directory
873 * RETURNS
874 * TRUE on success
875 * FALSE on failure
878 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
879 LPDWORD lpdwCurrentDirectory)
881 LPWININETFTPSESSIONW lpwfs;
882 LPWININETAPPINFOW hIC = NULL;
883 BOOL r = FALSE;
885 TRACE("len(%d)\n", *lpdwCurrentDirectory);
887 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
888 if (NULL == lpwfs)
890 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
891 goto lend;
894 if (WH_HFTPSESSION != lpwfs->hdr.htype)
896 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
897 goto lend;
900 if (!lpdwCurrentDirectory)
902 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
903 goto lend;
906 if (lpszCurrentDirectory == NULL)
908 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
909 goto lend;
912 if (lpwfs->download_in_progress != NULL)
914 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
915 goto lend;
918 hIC = lpwfs->lpAppInfo;
919 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
921 WORKREQUEST workRequest;
922 struct WORKREQ_FTPGETCURRENTDIRECTORYW *req;
924 workRequest.asyncproc = AsyncFtpGetCurrentDirectoryProc;
925 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
926 req = &workRequest.u.FtpGetCurrentDirectoryW;
927 req->lpszDirectory = lpszCurrentDirectory;
928 req->lpdwDirectory = lpdwCurrentDirectory;
930 r = INTERNET_AsyncCall(&workRequest);
932 else
934 r = FTP_FtpGetCurrentDirectoryW(lpwfs, lpszCurrentDirectory,
935 lpdwCurrentDirectory);
938 lend:
939 if( lpwfs )
940 WININET_Release( &lpwfs->hdr );
942 return r;
946 /***********************************************************************
947 * FTP_FtpGetCurrentDirectoryW (Internal)
949 * Retrieves the current directory
951 * RETURNS
952 * TRUE on success
953 * FALSE on failure
956 BOOL WINAPI FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszCurrentDirectory,
957 LPDWORD lpdwCurrentDirectory)
959 INT nResCode;
960 LPWININETAPPINFOW hIC = NULL;
961 DWORD bSuccess = FALSE;
963 TRACE("len(%d)\n", *lpdwCurrentDirectory);
965 /* Clear any error information */
966 INTERNET_SetLastError(0);
968 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
970 hIC = lpwfs->lpAppInfo;
971 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
972 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
973 goto lend;
975 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
976 if (nResCode)
978 if (nResCode == 257) /* Extract directory name */
980 DWORD firstpos, lastpos, len;
981 LPWSTR lpszResponseBuffer = WININET_strdup_AtoW(INTERNET_GetResponseBuffer());
983 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
985 if ('"' == lpszResponseBuffer[lastpos])
987 if (!firstpos)
988 firstpos = lastpos;
989 else
990 break;
994 len = lastpos - firstpos - 1;
995 lstrcpynW(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1], *lpdwCurrentDirectory);
996 HeapFree(GetProcessHeap(), 0, lpszResponseBuffer);
997 *lpdwCurrentDirectory = len;
998 bSuccess = TRUE;
1000 else
1001 FTP_SetResponseError(nResCode);
1004 lend:
1005 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1007 INTERNET_ASYNC_RESULT iar;
1009 iar.dwResult = (DWORD)bSuccess;
1010 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
1011 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1012 &iar, sizeof(INTERNET_ASYNC_RESULT));
1015 return (DWORD) bSuccess;
1018 /***********************************************************************
1019 * FtpOpenFileA (WININET.@)
1021 * Open a remote file for writing or reading
1023 * RETURNS
1024 * HINTERNET handle on success
1025 * NULL on failure
1028 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
1029 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1030 DWORD_PTR dwContext)
1032 LPWSTR lpwzFileName;
1033 HINTERNET ret;
1035 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1036 ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext);
1037 HeapFree(GetProcessHeap(), 0, lpwzFileName);
1038 return ret;
1042 static void AsyncFtpOpenFileProc(WORKREQUEST *workRequest)
1044 struct WORKREQ_FTPOPENFILEW const *req = &workRequest->u.FtpOpenFileW;
1045 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1047 TRACE("%p\n", lpwfs);
1049 FTP_FtpOpenFileW(lpwfs, req->lpszFilename,
1050 req->dwAccess, req->dwFlags, req->dwContext);
1051 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1054 /***********************************************************************
1055 * FtpOpenFileW (WININET.@)
1057 * Open a remote file for writing or reading
1059 * RETURNS
1060 * HINTERNET handle on success
1061 * NULL on failure
1064 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
1065 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1066 DWORD_PTR dwContext)
1068 LPWININETFTPSESSIONW lpwfs;
1069 LPWININETAPPINFOW hIC = NULL;
1070 HINTERNET r = NULL;
1072 TRACE("(%p,%s,0x%08x,0x%08x,0x%08lx)\n", hFtpSession,
1073 debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext);
1075 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1076 if (!lpwfs)
1078 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1079 return FALSE;
1082 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1084 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1085 goto lend;
1088 if ((!lpszFileName) ||
1089 ((fdwAccess != GENERIC_READ) && (fdwAccess != GENERIC_WRITE)) ||
1090 ((dwFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY))
1092 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1093 goto lend;
1096 if (lpwfs->download_in_progress != NULL)
1098 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1099 goto lend;
1102 hIC = lpwfs->lpAppInfo;
1103 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1105 WORKREQUEST workRequest;
1106 struct WORKREQ_FTPOPENFILEW *req;
1108 workRequest.asyncproc = AsyncFtpOpenFileProc;
1109 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1110 req = &workRequest.u.FtpOpenFileW;
1111 req->lpszFilename = WININET_strdupW(lpszFileName);
1112 req->dwAccess = fdwAccess;
1113 req->dwFlags = dwFlags;
1114 req->dwContext = dwContext;
1116 INTERNET_AsyncCall(&workRequest);
1117 r = NULL;
1119 else
1121 r = FTP_FtpOpenFileW(lpwfs, lpszFileName, fdwAccess, dwFlags, dwContext);
1124 lend:
1125 WININET_Release( &lpwfs->hdr );
1127 return r;
1131 /***********************************************************************
1132 * FTP_FtpOpenFileW (Internal)
1134 * Open a remote file for writing or reading
1136 * RETURNS
1137 * HINTERNET handle on success
1138 * NULL on failure
1141 HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs,
1142 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1143 DWORD_PTR dwContext)
1145 INT nDataSocket;
1146 BOOL bSuccess = FALSE;
1147 LPWININETFTPFILE lpwh = NULL;
1148 LPWININETAPPINFOW hIC = NULL;
1149 HINTERNET handle = NULL;
1151 TRACE("\n");
1153 /* Clear any error information */
1154 INTERNET_SetLastError(0);
1156 if (GENERIC_READ == fdwAccess)
1158 /* Set up socket to retrieve data */
1159 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
1161 else if (GENERIC_WRITE == fdwAccess)
1163 /* Set up socket to send data */
1164 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
1167 /* Get data socket to server */
1168 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
1170 lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPFILE));
1171 lpwh->hdr.htype = WH_HFILE;
1172 lpwh->hdr.dwFlags = dwFlags;
1173 lpwh->hdr.dwContext = dwContext;
1174 lpwh->hdr.dwRefCount = 1;
1175 lpwh->hdr.close_connection = NULL;
1176 lpwh->hdr.destroy = FTP_CloseFileTransferHandle;
1177 lpwh->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
1178 lpwh->nDataSocket = nDataSocket;
1179 lpwh->session_deleted = FALSE;
1181 WININET_AddRef( &lpwfs->hdr );
1182 lpwh->lpFtpSession = lpwfs;
1183 list_add_head( &lpwfs->hdr.children, &lpwh->hdr.entry );
1185 handle = WININET_AllocHandle( &lpwh->hdr );
1186 if( !handle )
1187 goto lend;
1189 /* Indicate that a download is currently in progress */
1190 lpwfs->download_in_progress = lpwh;
1193 if (lpwfs->lstnSocket != -1)
1194 closesocket(lpwfs->lstnSocket);
1196 hIC = lpwfs->lpAppInfo;
1197 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1199 INTERNET_ASYNC_RESULT iar;
1201 if (lpwh)
1203 iar.dwResult = (DWORD)handle;
1204 iar.dwError = ERROR_SUCCESS;
1205 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
1206 &iar, sizeof(INTERNET_ASYNC_RESULT));
1209 iar.dwResult = (DWORD)bSuccess;
1210 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1211 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1212 &iar, sizeof(INTERNET_ASYNC_RESULT));
1215 lend:
1216 if( lpwh )
1217 WININET_Release( &lpwh->hdr );
1219 return handle;
1223 /***********************************************************************
1224 * FtpGetFileA (WININET.@)
1226 * Retrieve file from the FTP server
1228 * RETURNS
1229 * TRUE on success
1230 * FALSE on failure
1233 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1234 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1235 DWORD_PTR dwContext)
1237 LPWSTR lpwzRemoteFile;
1238 LPWSTR lpwzNewFile;
1239 BOOL ret;
1241 lpwzRemoteFile = lpszRemoteFile?WININET_strdup_AtoW(lpszRemoteFile):NULL;
1242 lpwzNewFile = lpszNewFile?WININET_strdup_AtoW(lpszNewFile):NULL;
1243 ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists,
1244 dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1245 HeapFree(GetProcessHeap(), 0, lpwzRemoteFile);
1246 HeapFree(GetProcessHeap(), 0, lpwzNewFile);
1247 return ret;
1251 static void AsyncFtpGetFileProc(WORKREQUEST *workRequest)
1253 struct WORKREQ_FTPGETFILEW const *req = &workRequest->u.FtpGetFileW;
1254 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1256 TRACE("%p\n", lpwfs);
1258 FTP_FtpGetFileW(lpwfs, req->lpszRemoteFile,
1259 req->lpszNewFile, req->fFailIfExists,
1260 req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext);
1261 HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile);
1262 HeapFree(GetProcessHeap(), 0, req->lpszNewFile);
1266 /***********************************************************************
1267 * FtpGetFileW (WININET.@)
1269 * Retrieve file from the FTP server
1271 * RETURNS
1272 * TRUE on success
1273 * FALSE on failure
1276 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1277 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1278 DWORD_PTR dwContext)
1280 LPWININETFTPSESSIONW lpwfs;
1281 LPWININETAPPINFOW hIC = NULL;
1282 BOOL r = FALSE;
1284 if (!lpszRemoteFile || !lpszNewFile)
1286 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1287 return FALSE;
1290 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet );
1291 if (!lpwfs)
1293 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1294 return FALSE;
1297 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1299 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1300 goto lend;
1303 if ((dwInternetFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY)
1305 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1306 goto lend;
1309 if (lpwfs->download_in_progress != NULL)
1311 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1312 goto lend;
1315 hIC = lpwfs->lpAppInfo;
1316 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1318 WORKREQUEST workRequest;
1319 struct WORKREQ_FTPGETFILEW *req;
1321 workRequest.asyncproc = AsyncFtpGetFileProc;
1322 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1323 req = &workRequest.u.FtpGetFileW;
1324 req->lpszRemoteFile = WININET_strdupW(lpszRemoteFile);
1325 req->lpszNewFile = WININET_strdupW(lpszNewFile);
1326 req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1327 req->fFailIfExists = fFailIfExists;
1328 req->dwFlags = dwInternetFlags;
1329 req->dwContext = dwContext;
1331 r = INTERNET_AsyncCall(&workRequest);
1333 else
1335 r = FTP_FtpGetFileW(lpwfs, lpszRemoteFile, lpszNewFile,
1336 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1339 lend:
1340 WININET_Release( &lpwfs->hdr );
1342 return r;
1346 /***********************************************************************
1347 * FTP_FtpGetFileW (Internal)
1349 * Retrieve file from the FTP server
1351 * RETURNS
1352 * TRUE on success
1353 * FALSE on failure
1356 BOOL WINAPI FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1357 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1358 DWORD_PTR dwContext)
1360 BOOL bSuccess = FALSE;
1361 HANDLE hFile;
1362 LPWININETAPPINFOW hIC = NULL;
1364 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile));
1366 /* Clear any error information */
1367 INTERNET_SetLastError(0);
1369 /* Ensure we can write to lpszNewfile by opening it */
1370 hFile = CreateFileW(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1371 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1372 if (INVALID_HANDLE_VALUE == hFile)
1373 return FALSE;
1375 /* Set up socket to retrieve data */
1376 if (FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags))
1378 INT nDataSocket;
1380 /* Get data socket to server */
1381 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1383 INT nResCode;
1385 /* Receive data */
1386 FTP_RetrieveFileData(lpwfs, nDataSocket, hFile);
1387 closesocket(nDataSocket);
1389 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
1390 if (nResCode)
1392 if (nResCode == 226)
1393 bSuccess = TRUE;
1394 else
1395 FTP_SetResponseError(nResCode);
1400 if (lpwfs->lstnSocket != -1)
1401 closesocket(lpwfs->lstnSocket);
1403 CloseHandle(hFile);
1405 hIC = lpwfs->lpAppInfo;
1406 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1408 INTERNET_ASYNC_RESULT iar;
1410 iar.dwResult = (DWORD)bSuccess;
1411 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1412 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1413 &iar, sizeof(INTERNET_ASYNC_RESULT));
1416 return bSuccess;
1419 /***********************************************************************
1420 * FtpGetFileSize (WININET.@)
1422 DWORD WINAPI FtpGetFileSize( HINTERNET hFile, LPDWORD lpdwFileSizeHigh )
1424 FIXME("(%p, %p)\n", hFile, lpdwFileSizeHigh);
1426 if (lpdwFileSizeHigh)
1427 *lpdwFileSizeHigh = 0;
1429 return 0;
1432 /***********************************************************************
1433 * FtpDeleteFileA (WININET.@)
1435 * Delete a file on the ftp server
1437 * RETURNS
1438 * TRUE on success
1439 * FALSE on failure
1442 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1444 LPWSTR lpwzFileName;
1445 BOOL ret;
1447 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1448 ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1449 HeapFree(GetProcessHeap(), 0, lpwzFileName);
1450 return ret;
1453 static void AsyncFtpDeleteFileProc(WORKREQUEST *workRequest)
1455 struct WORKREQ_FTPDELETEFILEW const *req = &workRequest->u.FtpDeleteFileW;
1456 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1458 TRACE("%p\n", lpwfs);
1460 FTP_FtpDeleteFileW(lpwfs, req->lpszFilename);
1461 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1464 /***********************************************************************
1465 * FtpDeleteFileW (WININET.@)
1467 * Delete a file on the ftp server
1469 * RETURNS
1470 * TRUE on success
1471 * FALSE on failure
1474 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1476 LPWININETFTPSESSIONW lpwfs;
1477 LPWININETAPPINFOW hIC = NULL;
1478 BOOL r = FALSE;
1480 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1481 if (!lpwfs)
1483 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1484 return FALSE;
1487 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1489 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1490 goto lend;
1493 if (lpwfs->download_in_progress != NULL)
1495 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1496 goto lend;
1499 if (!lpszFileName)
1501 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1502 goto lend;
1505 hIC = lpwfs->lpAppInfo;
1506 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1508 WORKREQUEST workRequest;
1509 struct WORKREQ_FTPDELETEFILEW *req;
1511 workRequest.asyncproc = AsyncFtpDeleteFileProc;
1512 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1513 req = &workRequest.u.FtpDeleteFileW;
1514 req->lpszFilename = WININET_strdupW(lpszFileName);
1516 r = INTERNET_AsyncCall(&workRequest);
1518 else
1520 r = FTP_FtpDeleteFileW(lpwfs, lpszFileName);
1523 lend:
1524 WININET_Release( &lpwfs->hdr );
1526 return r;
1529 /***********************************************************************
1530 * FTP_FtpDeleteFileW (Internal)
1532 * Delete a file on the ftp server
1534 * RETURNS
1535 * TRUE on success
1536 * FALSE on failure
1539 BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName)
1541 INT nResCode;
1542 BOOL bSuccess = FALSE;
1543 LPWININETAPPINFOW hIC = NULL;
1545 TRACE("%p\n", lpwfs);
1547 /* Clear any error information */
1548 INTERNET_SetLastError(0);
1550 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1551 goto lend;
1553 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1554 if (nResCode)
1556 if (nResCode == 250)
1557 bSuccess = TRUE;
1558 else
1559 FTP_SetResponseError(nResCode);
1561 lend:
1562 hIC = lpwfs->lpAppInfo;
1563 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1565 INTERNET_ASYNC_RESULT iar;
1567 iar.dwResult = (DWORD)bSuccess;
1568 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1569 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1570 &iar, sizeof(INTERNET_ASYNC_RESULT));
1573 return bSuccess;
1577 /***********************************************************************
1578 * FtpRemoveDirectoryA (WININET.@)
1580 * Remove a directory on the ftp server
1582 * RETURNS
1583 * TRUE on success
1584 * FALSE on failure
1587 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1589 LPWSTR lpwzDirectory;
1590 BOOL ret;
1592 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
1593 ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1594 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
1595 return ret;
1598 static void AsyncFtpRemoveDirectoryProc(WORKREQUEST *workRequest)
1600 struct WORKREQ_FTPREMOVEDIRECTORYW const *req = &workRequest->u.FtpRemoveDirectoryW;
1601 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1603 TRACE("%p\n", lpwfs);
1605 FTP_FtpRemoveDirectoryW(lpwfs, req->lpszDirectory);
1606 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
1609 /***********************************************************************
1610 * FtpRemoveDirectoryW (WININET.@)
1612 * Remove a directory on the ftp server
1614 * RETURNS
1615 * TRUE on success
1616 * FALSE on failure
1619 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1621 LPWININETFTPSESSIONW lpwfs;
1622 LPWININETAPPINFOW hIC = NULL;
1623 BOOL r = FALSE;
1625 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1626 if (!lpwfs)
1628 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1629 return FALSE;
1632 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1634 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1635 goto lend;
1638 if (lpwfs->download_in_progress != NULL)
1640 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1641 goto lend;
1644 if (!lpszDirectory)
1646 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1647 goto lend;
1650 hIC = lpwfs->lpAppInfo;
1651 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1653 WORKREQUEST workRequest;
1654 struct WORKREQ_FTPREMOVEDIRECTORYW *req;
1656 workRequest.asyncproc = AsyncFtpRemoveDirectoryProc;
1657 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1658 req = &workRequest.u.FtpRemoveDirectoryW;
1659 req->lpszDirectory = WININET_strdupW(lpszDirectory);
1661 r = INTERNET_AsyncCall(&workRequest);
1663 else
1665 r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory);
1668 lend:
1669 WININET_Release( &lpwfs->hdr );
1671 return r;
1674 /***********************************************************************
1675 * FTP_FtpRemoveDirectoryW (Internal)
1677 * Remove a directory on the ftp server
1679 * RETURNS
1680 * TRUE on success
1681 * FALSE on failure
1684 BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
1686 INT nResCode;
1687 BOOL bSuccess = FALSE;
1688 LPWININETAPPINFOW hIC = NULL;
1690 TRACE("\n");
1692 /* Clear any error information */
1693 INTERNET_SetLastError(0);
1695 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1696 goto lend;
1698 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1699 if (nResCode)
1701 if (nResCode == 250)
1702 bSuccess = TRUE;
1703 else
1704 FTP_SetResponseError(nResCode);
1707 lend:
1708 hIC = lpwfs->lpAppInfo;
1709 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1711 INTERNET_ASYNC_RESULT iar;
1713 iar.dwResult = (DWORD)bSuccess;
1714 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1715 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1716 &iar, sizeof(INTERNET_ASYNC_RESULT));
1719 return bSuccess;
1723 /***********************************************************************
1724 * FtpRenameFileA (WININET.@)
1726 * Rename a file on the ftp server
1728 * RETURNS
1729 * TRUE on success
1730 * FALSE on failure
1733 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1735 LPWSTR lpwzSrc;
1736 LPWSTR lpwzDest;
1737 BOOL ret;
1739 lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL;
1740 lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL;
1741 ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
1742 HeapFree(GetProcessHeap(), 0, lpwzSrc);
1743 HeapFree(GetProcessHeap(), 0, lpwzDest);
1744 return ret;
1747 static void AsyncFtpRenameFileProc(WORKREQUEST *workRequest)
1749 struct WORKREQ_FTPRENAMEFILEW const *req = &workRequest->u.FtpRenameFileW;
1750 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1752 TRACE("%p\n", lpwfs);
1754 FTP_FtpRenameFileW(lpwfs, req->lpszSrcFile, req->lpszDestFile);
1755 HeapFree(GetProcessHeap(), 0, req->lpszSrcFile);
1756 HeapFree(GetProcessHeap(), 0, req->lpszDestFile);
1759 /***********************************************************************
1760 * FtpRenameFileW (WININET.@)
1762 * Rename a file on the ftp server
1764 * RETURNS
1765 * TRUE on success
1766 * FALSE on failure
1769 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
1771 LPWININETFTPSESSIONW lpwfs;
1772 LPWININETAPPINFOW hIC = NULL;
1773 BOOL r = FALSE;
1775 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1776 if (!lpwfs)
1778 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1779 return FALSE;
1782 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1784 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1785 goto lend;
1788 if (lpwfs->download_in_progress != NULL)
1790 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1791 goto lend;
1794 if (!lpszSrc || !lpszDest)
1796 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1797 goto lend;
1800 hIC = lpwfs->lpAppInfo;
1801 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1803 WORKREQUEST workRequest;
1804 struct WORKREQ_FTPRENAMEFILEW *req;
1806 workRequest.asyncproc = AsyncFtpRenameFileProc;
1807 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1808 req = &workRequest.u.FtpRenameFileW;
1809 req->lpszSrcFile = WININET_strdupW(lpszSrc);
1810 req->lpszDestFile = WININET_strdupW(lpszDest);
1812 r = INTERNET_AsyncCall(&workRequest);
1814 else
1816 r = FTP_FtpRenameFileW(lpwfs, lpszSrc, lpszDest);
1819 lend:
1820 WININET_Release( &lpwfs->hdr );
1822 return r;
1825 /***********************************************************************
1826 * FTP_FtpRenameFileW (Internal)
1828 * Rename a file on the ftp server
1830 * RETURNS
1831 * TRUE on success
1832 * FALSE on failure
1835 BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs,
1836 LPCWSTR lpszSrc, LPCWSTR lpszDest)
1838 INT nResCode;
1839 BOOL bSuccess = FALSE;
1840 LPWININETAPPINFOW hIC = NULL;
1842 TRACE("\n");
1844 /* Clear any error information */
1845 INTERNET_SetLastError(0);
1847 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1848 goto lend;
1850 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1851 if (nResCode == 350)
1853 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1854 goto lend;
1856 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1859 if (nResCode == 250)
1860 bSuccess = TRUE;
1861 else
1862 FTP_SetResponseError(nResCode);
1864 lend:
1865 hIC = lpwfs->lpAppInfo;
1866 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1868 INTERNET_ASYNC_RESULT iar;
1870 iar.dwResult = (DWORD)bSuccess;
1871 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1872 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1873 &iar, sizeof(INTERNET_ASYNC_RESULT));
1876 return bSuccess;
1879 /***********************************************************************
1880 * FtpCommandA (WININET.@)
1882 BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1883 LPCSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1885 BOOL r;
1886 WCHAR *cmdW;
1888 TRACE("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1889 debugstr_a(lpszCommand), dwContext, phFtpCommand);
1891 if (fExpectResponse)
1893 FIXME("data connection not supported\n");
1894 return FALSE;
1897 if (!lpszCommand || !lpszCommand[0])
1899 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1900 return FALSE;
1903 if (!(cmdW = WININET_strdup_AtoW(lpszCommand)))
1905 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1906 return FALSE;
1909 r = FtpCommandW(hConnect, fExpectResponse, dwFlags, cmdW, dwContext, phFtpCommand);
1911 HeapFree(GetProcessHeap(), 0, cmdW);
1912 return r;
1915 /***********************************************************************
1916 * FtpCommandW (WININET.@)
1918 BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1919 LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1921 BOOL r = FALSE;
1922 LPWININETFTPSESSIONW lpwfs;
1923 LPSTR cmd = NULL;
1924 DWORD len, nBytesSent= 0;
1925 INT nResCode, nRC = 0;
1927 TRACE("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1928 debugstr_w(lpszCommand), dwContext, phFtpCommand);
1930 if (!lpszCommand || !lpszCommand[0])
1932 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1933 return FALSE;
1936 if (fExpectResponse)
1938 FIXME("data connection not supported\n");
1939 return FALSE;
1942 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
1943 if (!lpwfs)
1945 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1946 return FALSE;
1949 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1951 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1952 goto lend;
1955 if (lpwfs->download_in_progress != NULL)
1957 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1958 goto lend;
1961 len = WideCharToMultiByte(CP_ACP, 0, lpszCommand, -1, NULL, 0, NULL, NULL) + strlen(szCRLF);
1962 if ((cmd = HeapAlloc(GetProcessHeap(), 0, len )))
1963 WideCharToMultiByte(CP_ACP, 0, lpszCommand, -1, cmd, len, NULL, NULL);
1964 else
1966 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1967 goto lend;
1970 strcat(cmd, szCRLF);
1971 len--;
1973 TRACE("Sending (%s) len(%d)\n", cmd, len);
1974 while ((nBytesSent < len) && (nRC != -1))
1976 nRC = send(lpwfs->sndSocket, cmd + nBytesSent, len - nBytesSent, 0);
1977 if (nRC != -1)
1979 nBytesSent += nRC;
1980 TRACE("Sent %d bytes\n", nRC);
1984 if (nBytesSent)
1986 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1987 if (nResCode > 0 && nResCode < 400)
1988 r = TRUE;
1989 else
1990 FTP_SetResponseError(nResCode);
1993 lend:
1994 WININET_Release( &lpwfs->hdr );
1995 HeapFree(GetProcessHeap(), 0, cmd);
1996 return r;
1999 /***********************************************************************
2000 * FTP_Connect (internal)
2002 * Connect to a ftp server
2004 * RETURNS
2005 * HINTERNET a session handle on success
2006 * NULL on failure
2008 * NOTES:
2010 * Windows uses 'anonymous' as the username, when given a NULL username
2011 * and a NULL password. The password is first looked up in:
2013 * HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\EmailName
2015 * If this entry is not present it uses the current username as the password.
2019 HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
2020 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
2021 LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext,
2022 DWORD dwInternalFlags)
2024 static const WCHAR szKey[] = {'S','o','f','t','w','a','r','e','\\',
2025 'M','i','c','r','o','s','o','f','t','\\',
2026 'W','i','n','d','o','w','s','\\',
2027 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2028 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
2029 static const WCHAR szValue[] = {'E','m','a','i','l','N','a','m','e',0};
2030 static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'};
2031 static const WCHAR szEmpty[] = {'\0'};
2032 struct sockaddr_in socketAddr;
2033 INT nsocket = -1;
2034 UINT sock_namelen;
2035 BOOL bSuccess = FALSE;
2036 LPWININETFTPSESSIONW lpwfs = NULL;
2037 HINTERNET handle = NULL;
2039 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
2040 hIC, debugstr_w(lpszServerName),
2041 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
2043 assert( hIC->hdr.htype == WH_HINIT );
2045 if (NULL == lpszUserName && NULL != lpszPassword)
2047 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2048 goto lerror;
2051 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
2052 if (NULL == lpwfs)
2054 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2055 goto lerror;
2058 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
2059 nServerPort = INTERNET_DEFAULT_FTP_PORT;
2061 lpwfs->hdr.htype = WH_HFTPSESSION;
2062 lpwfs->hdr.dwFlags = dwFlags;
2063 lpwfs->hdr.dwContext = dwContext;
2064 lpwfs->hdr.dwInternalFlags = dwInternalFlags;
2065 lpwfs->hdr.dwRefCount = 1;
2066 lpwfs->hdr.close_connection = FTP_CloseConnection;
2067 lpwfs->hdr.destroy = FTP_CloseSessionHandle;
2068 lpwfs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
2069 lpwfs->download_in_progress = NULL;
2070 lpwfs->sndSocket = -1;
2071 lpwfs->lstnSocket = -1;
2072 lpwfs->pasvSocket = -1;
2074 WININET_AddRef( &hIC->hdr );
2075 lpwfs->lpAppInfo = hIC;
2076 list_add_head( &hIC->hdr.children, &lpwfs->hdr.entry );
2078 handle = WININET_AllocHandle( &lpwfs->hdr );
2079 if( !handle )
2081 ERR("Failed to alloc handle\n");
2082 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2083 goto lerror;
2086 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
2087 if(strchrW(hIC->lpszProxy, ' '))
2088 FIXME("Several proxies not implemented.\n");
2089 if(hIC->lpszProxyBypass)
2090 FIXME("Proxy bypass is ignored.\n");
2092 if ( !lpszUserName) {
2093 HKEY key;
2094 WCHAR szPassword[MAX_PATH];
2095 DWORD len = sizeof(szPassword);
2097 lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
2099 RegOpenKeyW(HKEY_CURRENT_USER, szKey, &key);
2100 if (RegQueryValueExW(key, szValue, NULL, NULL, (LPBYTE)szPassword, &len)) {
2101 /* Nothing in the registry, get the username and use that as the password */
2102 if (!GetUserNameW(szPassword, &len)) {
2103 /* Should never get here, but use an empty password as failsafe */
2104 strcpyW(szPassword, szEmpty);
2107 RegCloseKey(key);
2109 TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword));
2110 lpwfs->lpszPassword = WININET_strdupW(szPassword);
2112 else {
2113 lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
2115 if (lpszPassword)
2116 lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
2117 else
2118 lpwfs->lpszPassword = WININET_strdupW(szEmpty);
2121 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
2122 if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
2124 INTERNET_ASYNC_RESULT iar;
2126 iar.dwResult = (DWORD)handle;
2127 iar.dwError = ERROR_SUCCESS;
2129 SendAsyncCallback(&hIC->hdr, dwContext,
2130 INTERNET_STATUS_HANDLE_CREATED, &iar,
2131 sizeof(INTERNET_ASYNC_RESULT));
2134 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
2135 (LPWSTR) lpszServerName, strlenW(lpszServerName));
2137 if (!GetAddress(lpszServerName, nServerPort, &socketAddr))
2139 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
2140 goto lerror;
2143 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
2144 (LPWSTR) lpszServerName, strlenW(lpszServerName));
2146 nsocket = socket(AF_INET,SOCK_STREAM,0);
2147 if (nsocket == -1)
2149 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
2150 goto lerror;
2153 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
2154 &socketAddr, sizeof(struct sockaddr_in));
2156 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
2158 ERR("Unable to connect (%s)\n", strerror(errno));
2159 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
2161 else
2163 TRACE("Connected to server\n");
2164 lpwfs->sndSocket = nsocket;
2165 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
2166 &socketAddr, sizeof(struct sockaddr_in));
2168 sock_namelen = sizeof(lpwfs->socketAddress);
2169 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
2171 if (FTP_ConnectToHost(lpwfs))
2173 TRACE("Successfully logged into server\n");
2174 bSuccess = TRUE;
2178 lerror:
2179 if (lpwfs) WININET_Release( &lpwfs->hdr );
2181 if (!bSuccess && handle)
2183 WININET_FreeHandle( handle );
2184 handle = NULL;
2187 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2189 INTERNET_ASYNC_RESULT iar;
2191 iar.dwResult = bSuccess ? (DWORD_PTR)lpwfs : 0;
2192 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
2193 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
2194 &iar, sizeof(INTERNET_ASYNC_RESULT));
2197 return handle;
2201 /***********************************************************************
2202 * FTP_ConnectToHost (internal)
2204 * Connect to a ftp server
2206 * RETURNS
2207 * TRUE on success
2208 * NULL on failure
2211 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
2213 INT nResCode;
2214 BOOL bSuccess = FALSE;
2216 TRACE("\n");
2217 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2219 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
2220 goto lend;
2222 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2223 if (nResCode)
2225 /* Login successful... */
2226 if (nResCode == 230)
2227 bSuccess = TRUE;
2228 /* User name okay, need password... */
2229 else if (nResCode == 331)
2230 bSuccess = FTP_SendPassword(lpwfs);
2231 /* Need account for login... */
2232 else if (nResCode == 332)
2233 bSuccess = FTP_SendAccount(lpwfs);
2234 else
2235 FTP_SetResponseError(nResCode);
2238 TRACE("Returning %d\n", bSuccess);
2239 lend:
2240 return bSuccess;
2244 /***********************************************************************
2245 * FTP_SendCommandA (internal)
2247 * Send command to server
2249 * RETURNS
2250 * TRUE on success
2251 * NULL on failure
2254 static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
2255 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext)
2257 DWORD len;
2258 CHAR *buf;
2259 DWORD nBytesSent = 0;
2260 int nRC = 0;
2261 DWORD dwParamLen;
2263 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
2265 if (lpfnStatusCB)
2267 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
2270 dwParamLen = lpszParam?strlen(lpszParam)+1:0;
2271 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
2272 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
2274 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2275 return FALSE;
2277 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
2278 dwParamLen ? lpszParam : "", szCRLF);
2280 TRACE("Sending (%s) len(%d)\n", buf, len);
2281 while((nBytesSent < len) && (nRC != -1))
2283 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
2284 nBytesSent += nRC;
2287 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
2289 if (lpfnStatusCB)
2291 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_REQUEST_SENT,
2292 &nBytesSent, sizeof(DWORD));
2295 TRACE("Sent %d bytes\n", nBytesSent);
2296 return (nRC != -1);
2299 /***********************************************************************
2300 * FTP_SendCommand (internal)
2302 * Send command to server
2304 * RETURNS
2305 * TRUE on success
2306 * NULL on failure
2309 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
2310 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext)
2312 BOOL ret;
2313 LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
2314 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
2315 HeapFree(GetProcessHeap(), 0, lpszParamA);
2316 return ret;
2319 /***********************************************************************
2320 * FTP_ReceiveResponse (internal)
2322 * Receive response from server
2324 * RETURNS
2325 * Reply code on success
2326 * 0 on failure
2329 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD_PTR dwContext)
2331 LPSTR lpszResponse = INTERNET_GetResponseBuffer();
2332 DWORD nRecv;
2333 INT rc = 0;
2334 char firstprefix[5];
2335 BOOL multiline = FALSE;
2336 LPWININETAPPINFOW hIC = NULL;
2338 TRACE("socket(%d)\n", lpwfs->sndSocket);
2340 hIC = lpwfs->lpAppInfo;
2341 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2343 while(1)
2345 if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
2346 goto lerror;
2348 if (nRecv >= 3)
2350 if(!multiline)
2352 if(lpszResponse[3] != '-')
2353 break;
2354 else
2355 { /* Start of multiline repsonse. Loop until we get "nnn " */
2356 multiline = TRUE;
2357 memcpy(firstprefix, lpszResponse, 3);
2358 firstprefix[3] = ' ';
2359 firstprefix[4] = '\0';
2362 else
2364 if(!memcmp(firstprefix, lpszResponse, 4))
2365 break;
2370 if (nRecv >= 3)
2372 rc = atoi(lpszResponse);
2374 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2375 &nRecv, sizeof(DWORD));
2378 lerror:
2379 TRACE("return %d\n", rc);
2380 return rc;
2384 /***********************************************************************
2385 * FTP_SendPassword (internal)
2387 * Send password to ftp server
2389 * RETURNS
2390 * TRUE on success
2391 * NULL on failure
2394 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
2396 INT nResCode;
2397 BOOL bSuccess = FALSE;
2399 TRACE("\n");
2400 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
2401 goto lend;
2403 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2404 if (nResCode)
2406 TRACE("Received reply code %d\n", nResCode);
2407 /* Login successful... */
2408 if (nResCode == 230)
2409 bSuccess = TRUE;
2410 /* Command not implemented, superfluous at the server site... */
2411 /* Need account for login... */
2412 else if (nResCode == 332)
2413 bSuccess = FTP_SendAccount(lpwfs);
2414 else
2415 FTP_SetResponseError(nResCode);
2418 lend:
2419 TRACE("Returning %d\n", bSuccess);
2420 return bSuccess;
2424 /***********************************************************************
2425 * FTP_SendAccount (internal)
2429 * RETURNS
2430 * TRUE on success
2431 * FALSE on failure
2434 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
2436 INT nResCode;
2437 BOOL bSuccess = FALSE;
2439 TRACE("\n");
2440 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
2441 goto lend;
2443 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2444 if (nResCode)
2445 bSuccess = TRUE;
2446 else
2447 FTP_SetResponseError(nResCode);
2449 lend:
2450 return bSuccess;
2454 /***********************************************************************
2455 * FTP_SendStore (internal)
2457 * Send request to upload file to ftp server
2459 * RETURNS
2460 * TRUE on success
2461 * FALSE on failure
2464 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2466 INT nResCode;
2467 BOOL bSuccess = FALSE;
2469 TRACE("\n");
2470 if (!FTP_InitListenSocket(lpwfs))
2471 goto lend;
2473 if (!FTP_SendType(lpwfs, dwType))
2474 goto lend;
2476 if (!FTP_SendPortOrPasv(lpwfs))
2477 goto lend;
2479 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2480 goto lend;
2481 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2482 if (nResCode)
2484 if (nResCode == 150 || nResCode == 125)
2485 bSuccess = TRUE;
2486 else
2487 FTP_SetResponseError(nResCode);
2490 lend:
2491 if (!bSuccess && lpwfs->lstnSocket != -1)
2493 closesocket(lpwfs->lstnSocket);
2494 lpwfs->lstnSocket = -1;
2497 return bSuccess;
2501 /***********************************************************************
2502 * FTP_InitListenSocket (internal)
2504 * Create a socket to listen for server response
2506 * RETURNS
2507 * TRUE on success
2508 * FALSE on failure
2511 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
2513 BOOL bSuccess = FALSE;
2514 socklen_t namelen = sizeof(struct sockaddr_in);
2516 TRACE("\n");
2518 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2519 if (lpwfs->lstnSocket == -1)
2521 TRACE("Unable to create listening socket\n");
2522 goto lend;
2525 /* We obtain our ip addr from the name of the command channel socket */
2526 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2528 /* and get the system to assign us a port */
2529 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
2531 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
2533 TRACE("Unable to bind socket\n");
2534 goto lend;
2537 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2539 TRACE("listen failed\n");
2540 goto lend;
2543 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2544 bSuccess = TRUE;
2546 lend:
2547 if (!bSuccess && lpwfs->lstnSocket != -1)
2549 closesocket(lpwfs->lstnSocket);
2550 lpwfs->lstnSocket = -1;
2553 return bSuccess;
2557 /***********************************************************************
2558 * FTP_SendType (internal)
2560 * Tell server type of data being transferred
2562 * RETURNS
2563 * TRUE on success
2564 * FALSE on failure
2566 * W98SE doesn't cache the type that's currently set
2567 * (i.e. it sends it always),
2568 * so we probably don't want to do that either.
2570 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
2572 INT nResCode;
2573 WCHAR type[] = { 'I','\0' };
2574 BOOL bSuccess = FALSE;
2576 TRACE("\n");
2577 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2578 type[0] = 'A';
2580 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2581 goto lend;
2583 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2584 if (nResCode)
2586 if (nResCode == 2)
2587 bSuccess = TRUE;
2588 else
2589 FTP_SetResponseError(nResCode);
2592 lend:
2593 return bSuccess;
2597 #if 0 /* FIXME: should probably be used for FtpGetFileSize */
2598 /***********************************************************************
2599 * FTP_GetFileSize (internal)
2601 * Retrieves from the server the size of the given file
2603 * RETURNS
2604 * TRUE on success
2605 * FALSE on failure
2608 static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
2610 INT nResCode;
2611 BOOL bSuccess = FALSE;
2613 TRACE("\n");
2615 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2616 goto lend;
2618 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2619 if (nResCode)
2621 if (nResCode == 213) {
2622 /* Now parses the output to get the actual file size */
2623 int i;
2624 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2626 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2627 if (lpszResponseBuffer[i] == '\0') return FALSE;
2628 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2630 bSuccess = TRUE;
2631 } else {
2632 FTP_SetResponseError(nResCode);
2636 lend:
2637 return bSuccess;
2639 #endif
2642 /***********************************************************************
2643 * FTP_SendPort (internal)
2645 * Tell server which port to use
2647 * RETURNS
2648 * TRUE on success
2649 * FALSE on failure
2652 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
2654 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2655 INT nResCode;
2656 WCHAR szIPAddress[64];
2657 BOOL bSuccess = FALSE;
2658 TRACE("\n");
2660 sprintfW(szIPAddress, szIPFormat,
2661 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2662 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2663 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2664 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2665 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2666 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2668 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2669 goto lend;
2671 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2672 if (nResCode)
2674 if (nResCode == 200)
2675 bSuccess = TRUE;
2676 else
2677 FTP_SetResponseError(nResCode);
2680 lend:
2681 return bSuccess;
2685 /***********************************************************************
2686 * FTP_DoPassive (internal)
2688 * Tell server that we want to do passive transfers
2689 * and connect data socket
2691 * RETURNS
2692 * TRUE on success
2693 * FALSE on failure
2696 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
2698 INT nResCode;
2699 BOOL bSuccess = FALSE;
2701 TRACE("\n");
2702 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2703 goto lend;
2705 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2706 if (nResCode)
2708 if (nResCode == 227)
2710 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2711 LPSTR p;
2712 int f[6];
2713 int i;
2714 char *pAddr, *pPort;
2715 INT nsocket = -1;
2716 struct sockaddr_in dataSocketAddress;
2718 p = lpszResponseBuffer+4; /* skip status code */
2719 while (*p != '\0' && (*p < '0' || *p > '9')) p++;
2721 if (*p == '\0')
2723 ERR("no address found in response, aborting\n");
2724 goto lend;
2727 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2728 &f[4], &f[5]) != 6)
2730 ERR("unknown response address format '%s', aborting\n", p);
2731 goto lend;
2733 for (i=0; i < 6; i++)
2734 f[i] = f[i] & 0xff;
2736 dataSocketAddress = lpwfs->socketAddress;
2737 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2738 pPort = (char *)&(dataSocketAddress.sin_port);
2739 pAddr[0] = f[0];
2740 pAddr[1] = f[1];
2741 pAddr[2] = f[2];
2742 pAddr[3] = f[3];
2743 pPort[0] = f[4];
2744 pPort[1] = f[5];
2746 nsocket = socket(AF_INET,SOCK_STREAM,0);
2747 if (nsocket == -1)
2748 goto lend;
2750 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2752 ERR("can't connect passive FTP data port.\n");
2753 closesocket(nsocket);
2754 goto lend;
2756 lpwfs->pasvSocket = nsocket;
2757 bSuccess = TRUE;
2759 else
2760 FTP_SetResponseError(nResCode);
2763 lend:
2764 return bSuccess;
2768 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
2770 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2772 if (!FTP_DoPassive(lpwfs))
2773 return FALSE;
2775 else
2777 if (!FTP_SendPort(lpwfs))
2778 return FALSE;
2780 return TRUE;
2784 /***********************************************************************
2785 * FTP_GetDataSocket (internal)
2787 * Either accepts an incoming data socket connection from the server
2788 * or just returns the already opened socket after a PASV command
2789 * in case of passive FTP.
2792 * RETURNS
2793 * TRUE on success
2794 * FALSE on failure
2797 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
2799 struct sockaddr_in saddr;
2800 socklen_t addrlen = sizeof(struct sockaddr);
2802 TRACE("\n");
2803 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2805 *nDataSocket = lpwfs->pasvSocket;
2807 else
2809 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2810 closesocket(lpwfs->lstnSocket);
2811 lpwfs->lstnSocket = -1;
2813 return *nDataSocket != -1;
2817 /***********************************************************************
2818 * FTP_SendData (internal)
2820 * Send data to the server
2822 * RETURNS
2823 * TRUE on success
2824 * FALSE on failure
2827 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2829 BY_HANDLE_FILE_INFORMATION fi;
2830 DWORD nBytesRead = 0;
2831 DWORD nBytesSent = 0;
2832 DWORD nTotalSent = 0;
2833 DWORD nBytesToSend, nLen;
2834 int nRC = 1;
2835 time_t s_long_time, e_long_time;
2836 LONG nSeconds;
2837 CHAR *lpszBuffer;
2839 TRACE("\n");
2840 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2842 /* Get the size of the file. */
2843 GetFileInformationByHandle(hFile, &fi);
2844 time(&s_long_time);
2848 nBytesToSend = nBytesRead - nBytesSent;
2850 if (nBytesToSend <= 0)
2852 /* Read data from file. */
2853 nBytesSent = 0;
2854 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2855 ERR("Failed reading from file\n");
2857 if (nBytesRead > 0)
2858 nBytesToSend = nBytesRead;
2859 else
2860 break;
2863 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2864 DATA_PACKET_SIZE : nBytesToSend;
2865 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2867 if (nRC != -1)
2869 nBytesSent += nRC;
2870 nTotalSent += nRC;
2873 /* Do some computation to display the status. */
2874 time(&e_long_time);
2875 nSeconds = e_long_time - s_long_time;
2876 if( nSeconds / 60 > 0 )
2878 TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n",
2879 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2880 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2882 else
2884 TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n",
2885 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2886 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2888 } while (nRC != -1);
2890 TRACE("file transfer complete!\n");
2892 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2894 return nTotalSent;
2898 /***********************************************************************
2899 * FTP_SendRetrieve (internal)
2901 * Send request to retrieve a file
2903 * RETURNS
2904 * Number of bytes to be received on success
2905 * 0 on failure
2908 static BOOL FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2910 INT nResCode;
2911 BOOL ret;
2913 TRACE("\n");
2914 if (!(ret = FTP_InitListenSocket(lpwfs)))
2915 goto lend;
2917 if (!(ret = FTP_SendType(lpwfs, dwType)))
2918 goto lend;
2920 if (!(ret = FTP_SendPortOrPasv(lpwfs)))
2921 goto lend;
2923 if (!(ret = FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0)))
2924 goto lend;
2926 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2927 if ((nResCode != 125) && (nResCode != 150)) {
2928 /* That means that we got an error getting the file. */
2929 FTP_SetResponseError(nResCode);
2930 ret = FALSE;
2933 lend:
2934 if (!ret && lpwfs->lstnSocket != -1)
2936 closesocket(lpwfs->lstnSocket);
2937 lpwfs->lstnSocket = -1;
2940 return ret;
2944 /***********************************************************************
2945 * FTP_RetrieveData (internal)
2947 * Retrieve data from server
2949 * RETURNS
2950 * TRUE on success
2951 * FALSE on failure
2954 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2956 DWORD nBytesWritten;
2957 DWORD nBytesReceived = 0;
2958 INT nRC = 0;
2959 CHAR *lpszBuffer;
2961 TRACE("\n");
2963 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2964 if (NULL == lpszBuffer)
2966 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2967 return FALSE;
2970 while (nRC != -1)
2972 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2973 if (nRC != -1)
2975 /* other side closed socket. */
2976 if (nRC == 0)
2977 goto recv_end;
2978 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2979 nBytesReceived += nRC;
2983 TRACE("Data transfer complete\n");
2985 recv_end:
2986 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2988 return (nRC != -1);
2991 /***********************************************************************
2992 * FTP_CloseConnection (internal)
2994 * Close connections
2996 static void FTP_CloseConnection(LPWININETHANDLEHEADER hdr)
2998 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
3000 TRACE("\n");
3002 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext,
3003 INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
3005 if (lpwfs->download_in_progress != NULL)
3006 lpwfs->download_in_progress->session_deleted = TRUE;
3008 if (lpwfs->sndSocket != -1)
3009 closesocket(lpwfs->sndSocket);
3011 if (lpwfs->lstnSocket != -1)
3012 closesocket(lpwfs->lstnSocket);
3014 if (lpwfs->pasvSocket != -1)
3015 closesocket(lpwfs->pasvSocket);
3017 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext,
3018 INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
3022 /***********************************************************************
3023 * FTP_CloseSessionHandle (internal)
3025 * Deallocate session handle
3027 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr)
3029 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
3031 TRACE("\n");
3033 WININET_Release(&lpwfs->lpAppInfo->hdr);
3035 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
3036 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
3037 HeapFree(GetProcessHeap(), 0, lpwfs);
3041 /***********************************************************************
3042 * FTP_FindNextFileW (Internal)
3044 * Continues a file search from a previous call to FindFirstFile
3046 * RETURNS
3047 * TRUE on success
3048 * FALSE on failure
3051 BOOL WINAPI FTP_FindNextFileW(LPWININETFTPFINDNEXTW lpwh, LPVOID lpvFindData)
3053 BOOL bSuccess = TRUE;
3054 LPWIN32_FIND_DATAW lpFindFileData;
3056 TRACE("index(%d) size(%d)\n", lpwh->index, lpwh->size);
3058 assert (lpwh->hdr.htype == WH_HFTPFINDNEXT);
3060 /* Clear any error information */
3061 INTERNET_SetLastError(0);
3063 lpFindFileData = (LPWIN32_FIND_DATAW) lpvFindData;
3064 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
3066 if (lpwh->index >= lpwh->size)
3068 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3069 bSuccess = FALSE;
3070 goto lend;
3073 FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
3074 lpwh->index++;
3076 TRACE("\nName: %s\nSize: %d\n", debugstr_w(lpFindFileData->cFileName), lpFindFileData->nFileSizeLow);
3078 lend:
3080 if (lpwh->hdr.dwFlags & INTERNET_FLAG_ASYNC)
3082 INTERNET_ASYNC_RESULT iar;
3084 iar.dwResult = (DWORD)bSuccess;
3085 iar.dwError = iar.dwError = bSuccess ? ERROR_SUCCESS :
3086 INTERNET_GetLastError();
3088 INTERNET_SendCallback(&lpwh->hdr, lpwh->hdr.dwContext,
3089 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
3090 sizeof(INTERNET_ASYNC_RESULT));
3093 return bSuccess;
3097 /***********************************************************************
3098 * FTP_CloseFindNextHandle (internal)
3100 * Deallocate session handle
3102 * RETURNS
3103 * TRUE on success
3104 * FALSE on failure
3107 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr)
3109 LPWININETFTPFINDNEXTW lpwfn = (LPWININETFTPFINDNEXTW) hdr;
3110 DWORD i;
3112 TRACE("\n");
3114 WININET_Release(&lpwfn->lpFtpSession->hdr);
3116 for (i = 0; i < lpwfn->size; i++)
3118 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
3121 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
3122 HeapFree(GetProcessHeap(), 0, lpwfn);
3125 /***********************************************************************
3126 * FTP_CloseFileTransferHandle (internal)
3128 * Closes the file transfer handle. This also 'cleans' the data queue of
3129 * the 'transfer complete' message (this is a bit of a hack though :-/ )
3132 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr)
3134 LPWININETFTPFILE lpwh = (LPWININETFTPFILE) hdr;
3135 LPWININETFTPSESSIONW lpwfs = lpwh->lpFtpSession;
3136 INT nResCode;
3138 TRACE("\n");
3140 WININET_Release(&lpwh->lpFtpSession->hdr);
3142 if (!lpwh->session_deleted)
3143 lpwfs->download_in_progress = NULL;
3145 if (lpwh->nDataSocket != -1)
3146 closesocket(lpwh->nDataSocket);
3148 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
3149 if (nResCode > 0 && nResCode != 226) WARN("server reports failed transfer\n");
3151 HeapFree(GetProcessHeap(), 0, lpwh);
3154 /***********************************************************************
3155 * FTP_ReceiveFileList (internal)
3157 * Read file list from server
3159 * RETURNS
3160 * Handle to file list on success
3161 * NULL on failure
3164 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3165 LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext)
3167 DWORD dwSize = 0;
3168 LPFILEPROPERTIESW lpafp = NULL;
3169 LPWININETFTPFINDNEXTW lpwfn = NULL;
3170 HINTERNET handle = 0;
3172 TRACE("(%p,%d,%s,%p,%08lx)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
3174 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
3176 if(lpFindFileData)
3177 FTP_ConvertFileProp(lpafp, lpFindFileData);
3179 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFTPFINDNEXTW));
3180 if (lpwfn)
3182 lpwfn->hdr.htype = WH_HFTPFINDNEXT;
3183 lpwfn->hdr.dwContext = dwContext;
3184 lpwfn->hdr.dwRefCount = 1;
3185 lpwfn->hdr.close_connection = NULL;
3186 lpwfn->hdr.destroy = FTP_CloseFindNextHandle;
3187 lpwfn->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
3188 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
3189 lpwfn->size = dwSize;
3190 lpwfn->lpafp = lpafp;
3192 WININET_AddRef( &lpwfs->hdr );
3193 lpwfn->lpFtpSession = lpwfs;
3194 list_add_head( &lpwfs->hdr.children, &lpwfn->hdr.entry );
3196 handle = WININET_AllocHandle( &lpwfn->hdr );
3200 if( lpwfn )
3201 WININET_Release( &lpwfn->hdr );
3203 TRACE("Matched %d files\n", dwSize);
3204 return handle;
3208 /***********************************************************************
3209 * FTP_ConvertFileProp (internal)
3211 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
3213 * RETURNS
3214 * TRUE on success
3215 * FALSE on failure
3218 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
3220 BOOL bSuccess = FALSE;
3222 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
3224 if (lpafp)
3226 /* Convert 'Unix' time to Windows time */
3227 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
3228 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
3229 lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime;
3230 lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime;
3232 /* Not all fields are filled in */
3233 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
3234 lpFindFileData->nFileSizeLow = lpafp->nSize;
3236 if (lpafp->bIsDirectory)
3237 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
3239 if (lpafp->lpszName)
3240 lstrcpynW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
3242 bSuccess = TRUE;
3245 return bSuccess;
3248 /***********************************************************************
3249 * FTP_ParseNextFile (internal)
3251 * Parse the next line in file listing
3253 * RETURNS
3254 * TRUE on success
3255 * FALSE on failure
3257 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
3259 static const char szSpace[] = " \t";
3260 DWORD nBufLen;
3261 char *pszLine;
3262 char *pszToken;
3263 char *pszTmp;
3264 BOOL found = FALSE;
3265 int i;
3267 lpfp->lpszName = NULL;
3268 do {
3269 if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
3270 return FALSE;
3272 pszToken = strtok(pszLine, szSpace);
3273 /* ls format
3274 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
3276 * For instance:
3277 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
3279 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
3280 if(!FTP_ParsePermission(pszToken, lpfp))
3281 lpfp->bIsDirectory = FALSE;
3282 for(i=0; i<=3; i++) {
3283 if(!(pszToken = strtok(NULL, szSpace)))
3284 break;
3286 if(!pszToken) continue;
3287 if(lpfp->bIsDirectory) {
3288 TRACE("Is directory\n");
3289 lpfp->nSize = 0;
3291 else {
3292 TRACE("Size: %s\n", pszToken);
3293 lpfp->nSize = atol(pszToken);
3296 lpfp->tmLastModified.tm_sec = 0;
3297 lpfp->tmLastModified.tm_min = 0;
3298 lpfp->tmLastModified.tm_hour = 0;
3299 lpfp->tmLastModified.tm_mday = 0;
3300 lpfp->tmLastModified.tm_mon = 0;
3301 lpfp->tmLastModified.tm_year = 0;
3303 /* Determine month */
3304 pszToken = strtok(NULL, szSpace);
3305 if(!pszToken) continue;
3306 if(strlen(pszToken) >= 3) {
3307 pszToken[3] = 0;
3308 if((pszTmp = StrStrIA(szMonths, pszToken)))
3309 lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
3311 /* Determine day */
3312 pszToken = strtok(NULL, szSpace);
3313 if(!pszToken) continue;
3314 lpfp->tmLastModified.tm_mday = atoi(pszToken);
3315 /* Determine time or year */
3316 pszToken = strtok(NULL, szSpace);
3317 if(!pszToken) continue;
3318 if((pszTmp = strchr(pszToken, ':'))) {
3319 struct tm* apTM;
3320 time_t aTime;
3321 *pszTmp = 0;
3322 pszTmp++;
3323 lpfp->tmLastModified.tm_min = atoi(pszTmp);
3324 lpfp->tmLastModified.tm_hour = atoi(pszToken);
3325 time(&aTime);
3326 apTM = localtime(&aTime);
3327 lpfp->tmLastModified.tm_year = apTM->tm_year;
3329 else {
3330 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
3331 lpfp->tmLastModified.tm_hour = 12;
3333 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3334 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3335 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3336 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3338 pszToken = strtok(NULL, szSpace);
3339 if(!pszToken) continue;
3340 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3341 TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
3343 /* NT way of parsing ... :
3345 07-13-03 08:55PM <DIR> sakpatch
3346 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
3348 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
3349 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
3351 sscanf(pszToken, "%d-%d-%d",
3352 &lpfp->tmLastModified.tm_mon,
3353 &lpfp->tmLastModified.tm_mday,
3354 &lpfp->tmLastModified.tm_year);
3356 /* Hacky and bad Y2K protection :-) */
3357 if (lpfp->tmLastModified.tm_year < 70)
3358 lpfp->tmLastModified.tm_year += 100;
3360 pszToken = strtok(NULL, szSpace);
3361 if(!pszToken) continue;
3362 sscanf(pszToken, "%d:%d",
3363 &lpfp->tmLastModified.tm_hour,
3364 &lpfp->tmLastModified.tm_min);
3365 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
3366 lpfp->tmLastModified.tm_hour += 12;
3368 lpfp->tmLastModified.tm_sec = 0;
3370 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3371 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3372 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3373 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3375 pszToken = strtok(NULL, szSpace);
3376 if(!pszToken) continue;
3377 if(!strcasecmp(pszToken, "<DIR>")) {
3378 lpfp->bIsDirectory = TRUE;
3379 lpfp->nSize = 0;
3380 TRACE("Is directory\n");
3382 else {
3383 lpfp->bIsDirectory = FALSE;
3384 lpfp->nSize = atol(pszToken);
3385 TRACE("Size: %d\n", lpfp->nSize);
3388 pszToken = strtok(NULL, szSpace);
3389 if(!pszToken) continue;
3390 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3391 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
3393 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
3394 else if(pszToken[0] == '+') {
3395 FIXME("EPLF Format not implemented\n");
3398 if(lpfp->lpszName) {
3399 if((lpszSearchFile == NULL) ||
3400 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
3401 found = TRUE;
3402 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
3404 else {
3405 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
3406 lpfp->lpszName = NULL;
3409 } while(!found);
3410 return TRUE;
3413 /***********************************************************************
3414 * FTP_ParseDirectory (internal)
3416 * Parse string of directory information
3418 * RETURNS
3419 * TRUE on success
3420 * FALSE on failure
3422 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3423 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
3425 BOOL bSuccess = TRUE;
3426 INT sizeFilePropArray = 500;/*20; */
3427 INT indexFilePropArray = -1;
3429 TRACE("\n");
3431 /* Allocate intial file properties array */
3432 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
3433 if (!*lpafp)
3434 return FALSE;
3436 do {
3437 if (indexFilePropArray+1 >= sizeFilePropArray)
3439 LPFILEPROPERTIESW tmpafp;
3441 sizeFilePropArray *= 2;
3442 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
3443 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
3444 if (NULL == tmpafp)
3446 bSuccess = FALSE;
3447 break;
3450 *lpafp = tmpafp;
3452 indexFilePropArray++;
3453 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
3455 if (bSuccess && indexFilePropArray)
3457 if (indexFilePropArray < sizeFilePropArray - 1)
3459 LPFILEPROPERTIESW tmpafp;
3461 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
3462 sizeof(FILEPROPERTIESW)*indexFilePropArray);
3463 if (NULL == tmpafp)
3464 *lpafp = tmpafp;
3466 *dwfp = indexFilePropArray;
3468 else
3470 HeapFree(GetProcessHeap(), 0, *lpafp);
3471 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3472 bSuccess = FALSE;
3475 return bSuccess;
3479 /***********************************************************************
3480 * FTP_ParsePermission (internal)
3482 * Parse permission string of directory information
3484 * RETURNS
3485 * TRUE on success
3486 * FALSE on failure
3489 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3491 BOOL bSuccess = TRUE;
3492 unsigned short nPermission = 0;
3493 INT nPos = 1;
3494 INT nLast = 9;
3496 TRACE("\n");
3497 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3499 bSuccess = FALSE;
3500 return bSuccess;
3503 lpfp->bIsDirectory = (*lpszPermission == 'd');
3506 switch (nPos)
3508 case 1:
3509 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3510 break;
3511 case 2:
3512 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3513 break;
3514 case 3:
3515 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3516 break;
3517 case 4:
3518 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3519 break;
3520 case 5:
3521 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3522 break;
3523 case 6:
3524 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3525 break;
3526 case 7:
3527 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3528 break;
3529 case 8:
3530 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3531 break;
3532 case 9:
3533 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3534 break;
3536 nPos++;
3537 }while (nPos <= nLast);
3539 lpfp->permissions = nPermission;
3540 return bSuccess;
3544 /***********************************************************************
3545 * FTP_SetResponseError (internal)
3547 * Set the appropriate error code for a given response from the server
3549 * RETURNS
3552 static DWORD FTP_SetResponseError(DWORD dwResponse)
3554 DWORD dwCode = 0;
3556 switch(dwResponse)
3558 case 425: /* Cannot open data connection. */
3559 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3560 break;
3562 case 426: /* Connection closed, transer aborted. */
3563 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3564 break;
3566 case 530: /* Not logged in. Login incorrect. */
3567 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3568 break;
3570 case 421: /* Service not available - Server may be shutting down. */
3571 case 450: /* File action not taken. File may be busy. */
3572 case 451: /* Action aborted. Server error. */
3573 case 452: /* Action not taken. Insufficient storage space on server. */
3574 case 500: /* Syntax error. Command unrecognized. */
3575 case 501: /* Syntax error. Error in parameters or arguments. */
3576 case 502: /* Command not implemented. */
3577 case 503: /* Bad sequence of commands. */
3578 case 504: /* Command not implemented for that parameter. */
3579 case 532: /* Need account for storing files */
3580 case 550: /* File action not taken. File not found or no access. */
3581 case 551: /* Requested action aborted. Page type unknown */
3582 case 552: /* Action aborted. Exceeded storage allocation */
3583 case 553: /* Action not taken. File name not allowed. */
3585 default:
3586 dwCode = ERROR_INTERNET_EXTENDED_ERROR;
3587 break;
3590 INTERNET_SetLastError(dwCode);
3591 return dwCode;