wininet: Correct several ftp server response to error code mappings.
[wine.git] / dlls / wininet / ftp.c
blobc0452176c58623d6758af138df3b4ce53b5b1b7e
1 /*
2 * WININET - Ftp implementation
4 * Copyright 1999 Corel Corporation
5 * Copyright 2004 Mike McCormack for CodeWeavers
6 * Copyright 2004 Kevin Koltzau
8 * Ulrich Czekalla
9 * Noureddine Jemmali
11 * Copyright 2000 Andreas Mohr
12 * Copyright 2002 Jaco Greeff
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "config.h"
30 #include "wine/port.h"
32 #include <errno.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/types.h>
38 #ifdef HAVE_SYS_SOCKET_H
39 # include <sys/socket.h>
40 #endif
41 #ifdef HAVE_UNISTD_H
42 # include <unistd.h>
43 #endif
44 #include <time.h>
45 #include <assert.h>
47 #include "windef.h"
48 #include "winbase.h"
49 #include "wingdi.h"
50 #include "winuser.h"
51 #include "wininet.h"
52 #include "winnls.h"
53 #include "winerror.h"
54 #include "winreg.h"
55 #include "winternl.h"
56 #include "shlwapi.h"
58 #include "wine/debug.h"
59 #include "internet.h"
61 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
63 #define DATA_PACKET_SIZE 0x2000
64 #define szCRLF "\r\n"
65 #define MAX_BACKLOG 5
67 /* Testing shows that Windows only accepts dwFlags where the last
68 * 3 (yes 3) bits define FTP_TRANSFER_TYPE_UNKNOWN, FTP_TRANSFER_TYPE_ASCII or FTP_TRANSFER_TYPE_BINARY.
70 #define FTP_CONDITION_MASK 0x0007
72 typedef enum {
73 /* FTP commands with arguments. */
74 FTP_CMD_ACCT,
75 FTP_CMD_CWD,
76 FTP_CMD_DELE,
77 FTP_CMD_MKD,
78 FTP_CMD_PASS,
79 FTP_CMD_PORT,
80 FTP_CMD_RETR,
81 FTP_CMD_RMD,
82 FTP_CMD_RNFR,
83 FTP_CMD_RNTO,
84 FTP_CMD_STOR,
85 FTP_CMD_TYPE,
86 FTP_CMD_USER,
87 FTP_CMD_SIZE,
89 /* FTP commands without arguments. */
90 FTP_CMD_ABOR,
91 FTP_CMD_LIST,
92 FTP_CMD_NLST,
93 FTP_CMD_PASV,
94 FTP_CMD_PWD,
95 FTP_CMD_QUIT,
96 } FTP_COMMAND;
98 static const CHAR *const szFtpCommands[] = {
99 "ACCT",
100 "CWD",
101 "DELE",
102 "MKD",
103 "PASS",
104 "PORT",
105 "RETR",
106 "RMD",
107 "RNFR",
108 "RNTO",
109 "STOR",
110 "TYPE",
111 "USER",
112 "SIZE",
113 "ABOR",
114 "LIST",
115 "NLST",
116 "PASV",
117 "PWD",
118 "QUIT",
121 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
122 static const WCHAR szNoAccount[] = {'n','o','a','c','c','o','u','n','t','\0'};
124 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr);
125 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr);
126 static void FTP_CloseConnection(LPWININETHANDLEHEADER hdr);
127 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr);
128 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
129 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext);
130 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
131 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket);
132 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile);
133 static INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD_PTR dwContext);
134 static BOOL FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
135 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile);
136 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs);
137 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs);
138 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs);
139 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs);
140 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType);
141 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs);
142 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs);
143 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs);
144 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp);
145 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW fileprop);
146 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
147 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp);
148 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
149 LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext);
150 static DWORD FTP_SetResponseError(DWORD dwResponse);
152 /***********************************************************************
153 * FtpPutFileA (WININET.@)
155 * Uploads a file to the FTP server
157 * RETURNS
158 * TRUE on success
159 * FALSE on failure
162 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
163 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext)
165 LPWSTR lpwzLocalFile;
166 LPWSTR lpwzNewRemoteFile;
167 BOOL ret;
169 lpwzLocalFile = lpszLocalFile?WININET_strdup_AtoW(lpszLocalFile):NULL;
170 lpwzNewRemoteFile = lpszNewRemoteFile?WININET_strdup_AtoW(lpszNewRemoteFile):NULL;
171 ret = FtpPutFileW(hConnect, lpwzLocalFile, lpwzNewRemoteFile,
172 dwFlags, dwContext);
173 HeapFree(GetProcessHeap(), 0, lpwzLocalFile);
174 HeapFree(GetProcessHeap(), 0, lpwzNewRemoteFile);
175 return ret;
178 static void AsyncFtpPutFileProc(WORKREQUEST *workRequest)
180 struct WORKREQ_FTPPUTFILEW const *req = &workRequest->u.FtpPutFileW;
181 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
183 TRACE("%p\n", lpwfs);
185 FTP_FtpPutFileW(lpwfs, req->lpszLocalFile,
186 req->lpszNewRemoteFile, req->dwFlags, req->dwContext);
188 HeapFree(GetProcessHeap(), 0, req->lpszLocalFile);
189 HeapFree(GetProcessHeap(), 0, req->lpszNewRemoteFile);
192 /***********************************************************************
193 * FtpPutFileW (WININET.@)
195 * Uploads a file to the FTP server
197 * RETURNS
198 * TRUE on success
199 * FALSE on failure
202 BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile,
203 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext)
205 LPWININETFTPSESSIONW lpwfs;
206 LPWININETAPPINFOW hIC = NULL;
207 BOOL r = FALSE;
209 if (!lpszLocalFile || !lpszNewRemoteFile)
211 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
212 return FALSE;
215 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
216 if (!lpwfs)
218 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
219 return FALSE;
222 if (WH_HFTPSESSION != lpwfs->hdr.htype)
224 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
225 goto lend;
228 if (lpwfs->download_in_progress != NULL)
230 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
231 goto lend;
234 if ((dwFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY)
236 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
237 goto lend;
240 hIC = lpwfs->lpAppInfo;
241 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
243 WORKREQUEST workRequest;
244 struct WORKREQ_FTPPUTFILEW *req = &workRequest.u.FtpPutFileW;
246 workRequest.asyncproc = AsyncFtpPutFileProc;
247 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
248 req->lpszLocalFile = WININET_strdupW(lpszLocalFile);
249 req->lpszNewRemoteFile = WININET_strdupW(lpszNewRemoteFile);
250 req->dwFlags = dwFlags;
251 req->dwContext = dwContext;
253 r = INTERNET_AsyncCall(&workRequest);
255 else
257 r = FTP_FtpPutFileW(lpwfs, lpszLocalFile,
258 lpszNewRemoteFile, dwFlags, dwContext);
261 lend:
262 WININET_Release( &lpwfs->hdr );
264 return r;
267 /***********************************************************************
268 * FTP_FtpPutFileW (Internal)
270 * Uploads a file to the FTP server
272 * RETURNS
273 * TRUE on success
274 * FALSE on failure
277 BOOL WINAPI FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile,
278 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext)
280 HANDLE hFile;
281 BOOL bSuccess = FALSE;
282 LPWININETAPPINFOW hIC = NULL;
283 INT nResCode;
285 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", debugstr_w(lpszLocalFile), debugstr_w(lpszNewRemoteFile));
287 /* Clear any error information */
288 INTERNET_SetLastError(0);
290 /* Open file to be uploaded */
291 if (INVALID_HANDLE_VALUE ==
292 (hFile = CreateFileW(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
293 /* Let CreateFile set the appropriate error */
294 return FALSE;
296 hIC = lpwfs->lpAppInfo;
298 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
300 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
302 INT nDataSocket;
304 /* Get data socket to server */
305 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
307 FTP_SendData(lpwfs, nDataSocket, hFile);
308 closesocket(nDataSocket);
309 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
310 if (nResCode)
312 if (nResCode == 226)
313 bSuccess = TRUE;
314 else
315 FTP_SetResponseError(nResCode);
320 if (lpwfs->lstnSocket != -1)
321 closesocket(lpwfs->lstnSocket);
323 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
325 INTERNET_ASYNC_RESULT iar;
327 iar.dwResult = (DWORD)bSuccess;
328 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
329 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
330 &iar, sizeof(INTERNET_ASYNC_RESULT));
333 CloseHandle(hFile);
335 return bSuccess;
339 /***********************************************************************
340 * FtpSetCurrentDirectoryA (WININET.@)
342 * Change the working directory on the FTP server
344 * RETURNS
345 * TRUE on success
346 * FALSE on failure
349 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
351 LPWSTR lpwzDirectory;
352 BOOL ret;
354 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
355 ret = FtpSetCurrentDirectoryW(hConnect, lpwzDirectory);
356 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
357 return ret;
361 static void AsyncFtpSetCurrentDirectoryProc(WORKREQUEST *workRequest)
363 struct WORKREQ_FTPSETCURRENTDIRECTORYW const *req = &workRequest->u.FtpSetCurrentDirectoryW;
364 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
366 TRACE("%p\n", lpwfs);
368 FTP_FtpSetCurrentDirectoryW(lpwfs, req->lpszDirectory);
369 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
372 /***********************************************************************
373 * FtpSetCurrentDirectoryW (WININET.@)
375 * Change the working directory on the FTP server
377 * RETURNS
378 * TRUE on success
379 * FALSE on failure
382 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
384 LPWININETFTPSESSIONW lpwfs = NULL;
385 LPWININETAPPINFOW hIC = NULL;
386 BOOL r = FALSE;
388 if (!lpszDirectory)
390 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
391 goto lend;
394 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
395 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
397 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
398 goto lend;
401 if (lpwfs->download_in_progress != NULL)
403 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
404 goto lend;
407 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
409 hIC = lpwfs->lpAppInfo;
410 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
412 WORKREQUEST workRequest;
413 struct WORKREQ_FTPSETCURRENTDIRECTORYW *req;
415 workRequest.asyncproc = AsyncFtpSetCurrentDirectoryProc;
416 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
417 req = &workRequest.u.FtpSetCurrentDirectoryW;
418 req->lpszDirectory = WININET_strdupW(lpszDirectory);
420 r = INTERNET_AsyncCall(&workRequest);
422 else
424 r = FTP_FtpSetCurrentDirectoryW(lpwfs, lpszDirectory);
427 lend:
428 if( lpwfs )
429 WININET_Release( &lpwfs->hdr );
431 return r;
435 /***********************************************************************
436 * FTP_FtpSetCurrentDirectoryW (Internal)
438 * Change the working directory on the FTP server
440 * RETURNS
441 * TRUE on success
442 * FALSE on failure
445 BOOL WINAPI FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
447 INT nResCode;
448 LPWININETAPPINFOW hIC = NULL;
449 DWORD bSuccess = FALSE;
451 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
453 /* Clear any error information */
454 INTERNET_SetLastError(0);
456 hIC = lpwfs->lpAppInfo;
457 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
458 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
459 goto lend;
461 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
463 if (nResCode)
465 if (nResCode == 250)
466 bSuccess = TRUE;
467 else
468 FTP_SetResponseError(nResCode);
471 lend:
472 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
474 INTERNET_ASYNC_RESULT iar;
476 iar.dwResult = (DWORD)bSuccess;
477 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
478 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
479 &iar, sizeof(INTERNET_ASYNC_RESULT));
481 return bSuccess;
485 /***********************************************************************
486 * FtpCreateDirectoryA (WININET.@)
488 * Create new directory on the FTP server
490 * RETURNS
491 * TRUE on success
492 * FALSE on failure
495 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
497 LPWSTR lpwzDirectory;
498 BOOL ret;
500 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
501 ret = FtpCreateDirectoryW(hConnect, lpwzDirectory);
502 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
503 return ret;
507 static void AsyncFtpCreateDirectoryProc(WORKREQUEST *workRequest)
509 struct WORKREQ_FTPCREATEDIRECTORYW const *req = &workRequest->u.FtpCreateDirectoryW;
510 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
512 TRACE(" %p\n", lpwfs);
514 FTP_FtpCreateDirectoryW(lpwfs, req->lpszDirectory);
515 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
518 /***********************************************************************
519 * FtpCreateDirectoryW (WININET.@)
521 * Create new directory on the FTP server
523 * RETURNS
524 * TRUE on success
525 * FALSE on failure
528 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
530 LPWININETFTPSESSIONW lpwfs;
531 LPWININETAPPINFOW hIC = NULL;
532 BOOL r = FALSE;
534 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
535 if (!lpwfs)
537 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
538 return FALSE;
541 if (WH_HFTPSESSION != lpwfs->hdr.htype)
543 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
544 goto lend;
547 if (lpwfs->download_in_progress != NULL)
549 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
550 goto lend;
553 if (!lpszDirectory)
555 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
556 goto lend;
559 hIC = lpwfs->lpAppInfo;
560 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
562 WORKREQUEST workRequest;
563 struct WORKREQ_FTPCREATEDIRECTORYW *req;
565 workRequest.asyncproc = AsyncFtpCreateDirectoryProc;
566 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
567 req = &workRequest.u.FtpCreateDirectoryW;
568 req->lpszDirectory = WININET_strdupW(lpszDirectory);
570 r = INTERNET_AsyncCall(&workRequest);
572 else
574 r = FTP_FtpCreateDirectoryW(lpwfs, lpszDirectory);
576 lend:
577 WININET_Release( &lpwfs->hdr );
579 return r;
583 /***********************************************************************
584 * FTP_FtpCreateDirectoryW (Internal)
586 * Create new directory on the FTP server
588 * RETURNS
589 * TRUE on success
590 * FALSE on failure
593 BOOL WINAPI FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
595 INT nResCode;
596 BOOL bSuccess = FALSE;
597 LPWININETAPPINFOW hIC = NULL;
599 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
601 /* Clear any error information */
602 INTERNET_SetLastError(0);
604 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
605 goto lend;
607 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
608 if (nResCode)
610 if (nResCode == 257)
611 bSuccess = TRUE;
612 else
613 FTP_SetResponseError(nResCode);
616 lend:
617 hIC = lpwfs->lpAppInfo;
618 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
620 INTERNET_ASYNC_RESULT iar;
622 iar.dwResult = (DWORD)bSuccess;
623 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
624 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
625 &iar, sizeof(INTERNET_ASYNC_RESULT));
628 return bSuccess;
631 /***********************************************************************
632 * FtpFindFirstFileA (WININET.@)
634 * Search the specified directory
636 * RETURNS
637 * HINTERNET on success
638 * NULL on failure
641 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
642 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext)
644 LPWSTR lpwzSearchFile;
645 WIN32_FIND_DATAW wfd;
646 LPWIN32_FIND_DATAW lpFindFileDataW;
647 HINTERNET ret;
649 lpwzSearchFile = lpszSearchFile?WININET_strdup_AtoW(lpszSearchFile):NULL;
650 lpFindFileDataW = lpFindFileData?&wfd:NULL;
651 ret = FtpFindFirstFileW(hConnect, lpwzSearchFile, lpFindFileDataW, dwFlags, dwContext);
652 HeapFree(GetProcessHeap(), 0, lpwzSearchFile);
654 if(lpFindFileData) {
655 WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData);
657 return ret;
661 static void AsyncFtpFindFirstFileProc(WORKREQUEST *workRequest)
663 struct WORKREQ_FTPFINDFIRSTFILEW const *req = &workRequest->u.FtpFindFirstFileW;
664 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
666 TRACE("%p\n", lpwfs);
668 FTP_FtpFindFirstFileW(lpwfs, req->lpszSearchFile,
669 req->lpFindFileData, req->dwFlags, req->dwContext);
670 HeapFree(GetProcessHeap(), 0, req->lpszSearchFile);
673 /***********************************************************************
674 * FtpFindFirstFileW (WININET.@)
676 * Search the specified directory
678 * RETURNS
679 * HINTERNET on success
680 * NULL on failure
683 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
684 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext)
686 LPWININETFTPSESSIONW lpwfs;
687 LPWININETAPPINFOW hIC = NULL;
688 HINTERNET r = NULL;
690 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
691 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
693 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
694 goto lend;
697 if (lpwfs->download_in_progress != NULL)
699 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
700 goto lend;
703 hIC = lpwfs->lpAppInfo;
704 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
706 WORKREQUEST workRequest;
707 struct WORKREQ_FTPFINDFIRSTFILEW *req;
709 workRequest.asyncproc = AsyncFtpFindFirstFileProc;
710 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
711 req = &workRequest.u.FtpFindFirstFileW;
712 req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : WININET_strdupW(lpszSearchFile);
713 req->lpFindFileData = lpFindFileData;
714 req->dwFlags = dwFlags;
715 req->dwContext= dwContext;
717 INTERNET_AsyncCall(&workRequest);
718 r = NULL;
720 else
722 r = FTP_FtpFindFirstFileW(lpwfs, lpszSearchFile, lpFindFileData,
723 dwFlags, dwContext);
725 lend:
726 if( lpwfs )
727 WININET_Release( &lpwfs->hdr );
729 return r;
733 /***********************************************************************
734 * FTP_FtpFindFirstFileW (Internal)
736 * Search the specified directory
738 * RETURNS
739 * HINTERNET on success
740 * NULL on failure
743 HINTERNET WINAPI FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs,
744 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext)
746 INT nResCode;
747 LPWININETAPPINFOW hIC = NULL;
748 HINTERNET hFindNext = NULL;
750 TRACE("\n");
752 /* Clear any error information */
753 INTERNET_SetLastError(0);
755 if (!FTP_InitListenSocket(lpwfs))
756 goto lend;
758 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
759 goto lend;
761 if (!FTP_SendPortOrPasv(lpwfs))
762 goto lend;
764 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, NULL,
765 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
766 goto lend;
768 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
769 if (nResCode)
771 if (nResCode == 125 || nResCode == 150)
773 INT nDataSocket;
775 /* Get data socket to server */
776 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
778 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpszSearchFile, lpFindFileData, dwContext);
779 closesocket(nDataSocket);
780 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
781 if (nResCode != 226 && nResCode != 250)
782 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
785 else
786 FTP_SetResponseError(nResCode);
789 lend:
790 if (lpwfs->lstnSocket != -1)
791 closesocket(lpwfs->lstnSocket);
793 hIC = lpwfs->lpAppInfo;
794 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
796 INTERNET_ASYNC_RESULT iar;
798 if (hFindNext)
800 iar.dwResult = (DWORD)hFindNext;
801 iar.dwError = ERROR_SUCCESS;
802 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
803 &iar, sizeof(INTERNET_ASYNC_RESULT));
806 iar.dwResult = (DWORD)hFindNext;
807 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
808 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
809 &iar, sizeof(INTERNET_ASYNC_RESULT));
812 return hFindNext;
816 /***********************************************************************
817 * FtpGetCurrentDirectoryA (WININET.@)
819 * Retrieves the current directory
821 * RETURNS
822 * TRUE on success
823 * FALSE on failure
826 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
827 LPDWORD lpdwCurrentDirectory)
829 WCHAR *dir = NULL;
830 DWORD len;
831 BOOL ret;
833 if(lpdwCurrentDirectory) {
834 len = *lpdwCurrentDirectory;
835 if(lpszCurrentDirectory)
837 dir = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
838 if (NULL == dir)
840 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
841 return FALSE;
845 ret = FtpGetCurrentDirectoryW(hFtpSession, lpszCurrentDirectory?dir:NULL, lpdwCurrentDirectory?&len:NULL);
846 if(lpdwCurrentDirectory) {
847 *lpdwCurrentDirectory = len;
848 if(lpszCurrentDirectory) {
849 WideCharToMultiByte(CP_ACP, 0, dir, len, lpszCurrentDirectory, *lpdwCurrentDirectory, NULL, NULL);
850 HeapFree(GetProcessHeap(), 0, dir);
853 return ret;
857 static void AsyncFtpGetCurrentDirectoryProc(WORKREQUEST *workRequest)
859 struct WORKREQ_FTPGETCURRENTDIRECTORYW const *req = &workRequest->u.FtpGetCurrentDirectoryW;
860 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
862 TRACE("%p\n", lpwfs);
864 FTP_FtpGetCurrentDirectoryW(lpwfs, req->lpszDirectory, req->lpdwDirectory);
867 /***********************************************************************
868 * FtpGetCurrentDirectoryW (WININET.@)
870 * Retrieves the current directory
872 * RETURNS
873 * TRUE on success
874 * FALSE on failure
877 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
878 LPDWORD lpdwCurrentDirectory)
880 LPWININETFTPSESSIONW lpwfs;
881 LPWININETAPPINFOW hIC = NULL;
882 BOOL r = FALSE;
884 TRACE("len(%d)\n", *lpdwCurrentDirectory);
886 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
887 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
889 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
890 goto lend;
893 if (lpwfs->download_in_progress != NULL)
895 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
896 goto lend;
899 hIC = lpwfs->lpAppInfo;
900 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
902 WORKREQUEST workRequest;
903 struct WORKREQ_FTPGETCURRENTDIRECTORYW *req;
905 workRequest.asyncproc = AsyncFtpGetCurrentDirectoryProc;
906 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
907 req = &workRequest.u.FtpGetCurrentDirectoryW;
908 req->lpszDirectory = lpszCurrentDirectory;
909 req->lpdwDirectory = lpdwCurrentDirectory;
911 r = INTERNET_AsyncCall(&workRequest);
913 else
915 r = FTP_FtpGetCurrentDirectoryW(lpwfs, lpszCurrentDirectory,
916 lpdwCurrentDirectory);
919 lend:
920 if( lpwfs )
921 WININET_Release( &lpwfs->hdr );
923 return r;
927 /***********************************************************************
928 * FTP_FtpGetCurrentDirectoryW (Internal)
930 * Retrieves the current directory
932 * RETURNS
933 * TRUE on success
934 * FALSE on failure
937 BOOL WINAPI FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszCurrentDirectory,
938 LPDWORD lpdwCurrentDirectory)
940 INT nResCode;
941 LPWININETAPPINFOW hIC = NULL;
942 DWORD bSuccess = FALSE;
944 TRACE("len(%d)\n", *lpdwCurrentDirectory);
946 /* Clear any error information */
947 INTERNET_SetLastError(0);
949 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
951 hIC = lpwfs->lpAppInfo;
952 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
953 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
954 goto lend;
956 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
957 if (nResCode)
959 if (nResCode == 257) /* Extract directory name */
961 DWORD firstpos, lastpos, len;
962 LPWSTR lpszResponseBuffer = WININET_strdup_AtoW(INTERNET_GetResponseBuffer());
964 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
966 if ('"' == lpszResponseBuffer[lastpos])
968 if (!firstpos)
969 firstpos = lastpos;
970 else
971 break;
975 len = lastpos - firstpos - 1;
976 lstrcpynW(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1], *lpdwCurrentDirectory);
977 HeapFree(GetProcessHeap(), 0, lpszResponseBuffer);
978 *lpdwCurrentDirectory = len;
979 bSuccess = TRUE;
981 else
982 FTP_SetResponseError(nResCode);
985 lend:
986 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
988 INTERNET_ASYNC_RESULT iar;
990 iar.dwResult = (DWORD)bSuccess;
991 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
992 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
993 &iar, sizeof(INTERNET_ASYNC_RESULT));
996 return (DWORD) bSuccess;
999 /***********************************************************************
1000 * FtpOpenFileA (WININET.@)
1002 * Open a remote file for writing or reading
1004 * RETURNS
1005 * HINTERNET handle on success
1006 * NULL on failure
1009 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
1010 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1011 DWORD_PTR dwContext)
1013 LPWSTR lpwzFileName;
1014 HINTERNET ret;
1016 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1017 ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext);
1018 HeapFree(GetProcessHeap(), 0, lpwzFileName);
1019 return ret;
1023 static void AsyncFtpOpenFileProc(WORKREQUEST *workRequest)
1025 struct WORKREQ_FTPOPENFILEW const *req = &workRequest->u.FtpOpenFileW;
1026 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1028 TRACE("%p\n", lpwfs);
1030 FTP_FtpOpenFileW(lpwfs, req->lpszFilename,
1031 req->dwAccess, req->dwFlags, req->dwContext);
1032 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1035 /***********************************************************************
1036 * FtpOpenFileW (WININET.@)
1038 * Open a remote file for writing or reading
1040 * RETURNS
1041 * HINTERNET handle on success
1042 * NULL on failure
1045 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
1046 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1047 DWORD_PTR dwContext)
1049 LPWININETFTPSESSIONW lpwfs;
1050 LPWININETAPPINFOW hIC = NULL;
1051 HINTERNET r = NULL;
1053 TRACE("(%p,%s,0x%08x,0x%08x,0x%08lx)\n", hFtpSession,
1054 debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext);
1056 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1057 if (!lpwfs)
1059 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1060 return FALSE;
1063 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1065 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1066 goto lend;
1069 if ((!lpszFileName) ||
1070 ((fdwAccess != GENERIC_READ) && (fdwAccess != GENERIC_WRITE)) ||
1071 ((dwFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY))
1073 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1074 goto lend;
1077 if (lpwfs->download_in_progress != NULL)
1079 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1080 goto lend;
1083 hIC = lpwfs->lpAppInfo;
1084 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1086 WORKREQUEST workRequest;
1087 struct WORKREQ_FTPOPENFILEW *req;
1089 workRequest.asyncproc = AsyncFtpOpenFileProc;
1090 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1091 req = &workRequest.u.FtpOpenFileW;
1092 req->lpszFilename = WININET_strdupW(lpszFileName);
1093 req->dwAccess = fdwAccess;
1094 req->dwFlags = dwFlags;
1095 req->dwContext = dwContext;
1097 INTERNET_AsyncCall(&workRequest);
1098 r = NULL;
1100 else
1102 r = FTP_FtpOpenFileW(lpwfs, lpszFileName, fdwAccess, dwFlags, dwContext);
1105 lend:
1106 WININET_Release( &lpwfs->hdr );
1108 return r;
1112 /***********************************************************************
1113 * FTP_FtpOpenFileW (Internal)
1115 * Open a remote file for writing or reading
1117 * RETURNS
1118 * HINTERNET handle on success
1119 * NULL on failure
1122 HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs,
1123 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1124 DWORD_PTR dwContext)
1126 INT nDataSocket;
1127 BOOL bSuccess = FALSE;
1128 LPWININETFTPFILE lpwh = NULL;
1129 LPWININETAPPINFOW hIC = NULL;
1130 HINTERNET handle = NULL;
1132 TRACE("\n");
1134 /* Clear any error information */
1135 INTERNET_SetLastError(0);
1137 if (GENERIC_READ == fdwAccess)
1139 /* Set up socket to retrieve data */
1140 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
1142 else if (GENERIC_WRITE == fdwAccess)
1144 /* Set up socket to send data */
1145 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
1148 /* Get data socket to server */
1149 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
1151 lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPFILE));
1152 lpwh->hdr.htype = WH_HFILE;
1153 lpwh->hdr.dwFlags = dwFlags;
1154 lpwh->hdr.dwContext = dwContext;
1155 lpwh->hdr.dwRefCount = 1;
1156 lpwh->hdr.close_connection = NULL;
1157 lpwh->hdr.destroy = FTP_CloseFileTransferHandle;
1158 lpwh->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
1159 lpwh->nDataSocket = nDataSocket;
1160 lpwh->session_deleted = FALSE;
1162 WININET_AddRef( &lpwfs->hdr );
1163 lpwh->lpFtpSession = lpwfs;
1164 list_add_head( &lpwfs->hdr.children, &lpwh->hdr.entry );
1166 handle = WININET_AllocHandle( &lpwh->hdr );
1167 if( !handle )
1168 goto lend;
1170 /* Indicate that a download is currently in progress */
1171 lpwfs->download_in_progress = lpwh;
1174 if (lpwfs->lstnSocket != -1)
1175 closesocket(lpwfs->lstnSocket);
1177 hIC = lpwfs->lpAppInfo;
1178 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1180 INTERNET_ASYNC_RESULT iar;
1182 if (lpwh)
1184 iar.dwResult = (DWORD)handle;
1185 iar.dwError = ERROR_SUCCESS;
1186 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
1187 &iar, sizeof(INTERNET_ASYNC_RESULT));
1190 iar.dwResult = (DWORD)bSuccess;
1191 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1192 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1193 &iar, sizeof(INTERNET_ASYNC_RESULT));
1196 lend:
1197 if( lpwh )
1198 WININET_Release( &lpwh->hdr );
1200 return handle;
1204 /***********************************************************************
1205 * FtpGetFileA (WININET.@)
1207 * Retrieve file from the FTP server
1209 * RETURNS
1210 * TRUE on success
1211 * FALSE on failure
1214 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1215 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1216 DWORD_PTR dwContext)
1218 LPWSTR lpwzRemoteFile;
1219 LPWSTR lpwzNewFile;
1220 BOOL ret;
1222 lpwzRemoteFile = lpszRemoteFile?WININET_strdup_AtoW(lpszRemoteFile):NULL;
1223 lpwzNewFile = lpszNewFile?WININET_strdup_AtoW(lpszNewFile):NULL;
1224 ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists,
1225 dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1226 HeapFree(GetProcessHeap(), 0, lpwzRemoteFile);
1227 HeapFree(GetProcessHeap(), 0, lpwzNewFile);
1228 return ret;
1232 static void AsyncFtpGetFileProc(WORKREQUEST *workRequest)
1234 struct WORKREQ_FTPGETFILEW const *req = &workRequest->u.FtpGetFileW;
1235 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1237 TRACE("%p\n", lpwfs);
1239 FTP_FtpGetFileW(lpwfs, req->lpszRemoteFile,
1240 req->lpszNewFile, req->fFailIfExists,
1241 req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext);
1242 HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile);
1243 HeapFree(GetProcessHeap(), 0, req->lpszNewFile);
1247 /***********************************************************************
1248 * FtpGetFileW (WININET.@)
1250 * Retrieve file from the FTP server
1252 * RETURNS
1253 * TRUE on success
1254 * FALSE on failure
1257 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1258 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1259 DWORD_PTR dwContext)
1261 LPWININETFTPSESSIONW lpwfs;
1262 LPWININETAPPINFOW hIC = NULL;
1263 BOOL r = FALSE;
1265 if (!lpszRemoteFile || !lpszNewFile)
1267 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1268 return FALSE;
1271 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet );
1272 if (!lpwfs)
1274 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1275 return FALSE;
1278 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1280 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1281 goto lend;
1284 if ((dwInternetFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY)
1286 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1287 goto lend;
1290 if (lpwfs->download_in_progress != NULL)
1292 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1293 goto lend;
1296 hIC = lpwfs->lpAppInfo;
1297 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1299 WORKREQUEST workRequest;
1300 struct WORKREQ_FTPGETFILEW *req;
1302 workRequest.asyncproc = AsyncFtpGetFileProc;
1303 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1304 req = &workRequest.u.FtpGetFileW;
1305 req->lpszRemoteFile = WININET_strdupW(lpszRemoteFile);
1306 req->lpszNewFile = WININET_strdupW(lpszNewFile);
1307 req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1308 req->fFailIfExists = fFailIfExists;
1309 req->dwFlags = dwInternetFlags;
1310 req->dwContext = dwContext;
1312 r = INTERNET_AsyncCall(&workRequest);
1314 else
1316 r = FTP_FtpGetFileW(lpwfs, lpszRemoteFile, lpszNewFile,
1317 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1320 lend:
1321 WININET_Release( &lpwfs->hdr );
1323 return r;
1327 /***********************************************************************
1328 * FTP_FtpGetFileW (Internal)
1330 * Retrieve file from the FTP server
1332 * RETURNS
1333 * TRUE on success
1334 * FALSE on failure
1337 BOOL WINAPI FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1338 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1339 DWORD_PTR dwContext)
1341 BOOL bSuccess = FALSE;
1342 HANDLE hFile;
1343 LPWININETAPPINFOW hIC = NULL;
1345 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile));
1347 /* Clear any error information */
1348 INTERNET_SetLastError(0);
1350 /* Ensure we can write to lpszNewfile by opening it */
1351 hFile = CreateFileW(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1352 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1353 if (INVALID_HANDLE_VALUE == hFile)
1354 return FALSE;
1356 /* Set up socket to retrieve data */
1357 if (FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags))
1359 INT nDataSocket;
1361 /* Get data socket to server */
1362 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1364 INT nResCode;
1366 /* Receive data */
1367 FTP_RetrieveFileData(lpwfs, nDataSocket, hFile);
1368 closesocket(nDataSocket);
1370 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
1371 if (nResCode)
1373 if (nResCode == 226)
1374 bSuccess = TRUE;
1375 else
1376 FTP_SetResponseError(nResCode);
1381 if (lpwfs->lstnSocket != -1)
1382 closesocket(lpwfs->lstnSocket);
1384 CloseHandle(hFile);
1386 hIC = lpwfs->lpAppInfo;
1387 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1389 INTERNET_ASYNC_RESULT iar;
1391 iar.dwResult = (DWORD)bSuccess;
1392 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1393 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1394 &iar, sizeof(INTERNET_ASYNC_RESULT));
1397 return bSuccess;
1400 /***********************************************************************
1401 * FtpGetFileSize (WININET.@)
1403 DWORD WINAPI FtpGetFileSize( HINTERNET hFile, LPDWORD lpdwFileSizeHigh )
1405 FIXME("(%p, %p)\n", hFile, lpdwFileSizeHigh);
1407 if (lpdwFileSizeHigh)
1408 *lpdwFileSizeHigh = 0;
1410 return 0;
1413 /***********************************************************************
1414 * FtpDeleteFileA (WININET.@)
1416 * Delete a file on the ftp server
1418 * RETURNS
1419 * TRUE on success
1420 * FALSE on failure
1423 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1425 LPWSTR lpwzFileName;
1426 BOOL ret;
1428 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1429 ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1430 HeapFree(GetProcessHeap(), 0, lpwzFileName);
1431 return ret;
1434 static void AsyncFtpDeleteFileProc(WORKREQUEST *workRequest)
1436 struct WORKREQ_FTPDELETEFILEW const *req = &workRequest->u.FtpDeleteFileW;
1437 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1439 TRACE("%p\n", lpwfs);
1441 FTP_FtpDeleteFileW(lpwfs, req->lpszFilename);
1442 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1445 /***********************************************************************
1446 * FtpDeleteFileW (WININET.@)
1448 * Delete a file on the ftp server
1450 * RETURNS
1451 * TRUE on success
1452 * FALSE on failure
1455 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1457 LPWININETFTPSESSIONW lpwfs;
1458 LPWININETAPPINFOW hIC = NULL;
1459 BOOL r = FALSE;
1461 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1462 if (!lpwfs)
1464 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1465 return FALSE;
1468 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1470 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1471 goto lend;
1474 if (lpwfs->download_in_progress != NULL)
1476 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1477 goto lend;
1480 if (!lpszFileName)
1482 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1483 goto lend;
1486 hIC = lpwfs->lpAppInfo;
1487 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1489 WORKREQUEST workRequest;
1490 struct WORKREQ_FTPDELETEFILEW *req;
1492 workRequest.asyncproc = AsyncFtpDeleteFileProc;
1493 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1494 req = &workRequest.u.FtpDeleteFileW;
1495 req->lpszFilename = WININET_strdupW(lpszFileName);
1497 r = INTERNET_AsyncCall(&workRequest);
1499 else
1501 r = FTP_FtpDeleteFileW(lpwfs, lpszFileName);
1504 lend:
1505 WININET_Release( &lpwfs->hdr );
1507 return r;
1510 /***********************************************************************
1511 * FTP_FtpDeleteFileW (Internal)
1513 * Delete a file on the ftp server
1515 * RETURNS
1516 * TRUE on success
1517 * FALSE on failure
1520 BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName)
1522 INT nResCode;
1523 BOOL bSuccess = FALSE;
1524 LPWININETAPPINFOW hIC = NULL;
1526 TRACE("%p\n", lpwfs);
1528 /* Clear any error information */
1529 INTERNET_SetLastError(0);
1531 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1532 goto lend;
1534 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1535 if (nResCode)
1537 if (nResCode == 250)
1538 bSuccess = TRUE;
1539 else
1540 FTP_SetResponseError(nResCode);
1542 lend:
1543 hIC = lpwfs->lpAppInfo;
1544 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1546 INTERNET_ASYNC_RESULT iar;
1548 iar.dwResult = (DWORD)bSuccess;
1549 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1550 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1551 &iar, sizeof(INTERNET_ASYNC_RESULT));
1554 return bSuccess;
1558 /***********************************************************************
1559 * FtpRemoveDirectoryA (WININET.@)
1561 * Remove a directory on the ftp server
1563 * RETURNS
1564 * TRUE on success
1565 * FALSE on failure
1568 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1570 LPWSTR lpwzDirectory;
1571 BOOL ret;
1573 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
1574 ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1575 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
1576 return ret;
1579 static void AsyncFtpRemoveDirectoryProc(WORKREQUEST *workRequest)
1581 struct WORKREQ_FTPREMOVEDIRECTORYW const *req = &workRequest->u.FtpRemoveDirectoryW;
1582 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1584 TRACE("%p\n", lpwfs);
1586 FTP_FtpRemoveDirectoryW(lpwfs, req->lpszDirectory);
1587 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
1590 /***********************************************************************
1591 * FtpRemoveDirectoryW (WININET.@)
1593 * Remove a directory on the ftp server
1595 * RETURNS
1596 * TRUE on success
1597 * FALSE on failure
1600 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1602 LPWININETFTPSESSIONW lpwfs;
1603 LPWININETAPPINFOW hIC = NULL;
1604 BOOL r = FALSE;
1606 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1607 if (!lpwfs)
1609 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1610 return FALSE;
1613 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1615 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1616 goto lend;
1619 if (lpwfs->download_in_progress != NULL)
1621 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1622 goto lend;
1625 if (!lpszDirectory)
1627 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1628 goto lend;
1631 hIC = lpwfs->lpAppInfo;
1632 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1634 WORKREQUEST workRequest;
1635 struct WORKREQ_FTPREMOVEDIRECTORYW *req;
1637 workRequest.asyncproc = AsyncFtpRemoveDirectoryProc;
1638 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1639 req = &workRequest.u.FtpRemoveDirectoryW;
1640 req->lpszDirectory = WININET_strdupW(lpszDirectory);
1642 r = INTERNET_AsyncCall(&workRequest);
1644 else
1646 r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory);
1649 lend:
1650 WININET_Release( &lpwfs->hdr );
1652 return r;
1655 /***********************************************************************
1656 * FTP_FtpRemoveDirectoryW (Internal)
1658 * Remove a directory on the ftp server
1660 * RETURNS
1661 * TRUE on success
1662 * FALSE on failure
1665 BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
1667 INT nResCode;
1668 BOOL bSuccess = FALSE;
1669 LPWININETAPPINFOW hIC = NULL;
1671 TRACE("\n");
1673 /* Clear any error information */
1674 INTERNET_SetLastError(0);
1676 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1677 goto lend;
1679 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1680 if (nResCode)
1682 if (nResCode == 250)
1683 bSuccess = TRUE;
1684 else
1685 FTP_SetResponseError(nResCode);
1688 lend:
1689 hIC = lpwfs->lpAppInfo;
1690 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1692 INTERNET_ASYNC_RESULT iar;
1694 iar.dwResult = (DWORD)bSuccess;
1695 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1696 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1697 &iar, sizeof(INTERNET_ASYNC_RESULT));
1700 return bSuccess;
1704 /***********************************************************************
1705 * FtpRenameFileA (WININET.@)
1707 * Rename a file on the ftp server
1709 * RETURNS
1710 * TRUE on success
1711 * FALSE on failure
1714 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1716 LPWSTR lpwzSrc;
1717 LPWSTR lpwzDest;
1718 BOOL ret;
1720 lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL;
1721 lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL;
1722 ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
1723 HeapFree(GetProcessHeap(), 0, lpwzSrc);
1724 HeapFree(GetProcessHeap(), 0, lpwzDest);
1725 return ret;
1728 static void AsyncFtpRenameFileProc(WORKREQUEST *workRequest)
1730 struct WORKREQ_FTPRENAMEFILEW const *req = &workRequest->u.FtpRenameFileW;
1731 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1733 TRACE("%p\n", lpwfs);
1735 FTP_FtpRenameFileW(lpwfs, req->lpszSrcFile, req->lpszDestFile);
1736 HeapFree(GetProcessHeap(), 0, req->lpszSrcFile);
1737 HeapFree(GetProcessHeap(), 0, req->lpszDestFile);
1740 /***********************************************************************
1741 * FtpRenameFileW (WININET.@)
1743 * Rename a file on the ftp server
1745 * RETURNS
1746 * TRUE on success
1747 * FALSE on failure
1750 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
1752 LPWININETFTPSESSIONW lpwfs;
1753 LPWININETAPPINFOW hIC = NULL;
1754 BOOL r = FALSE;
1756 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1757 if (!lpwfs)
1759 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1760 return FALSE;
1763 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1765 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1766 goto lend;
1769 if (lpwfs->download_in_progress != NULL)
1771 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1772 goto lend;
1775 if (!lpszSrc || !lpszDest)
1777 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1778 goto lend;
1781 hIC = lpwfs->lpAppInfo;
1782 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1784 WORKREQUEST workRequest;
1785 struct WORKREQ_FTPRENAMEFILEW *req;
1787 workRequest.asyncproc = AsyncFtpRenameFileProc;
1788 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1789 req = &workRequest.u.FtpRenameFileW;
1790 req->lpszSrcFile = WININET_strdupW(lpszSrc);
1791 req->lpszDestFile = WININET_strdupW(lpszDest);
1793 r = INTERNET_AsyncCall(&workRequest);
1795 else
1797 r = FTP_FtpRenameFileW(lpwfs, lpszSrc, lpszDest);
1800 lend:
1801 WININET_Release( &lpwfs->hdr );
1803 return r;
1806 /***********************************************************************
1807 * FTP_FtpRenameFileW (Internal)
1809 * Rename a file on the ftp server
1811 * RETURNS
1812 * TRUE on success
1813 * FALSE on failure
1816 BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs,
1817 LPCWSTR lpszSrc, LPCWSTR lpszDest)
1819 INT nResCode;
1820 BOOL bSuccess = FALSE;
1821 LPWININETAPPINFOW hIC = NULL;
1823 TRACE("\n");
1825 /* Clear any error information */
1826 INTERNET_SetLastError(0);
1828 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1829 goto lend;
1831 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1832 if (nResCode == 350)
1834 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1835 goto lend;
1837 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1840 if (nResCode == 250)
1841 bSuccess = TRUE;
1842 else
1843 FTP_SetResponseError(nResCode);
1845 lend:
1846 hIC = lpwfs->lpAppInfo;
1847 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1849 INTERNET_ASYNC_RESULT iar;
1851 iar.dwResult = (DWORD)bSuccess;
1852 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1853 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1854 &iar, sizeof(INTERNET_ASYNC_RESULT));
1857 return bSuccess;
1860 /***********************************************************************
1861 * FtpCommandA (WININET.@)
1863 BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1864 LPCSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1866 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1867 debugstr_a(lpszCommand), dwContext, phFtpCommand);
1869 return TRUE;
1872 /***********************************************************************
1873 * FtpCommandW (WININET.@)
1875 BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1876 LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1878 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1879 debugstr_w(lpszCommand), dwContext, phFtpCommand);
1881 return TRUE;
1884 /***********************************************************************
1885 * FTP_Connect (internal)
1887 * Connect to a ftp server
1889 * RETURNS
1890 * HINTERNET a session handle on success
1891 * NULL on failure
1893 * NOTES:
1895 * Windows uses 'anonymous' as the username, when given a NULL username
1896 * and a NULL password. The password is first looked up in:
1898 * HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\EmailName
1900 * If this entry is not present it uses the current username as the password.
1904 HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
1905 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1906 LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext,
1907 DWORD dwInternalFlags)
1909 static const WCHAR szKey[] = {'S','o','f','t','w','a','r','e','\\',
1910 'M','i','c','r','o','s','o','f','t','\\',
1911 'W','i','n','d','o','w','s','\\',
1912 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1913 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
1914 static const WCHAR szValue[] = {'E','m','a','i','l','N','a','m','e',0};
1915 static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'};
1916 static const WCHAR szEmpty[] = {'\0'};
1917 struct sockaddr_in socketAddr;
1918 INT nsocket = -1;
1919 UINT sock_namelen;
1920 BOOL bSuccess = FALSE;
1921 LPWININETFTPSESSIONW lpwfs = NULL;
1922 HINTERNET handle = NULL;
1924 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1925 hIC, debugstr_w(lpszServerName),
1926 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
1928 assert( hIC->hdr.htype == WH_HINIT );
1930 if (NULL == lpszUserName && NULL != lpszPassword)
1932 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1933 goto lerror;
1936 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
1937 if (NULL == lpwfs)
1939 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1940 goto lerror;
1943 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1944 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1946 lpwfs->hdr.htype = WH_HFTPSESSION;
1947 lpwfs->hdr.dwFlags = dwFlags;
1948 lpwfs->hdr.dwContext = dwContext;
1949 lpwfs->hdr.dwInternalFlags = dwInternalFlags;
1950 lpwfs->hdr.dwRefCount = 1;
1951 lpwfs->hdr.close_connection = FTP_CloseConnection;
1952 lpwfs->hdr.destroy = FTP_CloseSessionHandle;
1953 lpwfs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
1954 lpwfs->download_in_progress = NULL;
1956 WININET_AddRef( &hIC->hdr );
1957 lpwfs->lpAppInfo = hIC;
1958 list_add_head( &hIC->hdr.children, &lpwfs->hdr.entry );
1960 handle = WININET_AllocHandle( &lpwfs->hdr );
1961 if( !handle )
1963 ERR("Failed to alloc handle\n");
1964 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1965 goto lerror;
1968 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1969 if(strchrW(hIC->lpszProxy, ' '))
1970 FIXME("Several proxies not implemented.\n");
1971 if(hIC->lpszProxyBypass)
1972 FIXME("Proxy bypass is ignored.\n");
1974 if ( !lpszUserName) {
1975 HKEY key;
1976 WCHAR szPassword[MAX_PATH];
1977 DWORD len = sizeof(szPassword);
1979 lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
1981 RegOpenKeyW(HKEY_CURRENT_USER, szKey, &key);
1982 if (RegQueryValueExW(key, szValue, NULL, NULL, (LPBYTE)szPassword, &len)) {
1983 /* Nothing in the registry, get the username and use that as the password */
1984 if (!GetUserNameW(szPassword, &len)) {
1985 /* Should never get here, but use an empty password as failsafe */
1986 strcpyW(szPassword, szEmpty);
1989 RegCloseKey(key);
1991 TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword));
1992 lpwfs->lpszPassword = WININET_strdupW(szPassword);
1994 else {
1995 lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
1997 if (lpszPassword)
1998 lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
1999 else
2000 lpwfs->lpszPassword = WININET_strdupW(szEmpty);
2003 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
2004 if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
2006 INTERNET_ASYNC_RESULT iar;
2008 iar.dwResult = (DWORD)handle;
2009 iar.dwError = ERROR_SUCCESS;
2011 SendAsyncCallback(&hIC->hdr, dwContext,
2012 INTERNET_STATUS_HANDLE_CREATED, &iar,
2013 sizeof(INTERNET_ASYNC_RESULT));
2016 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
2017 (LPWSTR) lpszServerName, strlenW(lpszServerName));
2019 if (!GetAddress(lpszServerName, nServerPort, &socketAddr))
2021 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
2022 goto lerror;
2025 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
2026 (LPWSTR) lpszServerName, strlenW(lpszServerName));
2028 nsocket = socket(AF_INET,SOCK_STREAM,0);
2029 if (nsocket == -1)
2031 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
2032 goto lerror;
2035 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
2036 &socketAddr, sizeof(struct sockaddr_in));
2038 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
2040 ERR("Unable to connect (%s)\n", strerror(errno));
2041 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
2043 else
2045 TRACE("Connected to server\n");
2046 lpwfs->sndSocket = nsocket;
2047 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
2048 &socketAddr, sizeof(struct sockaddr_in));
2050 sock_namelen = sizeof(lpwfs->socketAddress);
2051 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
2053 if (FTP_ConnectToHost(lpwfs))
2055 TRACE("Successfully logged into server\n");
2056 bSuccess = TRUE;
2060 lerror:
2061 if (lpwfs) WININET_Release( &lpwfs->hdr );
2063 if (!bSuccess && handle)
2065 WININET_FreeHandle( handle );
2066 handle = NULL;
2069 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2071 INTERNET_ASYNC_RESULT iar;
2073 iar.dwResult = bSuccess ? (DWORD_PTR)lpwfs : 0;
2074 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
2075 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
2076 &iar, sizeof(INTERNET_ASYNC_RESULT));
2079 return handle;
2083 /***********************************************************************
2084 * FTP_ConnectToHost (internal)
2086 * Connect to a ftp server
2088 * RETURNS
2089 * TRUE on success
2090 * NULL on failure
2093 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
2095 INT nResCode;
2096 BOOL bSuccess = FALSE;
2098 TRACE("\n");
2099 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2101 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
2102 goto lend;
2104 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2105 if (nResCode)
2107 /* Login successful... */
2108 if (nResCode == 230)
2109 bSuccess = TRUE;
2110 /* User name okay, need password... */
2111 else if (nResCode == 331)
2112 bSuccess = FTP_SendPassword(lpwfs);
2113 /* Need account for login... */
2114 else if (nResCode == 332)
2115 bSuccess = FTP_SendAccount(lpwfs);
2116 else
2117 FTP_SetResponseError(nResCode);
2120 TRACE("Returning %d\n", bSuccess);
2121 lend:
2122 return bSuccess;
2126 /***********************************************************************
2127 * FTP_SendCommandA (internal)
2129 * Send command to server
2131 * RETURNS
2132 * TRUE on success
2133 * NULL on failure
2136 static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
2137 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext)
2139 DWORD len;
2140 CHAR *buf;
2141 DWORD nBytesSent = 0;
2142 int nRC = 0;
2143 DWORD dwParamLen;
2145 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
2147 if (lpfnStatusCB)
2149 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
2152 dwParamLen = lpszParam?strlen(lpszParam)+1:0;
2153 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
2154 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
2156 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2157 return FALSE;
2159 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
2160 dwParamLen ? lpszParam : "", szCRLF);
2162 TRACE("Sending (%s) len(%d)\n", buf, len);
2163 while((nBytesSent < len) && (nRC != -1))
2165 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
2166 nBytesSent += nRC;
2169 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
2171 if (lpfnStatusCB)
2173 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_REQUEST_SENT,
2174 &nBytesSent, sizeof(DWORD));
2177 TRACE("Sent %d bytes\n", nBytesSent);
2178 return (nRC != -1);
2181 /***********************************************************************
2182 * FTP_SendCommand (internal)
2184 * Send command to server
2186 * RETURNS
2187 * TRUE on success
2188 * NULL on failure
2191 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
2192 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext)
2194 BOOL ret;
2195 LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
2196 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
2197 HeapFree(GetProcessHeap(), 0, lpszParamA);
2198 return ret;
2201 /***********************************************************************
2202 * FTP_ReceiveResponse (internal)
2204 * Receive response from server
2206 * RETURNS
2207 * Reply code on success
2208 * 0 on failure
2211 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD_PTR dwContext)
2213 LPSTR lpszResponse = INTERNET_GetResponseBuffer();
2214 DWORD nRecv;
2215 INT rc = 0;
2216 char firstprefix[5];
2217 BOOL multiline = FALSE;
2218 LPWININETAPPINFOW hIC = NULL;
2220 TRACE("socket(%d)\n", lpwfs->sndSocket);
2222 hIC = lpwfs->lpAppInfo;
2223 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2225 while(1)
2227 if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
2228 goto lerror;
2230 if (nRecv >= 3)
2232 if(!multiline)
2234 if(lpszResponse[3] != '-')
2235 break;
2236 else
2237 { /* Start of multiline repsonse. Loop until we get "nnn " */
2238 multiline = TRUE;
2239 memcpy(firstprefix, lpszResponse, 3);
2240 firstprefix[3] = ' ';
2241 firstprefix[4] = '\0';
2244 else
2246 if(!memcmp(firstprefix, lpszResponse, 4))
2247 break;
2252 if (nRecv >= 3)
2254 rc = atoi(lpszResponse);
2256 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2257 &nRecv, sizeof(DWORD));
2260 lerror:
2261 TRACE("return %d\n", rc);
2262 return rc;
2266 /***********************************************************************
2267 * FTP_SendPassword (internal)
2269 * Send password to ftp server
2271 * RETURNS
2272 * TRUE on success
2273 * NULL on failure
2276 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
2278 INT nResCode;
2279 BOOL bSuccess = FALSE;
2281 TRACE("\n");
2282 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
2283 goto lend;
2285 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2286 if (nResCode)
2288 TRACE("Received reply code %d\n", nResCode);
2289 /* Login successful... */
2290 if (nResCode == 230)
2291 bSuccess = TRUE;
2292 /* Command not implemented, superfluous at the server site... */
2293 /* Need account for login... */
2294 else if (nResCode == 332)
2295 bSuccess = FTP_SendAccount(lpwfs);
2296 else
2297 FTP_SetResponseError(nResCode);
2300 lend:
2301 TRACE("Returning %d\n", bSuccess);
2302 return bSuccess;
2306 /***********************************************************************
2307 * FTP_SendAccount (internal)
2311 * RETURNS
2312 * TRUE on success
2313 * FALSE on failure
2316 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
2318 INT nResCode;
2319 BOOL bSuccess = FALSE;
2321 TRACE("\n");
2322 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
2323 goto lend;
2325 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2326 if (nResCode)
2327 bSuccess = TRUE;
2328 else
2329 FTP_SetResponseError(nResCode);
2331 lend:
2332 return bSuccess;
2336 /***********************************************************************
2337 * FTP_SendStore (internal)
2339 * Send request to upload file to ftp server
2341 * RETURNS
2342 * TRUE on success
2343 * FALSE on failure
2346 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2348 INT nResCode;
2349 BOOL bSuccess = FALSE;
2351 TRACE("\n");
2352 if (!FTP_InitListenSocket(lpwfs))
2353 goto lend;
2355 if (!FTP_SendType(lpwfs, dwType))
2356 goto lend;
2358 if (!FTP_SendPortOrPasv(lpwfs))
2359 goto lend;
2361 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2362 goto lend;
2363 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2364 if (nResCode)
2366 if (nResCode == 150 || nResCode == 125)
2367 bSuccess = TRUE;
2368 else
2369 FTP_SetResponseError(nResCode);
2372 lend:
2373 if (!bSuccess && lpwfs->lstnSocket != -1)
2375 closesocket(lpwfs->lstnSocket);
2376 lpwfs->lstnSocket = -1;
2379 return bSuccess;
2383 /***********************************************************************
2384 * FTP_InitListenSocket (internal)
2386 * Create a socket to listen for server response
2388 * RETURNS
2389 * TRUE on success
2390 * FALSE on failure
2393 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
2395 BOOL bSuccess = FALSE;
2396 socklen_t namelen = sizeof(struct sockaddr_in);
2398 TRACE("\n");
2400 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2401 if (lpwfs->lstnSocket == -1)
2403 TRACE("Unable to create listening socket\n");
2404 goto lend;
2407 /* We obtain our ip addr from the name of the command channel socket */
2408 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2410 /* and get the system to assign us a port */
2411 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
2413 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
2415 TRACE("Unable to bind socket\n");
2416 goto lend;
2419 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2421 TRACE("listen failed\n");
2422 goto lend;
2425 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2426 bSuccess = TRUE;
2428 lend:
2429 if (!bSuccess && lpwfs->lstnSocket != -1)
2431 closesocket(lpwfs->lstnSocket);
2432 lpwfs->lstnSocket = -1;
2435 return bSuccess;
2439 /***********************************************************************
2440 * FTP_SendType (internal)
2442 * Tell server type of data being transferred
2444 * RETURNS
2445 * TRUE on success
2446 * FALSE on failure
2448 * W98SE doesn't cache the type that's currently set
2449 * (i.e. it sends it always),
2450 * so we probably don't want to do that either.
2452 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
2454 INT nResCode;
2455 WCHAR type[] = { 'I','\0' };
2456 BOOL bSuccess = FALSE;
2458 TRACE("\n");
2459 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2460 type[0] = 'A';
2462 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2463 goto lend;
2465 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2466 if (nResCode)
2468 if (nResCode == 2)
2469 bSuccess = TRUE;
2470 else
2471 FTP_SetResponseError(nResCode);
2474 lend:
2475 return bSuccess;
2479 #if 0 /* FIXME: should probably be used for FtpGetFileSize */
2480 /***********************************************************************
2481 * FTP_GetFileSize (internal)
2483 * Retrieves from the server the size of the given file
2485 * RETURNS
2486 * TRUE on success
2487 * FALSE on failure
2490 static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
2492 INT nResCode;
2493 BOOL bSuccess = FALSE;
2495 TRACE("\n");
2497 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2498 goto lend;
2500 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2501 if (nResCode)
2503 if (nResCode == 213) {
2504 /* Now parses the output to get the actual file size */
2505 int i;
2506 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2508 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2509 if (lpszResponseBuffer[i] == '\0') return FALSE;
2510 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2512 bSuccess = TRUE;
2513 } else {
2514 FTP_SetResponseError(nResCode);
2518 lend:
2519 return bSuccess;
2521 #endif
2524 /***********************************************************************
2525 * FTP_SendPort (internal)
2527 * Tell server which port to use
2529 * RETURNS
2530 * TRUE on success
2531 * FALSE on failure
2534 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
2536 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2537 INT nResCode;
2538 WCHAR szIPAddress[64];
2539 BOOL bSuccess = FALSE;
2540 TRACE("\n");
2542 sprintfW(szIPAddress, szIPFormat,
2543 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2544 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2545 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2546 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2547 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2548 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2550 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2551 goto lend;
2553 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2554 if (nResCode)
2556 if (nResCode == 200)
2557 bSuccess = TRUE;
2558 else
2559 FTP_SetResponseError(nResCode);
2562 lend:
2563 return bSuccess;
2567 /***********************************************************************
2568 * FTP_DoPassive (internal)
2570 * Tell server that we want to do passive transfers
2571 * and connect data socket
2573 * RETURNS
2574 * TRUE on success
2575 * FALSE on failure
2578 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
2580 INT nResCode;
2581 BOOL bSuccess = FALSE;
2583 TRACE("\n");
2584 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2585 goto lend;
2587 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2588 if (nResCode)
2590 if (nResCode == 227)
2592 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2593 LPSTR p;
2594 int f[6];
2595 int i;
2596 char *pAddr, *pPort;
2597 INT nsocket = -1;
2598 struct sockaddr_in dataSocketAddress;
2600 p = lpszResponseBuffer+4; /* skip status code */
2601 while (*p != '\0' && (*p < '0' || *p > '9')) p++;
2603 if (*p == '\0')
2605 ERR("no address found in response, aborting\n");
2606 goto lend;
2609 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2610 &f[4], &f[5]) != 6)
2612 ERR("unknown response address format '%s', aborting\n", p);
2613 goto lend;
2615 for (i=0; i < 6; i++)
2616 f[i] = f[i] & 0xff;
2618 dataSocketAddress = lpwfs->socketAddress;
2619 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2620 pPort = (char *)&(dataSocketAddress.sin_port);
2621 pAddr[0] = f[0];
2622 pAddr[1] = f[1];
2623 pAddr[2] = f[2];
2624 pAddr[3] = f[3];
2625 pPort[0] = f[4];
2626 pPort[1] = f[5];
2628 nsocket = socket(AF_INET,SOCK_STREAM,0);
2629 if (nsocket == -1)
2630 goto lend;
2632 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2634 ERR("can't connect passive FTP data port.\n");
2635 closesocket(nsocket);
2636 goto lend;
2638 lpwfs->pasvSocket = nsocket;
2639 bSuccess = TRUE;
2641 else
2642 FTP_SetResponseError(nResCode);
2645 lend:
2646 return bSuccess;
2650 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
2652 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2654 if (!FTP_DoPassive(lpwfs))
2655 return FALSE;
2657 else
2659 if (!FTP_SendPort(lpwfs))
2660 return FALSE;
2662 return TRUE;
2666 /***********************************************************************
2667 * FTP_GetDataSocket (internal)
2669 * Either accepts an incoming data socket connection from the server
2670 * or just returns the already opened socket after a PASV command
2671 * in case of passive FTP.
2674 * RETURNS
2675 * TRUE on success
2676 * FALSE on failure
2679 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
2681 struct sockaddr_in saddr;
2682 socklen_t addrlen = sizeof(struct sockaddr);
2684 TRACE("\n");
2685 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2687 *nDataSocket = lpwfs->pasvSocket;
2689 else
2691 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2692 closesocket(lpwfs->lstnSocket);
2693 lpwfs->lstnSocket = -1;
2695 return *nDataSocket != -1;
2699 /***********************************************************************
2700 * FTP_SendData (internal)
2702 * Send data to the server
2704 * RETURNS
2705 * TRUE on success
2706 * FALSE on failure
2709 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2711 BY_HANDLE_FILE_INFORMATION fi;
2712 DWORD nBytesRead = 0;
2713 DWORD nBytesSent = 0;
2714 DWORD nTotalSent = 0;
2715 DWORD nBytesToSend, nLen;
2716 int nRC = 1;
2717 time_t s_long_time, e_long_time;
2718 LONG nSeconds;
2719 CHAR *lpszBuffer;
2721 TRACE("\n");
2722 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2724 /* Get the size of the file. */
2725 GetFileInformationByHandle(hFile, &fi);
2726 time(&s_long_time);
2730 nBytesToSend = nBytesRead - nBytesSent;
2732 if (nBytesToSend <= 0)
2734 /* Read data from file. */
2735 nBytesSent = 0;
2736 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2737 ERR("Failed reading from file\n");
2739 if (nBytesRead > 0)
2740 nBytesToSend = nBytesRead;
2741 else
2742 break;
2745 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2746 DATA_PACKET_SIZE : nBytesToSend;
2747 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2749 if (nRC != -1)
2751 nBytesSent += nRC;
2752 nTotalSent += nRC;
2755 /* Do some computation to display the status. */
2756 time(&e_long_time);
2757 nSeconds = e_long_time - s_long_time;
2758 if( nSeconds / 60 > 0 )
2760 TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n",
2761 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2762 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2764 else
2766 TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n",
2767 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2768 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2770 } while (nRC != -1);
2772 TRACE("file transfer complete!\n");
2774 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2776 return nTotalSent;
2780 /***********************************************************************
2781 * FTP_SendRetrieve (internal)
2783 * Send request to retrieve a file
2785 * RETURNS
2786 * Number of bytes to be received on success
2787 * 0 on failure
2790 static BOOL FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2792 INT nResCode;
2793 BOOL ret;
2795 TRACE("\n");
2796 if (!(ret = FTP_InitListenSocket(lpwfs)))
2797 goto lend;
2799 if (!(ret = FTP_SendType(lpwfs, dwType)))
2800 goto lend;
2802 if (!(ret = FTP_SendPortOrPasv(lpwfs)))
2803 goto lend;
2805 if (!(ret = FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0)))
2806 goto lend;
2808 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2809 if ((nResCode != 125) && (nResCode != 150)) {
2810 /* That means that we got an error getting the file. */
2811 FTP_SetResponseError(nResCode);
2812 ret = FALSE;
2815 lend:
2816 if (!ret && lpwfs->lstnSocket != -1)
2818 closesocket(lpwfs->lstnSocket);
2819 lpwfs->lstnSocket = -1;
2822 return ret;
2826 /***********************************************************************
2827 * FTP_RetrieveData (internal)
2829 * Retrieve data from server
2831 * RETURNS
2832 * TRUE on success
2833 * FALSE on failure
2836 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2838 DWORD nBytesWritten;
2839 DWORD nBytesReceived = 0;
2840 INT nRC = 0;
2841 CHAR *lpszBuffer;
2843 TRACE("\n");
2845 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2846 if (NULL == lpszBuffer)
2848 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2849 return FALSE;
2852 while (nRC != -1)
2854 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2855 if (nRC != -1)
2857 /* other side closed socket. */
2858 if (nRC == 0)
2859 goto recv_end;
2860 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2861 nBytesReceived += nRC;
2865 TRACE("Data transfer complete\n");
2867 recv_end:
2868 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2870 return (nRC != -1);
2873 /***********************************************************************
2874 * FTP_CloseConnection (internal)
2876 * Close connections
2878 static void FTP_CloseConnection(LPWININETHANDLEHEADER hdr)
2880 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2882 TRACE("\n");
2884 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext,
2885 INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
2887 if (lpwfs->download_in_progress != NULL)
2888 lpwfs->download_in_progress->session_deleted = TRUE;
2890 if (lpwfs->sndSocket != -1)
2891 closesocket(lpwfs->sndSocket);
2893 if (lpwfs->lstnSocket != -1)
2894 closesocket(lpwfs->lstnSocket);
2896 if (lpwfs->pasvSocket != -1)
2897 closesocket(lpwfs->pasvSocket);
2899 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext,
2900 INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
2904 /***********************************************************************
2905 * FTP_CloseSessionHandle (internal)
2907 * Deallocate session handle
2909 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr)
2911 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2913 TRACE("\n");
2915 WININET_Release(&lpwfs->lpAppInfo->hdr);
2917 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2918 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2919 HeapFree(GetProcessHeap(), 0, lpwfs);
2923 /***********************************************************************
2924 * FTP_FindNextFileW (Internal)
2926 * Continues a file search from a previous call to FindFirstFile
2928 * RETURNS
2929 * TRUE on success
2930 * FALSE on failure
2933 BOOL WINAPI FTP_FindNextFileW(LPWININETFTPFINDNEXTW lpwh, LPVOID lpvFindData)
2935 BOOL bSuccess = TRUE;
2936 LPWIN32_FIND_DATAW lpFindFileData;
2938 TRACE("index(%d) size(%d)\n", lpwh->index, lpwh->size);
2940 assert (lpwh->hdr.htype == WH_HFTPFINDNEXT);
2942 /* Clear any error information */
2943 INTERNET_SetLastError(0);
2945 lpFindFileData = (LPWIN32_FIND_DATAW) lpvFindData;
2946 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2948 if (lpwh->index >= lpwh->size)
2950 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2951 bSuccess = FALSE;
2952 goto lend;
2955 FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
2956 lpwh->index++;
2958 TRACE("\nName: %s\nSize: %d\n", debugstr_w(lpFindFileData->cFileName), lpFindFileData->nFileSizeLow);
2960 lend:
2962 if (lpwh->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2964 INTERNET_ASYNC_RESULT iar;
2966 iar.dwResult = (DWORD)bSuccess;
2967 iar.dwError = iar.dwError = bSuccess ? ERROR_SUCCESS :
2968 INTERNET_GetLastError();
2970 INTERNET_SendCallback(&lpwh->hdr, lpwh->hdr.dwContext,
2971 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
2972 sizeof(INTERNET_ASYNC_RESULT));
2975 return bSuccess;
2979 /***********************************************************************
2980 * FTP_CloseFindNextHandle (internal)
2982 * Deallocate session handle
2984 * RETURNS
2985 * TRUE on success
2986 * FALSE on failure
2989 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr)
2991 LPWININETFTPFINDNEXTW lpwfn = (LPWININETFTPFINDNEXTW) hdr;
2992 DWORD i;
2994 TRACE("\n");
2996 WININET_Release(&lpwfn->lpFtpSession->hdr);
2998 for (i = 0; i < lpwfn->size; i++)
3000 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
3003 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
3004 HeapFree(GetProcessHeap(), 0, lpwfn);
3007 /***********************************************************************
3008 * FTP_CloseFileTransferHandle (internal)
3010 * Closes the file transfer handle. This also 'cleans' the data queue of
3011 * the 'transfer complete' message (this is a bit of a hack though :-/ )
3014 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr)
3016 LPWININETFTPFILE lpwh = (LPWININETFTPFILE) hdr;
3017 LPWININETFTPSESSIONW lpwfs = lpwh->lpFtpSession;
3018 INT nResCode;
3020 TRACE("\n");
3022 WININET_Release(&lpwh->lpFtpSession->hdr);
3024 if (!lpwh->session_deleted)
3025 lpwfs->download_in_progress = NULL;
3027 if (lpwh->nDataSocket != -1)
3028 closesocket(lpwh->nDataSocket);
3030 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
3031 if (nResCode > 0 && nResCode != 226) WARN("server reports failed transfer\n");
3033 HeapFree(GetProcessHeap(), 0, lpwh);
3036 /***********************************************************************
3037 * FTP_ReceiveFileList (internal)
3039 * Read file list from server
3041 * RETURNS
3042 * Handle to file list on success
3043 * NULL on failure
3046 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3047 LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext)
3049 DWORD dwSize = 0;
3050 LPFILEPROPERTIESW lpafp = NULL;
3051 LPWININETFTPFINDNEXTW lpwfn = NULL;
3052 HINTERNET handle = 0;
3054 TRACE("(%p,%d,%s,%p,%08lx)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
3056 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
3058 if(lpFindFileData)
3059 FTP_ConvertFileProp(lpafp, lpFindFileData);
3061 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFTPFINDNEXTW));
3062 if (lpwfn)
3064 lpwfn->hdr.htype = WH_HFTPFINDNEXT;
3065 lpwfn->hdr.dwContext = dwContext;
3066 lpwfn->hdr.dwRefCount = 1;
3067 lpwfn->hdr.close_connection = NULL;
3068 lpwfn->hdr.destroy = FTP_CloseFindNextHandle;
3069 lpwfn->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
3070 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
3071 lpwfn->size = dwSize;
3072 lpwfn->lpafp = lpafp;
3074 WININET_AddRef( &lpwfs->hdr );
3075 lpwfn->lpFtpSession = lpwfs;
3076 list_add_head( &lpwfs->hdr.children, &lpwfn->hdr.entry );
3078 handle = WININET_AllocHandle( &lpwfn->hdr );
3082 if( lpwfn )
3083 WININET_Release( &lpwfn->hdr );
3085 TRACE("Matched %d files\n", dwSize);
3086 return handle;
3090 /***********************************************************************
3091 * FTP_ConvertFileProp (internal)
3093 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
3095 * RETURNS
3096 * TRUE on success
3097 * FALSE on failure
3100 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
3102 BOOL bSuccess = FALSE;
3104 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
3106 if (lpafp)
3108 /* Convert 'Unix' time to Windows time */
3109 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
3110 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
3111 lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime;
3112 lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime;
3114 /* Not all fields are filled in */
3115 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
3116 lpFindFileData->nFileSizeLow = lpafp->nSize;
3118 if (lpafp->bIsDirectory)
3119 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
3121 if (lpafp->lpszName)
3122 lstrcpynW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
3124 bSuccess = TRUE;
3127 return bSuccess;
3130 /***********************************************************************
3131 * FTP_ParseNextFile (internal)
3133 * Parse the next line in file listing
3135 * RETURNS
3136 * TRUE on success
3137 * FALSE on failure
3139 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
3141 static const char szSpace[] = " \t";
3142 DWORD nBufLen;
3143 char *pszLine;
3144 char *pszToken;
3145 char *pszTmp;
3146 BOOL found = FALSE;
3147 int i;
3149 lpfp->lpszName = NULL;
3150 do {
3151 if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
3152 return FALSE;
3154 pszToken = strtok(pszLine, szSpace);
3155 /* ls format
3156 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
3158 * For instance:
3159 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
3161 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
3162 if(!FTP_ParsePermission(pszToken, lpfp))
3163 lpfp->bIsDirectory = FALSE;
3164 for(i=0; i<=3; i++) {
3165 if(!(pszToken = strtok(NULL, szSpace)))
3166 break;
3168 if(!pszToken) continue;
3169 if(lpfp->bIsDirectory) {
3170 TRACE("Is directory\n");
3171 lpfp->nSize = 0;
3173 else {
3174 TRACE("Size: %s\n", pszToken);
3175 lpfp->nSize = atol(pszToken);
3178 lpfp->tmLastModified.tm_sec = 0;
3179 lpfp->tmLastModified.tm_min = 0;
3180 lpfp->tmLastModified.tm_hour = 0;
3181 lpfp->tmLastModified.tm_mday = 0;
3182 lpfp->tmLastModified.tm_mon = 0;
3183 lpfp->tmLastModified.tm_year = 0;
3185 /* Determine month */
3186 pszToken = strtok(NULL, szSpace);
3187 if(!pszToken) continue;
3188 if(strlen(pszToken) >= 3) {
3189 pszToken[3] = 0;
3190 if((pszTmp = StrStrIA(szMonths, pszToken)))
3191 lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
3193 /* Determine day */
3194 pszToken = strtok(NULL, szSpace);
3195 if(!pszToken) continue;
3196 lpfp->tmLastModified.tm_mday = atoi(pszToken);
3197 /* Determine time or year */
3198 pszToken = strtok(NULL, szSpace);
3199 if(!pszToken) continue;
3200 if((pszTmp = strchr(pszToken, ':'))) {
3201 struct tm* apTM;
3202 time_t aTime;
3203 *pszTmp = 0;
3204 pszTmp++;
3205 lpfp->tmLastModified.tm_min = atoi(pszTmp);
3206 lpfp->tmLastModified.tm_hour = atoi(pszToken);
3207 time(&aTime);
3208 apTM = localtime(&aTime);
3209 lpfp->tmLastModified.tm_year = apTM->tm_year;
3211 else {
3212 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
3213 lpfp->tmLastModified.tm_hour = 12;
3215 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3216 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3217 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3218 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3220 pszToken = strtok(NULL, szSpace);
3221 if(!pszToken) continue;
3222 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3223 TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
3225 /* NT way of parsing ... :
3227 07-13-03 08:55PM <DIR> sakpatch
3228 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
3230 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
3231 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
3233 sscanf(pszToken, "%d-%d-%d",
3234 &lpfp->tmLastModified.tm_mon,
3235 &lpfp->tmLastModified.tm_mday,
3236 &lpfp->tmLastModified.tm_year);
3238 /* Hacky and bad Y2K protection :-) */
3239 if (lpfp->tmLastModified.tm_year < 70)
3240 lpfp->tmLastModified.tm_year += 100;
3242 pszToken = strtok(NULL, szSpace);
3243 if(!pszToken) continue;
3244 sscanf(pszToken, "%d:%d",
3245 &lpfp->tmLastModified.tm_hour,
3246 &lpfp->tmLastModified.tm_min);
3247 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
3248 lpfp->tmLastModified.tm_hour += 12;
3250 lpfp->tmLastModified.tm_sec = 0;
3252 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3253 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3254 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3255 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3257 pszToken = strtok(NULL, szSpace);
3258 if(!pszToken) continue;
3259 if(!strcasecmp(pszToken, "<DIR>")) {
3260 lpfp->bIsDirectory = TRUE;
3261 lpfp->nSize = 0;
3262 TRACE("Is directory\n");
3264 else {
3265 lpfp->bIsDirectory = FALSE;
3266 lpfp->nSize = atol(pszToken);
3267 TRACE("Size: %d\n", lpfp->nSize);
3270 pszToken = strtok(NULL, szSpace);
3271 if(!pszToken) continue;
3272 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3273 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
3275 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
3276 else if(pszToken[0] == '+') {
3277 FIXME("EPLF Format not implemented\n");
3280 if(lpfp->lpszName) {
3281 if((lpszSearchFile == NULL) ||
3282 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
3283 found = TRUE;
3284 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
3286 else {
3287 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
3288 lpfp->lpszName = NULL;
3291 } while(!found);
3292 return TRUE;
3295 /***********************************************************************
3296 * FTP_ParseDirectory (internal)
3298 * Parse string of directory information
3300 * RETURNS
3301 * TRUE on success
3302 * FALSE on failure
3304 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3305 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
3307 BOOL bSuccess = TRUE;
3308 INT sizeFilePropArray = 500;/*20; */
3309 INT indexFilePropArray = -1;
3311 TRACE("\n");
3313 /* Allocate intial file properties array */
3314 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
3315 if (!*lpafp)
3316 return FALSE;
3318 do {
3319 if (indexFilePropArray+1 >= sizeFilePropArray)
3321 LPFILEPROPERTIESW tmpafp;
3323 sizeFilePropArray *= 2;
3324 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
3325 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
3326 if (NULL == tmpafp)
3328 bSuccess = FALSE;
3329 break;
3332 *lpafp = tmpafp;
3334 indexFilePropArray++;
3335 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
3337 if (bSuccess && indexFilePropArray)
3339 if (indexFilePropArray < sizeFilePropArray - 1)
3341 LPFILEPROPERTIESW tmpafp;
3343 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
3344 sizeof(FILEPROPERTIESW)*indexFilePropArray);
3345 if (NULL == tmpafp)
3346 *lpafp = tmpafp;
3348 *dwfp = indexFilePropArray;
3350 else
3352 HeapFree(GetProcessHeap(), 0, *lpafp);
3353 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3354 bSuccess = FALSE;
3357 return bSuccess;
3361 /***********************************************************************
3362 * FTP_ParsePermission (internal)
3364 * Parse permission string of directory information
3366 * RETURNS
3367 * TRUE on success
3368 * FALSE on failure
3371 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3373 BOOL bSuccess = TRUE;
3374 unsigned short nPermission = 0;
3375 INT nPos = 1;
3376 INT nLast = 9;
3378 TRACE("\n");
3379 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3381 bSuccess = FALSE;
3382 return bSuccess;
3385 lpfp->bIsDirectory = (*lpszPermission == 'd');
3388 switch (nPos)
3390 case 1:
3391 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3392 break;
3393 case 2:
3394 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3395 break;
3396 case 3:
3397 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3398 break;
3399 case 4:
3400 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3401 break;
3402 case 5:
3403 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3404 break;
3405 case 6:
3406 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3407 break;
3408 case 7:
3409 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3410 break;
3411 case 8:
3412 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3413 break;
3414 case 9:
3415 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3416 break;
3418 nPos++;
3419 }while (nPos <= nLast);
3421 lpfp->permissions = nPermission;
3422 return bSuccess;
3426 /***********************************************************************
3427 * FTP_SetResponseError (internal)
3429 * Set the appropriate error code for a given response from the server
3431 * RETURNS
3434 static DWORD FTP_SetResponseError(DWORD dwResponse)
3436 DWORD dwCode = 0;
3438 switch(dwResponse)
3440 case 425: /* Cannot open data connection. */
3441 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3442 break;
3444 case 426: /* Connection closed, transer aborted. */
3445 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3446 break;
3448 case 530: /* Not logged in. Login incorrect. */
3449 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3450 break;
3452 case 421: /* Service not available - Server may be shutting down. */
3453 case 450: /* File action not taken. File may be busy. */
3454 case 451: /* Action aborted. Server error. */
3455 case 452: /* Action not taken. Insufficient storage space on server. */
3456 case 500: /* Syntax error. Command unrecognized. */
3457 case 501: /* Syntax error. Error in parameters or arguments. */
3458 case 502: /* Command not implemented. */
3459 case 503: /* Bad sequence of commands. */
3460 case 504: /* Command not implemented for that parameter. */
3461 case 532: /* Need account for storing files */
3462 case 550: /* File action not taken. File not found or no access. */
3463 case 551: /* Requested action aborted. Page type unknown */
3464 case 552: /* Action aborted. Exceeded storage allocation */
3465 case 553: /* Action not taken. File name not allowed. */
3467 default:
3468 dwCode = ERROR_INTERNET_EXTENDED_ERROR;
3469 break;
3472 INTERNET_SetLastError(dwCode);
3473 return dwCode;