ntdll: Fix RtlValidAcl to accept newer ACL revisions.
[wine/multimedia.git] / dlls / wininet / ftp.c
blobbbaef8a5b5f9c6a36f8f9caea7d676c9fed78d0f
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 ((dwFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY)
230 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
231 goto lend;
234 hIC = lpwfs->lpAppInfo;
235 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
237 WORKREQUEST workRequest;
238 struct WORKREQ_FTPPUTFILEW *req = &workRequest.u.FtpPutFileW;
240 workRequest.asyncproc = AsyncFtpPutFileProc;
241 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
242 req->lpszLocalFile = WININET_strdupW(lpszLocalFile);
243 req->lpszNewRemoteFile = WININET_strdupW(lpszNewRemoteFile);
244 req->dwFlags = dwFlags;
245 req->dwContext = dwContext;
247 r = INTERNET_AsyncCall(&workRequest);
249 else
251 r = FTP_FtpPutFileW(lpwfs, lpszLocalFile,
252 lpszNewRemoteFile, dwFlags, dwContext);
255 lend:
256 WININET_Release( &lpwfs->hdr );
258 return r;
261 /***********************************************************************
262 * FTP_FtpPutFileW (Internal)
264 * Uploads a file to the FTP server
266 * RETURNS
267 * TRUE on success
268 * FALSE on failure
271 BOOL WINAPI FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile,
272 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext)
274 HANDLE hFile;
275 BOOL bSuccess = FALSE;
276 LPWININETAPPINFOW hIC = NULL;
277 INT nResCode;
279 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", debugstr_w(lpszLocalFile), debugstr_w(lpszNewRemoteFile));
281 /* Clear any error information */
282 INTERNET_SetLastError(0);
284 /* Open file to be uploaded */
285 if (INVALID_HANDLE_VALUE ==
286 (hFile = CreateFileW(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
287 /* Let CreateFile set the appropriate error */
288 return FALSE;
290 hIC = lpwfs->lpAppInfo;
292 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
294 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
296 INT nDataSocket;
298 /* Get data socket to server */
299 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
301 FTP_SendData(lpwfs, nDataSocket, hFile);
302 closesocket(nDataSocket);
303 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
304 if (nResCode)
306 if (nResCode == 226)
307 bSuccess = TRUE;
308 else
309 FTP_SetResponseError(nResCode);
314 if (lpwfs->lstnSocket != -1)
315 closesocket(lpwfs->lstnSocket);
317 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
319 INTERNET_ASYNC_RESULT iar;
321 iar.dwResult = (DWORD)bSuccess;
322 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
323 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
324 &iar, sizeof(INTERNET_ASYNC_RESULT));
327 CloseHandle(hFile);
329 return bSuccess;
333 /***********************************************************************
334 * FtpSetCurrentDirectoryA (WININET.@)
336 * Change the working directory on the FTP server
338 * RETURNS
339 * TRUE on success
340 * FALSE on failure
343 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
345 LPWSTR lpwzDirectory;
346 BOOL ret;
348 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
349 ret = FtpSetCurrentDirectoryW(hConnect, lpwzDirectory);
350 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
351 return ret;
355 static void AsyncFtpSetCurrentDirectoryProc(WORKREQUEST *workRequest)
357 struct WORKREQ_FTPSETCURRENTDIRECTORYW const *req = &workRequest->u.FtpSetCurrentDirectoryW;
358 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
360 TRACE("%p\n", lpwfs);
362 FTP_FtpSetCurrentDirectoryW(lpwfs, req->lpszDirectory);
363 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
366 /***********************************************************************
367 * FtpSetCurrentDirectoryW (WININET.@)
369 * Change the working directory on the FTP server
371 * RETURNS
372 * TRUE on success
373 * FALSE on failure
376 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
378 LPWININETFTPSESSIONW lpwfs = NULL;
379 LPWININETAPPINFOW hIC = NULL;
380 BOOL r = FALSE;
382 if (!lpszDirectory)
384 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
385 goto lend;
388 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
389 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
391 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
392 goto lend;
395 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
397 hIC = lpwfs->lpAppInfo;
398 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
400 WORKREQUEST workRequest;
401 struct WORKREQ_FTPSETCURRENTDIRECTORYW *req;
403 workRequest.asyncproc = AsyncFtpSetCurrentDirectoryProc;
404 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
405 req = &workRequest.u.FtpSetCurrentDirectoryW;
406 req->lpszDirectory = WININET_strdupW(lpszDirectory);
408 r = INTERNET_AsyncCall(&workRequest);
410 else
412 r = FTP_FtpSetCurrentDirectoryW(lpwfs, lpszDirectory);
415 lend:
416 if( lpwfs )
417 WININET_Release( &lpwfs->hdr );
419 return r;
423 /***********************************************************************
424 * FTP_FtpSetCurrentDirectoryW (Internal)
426 * Change the working directory on the FTP server
428 * RETURNS
429 * TRUE on success
430 * FALSE on failure
433 BOOL WINAPI FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
435 INT nResCode;
436 LPWININETAPPINFOW hIC = NULL;
437 DWORD bSuccess = FALSE;
439 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
441 /* Clear any error information */
442 INTERNET_SetLastError(0);
444 hIC = lpwfs->lpAppInfo;
445 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
446 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
447 goto lend;
449 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
451 if (nResCode)
453 if (nResCode == 250)
454 bSuccess = TRUE;
455 else
456 FTP_SetResponseError(nResCode);
459 lend:
460 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
462 INTERNET_ASYNC_RESULT iar;
464 iar.dwResult = (DWORD)bSuccess;
465 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
466 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
467 &iar, sizeof(INTERNET_ASYNC_RESULT));
469 return bSuccess;
473 /***********************************************************************
474 * FtpCreateDirectoryA (WININET.@)
476 * Create new directory on the FTP server
478 * RETURNS
479 * TRUE on success
480 * FALSE on failure
483 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
485 LPWSTR lpwzDirectory;
486 BOOL ret;
488 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
489 ret = FtpCreateDirectoryW(hConnect, lpwzDirectory);
490 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
491 return ret;
495 static void AsyncFtpCreateDirectoryProc(WORKREQUEST *workRequest)
497 struct WORKREQ_FTPCREATEDIRECTORYW const *req = &workRequest->u.FtpCreateDirectoryW;
498 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
500 TRACE(" %p\n", lpwfs);
502 FTP_FtpCreateDirectoryW(lpwfs, req->lpszDirectory);
503 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
506 /***********************************************************************
507 * FtpCreateDirectoryW (WININET.@)
509 * Create new directory on the FTP server
511 * RETURNS
512 * TRUE on success
513 * FALSE on failure
516 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
518 LPWININETFTPSESSIONW lpwfs;
519 LPWININETAPPINFOW hIC = NULL;
520 BOOL r = FALSE;
522 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
523 if (!lpwfs)
525 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
526 return FALSE;
529 if (WH_HFTPSESSION != lpwfs->hdr.htype)
531 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
532 goto lend;
535 if (!lpszDirectory)
537 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
538 goto lend;
541 hIC = lpwfs->lpAppInfo;
542 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
544 WORKREQUEST workRequest;
545 struct WORKREQ_FTPCREATEDIRECTORYW *req;
547 workRequest.asyncproc = AsyncFtpCreateDirectoryProc;
548 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
549 req = &workRequest.u.FtpCreateDirectoryW;
550 req->lpszDirectory = WININET_strdupW(lpszDirectory);
552 r = INTERNET_AsyncCall(&workRequest);
554 else
556 r = FTP_FtpCreateDirectoryW(lpwfs, lpszDirectory);
558 lend:
559 WININET_Release( &lpwfs->hdr );
561 return r;
565 /***********************************************************************
566 * FTP_FtpCreateDirectoryW (Internal)
568 * Create new directory on the FTP server
570 * RETURNS
571 * TRUE on success
572 * FALSE on failure
575 BOOL WINAPI FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
577 INT nResCode;
578 BOOL bSuccess = FALSE;
579 LPWININETAPPINFOW hIC = NULL;
581 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
583 /* Clear any error information */
584 INTERNET_SetLastError(0);
586 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
587 goto lend;
589 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
590 if (nResCode)
592 if (nResCode == 257)
593 bSuccess = TRUE;
594 else
595 FTP_SetResponseError(nResCode);
598 lend:
599 hIC = lpwfs->lpAppInfo;
600 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
602 INTERNET_ASYNC_RESULT iar;
604 iar.dwResult = (DWORD)bSuccess;
605 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
606 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
607 &iar, sizeof(INTERNET_ASYNC_RESULT));
610 return bSuccess;
613 /***********************************************************************
614 * FtpFindFirstFileA (WININET.@)
616 * Search the specified directory
618 * RETURNS
619 * HINTERNET on success
620 * NULL on failure
623 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
624 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext)
626 LPWSTR lpwzSearchFile;
627 WIN32_FIND_DATAW wfd;
628 LPWIN32_FIND_DATAW lpFindFileDataW;
629 HINTERNET ret;
631 lpwzSearchFile = lpszSearchFile?WININET_strdup_AtoW(lpszSearchFile):NULL;
632 lpFindFileDataW = lpFindFileData?&wfd:NULL;
633 ret = FtpFindFirstFileW(hConnect, lpwzSearchFile, lpFindFileDataW, dwFlags, dwContext);
634 HeapFree(GetProcessHeap(), 0, lpwzSearchFile);
636 if(lpFindFileData) {
637 WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData);
639 return ret;
643 static void AsyncFtpFindFirstFileProc(WORKREQUEST *workRequest)
645 struct WORKREQ_FTPFINDFIRSTFILEW const *req = &workRequest->u.FtpFindFirstFileW;
646 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
648 TRACE("%p\n", lpwfs);
650 FTP_FtpFindFirstFileW(lpwfs, req->lpszSearchFile,
651 req->lpFindFileData, req->dwFlags, req->dwContext);
652 HeapFree(GetProcessHeap(), 0, req->lpszSearchFile);
655 /***********************************************************************
656 * FtpFindFirstFileW (WININET.@)
658 * Search the specified directory
660 * RETURNS
661 * HINTERNET on success
662 * NULL on failure
665 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
666 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext)
668 LPWININETFTPSESSIONW lpwfs;
669 LPWININETAPPINFOW hIC = NULL;
670 HINTERNET r = NULL;
672 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
673 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
675 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
676 goto lend;
679 hIC = lpwfs->lpAppInfo;
680 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
682 WORKREQUEST workRequest;
683 struct WORKREQ_FTPFINDFIRSTFILEW *req;
685 workRequest.asyncproc = AsyncFtpFindFirstFileProc;
686 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
687 req = &workRequest.u.FtpFindFirstFileW;
688 req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : WININET_strdupW(lpszSearchFile);
689 req->lpFindFileData = lpFindFileData;
690 req->dwFlags = dwFlags;
691 req->dwContext= dwContext;
693 INTERNET_AsyncCall(&workRequest);
694 r = NULL;
696 else
698 r = FTP_FtpFindFirstFileW(lpwfs, lpszSearchFile, lpFindFileData,
699 dwFlags, dwContext);
701 lend:
702 if( lpwfs )
703 WININET_Release( &lpwfs->hdr );
705 return r;
709 /***********************************************************************
710 * FTP_FtpFindFirstFileW (Internal)
712 * Search the specified directory
714 * RETURNS
715 * HINTERNET on success
716 * NULL on failure
719 HINTERNET WINAPI FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs,
720 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext)
722 INT nResCode;
723 LPWININETAPPINFOW hIC = NULL;
724 HINTERNET hFindNext = NULL;
726 TRACE("\n");
728 /* Clear any error information */
729 INTERNET_SetLastError(0);
731 if (!FTP_InitListenSocket(lpwfs))
732 goto lend;
734 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
735 goto lend;
737 if (!FTP_SendPortOrPasv(lpwfs))
738 goto lend;
740 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, NULL,
741 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
742 goto lend;
744 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
745 if (nResCode)
747 if (nResCode == 125 || nResCode == 150)
749 INT nDataSocket;
751 /* Get data socket to server */
752 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
754 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpszSearchFile, lpFindFileData, dwContext);
755 closesocket(nDataSocket);
756 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
757 if (nResCode != 226 && nResCode != 250)
758 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
761 else
762 FTP_SetResponseError(nResCode);
765 lend:
766 if (lpwfs->lstnSocket != -1)
767 closesocket(lpwfs->lstnSocket);
769 hIC = lpwfs->lpAppInfo;
770 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
772 INTERNET_ASYNC_RESULT iar;
774 if (hFindNext)
776 iar.dwResult = (DWORD)hFindNext;
777 iar.dwError = ERROR_SUCCESS;
778 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
779 &iar, sizeof(INTERNET_ASYNC_RESULT));
782 iar.dwResult = (DWORD)hFindNext;
783 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
784 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
785 &iar, sizeof(INTERNET_ASYNC_RESULT));
788 return hFindNext;
792 /***********************************************************************
793 * FtpGetCurrentDirectoryA (WININET.@)
795 * Retrieves the current directory
797 * RETURNS
798 * TRUE on success
799 * FALSE on failure
802 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
803 LPDWORD lpdwCurrentDirectory)
805 WCHAR *dir = NULL;
806 DWORD len;
807 BOOL ret;
809 if(lpdwCurrentDirectory) {
810 len = *lpdwCurrentDirectory;
811 if(lpszCurrentDirectory)
813 dir = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
814 if (NULL == dir)
816 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
817 return FALSE;
821 ret = FtpGetCurrentDirectoryW(hFtpSession, lpszCurrentDirectory?dir:NULL, lpdwCurrentDirectory?&len:NULL);
822 if(lpdwCurrentDirectory) {
823 *lpdwCurrentDirectory = len;
824 if(lpszCurrentDirectory) {
825 WideCharToMultiByte(CP_ACP, 0, dir, len, lpszCurrentDirectory, *lpdwCurrentDirectory, NULL, NULL);
826 HeapFree(GetProcessHeap(), 0, dir);
829 return ret;
833 static void AsyncFtpGetCurrentDirectoryProc(WORKREQUEST *workRequest)
835 struct WORKREQ_FTPGETCURRENTDIRECTORYW const *req = &workRequest->u.FtpGetCurrentDirectoryW;
836 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
838 TRACE("%p\n", lpwfs);
840 FTP_FtpGetCurrentDirectoryW(lpwfs, req->lpszDirectory, req->lpdwDirectory);
843 /***********************************************************************
844 * FtpGetCurrentDirectoryW (WININET.@)
846 * Retrieves the current directory
848 * RETURNS
849 * TRUE on success
850 * FALSE on failure
853 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
854 LPDWORD lpdwCurrentDirectory)
856 LPWININETFTPSESSIONW lpwfs;
857 LPWININETAPPINFOW hIC = NULL;
858 BOOL r = FALSE;
860 TRACE("len(%d)\n", *lpdwCurrentDirectory);
862 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
863 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
865 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
866 goto lend;
869 hIC = lpwfs->lpAppInfo;
870 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
872 WORKREQUEST workRequest;
873 struct WORKREQ_FTPGETCURRENTDIRECTORYW *req;
875 workRequest.asyncproc = AsyncFtpGetCurrentDirectoryProc;
876 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
877 req = &workRequest.u.FtpGetCurrentDirectoryW;
878 req->lpszDirectory = lpszCurrentDirectory;
879 req->lpdwDirectory = lpdwCurrentDirectory;
881 r = INTERNET_AsyncCall(&workRequest);
883 else
885 r = FTP_FtpGetCurrentDirectoryW(lpwfs, lpszCurrentDirectory,
886 lpdwCurrentDirectory);
889 lend:
890 if( lpwfs )
891 WININET_Release( &lpwfs->hdr );
893 return r;
897 /***********************************************************************
898 * FTP_FtpGetCurrentDirectoryW (Internal)
900 * Retrieves the current directory
902 * RETURNS
903 * TRUE on success
904 * FALSE on failure
907 BOOL WINAPI FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszCurrentDirectory,
908 LPDWORD lpdwCurrentDirectory)
910 INT nResCode;
911 LPWININETAPPINFOW hIC = NULL;
912 DWORD bSuccess = FALSE;
914 TRACE("len(%d)\n", *lpdwCurrentDirectory);
916 /* Clear any error information */
917 INTERNET_SetLastError(0);
919 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
921 hIC = lpwfs->lpAppInfo;
922 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
923 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
924 goto lend;
926 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
927 if (nResCode)
929 if (nResCode == 257) /* Extract directory name */
931 DWORD firstpos, lastpos, len;
932 LPWSTR lpszResponseBuffer = WININET_strdup_AtoW(INTERNET_GetResponseBuffer());
934 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
936 if ('"' == lpszResponseBuffer[lastpos])
938 if (!firstpos)
939 firstpos = lastpos;
940 else
941 break;
945 len = lastpos - firstpos - 1;
946 lstrcpynW(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1], *lpdwCurrentDirectory);
947 HeapFree(GetProcessHeap(), 0, lpszResponseBuffer);
948 *lpdwCurrentDirectory = len;
949 bSuccess = TRUE;
951 else
952 FTP_SetResponseError(nResCode);
955 lend:
956 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
958 INTERNET_ASYNC_RESULT iar;
960 iar.dwResult = (DWORD)bSuccess;
961 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
962 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
963 &iar, sizeof(INTERNET_ASYNC_RESULT));
966 return (DWORD) bSuccess;
969 /***********************************************************************
970 * FtpOpenFileA (WININET.@)
972 * Open a remote file for writing or reading
974 * RETURNS
975 * HINTERNET handle on success
976 * NULL on failure
979 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
980 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
981 DWORD_PTR dwContext)
983 LPWSTR lpwzFileName;
984 HINTERNET ret;
986 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
987 ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext);
988 HeapFree(GetProcessHeap(), 0, lpwzFileName);
989 return ret;
993 static void AsyncFtpOpenFileProc(WORKREQUEST *workRequest)
995 struct WORKREQ_FTPOPENFILEW const *req = &workRequest->u.FtpOpenFileW;
996 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
998 TRACE("%p\n", lpwfs);
1000 FTP_FtpOpenFileW(lpwfs, req->lpszFilename,
1001 req->dwAccess, req->dwFlags, req->dwContext);
1002 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1005 /***********************************************************************
1006 * FtpOpenFileW (WININET.@)
1008 * Open a remote file for writing or reading
1010 * RETURNS
1011 * HINTERNET handle on success
1012 * NULL on failure
1015 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
1016 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1017 DWORD_PTR dwContext)
1019 LPWININETFTPSESSIONW lpwfs;
1020 LPWININETAPPINFOW hIC = NULL;
1021 HINTERNET r = NULL;
1023 TRACE("(%p,%s,0x%08x,0x%08x,0x%08lx)\n", hFtpSession,
1024 debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext);
1026 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1027 if (!lpwfs)
1029 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1030 return FALSE;
1033 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1035 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1036 goto lend;
1039 if ((!lpszFileName) ||
1040 ((fdwAccess != GENERIC_READ) && (fdwAccess != GENERIC_WRITE)) ||
1041 ((dwFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY))
1043 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1044 goto lend;
1047 if (lpwfs->download_in_progress != NULL) {
1048 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1049 goto lend;
1051 hIC = lpwfs->lpAppInfo;
1052 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1054 WORKREQUEST workRequest;
1055 struct WORKREQ_FTPOPENFILEW *req;
1057 workRequest.asyncproc = AsyncFtpOpenFileProc;
1058 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1059 req = &workRequest.u.FtpOpenFileW;
1060 req->lpszFilename = WININET_strdupW(lpszFileName);
1061 req->dwAccess = fdwAccess;
1062 req->dwFlags = dwFlags;
1063 req->dwContext = dwContext;
1065 INTERNET_AsyncCall(&workRequest);
1066 r = NULL;
1068 else
1070 r = FTP_FtpOpenFileW(lpwfs, lpszFileName, fdwAccess, dwFlags, dwContext);
1073 lend:
1074 WININET_Release( &lpwfs->hdr );
1076 return r;
1080 /***********************************************************************
1081 * FTP_FtpOpenFileW (Internal)
1083 * Open a remote file for writing or reading
1085 * RETURNS
1086 * HINTERNET handle on success
1087 * NULL on failure
1090 HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs,
1091 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1092 DWORD_PTR dwContext)
1094 INT nDataSocket;
1095 BOOL bSuccess = FALSE;
1096 LPWININETFTPFILE lpwh = NULL;
1097 LPWININETAPPINFOW hIC = NULL;
1098 HINTERNET handle = NULL;
1100 TRACE("\n");
1102 /* Clear any error information */
1103 INTERNET_SetLastError(0);
1105 if (GENERIC_READ == fdwAccess)
1107 /* Set up socket to retrieve data */
1108 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
1110 else if (GENERIC_WRITE == fdwAccess)
1112 /* Set up socket to send data */
1113 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
1116 /* Get data socket to server */
1117 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
1119 lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPFILE));
1120 lpwh->hdr.htype = WH_HFILE;
1121 lpwh->hdr.dwFlags = dwFlags;
1122 lpwh->hdr.dwContext = dwContext;
1123 lpwh->hdr.dwRefCount = 1;
1124 lpwh->hdr.close_connection = NULL;
1125 lpwh->hdr.destroy = FTP_CloseFileTransferHandle;
1126 lpwh->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
1127 lpwh->nDataSocket = nDataSocket;
1128 lpwh->session_deleted = FALSE;
1130 WININET_AddRef( &lpwfs->hdr );
1131 lpwh->lpFtpSession = lpwfs;
1132 list_add_head( &lpwfs->hdr.children, &lpwh->hdr.entry );
1134 handle = WININET_AllocHandle( &lpwh->hdr );
1135 if( !handle )
1136 goto lend;
1138 /* Indicate that a download is currently in progress */
1139 lpwfs->download_in_progress = lpwh;
1142 if (lpwfs->lstnSocket != -1)
1143 closesocket(lpwfs->lstnSocket);
1145 hIC = lpwfs->lpAppInfo;
1146 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1148 INTERNET_ASYNC_RESULT iar;
1150 if (lpwh)
1152 iar.dwResult = (DWORD)handle;
1153 iar.dwError = ERROR_SUCCESS;
1154 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
1155 &iar, sizeof(INTERNET_ASYNC_RESULT));
1158 iar.dwResult = (DWORD)bSuccess;
1159 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1160 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1161 &iar, sizeof(INTERNET_ASYNC_RESULT));
1164 lend:
1165 if( lpwh )
1166 WININET_Release( &lpwh->hdr );
1168 return handle;
1172 /***********************************************************************
1173 * FtpGetFileA (WININET.@)
1175 * Retrieve file from the FTP server
1177 * RETURNS
1178 * TRUE on success
1179 * FALSE on failure
1182 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1183 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1184 DWORD_PTR dwContext)
1186 LPWSTR lpwzRemoteFile;
1187 LPWSTR lpwzNewFile;
1188 BOOL ret;
1190 lpwzRemoteFile = lpszRemoteFile?WININET_strdup_AtoW(lpszRemoteFile):NULL;
1191 lpwzNewFile = lpszNewFile?WININET_strdup_AtoW(lpszNewFile):NULL;
1192 ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists,
1193 dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1194 HeapFree(GetProcessHeap(), 0, lpwzRemoteFile);
1195 HeapFree(GetProcessHeap(), 0, lpwzNewFile);
1196 return ret;
1200 static void AsyncFtpGetFileProc(WORKREQUEST *workRequest)
1202 struct WORKREQ_FTPGETFILEW const *req = &workRequest->u.FtpGetFileW;
1203 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1205 TRACE("%p\n", lpwfs);
1207 FTP_FtpGetFileW(lpwfs, req->lpszRemoteFile,
1208 req->lpszNewFile, req->fFailIfExists,
1209 req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext);
1210 HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile);
1211 HeapFree(GetProcessHeap(), 0, req->lpszNewFile);
1215 /***********************************************************************
1216 * FtpGetFileW (WININET.@)
1218 * Retrieve file from the FTP server
1220 * RETURNS
1221 * TRUE on success
1222 * FALSE on failure
1225 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1226 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1227 DWORD_PTR dwContext)
1229 LPWININETFTPSESSIONW lpwfs;
1230 LPWININETAPPINFOW hIC = NULL;
1231 BOOL r = FALSE;
1233 if (!lpszRemoteFile || !lpszNewFile)
1235 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1236 return FALSE;
1239 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet );
1240 if (!lpwfs)
1242 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1243 return FALSE;
1246 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1248 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1249 goto lend;
1252 if ((dwInternetFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY)
1254 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1255 goto lend;
1258 if (lpwfs->download_in_progress != NULL) {
1259 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1260 goto lend;
1263 hIC = lpwfs->lpAppInfo;
1264 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1266 WORKREQUEST workRequest;
1267 struct WORKREQ_FTPGETFILEW *req;
1269 workRequest.asyncproc = AsyncFtpGetFileProc;
1270 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1271 req = &workRequest.u.FtpGetFileW;
1272 req->lpszRemoteFile = WININET_strdupW(lpszRemoteFile);
1273 req->lpszNewFile = WININET_strdupW(lpszNewFile);
1274 req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1275 req->fFailIfExists = fFailIfExists;
1276 req->dwFlags = dwInternetFlags;
1277 req->dwContext = dwContext;
1279 r = INTERNET_AsyncCall(&workRequest);
1281 else
1283 r = FTP_FtpGetFileW(lpwfs, lpszRemoteFile, lpszNewFile,
1284 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1287 lend:
1288 WININET_Release( &lpwfs->hdr );
1290 return r;
1294 /***********************************************************************
1295 * FTP_FtpGetFileW (Internal)
1297 * Retrieve file from the FTP server
1299 * RETURNS
1300 * TRUE on success
1301 * FALSE on failure
1304 BOOL WINAPI FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1305 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1306 DWORD_PTR dwContext)
1308 BOOL bSuccess = FALSE;
1309 HANDLE hFile;
1310 LPWININETAPPINFOW hIC = NULL;
1312 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile));
1314 /* Clear any error information */
1315 INTERNET_SetLastError(0);
1317 /* Ensure we can write to lpszNewfile by opening it */
1318 hFile = CreateFileW(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1319 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1320 if (INVALID_HANDLE_VALUE == hFile)
1321 return FALSE;
1323 /* Set up socket to retrieve data */
1324 if (FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags))
1326 INT nDataSocket;
1328 /* Get data socket to server */
1329 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1331 INT nResCode;
1333 /* Receive data */
1334 FTP_RetrieveFileData(lpwfs, nDataSocket, hFile);
1335 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
1336 if (nResCode)
1338 if (nResCode == 226)
1339 bSuccess = TRUE;
1340 else
1341 FTP_SetResponseError(nResCode);
1343 closesocket(nDataSocket);
1347 if (lpwfs->lstnSocket != -1)
1348 closesocket(lpwfs->lstnSocket);
1350 CloseHandle(hFile);
1352 hIC = lpwfs->lpAppInfo;
1353 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1355 INTERNET_ASYNC_RESULT iar;
1357 iar.dwResult = (DWORD)bSuccess;
1358 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1359 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1360 &iar, sizeof(INTERNET_ASYNC_RESULT));
1363 return bSuccess;
1366 /***********************************************************************
1367 * FtpGetFileSize (WININET.@)
1369 DWORD WINAPI FtpGetFileSize( HINTERNET hFile, LPDWORD lpdwFileSizeHigh )
1371 FIXME("(%p, %p)\n", hFile, lpdwFileSizeHigh);
1373 if (lpdwFileSizeHigh)
1374 *lpdwFileSizeHigh = 0;
1376 return 0;
1379 /***********************************************************************
1380 * FtpDeleteFileA (WININET.@)
1382 * Delete a file on the ftp server
1384 * RETURNS
1385 * TRUE on success
1386 * FALSE on failure
1389 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1391 LPWSTR lpwzFileName;
1392 BOOL ret;
1394 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1395 ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1396 HeapFree(GetProcessHeap(), 0, lpwzFileName);
1397 return ret;
1400 static void AsyncFtpDeleteFileProc(WORKREQUEST *workRequest)
1402 struct WORKREQ_FTPDELETEFILEW const *req = &workRequest->u.FtpDeleteFileW;
1403 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1405 TRACE("%p\n", lpwfs);
1407 FTP_FtpDeleteFileW(lpwfs, req->lpszFilename);
1408 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1411 /***********************************************************************
1412 * FtpDeleteFileW (WININET.@)
1414 * Delete a file on the ftp server
1416 * RETURNS
1417 * TRUE on success
1418 * FALSE on failure
1421 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1423 LPWININETFTPSESSIONW lpwfs;
1424 LPWININETAPPINFOW hIC = NULL;
1425 BOOL r = FALSE;
1427 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1428 if (!lpwfs)
1430 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1431 return FALSE;
1434 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1436 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1437 goto lend;
1440 if (!lpszFileName)
1442 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1443 goto lend;
1446 hIC = lpwfs->lpAppInfo;
1447 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1449 WORKREQUEST workRequest;
1450 struct WORKREQ_FTPDELETEFILEW *req;
1452 workRequest.asyncproc = AsyncFtpDeleteFileProc;
1453 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1454 req = &workRequest.u.FtpDeleteFileW;
1455 req->lpszFilename = WININET_strdupW(lpszFileName);
1457 r = INTERNET_AsyncCall(&workRequest);
1459 else
1461 r = FTP_FtpDeleteFileW(lpwfs, lpszFileName);
1464 lend:
1465 WININET_Release( &lpwfs->hdr );
1467 return r;
1470 /***********************************************************************
1471 * FTP_FtpDeleteFileW (Internal)
1473 * Delete a file on the ftp server
1475 * RETURNS
1476 * TRUE on success
1477 * FALSE on failure
1480 BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName)
1482 INT nResCode;
1483 BOOL bSuccess = FALSE;
1484 LPWININETAPPINFOW hIC = NULL;
1486 TRACE("%p\n", lpwfs);
1488 /* Clear any error information */
1489 INTERNET_SetLastError(0);
1491 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1492 goto lend;
1494 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1495 if (nResCode)
1497 if (nResCode == 250)
1498 bSuccess = TRUE;
1499 else
1500 FTP_SetResponseError(nResCode);
1502 lend:
1503 hIC = lpwfs->lpAppInfo;
1504 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1506 INTERNET_ASYNC_RESULT iar;
1508 iar.dwResult = (DWORD)bSuccess;
1509 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1510 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1511 &iar, sizeof(INTERNET_ASYNC_RESULT));
1514 return bSuccess;
1518 /***********************************************************************
1519 * FtpRemoveDirectoryA (WININET.@)
1521 * Remove a directory on the ftp server
1523 * RETURNS
1524 * TRUE on success
1525 * FALSE on failure
1528 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1530 LPWSTR lpwzDirectory;
1531 BOOL ret;
1533 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
1534 ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1535 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
1536 return ret;
1539 static void AsyncFtpRemoveDirectoryProc(WORKREQUEST *workRequest)
1541 struct WORKREQ_FTPREMOVEDIRECTORYW const *req = &workRequest->u.FtpRemoveDirectoryW;
1542 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1544 TRACE("%p\n", lpwfs);
1546 FTP_FtpRemoveDirectoryW(lpwfs, req->lpszDirectory);
1547 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
1550 /***********************************************************************
1551 * FtpRemoveDirectoryW (WININET.@)
1553 * Remove a directory on the ftp server
1555 * RETURNS
1556 * TRUE on success
1557 * FALSE on failure
1560 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1562 LPWININETFTPSESSIONW lpwfs;
1563 LPWININETAPPINFOW hIC = NULL;
1564 BOOL r = FALSE;
1566 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1567 if (!lpwfs)
1569 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1570 return FALSE;
1573 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1575 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1576 goto lend;
1579 if (!lpszDirectory)
1581 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1582 goto lend;
1585 hIC = lpwfs->lpAppInfo;
1586 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1588 WORKREQUEST workRequest;
1589 struct WORKREQ_FTPREMOVEDIRECTORYW *req;
1591 workRequest.asyncproc = AsyncFtpRemoveDirectoryProc;
1592 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1593 req = &workRequest.u.FtpRemoveDirectoryW;
1594 req->lpszDirectory = WININET_strdupW(lpszDirectory);
1596 r = INTERNET_AsyncCall(&workRequest);
1598 else
1600 r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory);
1603 lend:
1604 WININET_Release( &lpwfs->hdr );
1606 return r;
1609 /***********************************************************************
1610 * FTP_FtpRemoveDirectoryW (Internal)
1612 * Remove a directory on the ftp server
1614 * RETURNS
1615 * TRUE on success
1616 * FALSE on failure
1619 BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
1621 INT nResCode;
1622 BOOL bSuccess = FALSE;
1623 LPWININETAPPINFOW hIC = NULL;
1625 TRACE("\n");
1627 /* Clear any error information */
1628 INTERNET_SetLastError(0);
1630 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1631 goto lend;
1633 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1634 if (nResCode)
1636 if (nResCode == 250)
1637 bSuccess = TRUE;
1638 else
1639 FTP_SetResponseError(nResCode);
1642 lend:
1643 hIC = lpwfs->lpAppInfo;
1644 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1646 INTERNET_ASYNC_RESULT iar;
1648 iar.dwResult = (DWORD)bSuccess;
1649 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1650 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1651 &iar, sizeof(INTERNET_ASYNC_RESULT));
1654 return bSuccess;
1658 /***********************************************************************
1659 * FtpRenameFileA (WININET.@)
1661 * Rename a file on the ftp server
1663 * RETURNS
1664 * TRUE on success
1665 * FALSE on failure
1668 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1670 LPWSTR lpwzSrc;
1671 LPWSTR lpwzDest;
1672 BOOL ret;
1674 lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL;
1675 lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL;
1676 ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
1677 HeapFree(GetProcessHeap(), 0, lpwzSrc);
1678 HeapFree(GetProcessHeap(), 0, lpwzDest);
1679 return ret;
1682 static void AsyncFtpRenameFileProc(WORKREQUEST *workRequest)
1684 struct WORKREQ_FTPRENAMEFILEW const *req = &workRequest->u.FtpRenameFileW;
1685 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1687 TRACE("%p\n", lpwfs);
1689 FTP_FtpRenameFileW(lpwfs, req->lpszSrcFile, req->lpszDestFile);
1690 HeapFree(GetProcessHeap(), 0, req->lpszSrcFile);
1691 HeapFree(GetProcessHeap(), 0, req->lpszDestFile);
1694 /***********************************************************************
1695 * FtpRenameFileW (WININET.@)
1697 * Rename a file on the ftp server
1699 * RETURNS
1700 * TRUE on success
1701 * FALSE on failure
1704 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
1706 LPWININETFTPSESSIONW lpwfs;
1707 LPWININETAPPINFOW hIC = NULL;
1708 BOOL r = FALSE;
1710 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1711 if (!lpwfs)
1713 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1714 return FALSE;
1717 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1719 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1720 goto lend;
1723 if (!lpszSrc || !lpszDest)
1725 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1726 goto lend;
1729 hIC = lpwfs->lpAppInfo;
1730 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1732 WORKREQUEST workRequest;
1733 struct WORKREQ_FTPRENAMEFILEW *req;
1735 workRequest.asyncproc = AsyncFtpRenameFileProc;
1736 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1737 req = &workRequest.u.FtpRenameFileW;
1738 req->lpszSrcFile = WININET_strdupW(lpszSrc);
1739 req->lpszDestFile = WININET_strdupW(lpszDest);
1741 r = INTERNET_AsyncCall(&workRequest);
1743 else
1745 r = FTP_FtpRenameFileW(lpwfs, lpszSrc, lpszDest);
1748 lend:
1749 WININET_Release( &lpwfs->hdr );
1751 return r;
1754 /***********************************************************************
1755 * FTP_FtpRenameFileW (Internal)
1757 * Rename a file on the ftp server
1759 * RETURNS
1760 * TRUE on success
1761 * FALSE on failure
1764 BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs,
1765 LPCWSTR lpszSrc, LPCWSTR lpszDest)
1767 INT nResCode;
1768 BOOL bSuccess = FALSE;
1769 LPWININETAPPINFOW hIC = NULL;
1771 TRACE("\n");
1773 /* Clear any error information */
1774 INTERNET_SetLastError(0);
1776 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1777 goto lend;
1779 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1780 if (nResCode == 350)
1782 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1783 goto lend;
1785 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1788 if (nResCode == 250)
1789 bSuccess = TRUE;
1790 else
1791 FTP_SetResponseError(nResCode);
1793 lend:
1794 hIC = lpwfs->lpAppInfo;
1795 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1797 INTERNET_ASYNC_RESULT iar;
1799 iar.dwResult = (DWORD)bSuccess;
1800 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1801 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1802 &iar, sizeof(INTERNET_ASYNC_RESULT));
1805 return bSuccess;
1808 /***********************************************************************
1809 * FtpCommandA (WININET.@)
1811 BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1812 LPCSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1814 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1815 debugstr_a(lpszCommand), dwContext, phFtpCommand);
1817 return TRUE;
1820 /***********************************************************************
1821 * FtpCommandW (WININET.@)
1823 BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1824 LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1826 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1827 debugstr_w(lpszCommand), dwContext, phFtpCommand);
1829 return TRUE;
1832 /***********************************************************************
1833 * FTP_Connect (internal)
1835 * Connect to a ftp server
1837 * RETURNS
1838 * HINTERNET a session handle on success
1839 * NULL on failure
1841 * NOTES:
1843 * Windows uses 'anonymous' as the username, when given a NULL username
1844 * and a NULL password. The password is first looked up in:
1846 * HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\EmailName
1848 * If this entry is not present it uses the current username as the password.
1852 HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
1853 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1854 LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext,
1855 DWORD dwInternalFlags)
1857 static const WCHAR szKey[] = {'S','o','f','t','w','a','r','e','\\',
1858 'M','i','c','r','o','s','o','f','t','\\',
1859 'W','i','n','d','o','w','s','\\',
1860 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1861 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
1862 static const WCHAR szValue[] = {'E','m','a','i','l','N','a','m','e',0};
1863 static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'};
1864 static const WCHAR szEmpty[] = {'\0'};
1865 struct sockaddr_in socketAddr;
1866 INT nsocket = -1;
1867 UINT sock_namelen;
1868 BOOL bSuccess = FALSE;
1869 LPWININETFTPSESSIONW lpwfs = NULL;
1870 HINTERNET handle = NULL;
1872 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1873 hIC, debugstr_w(lpszServerName),
1874 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
1876 assert( hIC->hdr.htype == WH_HINIT );
1878 if (NULL == lpszUserName && NULL != lpszPassword)
1880 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1881 goto lerror;
1884 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
1885 if (NULL == lpwfs)
1887 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1888 goto lerror;
1891 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1892 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1894 lpwfs->hdr.htype = WH_HFTPSESSION;
1895 lpwfs->hdr.dwFlags = dwFlags;
1896 lpwfs->hdr.dwContext = dwContext;
1897 lpwfs->hdr.dwInternalFlags = dwInternalFlags;
1898 lpwfs->hdr.dwRefCount = 1;
1899 lpwfs->hdr.close_connection = FTP_CloseConnection;
1900 lpwfs->hdr.destroy = FTP_CloseSessionHandle;
1901 lpwfs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
1902 lpwfs->download_in_progress = NULL;
1904 WININET_AddRef( &hIC->hdr );
1905 lpwfs->lpAppInfo = hIC;
1906 list_add_head( &hIC->hdr.children, &lpwfs->hdr.entry );
1908 handle = WININET_AllocHandle( &lpwfs->hdr );
1909 if( !handle )
1911 ERR("Failed to alloc handle\n");
1912 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1913 goto lerror;
1916 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1917 if(strchrW(hIC->lpszProxy, ' '))
1918 FIXME("Several proxies not implemented.\n");
1919 if(hIC->lpszProxyBypass)
1920 FIXME("Proxy bypass is ignored.\n");
1922 if ( !lpszUserName) {
1923 HKEY key;
1924 WCHAR szPassword[MAX_PATH];
1925 DWORD len = sizeof(szPassword);
1927 lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
1929 RegOpenKeyW(HKEY_CURRENT_USER, szKey, &key);
1930 if (RegQueryValueExW(key, szValue, NULL, NULL, (LPBYTE)szPassword, &len)) {
1931 /* Nothing in the registry, get the username and use that as the password */
1932 if (!GetUserNameW(szPassword, &len)) {
1933 /* Should never get here, but use an empty password as failsafe */
1934 strcpyW(szPassword, szEmpty);
1937 RegCloseKey(key);
1939 TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword));
1940 lpwfs->lpszPassword = WININET_strdupW(szPassword);
1942 else {
1943 lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
1945 if (lpszPassword)
1946 lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
1947 else
1948 lpwfs->lpszPassword = WININET_strdupW(szEmpty);
1951 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1952 if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
1954 INTERNET_ASYNC_RESULT iar;
1956 iar.dwResult = (DWORD)handle;
1957 iar.dwError = ERROR_SUCCESS;
1959 SendAsyncCallback(&hIC->hdr, dwContext,
1960 INTERNET_STATUS_HANDLE_CREATED, &iar,
1961 sizeof(INTERNET_ASYNC_RESULT));
1964 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1965 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1967 if (!GetAddress(lpszServerName, nServerPort, &socketAddr))
1969 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1970 goto lerror;
1973 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1974 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1976 nsocket = socket(AF_INET,SOCK_STREAM,0);
1977 if (nsocket == -1)
1979 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1980 goto lerror;
1983 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1984 &socketAddr, sizeof(struct sockaddr_in));
1986 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1988 ERR("Unable to connect (%s)\n", strerror(errno));
1989 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1991 else
1993 TRACE("Connected to server\n");
1994 lpwfs->sndSocket = nsocket;
1995 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1996 &socketAddr, sizeof(struct sockaddr_in));
1998 sock_namelen = sizeof(lpwfs->socketAddress);
1999 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
2001 if (FTP_ConnectToHost(lpwfs))
2003 TRACE("Successfully logged into server\n");
2004 bSuccess = TRUE;
2008 lerror:
2009 if (lpwfs) WININET_Release( &lpwfs->hdr );
2011 if (!bSuccess && handle)
2013 WININET_Release( &hIC->hdr );
2014 WININET_FreeHandle( handle );
2015 handle = NULL;
2018 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2020 INTERNET_ASYNC_RESULT iar;
2022 iar.dwResult = bSuccess ? (DWORD_PTR)lpwfs : 0;
2023 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
2024 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
2025 &iar, sizeof(INTERNET_ASYNC_RESULT));
2028 return handle;
2032 /***********************************************************************
2033 * FTP_ConnectToHost (internal)
2035 * Connect to a ftp server
2037 * RETURNS
2038 * TRUE on success
2039 * NULL on failure
2042 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
2044 INT nResCode;
2045 BOOL bSuccess = FALSE;
2047 TRACE("\n");
2048 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2050 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
2051 goto lend;
2053 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2054 if (nResCode)
2056 /* Login successful... */
2057 if (nResCode == 230)
2058 bSuccess = TRUE;
2059 /* User name okay, need password... */
2060 else if (nResCode == 331)
2061 bSuccess = FTP_SendPassword(lpwfs);
2062 /* Need account for login... */
2063 else if (nResCode == 332)
2064 bSuccess = FTP_SendAccount(lpwfs);
2065 else
2066 FTP_SetResponseError(nResCode);
2069 TRACE("Returning %d\n", bSuccess);
2070 lend:
2071 return bSuccess;
2075 /***********************************************************************
2076 * FTP_SendCommandA (internal)
2078 * Send command to server
2080 * RETURNS
2081 * TRUE on success
2082 * NULL on failure
2085 static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
2086 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext)
2088 DWORD len;
2089 CHAR *buf;
2090 DWORD nBytesSent = 0;
2091 int nRC = 0;
2092 DWORD dwParamLen;
2094 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
2096 if (lpfnStatusCB)
2098 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
2101 dwParamLen = lpszParam?strlen(lpszParam)+1:0;
2102 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
2103 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
2105 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2106 return FALSE;
2108 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
2109 dwParamLen ? lpszParam : "", szCRLF);
2111 TRACE("Sending (%s) len(%d)\n", buf, len);
2112 while((nBytesSent < len) && (nRC != -1))
2114 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
2115 nBytesSent += nRC;
2118 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
2120 if (lpfnStatusCB)
2122 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_REQUEST_SENT,
2123 &nBytesSent, sizeof(DWORD));
2126 TRACE("Sent %d bytes\n", nBytesSent);
2127 return (nRC != -1);
2130 /***********************************************************************
2131 * FTP_SendCommand (internal)
2133 * Send command to server
2135 * RETURNS
2136 * TRUE on success
2137 * NULL on failure
2140 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
2141 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext)
2143 BOOL ret;
2144 LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
2145 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
2146 HeapFree(GetProcessHeap(), 0, lpszParamA);
2147 return ret;
2150 /***********************************************************************
2151 * FTP_ReceiveResponse (internal)
2153 * Receive response from server
2155 * RETURNS
2156 * Reply code on success
2157 * 0 on failure
2160 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD_PTR dwContext)
2162 LPSTR lpszResponse = INTERNET_GetResponseBuffer();
2163 DWORD nRecv;
2164 INT rc = 0;
2165 char firstprefix[5];
2166 BOOL multiline = FALSE;
2167 LPWININETAPPINFOW hIC = NULL;
2169 TRACE("socket(%d)\n", lpwfs->sndSocket);
2171 hIC = lpwfs->lpAppInfo;
2172 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2174 while(1)
2176 if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
2177 goto lerror;
2179 if (nRecv >= 3)
2181 if(!multiline)
2183 if(lpszResponse[3] != '-')
2184 break;
2185 else
2186 { /* Start of multiline repsonse. Loop until we get "nnn " */
2187 multiline = TRUE;
2188 memcpy(firstprefix, lpszResponse, 3);
2189 firstprefix[3] = ' ';
2190 firstprefix[4] = '\0';
2193 else
2195 if(!memcmp(firstprefix, lpszResponse, 4))
2196 break;
2201 if (nRecv >= 3)
2203 rc = atoi(lpszResponse);
2205 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2206 &nRecv, sizeof(DWORD));
2209 lerror:
2210 TRACE("return %d\n", rc);
2211 return rc;
2215 /***********************************************************************
2216 * FTP_SendPassword (internal)
2218 * Send password to ftp server
2220 * RETURNS
2221 * TRUE on success
2222 * NULL on failure
2225 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
2227 INT nResCode;
2228 BOOL bSuccess = FALSE;
2230 TRACE("\n");
2231 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
2232 goto lend;
2234 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2235 if (nResCode)
2237 TRACE("Received reply code %d\n", nResCode);
2238 /* Login successful... */
2239 if (nResCode == 230)
2240 bSuccess = TRUE;
2241 /* Command not implemented, superfluous at the server site... */
2242 /* Need account for login... */
2243 else if (nResCode == 332)
2244 bSuccess = FTP_SendAccount(lpwfs);
2245 else
2246 FTP_SetResponseError(nResCode);
2249 lend:
2250 TRACE("Returning %d\n", bSuccess);
2251 return bSuccess;
2255 /***********************************************************************
2256 * FTP_SendAccount (internal)
2260 * RETURNS
2261 * TRUE on success
2262 * FALSE on failure
2265 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
2267 INT nResCode;
2268 BOOL bSuccess = FALSE;
2270 TRACE("\n");
2271 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
2272 goto lend;
2274 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2275 if (nResCode)
2276 bSuccess = TRUE;
2277 else
2278 FTP_SetResponseError(nResCode);
2280 lend:
2281 return bSuccess;
2285 /***********************************************************************
2286 * FTP_SendStore (internal)
2288 * Send request to upload file to ftp server
2290 * RETURNS
2291 * TRUE on success
2292 * FALSE on failure
2295 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2297 INT nResCode;
2298 BOOL bSuccess = FALSE;
2300 TRACE("\n");
2301 if (!FTP_InitListenSocket(lpwfs))
2302 goto lend;
2304 if (!FTP_SendType(lpwfs, dwType))
2305 goto lend;
2307 if (!FTP_SendPortOrPasv(lpwfs))
2308 goto lend;
2310 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2311 goto lend;
2312 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2313 if (nResCode)
2315 if (nResCode == 150 || nResCode == 125)
2316 bSuccess = TRUE;
2317 else
2318 FTP_SetResponseError(nResCode);
2321 lend:
2322 if (!bSuccess && lpwfs->lstnSocket != -1)
2324 closesocket(lpwfs->lstnSocket);
2325 lpwfs->lstnSocket = -1;
2328 return bSuccess;
2332 /***********************************************************************
2333 * FTP_InitListenSocket (internal)
2335 * Create a socket to listen for server response
2337 * RETURNS
2338 * TRUE on success
2339 * FALSE on failure
2342 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
2344 BOOL bSuccess = FALSE;
2345 socklen_t namelen = sizeof(struct sockaddr_in);
2347 TRACE("\n");
2349 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2350 if (lpwfs->lstnSocket == -1)
2352 TRACE("Unable to create listening socket\n");
2353 goto lend;
2356 /* We obtain our ip addr from the name of the command channel socket */
2357 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2359 /* and get the system to assign us a port */
2360 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
2362 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
2364 TRACE("Unable to bind socket\n");
2365 goto lend;
2368 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2370 TRACE("listen failed\n");
2371 goto lend;
2374 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2375 bSuccess = TRUE;
2377 lend:
2378 if (!bSuccess && lpwfs->lstnSocket != -1)
2380 closesocket(lpwfs->lstnSocket);
2381 lpwfs->lstnSocket = -1;
2384 return bSuccess;
2388 /***********************************************************************
2389 * FTP_SendType (internal)
2391 * Tell server type of data being transferred
2393 * RETURNS
2394 * TRUE on success
2395 * FALSE on failure
2397 * W98SE doesn't cache the type that's currently set
2398 * (i.e. it sends it always),
2399 * so we probably don't want to do that either.
2401 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
2403 INT nResCode;
2404 WCHAR type[] = { 'I','\0' };
2405 BOOL bSuccess = FALSE;
2407 TRACE("\n");
2408 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2409 type[0] = 'A';
2411 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2412 goto lend;
2414 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2415 if (nResCode)
2417 if (nResCode == 2)
2418 bSuccess = TRUE;
2419 else
2420 FTP_SetResponseError(nResCode);
2423 lend:
2424 return bSuccess;
2428 #if 0 /* FIXME: should probably be used for FtpGetFileSize */
2429 /***********************************************************************
2430 * FTP_GetFileSize (internal)
2432 * Retrieves from the server the size of the given file
2434 * RETURNS
2435 * TRUE on success
2436 * FALSE on failure
2439 static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
2441 INT nResCode;
2442 BOOL bSuccess = FALSE;
2444 TRACE("\n");
2446 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2447 goto lend;
2449 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2450 if (nResCode)
2452 if (nResCode == 213) {
2453 /* Now parses the output to get the actual file size */
2454 int i;
2455 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2457 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2458 if (lpszResponseBuffer[i] == '\0') return FALSE;
2459 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2461 bSuccess = TRUE;
2462 } else {
2463 FTP_SetResponseError(nResCode);
2467 lend:
2468 return bSuccess;
2470 #endif
2473 /***********************************************************************
2474 * FTP_SendPort (internal)
2476 * Tell server which port to use
2478 * RETURNS
2479 * TRUE on success
2480 * FALSE on failure
2483 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
2485 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2486 INT nResCode;
2487 WCHAR szIPAddress[64];
2488 BOOL bSuccess = FALSE;
2489 TRACE("\n");
2491 sprintfW(szIPAddress, szIPFormat,
2492 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2493 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2494 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2495 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2496 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2497 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2499 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2500 goto lend;
2502 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2503 if (nResCode)
2505 if (nResCode == 200)
2506 bSuccess = TRUE;
2507 else
2508 FTP_SetResponseError(nResCode);
2511 lend:
2512 return bSuccess;
2516 /***********************************************************************
2517 * FTP_DoPassive (internal)
2519 * Tell server that we want to do passive transfers
2520 * and connect data socket
2522 * RETURNS
2523 * TRUE on success
2524 * FALSE on failure
2527 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
2529 INT nResCode;
2530 BOOL bSuccess = FALSE;
2532 TRACE("\n");
2533 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2534 goto lend;
2536 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2537 if (nResCode)
2539 if (nResCode == 227)
2541 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2542 LPSTR p;
2543 int f[6];
2544 int i;
2545 char *pAddr, *pPort;
2546 INT nsocket = -1;
2547 struct sockaddr_in dataSocketAddress;
2549 p = lpszResponseBuffer+4; /* skip status code */
2550 while (*p != '\0' && (*p < '0' || *p > '9')) p++;
2552 if (*p == '\0')
2554 ERR("no address found in response, aborting\n");
2555 goto lend;
2558 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2559 &f[4], &f[5]) != 6)
2561 ERR("unknown response address format '%s', aborting\n", p);
2562 goto lend;
2564 for (i=0; i < 6; i++)
2565 f[i] = f[i] & 0xff;
2567 dataSocketAddress = lpwfs->socketAddress;
2568 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2569 pPort = (char *)&(dataSocketAddress.sin_port);
2570 pAddr[0] = f[0];
2571 pAddr[1] = f[1];
2572 pAddr[2] = f[2];
2573 pAddr[3] = f[3];
2574 pPort[0] = f[4];
2575 pPort[1] = f[5];
2577 nsocket = socket(AF_INET,SOCK_STREAM,0);
2578 if (nsocket == -1)
2579 goto lend;
2581 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2583 ERR("can't connect passive FTP data port.\n");
2584 closesocket(nsocket);
2585 goto lend;
2587 lpwfs->pasvSocket = nsocket;
2588 bSuccess = TRUE;
2590 else
2591 FTP_SetResponseError(nResCode);
2594 lend:
2595 return bSuccess;
2599 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
2601 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2603 if (!FTP_DoPassive(lpwfs))
2604 return FALSE;
2606 else
2608 if (!FTP_SendPort(lpwfs))
2609 return FALSE;
2611 return TRUE;
2615 /***********************************************************************
2616 * FTP_GetDataSocket (internal)
2618 * Either accepts an incoming data socket connection from the server
2619 * or just returns the already opened socket after a PASV command
2620 * in case of passive FTP.
2623 * RETURNS
2624 * TRUE on success
2625 * FALSE on failure
2628 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
2630 struct sockaddr_in saddr;
2631 socklen_t addrlen = sizeof(struct sockaddr);
2633 TRACE("\n");
2634 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2636 *nDataSocket = lpwfs->pasvSocket;
2638 else
2640 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2641 closesocket(lpwfs->lstnSocket);
2642 lpwfs->lstnSocket = -1;
2644 return *nDataSocket != -1;
2648 /***********************************************************************
2649 * FTP_SendData (internal)
2651 * Send data to the server
2653 * RETURNS
2654 * TRUE on success
2655 * FALSE on failure
2658 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2660 BY_HANDLE_FILE_INFORMATION fi;
2661 DWORD nBytesRead = 0;
2662 DWORD nBytesSent = 0;
2663 DWORD nTotalSent = 0;
2664 DWORD nBytesToSend, nLen;
2665 int nRC = 1;
2666 time_t s_long_time, e_long_time;
2667 LONG nSeconds;
2668 CHAR *lpszBuffer;
2670 TRACE("\n");
2671 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2673 /* Get the size of the file. */
2674 GetFileInformationByHandle(hFile, &fi);
2675 time(&s_long_time);
2679 nBytesToSend = nBytesRead - nBytesSent;
2681 if (nBytesToSend <= 0)
2683 /* Read data from file. */
2684 nBytesSent = 0;
2685 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2686 ERR("Failed reading from file\n");
2688 if (nBytesRead > 0)
2689 nBytesToSend = nBytesRead;
2690 else
2691 break;
2694 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2695 DATA_PACKET_SIZE : nBytesToSend;
2696 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2698 if (nRC != -1)
2700 nBytesSent += nRC;
2701 nTotalSent += nRC;
2704 /* Do some computation to display the status. */
2705 time(&e_long_time);
2706 nSeconds = e_long_time - s_long_time;
2707 if( nSeconds / 60 > 0 )
2709 TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n",
2710 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2711 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2713 else
2715 TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n",
2716 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2717 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2719 } while (nRC != -1);
2721 TRACE("file transfer complete!\n");
2723 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2725 return nTotalSent;
2729 /***********************************************************************
2730 * FTP_SendRetrieve (internal)
2732 * Send request to retrieve a file
2734 * RETURNS
2735 * Number of bytes to be received on success
2736 * 0 on failure
2739 static BOOL FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2741 INT nResCode;
2742 BOOL ret;
2744 TRACE("\n");
2745 if (!(ret = FTP_InitListenSocket(lpwfs)))
2746 goto lend;
2748 if (!(ret = FTP_SendType(lpwfs, dwType)))
2749 goto lend;
2751 if (!(ret = FTP_SendPortOrPasv(lpwfs)))
2752 goto lend;
2754 if (!(ret = FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0)))
2755 goto lend;
2757 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2758 if ((nResCode != 125) && (nResCode != 150)) {
2759 /* That means that we got an error getting the file. */
2760 FTP_SetResponseError(nResCode);
2761 ret = FALSE;
2764 lend:
2765 if (!ret && lpwfs->lstnSocket != -1)
2767 closesocket(lpwfs->lstnSocket);
2768 lpwfs->lstnSocket = -1;
2771 return ret;
2775 /***********************************************************************
2776 * FTP_RetrieveData (internal)
2778 * Retrieve data from server
2780 * RETURNS
2781 * TRUE on success
2782 * FALSE on failure
2785 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2787 DWORD nBytesWritten;
2788 DWORD nBytesReceived = 0;
2789 INT nRC = 0;
2790 CHAR *lpszBuffer;
2792 TRACE("\n");
2794 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2795 if (NULL == lpszBuffer)
2797 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2798 return FALSE;
2801 while (nRC != -1)
2803 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2804 if (nRC != -1)
2806 /* other side closed socket. */
2807 if (nRC == 0)
2808 goto recv_end;
2809 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2810 nBytesReceived += nRC;
2814 TRACE("Data transfer complete\n");
2816 recv_end:
2817 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2819 return (nRC != -1);
2822 /***********************************************************************
2823 * FTP_CloseConnection (internal)
2825 * Close connections
2827 static void FTP_CloseConnection(LPWININETHANDLEHEADER hdr)
2829 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2831 TRACE("\n");
2833 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext,
2834 INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
2836 if (lpwfs->download_in_progress != NULL)
2837 lpwfs->download_in_progress->session_deleted = TRUE;
2839 if (lpwfs->sndSocket != -1)
2840 closesocket(lpwfs->sndSocket);
2842 if (lpwfs->lstnSocket != -1)
2843 closesocket(lpwfs->lstnSocket);
2845 if (lpwfs->pasvSocket != -1)
2846 closesocket(lpwfs->pasvSocket);
2848 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext,
2849 INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
2853 /***********************************************************************
2854 * FTP_CloseSessionHandle (internal)
2856 * Deallocate session handle
2858 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr)
2860 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2862 TRACE("\n");
2864 WININET_Release(&lpwfs->lpAppInfo->hdr);
2866 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2867 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2868 HeapFree(GetProcessHeap(), 0, lpwfs);
2872 /***********************************************************************
2873 * FTP_FindNextFileW (Internal)
2875 * Continues a file search from a previous call to FindFirstFile
2877 * RETURNS
2878 * TRUE on success
2879 * FALSE on failure
2882 BOOL WINAPI FTP_FindNextFileW(LPWININETFTPFINDNEXTW lpwh, LPVOID lpvFindData)
2884 BOOL bSuccess = TRUE;
2885 LPWIN32_FIND_DATAW lpFindFileData;
2887 TRACE("index(%d) size(%d)\n", lpwh->index, lpwh->size);
2889 assert (lpwh->hdr.htype == WH_HFTPFINDNEXT);
2891 /* Clear any error information */
2892 INTERNET_SetLastError(0);
2894 lpFindFileData = (LPWIN32_FIND_DATAW) lpvFindData;
2895 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2897 if (lpwh->index >= lpwh->size)
2899 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2900 bSuccess = FALSE;
2901 goto lend;
2904 FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
2905 lpwh->index++;
2907 TRACE("\nName: %s\nSize: %d\n", debugstr_w(lpFindFileData->cFileName), lpFindFileData->nFileSizeLow);
2909 lend:
2911 if (lpwh->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2913 INTERNET_ASYNC_RESULT iar;
2915 iar.dwResult = (DWORD)bSuccess;
2916 iar.dwError = iar.dwError = bSuccess ? ERROR_SUCCESS :
2917 INTERNET_GetLastError();
2919 INTERNET_SendCallback(&lpwh->hdr, lpwh->hdr.dwContext,
2920 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
2921 sizeof(INTERNET_ASYNC_RESULT));
2924 return bSuccess;
2928 /***********************************************************************
2929 * FTP_CloseFindNextHandle (internal)
2931 * Deallocate session handle
2933 * RETURNS
2934 * TRUE on success
2935 * FALSE on failure
2938 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr)
2940 LPWININETFTPFINDNEXTW lpwfn = (LPWININETFTPFINDNEXTW) hdr;
2941 DWORD i;
2943 TRACE("\n");
2945 WININET_Release(&lpwfn->lpFtpSession->hdr);
2947 for (i = 0; i < lpwfn->size; i++)
2949 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2952 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2953 HeapFree(GetProcessHeap(), 0, lpwfn);
2956 /***********************************************************************
2957 * FTP_CloseFileTransferHandle (internal)
2959 * Closes the file transfer handle. This also 'cleans' the data queue of
2960 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2963 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr)
2965 LPWININETFTPFILE lpwh = (LPWININETFTPFILE) hdr;
2966 LPWININETFTPSESSIONW lpwfs = lpwh->lpFtpSession;
2967 INT nResCode;
2969 TRACE("\n");
2971 WININET_Release(&lpwh->lpFtpSession->hdr);
2973 if (!lpwh->session_deleted)
2974 lpwfs->download_in_progress = NULL;
2976 /* This just serves to flush the control socket of any spurrious lines written
2977 to it (like '226 Transfer complete.').
2979 Wonder what to do if the server sends us an error code though...
2981 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2983 if (lpwh->nDataSocket != -1)
2984 closesocket(lpwh->nDataSocket);
2986 HeapFree(GetProcessHeap(), 0, lpwh);
2989 /***********************************************************************
2990 * FTP_ReceiveFileList (internal)
2992 * Read file list from server
2994 * RETURNS
2995 * Handle to file list on success
2996 * NULL on failure
2999 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3000 LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext)
3002 DWORD dwSize = 0;
3003 LPFILEPROPERTIESW lpafp = NULL;
3004 LPWININETFTPFINDNEXTW lpwfn = NULL;
3005 HINTERNET handle = 0;
3007 TRACE("(%p,%d,%s,%p,%08lx)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
3009 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
3011 if(lpFindFileData)
3012 FTP_ConvertFileProp(lpafp, lpFindFileData);
3014 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFTPFINDNEXTW));
3015 if (lpwfn)
3017 lpwfn->hdr.htype = WH_HFTPFINDNEXT;
3018 lpwfn->hdr.dwContext = dwContext;
3019 lpwfn->hdr.dwRefCount = 1;
3020 lpwfn->hdr.close_connection = NULL;
3021 lpwfn->hdr.destroy = FTP_CloseFindNextHandle;
3022 lpwfn->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
3023 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
3024 lpwfn->size = dwSize;
3025 lpwfn->lpafp = lpafp;
3027 WININET_AddRef( &lpwfs->hdr );
3028 lpwfn->lpFtpSession = lpwfs;
3029 list_add_head( &lpwfs->hdr.children, &lpwfn->hdr.entry );
3031 handle = WININET_AllocHandle( &lpwfn->hdr );
3035 if( lpwfn )
3036 WININET_Release( &lpwfn->hdr );
3038 TRACE("Matched %d files\n", dwSize);
3039 return handle;
3043 /***********************************************************************
3044 * FTP_ConvertFileProp (internal)
3046 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
3048 * RETURNS
3049 * TRUE on success
3050 * FALSE on failure
3053 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
3055 BOOL bSuccess = FALSE;
3057 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
3059 if (lpafp)
3061 /* Convert 'Unix' time to Windows time */
3062 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
3063 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
3064 lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime;
3065 lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime;
3067 /* Not all fields are filled in */
3068 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
3069 lpFindFileData->nFileSizeLow = lpafp->nSize;
3071 if (lpafp->bIsDirectory)
3072 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
3074 if (lpafp->lpszName)
3075 lstrcpynW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
3077 bSuccess = TRUE;
3080 return bSuccess;
3083 /***********************************************************************
3084 * FTP_ParseNextFile (internal)
3086 * Parse the next line in file listing
3088 * RETURNS
3089 * TRUE on success
3090 * FALSE on failure
3092 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
3094 static const char szSpace[] = " \t";
3095 DWORD nBufLen;
3096 char *pszLine;
3097 char *pszToken;
3098 char *pszTmp;
3099 BOOL found = FALSE;
3100 int i;
3102 lpfp->lpszName = NULL;
3103 do {
3104 if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
3105 return FALSE;
3107 pszToken = strtok(pszLine, szSpace);
3108 /* ls format
3109 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
3111 * For instance:
3112 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
3114 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
3115 if(!FTP_ParsePermission(pszToken, lpfp))
3116 lpfp->bIsDirectory = FALSE;
3117 for(i=0; i<=3; i++) {
3118 if(!(pszToken = strtok(NULL, szSpace)))
3119 break;
3121 if(!pszToken) continue;
3122 if(lpfp->bIsDirectory) {
3123 TRACE("Is directory\n");
3124 lpfp->nSize = 0;
3126 else {
3127 TRACE("Size: %s\n", pszToken);
3128 lpfp->nSize = atol(pszToken);
3131 lpfp->tmLastModified.tm_sec = 0;
3132 lpfp->tmLastModified.tm_min = 0;
3133 lpfp->tmLastModified.tm_hour = 0;
3134 lpfp->tmLastModified.tm_mday = 0;
3135 lpfp->tmLastModified.tm_mon = 0;
3136 lpfp->tmLastModified.tm_year = 0;
3138 /* Determine month */
3139 pszToken = strtok(NULL, szSpace);
3140 if(!pszToken) continue;
3141 if(strlen(pszToken) >= 3) {
3142 pszToken[3] = 0;
3143 if((pszTmp = StrStrIA(szMonths, pszToken)))
3144 lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
3146 /* Determine day */
3147 pszToken = strtok(NULL, szSpace);
3148 if(!pszToken) continue;
3149 lpfp->tmLastModified.tm_mday = atoi(pszToken);
3150 /* Determine time or year */
3151 pszToken = strtok(NULL, szSpace);
3152 if(!pszToken) continue;
3153 if((pszTmp = strchr(pszToken, ':'))) {
3154 struct tm* apTM;
3155 time_t aTime;
3156 *pszTmp = 0;
3157 pszTmp++;
3158 lpfp->tmLastModified.tm_min = atoi(pszTmp);
3159 lpfp->tmLastModified.tm_hour = atoi(pszToken);
3160 time(&aTime);
3161 apTM = localtime(&aTime);
3162 lpfp->tmLastModified.tm_year = apTM->tm_year;
3164 else {
3165 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
3166 lpfp->tmLastModified.tm_hour = 12;
3168 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3169 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3170 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3171 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3173 pszToken = strtok(NULL, szSpace);
3174 if(!pszToken) continue;
3175 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3176 TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
3178 /* NT way of parsing ... :
3180 07-13-03 08:55PM <DIR> sakpatch
3181 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
3183 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
3184 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
3186 sscanf(pszToken, "%d-%d-%d",
3187 &lpfp->tmLastModified.tm_mon,
3188 &lpfp->tmLastModified.tm_mday,
3189 &lpfp->tmLastModified.tm_year);
3191 /* Hacky and bad Y2K protection :-) */
3192 if (lpfp->tmLastModified.tm_year < 70)
3193 lpfp->tmLastModified.tm_year += 100;
3195 pszToken = strtok(NULL, szSpace);
3196 if(!pszToken) continue;
3197 sscanf(pszToken, "%d:%d",
3198 &lpfp->tmLastModified.tm_hour,
3199 &lpfp->tmLastModified.tm_min);
3200 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
3201 lpfp->tmLastModified.tm_hour += 12;
3203 lpfp->tmLastModified.tm_sec = 0;
3205 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3206 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3207 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3208 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3210 pszToken = strtok(NULL, szSpace);
3211 if(!pszToken) continue;
3212 if(!strcasecmp(pszToken, "<DIR>")) {
3213 lpfp->bIsDirectory = TRUE;
3214 lpfp->nSize = 0;
3215 TRACE("Is directory\n");
3217 else {
3218 lpfp->bIsDirectory = FALSE;
3219 lpfp->nSize = atol(pszToken);
3220 TRACE("Size: %d\n", lpfp->nSize);
3223 pszToken = strtok(NULL, szSpace);
3224 if(!pszToken) continue;
3225 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3226 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
3228 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
3229 else if(pszToken[0] == '+') {
3230 FIXME("EPLF Format not implemented\n");
3233 if(lpfp->lpszName) {
3234 if((lpszSearchFile == NULL) ||
3235 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
3236 found = TRUE;
3237 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
3239 else {
3240 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
3241 lpfp->lpszName = NULL;
3244 } while(!found);
3245 return TRUE;
3248 /***********************************************************************
3249 * FTP_ParseDirectory (internal)
3251 * Parse string of directory information
3253 * RETURNS
3254 * TRUE on success
3255 * FALSE on failure
3257 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3258 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
3260 BOOL bSuccess = TRUE;
3261 INT sizeFilePropArray = 500;/*20; */
3262 INT indexFilePropArray = -1;
3264 TRACE("\n");
3266 /* Allocate intial file properties array */
3267 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
3268 if (!*lpafp)
3269 return FALSE;
3271 do {
3272 if (indexFilePropArray+1 >= sizeFilePropArray)
3274 LPFILEPROPERTIESW tmpafp;
3276 sizeFilePropArray *= 2;
3277 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
3278 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
3279 if (NULL == tmpafp)
3281 bSuccess = FALSE;
3282 break;
3285 *lpafp = tmpafp;
3287 indexFilePropArray++;
3288 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
3290 if (bSuccess && indexFilePropArray)
3292 if (indexFilePropArray < sizeFilePropArray - 1)
3294 LPFILEPROPERTIESW tmpafp;
3296 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
3297 sizeof(FILEPROPERTIESW)*indexFilePropArray);
3298 if (NULL == tmpafp)
3299 *lpafp = tmpafp;
3301 *dwfp = indexFilePropArray;
3303 else
3305 HeapFree(GetProcessHeap(), 0, *lpafp);
3306 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3307 bSuccess = FALSE;
3310 return bSuccess;
3314 /***********************************************************************
3315 * FTP_ParsePermission (internal)
3317 * Parse permission string of directory information
3319 * RETURNS
3320 * TRUE on success
3321 * FALSE on failure
3324 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3326 BOOL bSuccess = TRUE;
3327 unsigned short nPermission = 0;
3328 INT nPos = 1;
3329 INT nLast = 9;
3331 TRACE("\n");
3332 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3334 bSuccess = FALSE;
3335 return bSuccess;
3338 lpfp->bIsDirectory = (*lpszPermission == 'd');
3341 switch (nPos)
3343 case 1:
3344 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3345 break;
3346 case 2:
3347 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3348 break;
3349 case 3:
3350 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3351 break;
3352 case 4:
3353 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3354 break;
3355 case 5:
3356 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3357 break;
3358 case 6:
3359 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3360 break;
3361 case 7:
3362 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3363 break;
3364 case 8:
3365 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3366 break;
3367 case 9:
3368 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3369 break;
3371 nPos++;
3372 }while (nPos <= nLast);
3374 lpfp->permissions = nPermission;
3375 return bSuccess;
3379 /***********************************************************************
3380 * FTP_SetResponseError (internal)
3382 * Set the appropriate error code for a given response from the server
3384 * RETURNS
3387 static DWORD FTP_SetResponseError(DWORD dwResponse)
3389 DWORD dwCode = 0;
3391 switch(dwResponse)
3393 case 421: /* Service not available - Server may be shutting down. */
3394 dwCode = ERROR_INTERNET_EXTENDED_ERROR;
3395 break;
3397 case 425: /* Cannot open data connection. */
3398 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3399 break;
3401 case 426: /* Connection closed, transer aborted. */
3402 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3403 break;
3405 case 500: /* Syntax error. Command unrecognized. */
3406 case 501: /* Syntax error. Error in parameters or arguments. */
3407 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
3408 break;
3410 case 530: /* Not logged in. Login incorrect. */
3411 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3412 break;
3414 case 550: /* File action not taken. File not found or no access. */
3415 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
3416 break;
3418 case 450: /* File action not taken. File may be busy. */
3419 case 451: /* Action aborted. Server error. */
3420 case 452: /* Action not taken. Insufficient storage space on server. */
3421 case 502: /* Command not implemented. */
3422 case 503: /* Bad sequence of commands. */
3423 case 504: /* Command not implemented for that parameter. */
3424 case 532: /* Need account for storing files */
3425 case 551: /* Requested action aborted. Page type unknown */
3426 case 552: /* Action aborted. Exceeded storage allocation */
3427 case 553: /* Action not taken. File name not allowed. */
3429 default:
3430 dwCode = ERROR_INTERNET_EXTENDED_ERROR;
3431 break;
3434 INTERNET_SetLastError(dwCode);
3435 return dwCode;