push ad05fa8ea86b4a1581adad6c24ad723042d385d2
[wine/hacks.git] / dlls / wininet / ftp.c
blob8c0cc5d7f4c4966ee70f8c8c5ba5b30dcfacb750
1 /*
2 * WININET - Ftp implementation
4 * Copyright 1999 Corel Corporation
5 * Copyright 2004 Mike McCormack for CodeWeavers
6 * Copyright 2004 Kevin Koltzau
7 * Copyright 2007 Hans Leidekker
9 * Ulrich Czekalla
10 * Noureddine Jemmali
12 * Copyright 2000 Andreas Mohr
13 * Copyright 2002 Jaco Greeff
15 * This library is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU Lesser General Public
17 * License as published by the Free Software Foundation; either
18 * version 2.1 of the License, or (at your option) any later version.
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "config.h"
31 #include "wine/port.h"
33 #include <errno.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/types.h>
39 #ifdef HAVE_SYS_SOCKET_H
40 # include <sys/socket.h>
41 #endif
42 #ifdef HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif
45 #include <time.h>
46 #include <assert.h>
48 #include "windef.h"
49 #include "winbase.h"
50 #include "wingdi.h"
51 #include "winuser.h"
52 #include "wininet.h"
53 #include "winnls.h"
54 #include "winerror.h"
55 #include "winreg.h"
56 #include "winternl.h"
57 #include "shlwapi.h"
59 #include "wine/debug.h"
60 #include "internet.h"
62 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
64 #define DATA_PACKET_SIZE 0x2000
65 #define szCRLF "\r\n"
66 #define MAX_BACKLOG 5
68 /* Testing shows that Windows only accepts dwFlags where the last
69 * 3 (yes 3) bits define FTP_TRANSFER_TYPE_UNKNOWN, FTP_TRANSFER_TYPE_ASCII or FTP_TRANSFER_TYPE_BINARY.
71 #define FTP_CONDITION_MASK 0x0007
73 typedef enum {
74 /* FTP commands with arguments. */
75 FTP_CMD_ACCT,
76 FTP_CMD_CWD,
77 FTP_CMD_DELE,
78 FTP_CMD_MKD,
79 FTP_CMD_PASS,
80 FTP_CMD_PORT,
81 FTP_CMD_RETR,
82 FTP_CMD_RMD,
83 FTP_CMD_RNFR,
84 FTP_CMD_RNTO,
85 FTP_CMD_STOR,
86 FTP_CMD_TYPE,
87 FTP_CMD_USER,
88 FTP_CMD_SIZE,
90 /* FTP commands without arguments. */
91 FTP_CMD_ABOR,
92 FTP_CMD_LIST,
93 FTP_CMD_NLST,
94 FTP_CMD_PASV,
95 FTP_CMD_PWD,
96 FTP_CMD_QUIT,
97 } FTP_COMMAND;
99 static const CHAR *const szFtpCommands[] = {
100 "ACCT",
101 "CWD",
102 "DELE",
103 "MKD",
104 "PASS",
105 "PORT",
106 "RETR",
107 "RMD",
108 "RNFR",
109 "RNTO",
110 "STOR",
111 "TYPE",
112 "USER",
113 "SIZE",
114 "ABOR",
115 "LIST",
116 "NLST",
117 "PASV",
118 "PWD",
119 "QUIT",
122 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
123 static const WCHAR szNoAccount[] = {'n','o','a','c','c','o','u','n','t','\0'};
125 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr);
126 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr);
127 static void FTP_CloseConnection(LPWININETHANDLEHEADER hdr);
128 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr);
129 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
130 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext);
131 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
132 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket);
133 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile);
134 static INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD_PTR dwContext);
135 static BOOL FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
136 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile);
137 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs);
138 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs);
139 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs);
140 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs);
141 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType);
142 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs);
143 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs);
144 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs);
145 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp);
146 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW fileprop);
147 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
148 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp);
149 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
150 LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext);
151 static DWORD FTP_SetResponseError(DWORD dwResponse);
153 /***********************************************************************
154 * FtpPutFileA (WININET.@)
156 * Uploads a file to the FTP server
158 * RETURNS
159 * TRUE on success
160 * FALSE on failure
163 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
164 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext)
166 LPWSTR lpwzLocalFile;
167 LPWSTR lpwzNewRemoteFile;
168 BOOL ret;
170 lpwzLocalFile = lpszLocalFile?WININET_strdup_AtoW(lpszLocalFile):NULL;
171 lpwzNewRemoteFile = lpszNewRemoteFile?WININET_strdup_AtoW(lpszNewRemoteFile):NULL;
172 ret = FtpPutFileW(hConnect, lpwzLocalFile, lpwzNewRemoteFile,
173 dwFlags, dwContext);
174 HeapFree(GetProcessHeap(), 0, lpwzLocalFile);
175 HeapFree(GetProcessHeap(), 0, lpwzNewRemoteFile);
176 return ret;
179 static void AsyncFtpPutFileProc(WORKREQUEST *workRequest)
181 struct WORKREQ_FTPPUTFILEW const *req = &workRequest->u.FtpPutFileW;
182 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
184 TRACE("%p\n", lpwfs);
186 FTP_FtpPutFileW(lpwfs, req->lpszLocalFile,
187 req->lpszNewRemoteFile, req->dwFlags, req->dwContext);
189 HeapFree(GetProcessHeap(), 0, req->lpszLocalFile);
190 HeapFree(GetProcessHeap(), 0, req->lpszNewRemoteFile);
193 /***********************************************************************
194 * FtpPutFileW (WININET.@)
196 * Uploads a file to the FTP server
198 * RETURNS
199 * TRUE on success
200 * FALSE on failure
203 BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile,
204 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext)
206 LPWININETFTPSESSIONW lpwfs;
207 LPWININETAPPINFOW hIC = NULL;
208 BOOL r = FALSE;
210 if (!lpszLocalFile || !lpszNewRemoteFile)
212 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
213 return FALSE;
216 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
217 if (!lpwfs)
219 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
220 return FALSE;
223 if (WH_HFTPSESSION != lpwfs->hdr.htype)
225 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
226 goto lend;
229 if (lpwfs->download_in_progress != NULL)
231 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
232 goto lend;
235 if ((dwFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY)
237 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
238 goto lend;
241 hIC = lpwfs->lpAppInfo;
242 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
244 WORKREQUEST workRequest;
245 struct WORKREQ_FTPPUTFILEW *req = &workRequest.u.FtpPutFileW;
247 workRequest.asyncproc = AsyncFtpPutFileProc;
248 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
249 req->lpszLocalFile = WININET_strdupW(lpszLocalFile);
250 req->lpszNewRemoteFile = WININET_strdupW(lpszNewRemoteFile);
251 req->dwFlags = dwFlags;
252 req->dwContext = dwContext;
254 r = INTERNET_AsyncCall(&workRequest);
256 else
258 r = FTP_FtpPutFileW(lpwfs, lpszLocalFile,
259 lpszNewRemoteFile, dwFlags, dwContext);
262 lend:
263 WININET_Release( &lpwfs->hdr );
265 return r;
268 /***********************************************************************
269 * FTP_FtpPutFileW (Internal)
271 * Uploads a file to the FTP server
273 * RETURNS
274 * TRUE on success
275 * FALSE on failure
278 BOOL WINAPI FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile,
279 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext)
281 HANDLE hFile;
282 BOOL bSuccess = FALSE;
283 LPWININETAPPINFOW hIC = NULL;
284 INT nResCode;
286 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", debugstr_w(lpszLocalFile), debugstr_w(lpszNewRemoteFile));
288 /* Clear any error information */
289 INTERNET_SetLastError(0);
291 /* Open file to be uploaded */
292 if (INVALID_HANDLE_VALUE ==
293 (hFile = CreateFileW(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
294 /* Let CreateFile set the appropriate error */
295 return FALSE;
297 hIC = lpwfs->lpAppInfo;
299 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
301 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
303 INT nDataSocket;
305 /* Get data socket to server */
306 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
308 FTP_SendData(lpwfs, nDataSocket, hFile);
309 closesocket(nDataSocket);
310 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
311 if (nResCode)
313 if (nResCode == 226)
314 bSuccess = TRUE;
315 else
316 FTP_SetResponseError(nResCode);
321 if (lpwfs->lstnSocket != -1)
322 closesocket(lpwfs->lstnSocket);
324 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
326 INTERNET_ASYNC_RESULT iar;
328 iar.dwResult = (DWORD)bSuccess;
329 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
330 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
331 &iar, sizeof(INTERNET_ASYNC_RESULT));
334 CloseHandle(hFile);
336 return bSuccess;
340 /***********************************************************************
341 * FtpSetCurrentDirectoryA (WININET.@)
343 * Change the working directory on the FTP server
345 * RETURNS
346 * TRUE on success
347 * FALSE on failure
350 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
352 LPWSTR lpwzDirectory;
353 BOOL ret;
355 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
356 ret = FtpSetCurrentDirectoryW(hConnect, lpwzDirectory);
357 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
358 return ret;
362 static void AsyncFtpSetCurrentDirectoryProc(WORKREQUEST *workRequest)
364 struct WORKREQ_FTPSETCURRENTDIRECTORYW const *req = &workRequest->u.FtpSetCurrentDirectoryW;
365 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
367 TRACE("%p\n", lpwfs);
369 FTP_FtpSetCurrentDirectoryW(lpwfs, req->lpszDirectory);
370 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
373 /***********************************************************************
374 * FtpSetCurrentDirectoryW (WININET.@)
376 * Change the working directory on the FTP server
378 * RETURNS
379 * TRUE on success
380 * FALSE on failure
383 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
385 LPWININETFTPSESSIONW lpwfs = NULL;
386 LPWININETAPPINFOW hIC = NULL;
387 BOOL r = FALSE;
389 if (!lpszDirectory)
391 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
392 goto lend;
395 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
396 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
398 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
399 goto lend;
402 if (lpwfs->download_in_progress != NULL)
404 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
405 goto lend;
408 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
410 hIC = lpwfs->lpAppInfo;
411 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
413 WORKREQUEST workRequest;
414 struct WORKREQ_FTPSETCURRENTDIRECTORYW *req;
416 workRequest.asyncproc = AsyncFtpSetCurrentDirectoryProc;
417 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
418 req = &workRequest.u.FtpSetCurrentDirectoryW;
419 req->lpszDirectory = WININET_strdupW(lpszDirectory);
421 r = INTERNET_AsyncCall(&workRequest);
423 else
425 r = FTP_FtpSetCurrentDirectoryW(lpwfs, lpszDirectory);
428 lend:
429 if( lpwfs )
430 WININET_Release( &lpwfs->hdr );
432 return r;
436 /***********************************************************************
437 * FTP_FtpSetCurrentDirectoryW (Internal)
439 * Change the working directory on the FTP server
441 * RETURNS
442 * TRUE on success
443 * FALSE on failure
446 BOOL WINAPI FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
448 INT nResCode;
449 LPWININETAPPINFOW hIC = NULL;
450 DWORD bSuccess = FALSE;
452 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
454 /* Clear any error information */
455 INTERNET_SetLastError(0);
457 hIC = lpwfs->lpAppInfo;
458 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
459 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
460 goto lend;
462 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
464 if (nResCode)
466 if (nResCode == 250)
467 bSuccess = TRUE;
468 else
469 FTP_SetResponseError(nResCode);
472 lend:
473 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
475 INTERNET_ASYNC_RESULT iar;
477 iar.dwResult = (DWORD)bSuccess;
478 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
479 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
480 &iar, sizeof(INTERNET_ASYNC_RESULT));
482 return bSuccess;
486 /***********************************************************************
487 * FtpCreateDirectoryA (WININET.@)
489 * Create new directory on the FTP server
491 * RETURNS
492 * TRUE on success
493 * FALSE on failure
496 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
498 LPWSTR lpwzDirectory;
499 BOOL ret;
501 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
502 ret = FtpCreateDirectoryW(hConnect, lpwzDirectory);
503 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
504 return ret;
508 static void AsyncFtpCreateDirectoryProc(WORKREQUEST *workRequest)
510 struct WORKREQ_FTPCREATEDIRECTORYW const *req = &workRequest->u.FtpCreateDirectoryW;
511 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
513 TRACE(" %p\n", lpwfs);
515 FTP_FtpCreateDirectoryW(lpwfs, req->lpszDirectory);
516 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
519 /***********************************************************************
520 * FtpCreateDirectoryW (WININET.@)
522 * Create new directory on the FTP server
524 * RETURNS
525 * TRUE on success
526 * FALSE on failure
529 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
531 LPWININETFTPSESSIONW lpwfs;
532 LPWININETAPPINFOW hIC = NULL;
533 BOOL r = FALSE;
535 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
536 if (!lpwfs)
538 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
539 return FALSE;
542 if (WH_HFTPSESSION != lpwfs->hdr.htype)
544 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
545 goto lend;
548 if (lpwfs->download_in_progress != NULL)
550 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
551 goto lend;
554 if (!lpszDirectory)
556 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
557 goto lend;
560 hIC = lpwfs->lpAppInfo;
561 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
563 WORKREQUEST workRequest;
564 struct WORKREQ_FTPCREATEDIRECTORYW *req;
566 workRequest.asyncproc = AsyncFtpCreateDirectoryProc;
567 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
568 req = &workRequest.u.FtpCreateDirectoryW;
569 req->lpszDirectory = WININET_strdupW(lpszDirectory);
571 r = INTERNET_AsyncCall(&workRequest);
573 else
575 r = FTP_FtpCreateDirectoryW(lpwfs, lpszDirectory);
577 lend:
578 WININET_Release( &lpwfs->hdr );
580 return r;
584 /***********************************************************************
585 * FTP_FtpCreateDirectoryW (Internal)
587 * Create new directory on the FTP server
589 * RETURNS
590 * TRUE on success
591 * FALSE on failure
594 BOOL WINAPI FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
596 INT nResCode;
597 BOOL bSuccess = FALSE;
598 LPWININETAPPINFOW hIC = NULL;
600 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
602 /* Clear any error information */
603 INTERNET_SetLastError(0);
605 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
606 goto lend;
608 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
609 if (nResCode)
611 if (nResCode == 257)
612 bSuccess = TRUE;
613 else
614 FTP_SetResponseError(nResCode);
617 lend:
618 hIC = lpwfs->lpAppInfo;
619 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
621 INTERNET_ASYNC_RESULT iar;
623 iar.dwResult = (DWORD)bSuccess;
624 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
625 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
626 &iar, sizeof(INTERNET_ASYNC_RESULT));
629 return bSuccess;
632 /***********************************************************************
633 * FtpFindFirstFileA (WININET.@)
635 * Search the specified directory
637 * RETURNS
638 * HINTERNET on success
639 * NULL on failure
642 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
643 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext)
645 LPWSTR lpwzSearchFile;
646 WIN32_FIND_DATAW wfd;
647 LPWIN32_FIND_DATAW lpFindFileDataW;
648 HINTERNET ret;
650 lpwzSearchFile = lpszSearchFile?WININET_strdup_AtoW(lpszSearchFile):NULL;
651 lpFindFileDataW = lpFindFileData?&wfd:NULL;
652 ret = FtpFindFirstFileW(hConnect, lpwzSearchFile, lpFindFileDataW, dwFlags, dwContext);
653 HeapFree(GetProcessHeap(), 0, lpwzSearchFile);
655 if(lpFindFileData) {
656 WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData);
658 return ret;
662 static void AsyncFtpFindFirstFileProc(WORKREQUEST *workRequest)
664 struct WORKREQ_FTPFINDFIRSTFILEW const *req = &workRequest->u.FtpFindFirstFileW;
665 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
667 TRACE("%p\n", lpwfs);
669 FTP_FtpFindFirstFileW(lpwfs, req->lpszSearchFile,
670 req->lpFindFileData, req->dwFlags, req->dwContext);
671 HeapFree(GetProcessHeap(), 0, req->lpszSearchFile);
674 /***********************************************************************
675 * FtpFindFirstFileW (WININET.@)
677 * Search the specified directory
679 * RETURNS
680 * HINTERNET on success
681 * NULL on failure
684 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
685 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext)
687 LPWININETFTPSESSIONW lpwfs;
688 LPWININETAPPINFOW hIC = NULL;
689 HINTERNET r = NULL;
691 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
692 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
694 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
695 goto lend;
698 if (lpwfs->download_in_progress != NULL)
700 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
701 goto lend;
704 hIC = lpwfs->lpAppInfo;
705 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
707 WORKREQUEST workRequest;
708 struct WORKREQ_FTPFINDFIRSTFILEW *req;
710 workRequest.asyncproc = AsyncFtpFindFirstFileProc;
711 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
712 req = &workRequest.u.FtpFindFirstFileW;
713 req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : WININET_strdupW(lpszSearchFile);
714 req->lpFindFileData = lpFindFileData;
715 req->dwFlags = dwFlags;
716 req->dwContext= dwContext;
718 INTERNET_AsyncCall(&workRequest);
719 r = NULL;
721 else
723 r = FTP_FtpFindFirstFileW(lpwfs, lpszSearchFile, lpFindFileData,
724 dwFlags, dwContext);
726 lend:
727 if( lpwfs )
728 WININET_Release( &lpwfs->hdr );
730 return r;
734 /***********************************************************************
735 * FTP_FtpFindFirstFileW (Internal)
737 * Search the specified directory
739 * RETURNS
740 * HINTERNET on success
741 * NULL on failure
744 HINTERNET WINAPI FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs,
745 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext)
747 INT nResCode;
748 LPWININETAPPINFOW hIC = NULL;
749 HINTERNET hFindNext = NULL;
751 TRACE("\n");
753 /* Clear any error information */
754 INTERNET_SetLastError(0);
756 if (!FTP_InitListenSocket(lpwfs))
757 goto lend;
759 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
760 goto lend;
762 if (!FTP_SendPortOrPasv(lpwfs))
763 goto lend;
765 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, NULL,
766 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
767 goto lend;
769 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
770 if (nResCode)
772 if (nResCode == 125 || nResCode == 150)
774 INT nDataSocket;
776 /* Get data socket to server */
777 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
779 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpszSearchFile, lpFindFileData, dwContext);
780 closesocket(nDataSocket);
781 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
782 if (nResCode != 226 && nResCode != 250)
783 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
786 else
787 FTP_SetResponseError(nResCode);
790 lend:
791 if (lpwfs->lstnSocket != -1)
792 closesocket(lpwfs->lstnSocket);
794 hIC = lpwfs->lpAppInfo;
795 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
797 INTERNET_ASYNC_RESULT iar;
799 if (hFindNext)
801 iar.dwResult = (DWORD)hFindNext;
802 iar.dwError = ERROR_SUCCESS;
803 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
804 &iar, sizeof(INTERNET_ASYNC_RESULT));
807 iar.dwResult = (DWORD)hFindNext;
808 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
809 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
810 &iar, sizeof(INTERNET_ASYNC_RESULT));
813 return hFindNext;
817 /***********************************************************************
818 * FtpGetCurrentDirectoryA (WININET.@)
820 * Retrieves the current directory
822 * RETURNS
823 * TRUE on success
824 * FALSE on failure
827 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
828 LPDWORD lpdwCurrentDirectory)
830 WCHAR *dir = NULL;
831 DWORD len;
832 BOOL ret;
834 if(lpdwCurrentDirectory) {
835 len = *lpdwCurrentDirectory;
836 if(lpszCurrentDirectory)
838 dir = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
839 if (NULL == dir)
841 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
842 return FALSE;
846 ret = FtpGetCurrentDirectoryW(hFtpSession, lpszCurrentDirectory?dir:NULL, lpdwCurrentDirectory?&len:NULL);
847 if(lpdwCurrentDirectory) {
848 *lpdwCurrentDirectory = len;
849 if(lpszCurrentDirectory) {
850 WideCharToMultiByte(CP_ACP, 0, dir, len, lpszCurrentDirectory, *lpdwCurrentDirectory, NULL, NULL);
851 HeapFree(GetProcessHeap(), 0, dir);
854 return ret;
858 static void AsyncFtpGetCurrentDirectoryProc(WORKREQUEST *workRequest)
860 struct WORKREQ_FTPGETCURRENTDIRECTORYW const *req = &workRequest->u.FtpGetCurrentDirectoryW;
861 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
863 TRACE("%p\n", lpwfs);
865 FTP_FtpGetCurrentDirectoryW(lpwfs, req->lpszDirectory, req->lpdwDirectory);
868 /***********************************************************************
869 * FtpGetCurrentDirectoryW (WININET.@)
871 * Retrieves the current directory
873 * RETURNS
874 * TRUE on success
875 * FALSE on failure
878 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
879 LPDWORD lpdwCurrentDirectory)
881 LPWININETFTPSESSIONW lpwfs;
882 LPWININETAPPINFOW hIC = NULL;
883 BOOL r = FALSE;
885 TRACE("len(%d)\n", *lpdwCurrentDirectory);
887 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
888 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
890 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
891 goto lend;
894 if (lpwfs->download_in_progress != NULL)
896 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
897 goto lend;
900 hIC = lpwfs->lpAppInfo;
901 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
903 WORKREQUEST workRequest;
904 struct WORKREQ_FTPGETCURRENTDIRECTORYW *req;
906 workRequest.asyncproc = AsyncFtpGetCurrentDirectoryProc;
907 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
908 req = &workRequest.u.FtpGetCurrentDirectoryW;
909 req->lpszDirectory = lpszCurrentDirectory;
910 req->lpdwDirectory = lpdwCurrentDirectory;
912 r = INTERNET_AsyncCall(&workRequest);
914 else
916 r = FTP_FtpGetCurrentDirectoryW(lpwfs, lpszCurrentDirectory,
917 lpdwCurrentDirectory);
920 lend:
921 if( lpwfs )
922 WININET_Release( &lpwfs->hdr );
924 return r;
928 /***********************************************************************
929 * FTP_FtpGetCurrentDirectoryW (Internal)
931 * Retrieves the current directory
933 * RETURNS
934 * TRUE on success
935 * FALSE on failure
938 BOOL WINAPI FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszCurrentDirectory,
939 LPDWORD lpdwCurrentDirectory)
941 INT nResCode;
942 LPWININETAPPINFOW hIC = NULL;
943 DWORD bSuccess = FALSE;
945 TRACE("len(%d)\n", *lpdwCurrentDirectory);
947 /* Clear any error information */
948 INTERNET_SetLastError(0);
950 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
952 hIC = lpwfs->lpAppInfo;
953 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
954 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
955 goto lend;
957 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
958 if (nResCode)
960 if (nResCode == 257) /* Extract directory name */
962 DWORD firstpos, lastpos, len;
963 LPWSTR lpszResponseBuffer = WININET_strdup_AtoW(INTERNET_GetResponseBuffer());
965 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
967 if ('"' == lpszResponseBuffer[lastpos])
969 if (!firstpos)
970 firstpos = lastpos;
971 else
972 break;
976 len = lastpos - firstpos - 1;
977 lstrcpynW(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1], *lpdwCurrentDirectory);
978 HeapFree(GetProcessHeap(), 0, lpszResponseBuffer);
979 *lpdwCurrentDirectory = len;
980 bSuccess = TRUE;
982 else
983 FTP_SetResponseError(nResCode);
986 lend:
987 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
989 INTERNET_ASYNC_RESULT iar;
991 iar.dwResult = (DWORD)bSuccess;
992 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
993 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
994 &iar, sizeof(INTERNET_ASYNC_RESULT));
997 return (DWORD) bSuccess;
1000 /***********************************************************************
1001 * FtpOpenFileA (WININET.@)
1003 * Open a remote file for writing or reading
1005 * RETURNS
1006 * HINTERNET handle on success
1007 * NULL on failure
1010 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
1011 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1012 DWORD_PTR dwContext)
1014 LPWSTR lpwzFileName;
1015 HINTERNET ret;
1017 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1018 ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext);
1019 HeapFree(GetProcessHeap(), 0, lpwzFileName);
1020 return ret;
1024 static void AsyncFtpOpenFileProc(WORKREQUEST *workRequest)
1026 struct WORKREQ_FTPOPENFILEW const *req = &workRequest->u.FtpOpenFileW;
1027 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1029 TRACE("%p\n", lpwfs);
1031 FTP_FtpOpenFileW(lpwfs, req->lpszFilename,
1032 req->dwAccess, req->dwFlags, req->dwContext);
1033 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1036 /***********************************************************************
1037 * FtpOpenFileW (WININET.@)
1039 * Open a remote file for writing or reading
1041 * RETURNS
1042 * HINTERNET handle on success
1043 * NULL on failure
1046 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
1047 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1048 DWORD_PTR dwContext)
1050 LPWININETFTPSESSIONW lpwfs;
1051 LPWININETAPPINFOW hIC = NULL;
1052 HINTERNET r = NULL;
1054 TRACE("(%p,%s,0x%08x,0x%08x,0x%08lx)\n", hFtpSession,
1055 debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext);
1057 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1058 if (!lpwfs)
1060 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1061 return FALSE;
1064 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1066 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1067 goto lend;
1070 if ((!lpszFileName) ||
1071 ((fdwAccess != GENERIC_READ) && (fdwAccess != GENERIC_WRITE)) ||
1072 ((dwFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY))
1074 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1075 goto lend;
1078 if (lpwfs->download_in_progress != NULL)
1080 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1081 goto lend;
1084 hIC = lpwfs->lpAppInfo;
1085 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1087 WORKREQUEST workRequest;
1088 struct WORKREQ_FTPOPENFILEW *req;
1090 workRequest.asyncproc = AsyncFtpOpenFileProc;
1091 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1092 req = &workRequest.u.FtpOpenFileW;
1093 req->lpszFilename = WININET_strdupW(lpszFileName);
1094 req->dwAccess = fdwAccess;
1095 req->dwFlags = dwFlags;
1096 req->dwContext = dwContext;
1098 INTERNET_AsyncCall(&workRequest);
1099 r = NULL;
1101 else
1103 r = FTP_FtpOpenFileW(lpwfs, lpszFileName, fdwAccess, dwFlags, dwContext);
1106 lend:
1107 WININET_Release( &lpwfs->hdr );
1109 return r;
1113 /***********************************************************************
1114 * FTP_FtpOpenFileW (Internal)
1116 * Open a remote file for writing or reading
1118 * RETURNS
1119 * HINTERNET handle on success
1120 * NULL on failure
1123 HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs,
1124 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1125 DWORD_PTR dwContext)
1127 INT nDataSocket;
1128 BOOL bSuccess = FALSE;
1129 LPWININETFTPFILE lpwh = NULL;
1130 LPWININETAPPINFOW hIC = NULL;
1131 HINTERNET handle = NULL;
1133 TRACE("\n");
1135 /* Clear any error information */
1136 INTERNET_SetLastError(0);
1138 if (GENERIC_READ == fdwAccess)
1140 /* Set up socket to retrieve data */
1141 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
1143 else if (GENERIC_WRITE == fdwAccess)
1145 /* Set up socket to send data */
1146 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
1149 /* Get data socket to server */
1150 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
1152 lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPFILE));
1153 lpwh->hdr.htype = WH_HFILE;
1154 lpwh->hdr.dwFlags = dwFlags;
1155 lpwh->hdr.dwContext = dwContext;
1156 lpwh->hdr.dwRefCount = 1;
1157 lpwh->hdr.close_connection = NULL;
1158 lpwh->hdr.destroy = FTP_CloseFileTransferHandle;
1159 lpwh->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
1160 lpwh->nDataSocket = nDataSocket;
1161 lpwh->session_deleted = FALSE;
1163 WININET_AddRef( &lpwfs->hdr );
1164 lpwh->lpFtpSession = lpwfs;
1165 list_add_head( &lpwfs->hdr.children, &lpwh->hdr.entry );
1167 handle = WININET_AllocHandle( &lpwh->hdr );
1168 if( !handle )
1169 goto lend;
1171 /* Indicate that a download is currently in progress */
1172 lpwfs->download_in_progress = lpwh;
1175 if (lpwfs->lstnSocket != -1)
1176 closesocket(lpwfs->lstnSocket);
1178 hIC = lpwfs->lpAppInfo;
1179 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1181 INTERNET_ASYNC_RESULT iar;
1183 if (lpwh)
1185 iar.dwResult = (DWORD)handle;
1186 iar.dwError = ERROR_SUCCESS;
1187 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
1188 &iar, sizeof(INTERNET_ASYNC_RESULT));
1191 iar.dwResult = (DWORD)bSuccess;
1192 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1193 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1194 &iar, sizeof(INTERNET_ASYNC_RESULT));
1197 lend:
1198 if( lpwh )
1199 WININET_Release( &lpwh->hdr );
1201 return handle;
1205 /***********************************************************************
1206 * FtpGetFileA (WININET.@)
1208 * Retrieve file from the FTP server
1210 * RETURNS
1211 * TRUE on success
1212 * FALSE on failure
1215 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1216 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1217 DWORD_PTR dwContext)
1219 LPWSTR lpwzRemoteFile;
1220 LPWSTR lpwzNewFile;
1221 BOOL ret;
1223 lpwzRemoteFile = lpszRemoteFile?WININET_strdup_AtoW(lpszRemoteFile):NULL;
1224 lpwzNewFile = lpszNewFile?WININET_strdup_AtoW(lpszNewFile):NULL;
1225 ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists,
1226 dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1227 HeapFree(GetProcessHeap(), 0, lpwzRemoteFile);
1228 HeapFree(GetProcessHeap(), 0, lpwzNewFile);
1229 return ret;
1233 static void AsyncFtpGetFileProc(WORKREQUEST *workRequest)
1235 struct WORKREQ_FTPGETFILEW const *req = &workRequest->u.FtpGetFileW;
1236 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1238 TRACE("%p\n", lpwfs);
1240 FTP_FtpGetFileW(lpwfs, req->lpszRemoteFile,
1241 req->lpszNewFile, req->fFailIfExists,
1242 req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext);
1243 HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile);
1244 HeapFree(GetProcessHeap(), 0, req->lpszNewFile);
1248 /***********************************************************************
1249 * FtpGetFileW (WININET.@)
1251 * Retrieve file from the FTP server
1253 * RETURNS
1254 * TRUE on success
1255 * FALSE on failure
1258 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1259 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1260 DWORD_PTR dwContext)
1262 LPWININETFTPSESSIONW lpwfs;
1263 LPWININETAPPINFOW hIC = NULL;
1264 BOOL r = FALSE;
1266 if (!lpszRemoteFile || !lpszNewFile)
1268 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1269 return FALSE;
1272 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet );
1273 if (!lpwfs)
1275 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1276 return FALSE;
1279 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1281 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1282 goto lend;
1285 if ((dwInternetFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY)
1287 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1288 goto lend;
1291 if (lpwfs->download_in_progress != NULL)
1293 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1294 goto lend;
1297 hIC = lpwfs->lpAppInfo;
1298 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1300 WORKREQUEST workRequest;
1301 struct WORKREQ_FTPGETFILEW *req;
1303 workRequest.asyncproc = AsyncFtpGetFileProc;
1304 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1305 req = &workRequest.u.FtpGetFileW;
1306 req->lpszRemoteFile = WININET_strdupW(lpszRemoteFile);
1307 req->lpszNewFile = WININET_strdupW(lpszNewFile);
1308 req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1309 req->fFailIfExists = fFailIfExists;
1310 req->dwFlags = dwInternetFlags;
1311 req->dwContext = dwContext;
1313 r = INTERNET_AsyncCall(&workRequest);
1315 else
1317 r = FTP_FtpGetFileW(lpwfs, lpszRemoteFile, lpszNewFile,
1318 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1321 lend:
1322 WININET_Release( &lpwfs->hdr );
1324 return r;
1328 /***********************************************************************
1329 * FTP_FtpGetFileW (Internal)
1331 * Retrieve file from the FTP server
1333 * RETURNS
1334 * TRUE on success
1335 * FALSE on failure
1338 BOOL WINAPI FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1339 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1340 DWORD_PTR dwContext)
1342 BOOL bSuccess = FALSE;
1343 HANDLE hFile;
1344 LPWININETAPPINFOW hIC = NULL;
1346 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile));
1348 /* Clear any error information */
1349 INTERNET_SetLastError(0);
1351 /* Ensure we can write to lpszNewfile by opening it */
1352 hFile = CreateFileW(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1353 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1354 if (INVALID_HANDLE_VALUE == hFile)
1355 return FALSE;
1357 /* Set up socket to retrieve data */
1358 if (FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags))
1360 INT nDataSocket;
1362 /* Get data socket to server */
1363 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1365 INT nResCode;
1367 /* Receive data */
1368 FTP_RetrieveFileData(lpwfs, nDataSocket, hFile);
1369 closesocket(nDataSocket);
1371 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
1372 if (nResCode)
1374 if (nResCode == 226)
1375 bSuccess = TRUE;
1376 else
1377 FTP_SetResponseError(nResCode);
1382 if (lpwfs->lstnSocket != -1)
1383 closesocket(lpwfs->lstnSocket);
1385 CloseHandle(hFile);
1387 hIC = lpwfs->lpAppInfo;
1388 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1390 INTERNET_ASYNC_RESULT iar;
1392 iar.dwResult = (DWORD)bSuccess;
1393 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1394 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1395 &iar, sizeof(INTERNET_ASYNC_RESULT));
1398 return bSuccess;
1401 /***********************************************************************
1402 * FtpGetFileSize (WININET.@)
1404 DWORD WINAPI FtpGetFileSize( HINTERNET hFile, LPDWORD lpdwFileSizeHigh )
1406 FIXME("(%p, %p)\n", hFile, lpdwFileSizeHigh);
1408 if (lpdwFileSizeHigh)
1409 *lpdwFileSizeHigh = 0;
1411 return 0;
1414 /***********************************************************************
1415 * FtpDeleteFileA (WININET.@)
1417 * Delete a file on the ftp server
1419 * RETURNS
1420 * TRUE on success
1421 * FALSE on failure
1424 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1426 LPWSTR lpwzFileName;
1427 BOOL ret;
1429 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1430 ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1431 HeapFree(GetProcessHeap(), 0, lpwzFileName);
1432 return ret;
1435 static void AsyncFtpDeleteFileProc(WORKREQUEST *workRequest)
1437 struct WORKREQ_FTPDELETEFILEW const *req = &workRequest->u.FtpDeleteFileW;
1438 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1440 TRACE("%p\n", lpwfs);
1442 FTP_FtpDeleteFileW(lpwfs, req->lpszFilename);
1443 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1446 /***********************************************************************
1447 * FtpDeleteFileW (WININET.@)
1449 * Delete a file on the ftp server
1451 * RETURNS
1452 * TRUE on success
1453 * FALSE on failure
1456 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1458 LPWININETFTPSESSIONW lpwfs;
1459 LPWININETAPPINFOW hIC = NULL;
1460 BOOL r = FALSE;
1462 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1463 if (!lpwfs)
1465 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1466 return FALSE;
1469 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1471 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1472 goto lend;
1475 if (lpwfs->download_in_progress != NULL)
1477 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1478 goto lend;
1481 if (!lpszFileName)
1483 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1484 goto lend;
1487 hIC = lpwfs->lpAppInfo;
1488 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1490 WORKREQUEST workRequest;
1491 struct WORKREQ_FTPDELETEFILEW *req;
1493 workRequest.asyncproc = AsyncFtpDeleteFileProc;
1494 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1495 req = &workRequest.u.FtpDeleteFileW;
1496 req->lpszFilename = WININET_strdupW(lpszFileName);
1498 r = INTERNET_AsyncCall(&workRequest);
1500 else
1502 r = FTP_FtpDeleteFileW(lpwfs, lpszFileName);
1505 lend:
1506 WININET_Release( &lpwfs->hdr );
1508 return r;
1511 /***********************************************************************
1512 * FTP_FtpDeleteFileW (Internal)
1514 * Delete a file on the ftp server
1516 * RETURNS
1517 * TRUE on success
1518 * FALSE on failure
1521 BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName)
1523 INT nResCode;
1524 BOOL bSuccess = FALSE;
1525 LPWININETAPPINFOW hIC = NULL;
1527 TRACE("%p\n", lpwfs);
1529 /* Clear any error information */
1530 INTERNET_SetLastError(0);
1532 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1533 goto lend;
1535 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1536 if (nResCode)
1538 if (nResCode == 250)
1539 bSuccess = TRUE;
1540 else
1541 FTP_SetResponseError(nResCode);
1543 lend:
1544 hIC = lpwfs->lpAppInfo;
1545 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1547 INTERNET_ASYNC_RESULT iar;
1549 iar.dwResult = (DWORD)bSuccess;
1550 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1551 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1552 &iar, sizeof(INTERNET_ASYNC_RESULT));
1555 return bSuccess;
1559 /***********************************************************************
1560 * FtpRemoveDirectoryA (WININET.@)
1562 * Remove a directory on the ftp server
1564 * RETURNS
1565 * TRUE on success
1566 * FALSE on failure
1569 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1571 LPWSTR lpwzDirectory;
1572 BOOL ret;
1574 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
1575 ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1576 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
1577 return ret;
1580 static void AsyncFtpRemoveDirectoryProc(WORKREQUEST *workRequest)
1582 struct WORKREQ_FTPREMOVEDIRECTORYW const *req = &workRequest->u.FtpRemoveDirectoryW;
1583 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1585 TRACE("%p\n", lpwfs);
1587 FTP_FtpRemoveDirectoryW(lpwfs, req->lpszDirectory);
1588 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
1591 /***********************************************************************
1592 * FtpRemoveDirectoryW (WININET.@)
1594 * Remove a directory on the ftp server
1596 * RETURNS
1597 * TRUE on success
1598 * FALSE on failure
1601 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1603 LPWININETFTPSESSIONW lpwfs;
1604 LPWININETAPPINFOW hIC = NULL;
1605 BOOL r = FALSE;
1607 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1608 if (!lpwfs)
1610 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1611 return FALSE;
1614 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1616 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1617 goto lend;
1620 if (lpwfs->download_in_progress != NULL)
1622 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1623 goto lend;
1626 if (!lpszDirectory)
1628 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1629 goto lend;
1632 hIC = lpwfs->lpAppInfo;
1633 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1635 WORKREQUEST workRequest;
1636 struct WORKREQ_FTPREMOVEDIRECTORYW *req;
1638 workRequest.asyncproc = AsyncFtpRemoveDirectoryProc;
1639 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1640 req = &workRequest.u.FtpRemoveDirectoryW;
1641 req->lpszDirectory = WININET_strdupW(lpszDirectory);
1643 r = INTERNET_AsyncCall(&workRequest);
1645 else
1647 r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory);
1650 lend:
1651 WININET_Release( &lpwfs->hdr );
1653 return r;
1656 /***********************************************************************
1657 * FTP_FtpRemoveDirectoryW (Internal)
1659 * Remove a directory on the ftp server
1661 * RETURNS
1662 * TRUE on success
1663 * FALSE on failure
1666 BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
1668 INT nResCode;
1669 BOOL bSuccess = FALSE;
1670 LPWININETAPPINFOW hIC = NULL;
1672 TRACE("\n");
1674 /* Clear any error information */
1675 INTERNET_SetLastError(0);
1677 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1678 goto lend;
1680 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1681 if (nResCode)
1683 if (nResCode == 250)
1684 bSuccess = TRUE;
1685 else
1686 FTP_SetResponseError(nResCode);
1689 lend:
1690 hIC = lpwfs->lpAppInfo;
1691 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1693 INTERNET_ASYNC_RESULT iar;
1695 iar.dwResult = (DWORD)bSuccess;
1696 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1697 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1698 &iar, sizeof(INTERNET_ASYNC_RESULT));
1701 return bSuccess;
1705 /***********************************************************************
1706 * FtpRenameFileA (WININET.@)
1708 * Rename a file on the ftp server
1710 * RETURNS
1711 * TRUE on success
1712 * FALSE on failure
1715 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1717 LPWSTR lpwzSrc;
1718 LPWSTR lpwzDest;
1719 BOOL ret;
1721 lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL;
1722 lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL;
1723 ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
1724 HeapFree(GetProcessHeap(), 0, lpwzSrc);
1725 HeapFree(GetProcessHeap(), 0, lpwzDest);
1726 return ret;
1729 static void AsyncFtpRenameFileProc(WORKREQUEST *workRequest)
1731 struct WORKREQ_FTPRENAMEFILEW const *req = &workRequest->u.FtpRenameFileW;
1732 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1734 TRACE("%p\n", lpwfs);
1736 FTP_FtpRenameFileW(lpwfs, req->lpszSrcFile, req->lpszDestFile);
1737 HeapFree(GetProcessHeap(), 0, req->lpszSrcFile);
1738 HeapFree(GetProcessHeap(), 0, req->lpszDestFile);
1741 /***********************************************************************
1742 * FtpRenameFileW (WININET.@)
1744 * Rename a file on the ftp server
1746 * RETURNS
1747 * TRUE on success
1748 * FALSE on failure
1751 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
1753 LPWININETFTPSESSIONW lpwfs;
1754 LPWININETAPPINFOW hIC = NULL;
1755 BOOL r = FALSE;
1757 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1758 if (!lpwfs)
1760 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1761 return FALSE;
1764 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1766 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1767 goto lend;
1770 if (lpwfs->download_in_progress != NULL)
1772 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1773 goto lend;
1776 if (!lpszSrc || !lpszDest)
1778 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1779 goto lend;
1782 hIC = lpwfs->lpAppInfo;
1783 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1785 WORKREQUEST workRequest;
1786 struct WORKREQ_FTPRENAMEFILEW *req;
1788 workRequest.asyncproc = AsyncFtpRenameFileProc;
1789 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1790 req = &workRequest.u.FtpRenameFileW;
1791 req->lpszSrcFile = WININET_strdupW(lpszSrc);
1792 req->lpszDestFile = WININET_strdupW(lpszDest);
1794 r = INTERNET_AsyncCall(&workRequest);
1796 else
1798 r = FTP_FtpRenameFileW(lpwfs, lpszSrc, lpszDest);
1801 lend:
1802 WININET_Release( &lpwfs->hdr );
1804 return r;
1807 /***********************************************************************
1808 * FTP_FtpRenameFileW (Internal)
1810 * Rename a file on the ftp server
1812 * RETURNS
1813 * TRUE on success
1814 * FALSE on failure
1817 BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs,
1818 LPCWSTR lpszSrc, LPCWSTR lpszDest)
1820 INT nResCode;
1821 BOOL bSuccess = FALSE;
1822 LPWININETAPPINFOW hIC = NULL;
1824 TRACE("\n");
1826 /* Clear any error information */
1827 INTERNET_SetLastError(0);
1829 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1830 goto lend;
1832 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1833 if (nResCode == 350)
1835 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1836 goto lend;
1838 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1841 if (nResCode == 250)
1842 bSuccess = TRUE;
1843 else
1844 FTP_SetResponseError(nResCode);
1846 lend:
1847 hIC = lpwfs->lpAppInfo;
1848 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1850 INTERNET_ASYNC_RESULT iar;
1852 iar.dwResult = (DWORD)bSuccess;
1853 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1854 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1855 &iar, sizeof(INTERNET_ASYNC_RESULT));
1858 return bSuccess;
1861 /***********************************************************************
1862 * FtpCommandA (WININET.@)
1864 BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1865 LPCSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1867 BOOL r;
1868 WCHAR *cmdW;
1870 TRACE("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1871 debugstr_a(lpszCommand), dwContext, phFtpCommand);
1873 if (fExpectResponse)
1875 FIXME("data connection not supported\n");
1876 return FALSE;
1879 if (!lpszCommand || !lpszCommand[0])
1881 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1882 return FALSE;
1885 if (!(cmdW = WININET_strdup_AtoW(lpszCommand)))
1887 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1888 return FALSE;
1891 r = FtpCommandW(hConnect, fExpectResponse, dwFlags, cmdW, dwContext, phFtpCommand);
1893 HeapFree(GetProcessHeap(), 0, cmdW);
1894 return r;
1897 /***********************************************************************
1898 * FtpCommandW (WININET.@)
1900 BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1901 LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1903 BOOL r = FALSE;
1904 LPWININETFTPSESSIONW lpwfs;
1905 LPSTR cmd = NULL;
1906 DWORD len, nBytesSent= 0;
1907 INT nResCode, nRC = 0;
1909 TRACE("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1910 debugstr_w(lpszCommand), dwContext, phFtpCommand);
1912 if (!lpszCommand || !lpszCommand[0])
1914 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1915 return FALSE;
1918 if (fExpectResponse)
1920 FIXME("data connection not supported\n");
1921 return FALSE;
1924 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
1925 if (!lpwfs)
1927 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1928 return FALSE;
1931 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1933 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1934 goto lend;
1937 if (lpwfs->download_in_progress != NULL)
1939 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1940 goto lend;
1943 len = WideCharToMultiByte(CP_ACP, 0, lpszCommand, -1, NULL, 0, NULL, NULL) + strlen(szCRLF);
1944 if ((cmd = HeapAlloc(GetProcessHeap(), 0, len )))
1945 WideCharToMultiByte(CP_ACP, 0, lpszCommand, -1, cmd, len, NULL, NULL);
1946 else
1948 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1949 goto lend;
1952 strcat(cmd, szCRLF);
1953 len--;
1955 TRACE("Sending (%s) len(%d)\n", cmd, len);
1956 while ((nBytesSent < len) && (nRC != -1))
1958 nRC = send(lpwfs->sndSocket, cmd + nBytesSent, len - nBytesSent, 0);
1959 if (nRC != -1)
1961 nBytesSent += nRC;
1962 TRACE("Sent %d bytes\n", nRC);
1966 if (nBytesSent)
1968 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1969 if (nResCode > 0 && nResCode < 400)
1970 r = TRUE;
1971 else
1972 FTP_SetResponseError(nResCode);
1975 lend:
1976 WININET_Release( &lpwfs->hdr );
1977 HeapFree(GetProcessHeap(), 0, cmd);
1978 return r;
1981 /***********************************************************************
1982 * FTP_Connect (internal)
1984 * Connect to a ftp server
1986 * RETURNS
1987 * HINTERNET a session handle on success
1988 * NULL on failure
1990 * NOTES:
1992 * Windows uses 'anonymous' as the username, when given a NULL username
1993 * and a NULL password. The password is first looked up in:
1995 * HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\EmailName
1997 * If this entry is not present it uses the current username as the password.
2001 HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
2002 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
2003 LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext,
2004 DWORD dwInternalFlags)
2006 static const WCHAR szKey[] = {'S','o','f','t','w','a','r','e','\\',
2007 'M','i','c','r','o','s','o','f','t','\\',
2008 'W','i','n','d','o','w','s','\\',
2009 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2010 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
2011 static const WCHAR szValue[] = {'E','m','a','i','l','N','a','m','e',0};
2012 static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'};
2013 static const WCHAR szEmpty[] = {'\0'};
2014 struct sockaddr_in socketAddr;
2015 INT nsocket = -1;
2016 UINT sock_namelen;
2017 BOOL bSuccess = FALSE;
2018 LPWININETFTPSESSIONW lpwfs = NULL;
2019 HINTERNET handle = NULL;
2021 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
2022 hIC, debugstr_w(lpszServerName),
2023 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
2025 assert( hIC->hdr.htype == WH_HINIT );
2027 if (NULL == lpszUserName && NULL != lpszPassword)
2029 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2030 goto lerror;
2033 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
2034 if (NULL == lpwfs)
2036 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2037 goto lerror;
2040 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
2041 nServerPort = INTERNET_DEFAULT_FTP_PORT;
2043 lpwfs->hdr.htype = WH_HFTPSESSION;
2044 lpwfs->hdr.dwFlags = dwFlags;
2045 lpwfs->hdr.dwContext = dwContext;
2046 lpwfs->hdr.dwInternalFlags = dwInternalFlags;
2047 lpwfs->hdr.dwRefCount = 1;
2048 lpwfs->hdr.close_connection = FTP_CloseConnection;
2049 lpwfs->hdr.destroy = FTP_CloseSessionHandle;
2050 lpwfs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
2051 lpwfs->download_in_progress = NULL;
2053 WININET_AddRef( &hIC->hdr );
2054 lpwfs->lpAppInfo = hIC;
2055 list_add_head( &hIC->hdr.children, &lpwfs->hdr.entry );
2057 handle = WININET_AllocHandle( &lpwfs->hdr );
2058 if( !handle )
2060 ERR("Failed to alloc handle\n");
2061 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2062 goto lerror;
2065 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
2066 if(strchrW(hIC->lpszProxy, ' '))
2067 FIXME("Several proxies not implemented.\n");
2068 if(hIC->lpszProxyBypass)
2069 FIXME("Proxy bypass is ignored.\n");
2071 if ( !lpszUserName) {
2072 HKEY key;
2073 WCHAR szPassword[MAX_PATH];
2074 DWORD len = sizeof(szPassword);
2076 lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
2078 RegOpenKeyW(HKEY_CURRENT_USER, szKey, &key);
2079 if (RegQueryValueExW(key, szValue, NULL, NULL, (LPBYTE)szPassword, &len)) {
2080 /* Nothing in the registry, get the username and use that as the password */
2081 if (!GetUserNameW(szPassword, &len)) {
2082 /* Should never get here, but use an empty password as failsafe */
2083 strcpyW(szPassword, szEmpty);
2086 RegCloseKey(key);
2088 TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword));
2089 lpwfs->lpszPassword = WININET_strdupW(szPassword);
2091 else {
2092 lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
2094 if (lpszPassword)
2095 lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
2096 else
2097 lpwfs->lpszPassword = WININET_strdupW(szEmpty);
2100 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
2101 if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
2103 INTERNET_ASYNC_RESULT iar;
2105 iar.dwResult = (DWORD)handle;
2106 iar.dwError = ERROR_SUCCESS;
2108 SendAsyncCallback(&hIC->hdr, dwContext,
2109 INTERNET_STATUS_HANDLE_CREATED, &iar,
2110 sizeof(INTERNET_ASYNC_RESULT));
2113 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
2114 (LPWSTR) lpszServerName, strlenW(lpszServerName));
2116 if (!GetAddress(lpszServerName, nServerPort, &socketAddr))
2118 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
2119 goto lerror;
2122 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
2123 (LPWSTR) lpszServerName, strlenW(lpszServerName));
2125 nsocket = socket(AF_INET,SOCK_STREAM,0);
2126 if (nsocket == -1)
2128 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
2129 goto lerror;
2132 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
2133 &socketAddr, sizeof(struct sockaddr_in));
2135 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
2137 ERR("Unable to connect (%s)\n", strerror(errno));
2138 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
2140 else
2142 TRACE("Connected to server\n");
2143 lpwfs->sndSocket = nsocket;
2144 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
2145 &socketAddr, sizeof(struct sockaddr_in));
2147 sock_namelen = sizeof(lpwfs->socketAddress);
2148 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
2150 if (FTP_ConnectToHost(lpwfs))
2152 TRACE("Successfully logged into server\n");
2153 bSuccess = TRUE;
2157 lerror:
2158 if (lpwfs) WININET_Release( &lpwfs->hdr );
2160 if (!bSuccess && handle)
2162 WININET_FreeHandle( handle );
2163 handle = NULL;
2166 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2168 INTERNET_ASYNC_RESULT iar;
2170 iar.dwResult = bSuccess ? (DWORD_PTR)lpwfs : 0;
2171 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
2172 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
2173 &iar, sizeof(INTERNET_ASYNC_RESULT));
2176 return handle;
2180 /***********************************************************************
2181 * FTP_ConnectToHost (internal)
2183 * Connect to a ftp server
2185 * RETURNS
2186 * TRUE on success
2187 * NULL on failure
2190 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
2192 INT nResCode;
2193 BOOL bSuccess = FALSE;
2195 TRACE("\n");
2196 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2198 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
2199 goto lend;
2201 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2202 if (nResCode)
2204 /* Login successful... */
2205 if (nResCode == 230)
2206 bSuccess = TRUE;
2207 /* User name okay, need password... */
2208 else if (nResCode == 331)
2209 bSuccess = FTP_SendPassword(lpwfs);
2210 /* Need account for login... */
2211 else if (nResCode == 332)
2212 bSuccess = FTP_SendAccount(lpwfs);
2213 else
2214 FTP_SetResponseError(nResCode);
2217 TRACE("Returning %d\n", bSuccess);
2218 lend:
2219 return bSuccess;
2223 /***********************************************************************
2224 * FTP_SendCommandA (internal)
2226 * Send command to server
2228 * RETURNS
2229 * TRUE on success
2230 * NULL on failure
2233 static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
2234 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext)
2236 DWORD len;
2237 CHAR *buf;
2238 DWORD nBytesSent = 0;
2239 int nRC = 0;
2240 DWORD dwParamLen;
2242 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
2244 if (lpfnStatusCB)
2246 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
2249 dwParamLen = lpszParam?strlen(lpszParam)+1:0;
2250 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
2251 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
2253 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2254 return FALSE;
2256 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
2257 dwParamLen ? lpszParam : "", szCRLF);
2259 TRACE("Sending (%s) len(%d)\n", buf, len);
2260 while((nBytesSent < len) && (nRC != -1))
2262 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
2263 nBytesSent += nRC;
2266 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
2268 if (lpfnStatusCB)
2270 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_REQUEST_SENT,
2271 &nBytesSent, sizeof(DWORD));
2274 TRACE("Sent %d bytes\n", nBytesSent);
2275 return (nRC != -1);
2278 /***********************************************************************
2279 * FTP_SendCommand (internal)
2281 * Send command to server
2283 * RETURNS
2284 * TRUE on success
2285 * NULL on failure
2288 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
2289 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext)
2291 BOOL ret;
2292 LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
2293 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
2294 HeapFree(GetProcessHeap(), 0, lpszParamA);
2295 return ret;
2298 /***********************************************************************
2299 * FTP_ReceiveResponse (internal)
2301 * Receive response from server
2303 * RETURNS
2304 * Reply code on success
2305 * 0 on failure
2308 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD_PTR dwContext)
2310 LPSTR lpszResponse = INTERNET_GetResponseBuffer();
2311 DWORD nRecv;
2312 INT rc = 0;
2313 char firstprefix[5];
2314 BOOL multiline = FALSE;
2315 LPWININETAPPINFOW hIC = NULL;
2317 TRACE("socket(%d)\n", lpwfs->sndSocket);
2319 hIC = lpwfs->lpAppInfo;
2320 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2322 while(1)
2324 if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
2325 goto lerror;
2327 if (nRecv >= 3)
2329 if(!multiline)
2331 if(lpszResponse[3] != '-')
2332 break;
2333 else
2334 { /* Start of multiline repsonse. Loop until we get "nnn " */
2335 multiline = TRUE;
2336 memcpy(firstprefix, lpszResponse, 3);
2337 firstprefix[3] = ' ';
2338 firstprefix[4] = '\0';
2341 else
2343 if(!memcmp(firstprefix, lpszResponse, 4))
2344 break;
2349 if (nRecv >= 3)
2351 rc = atoi(lpszResponse);
2353 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2354 &nRecv, sizeof(DWORD));
2357 lerror:
2358 TRACE("return %d\n", rc);
2359 return rc;
2363 /***********************************************************************
2364 * FTP_SendPassword (internal)
2366 * Send password to ftp server
2368 * RETURNS
2369 * TRUE on success
2370 * NULL on failure
2373 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
2375 INT nResCode;
2376 BOOL bSuccess = FALSE;
2378 TRACE("\n");
2379 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
2380 goto lend;
2382 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2383 if (nResCode)
2385 TRACE("Received reply code %d\n", nResCode);
2386 /* Login successful... */
2387 if (nResCode == 230)
2388 bSuccess = TRUE;
2389 /* Command not implemented, superfluous at the server site... */
2390 /* Need account for login... */
2391 else if (nResCode == 332)
2392 bSuccess = FTP_SendAccount(lpwfs);
2393 else
2394 FTP_SetResponseError(nResCode);
2397 lend:
2398 TRACE("Returning %d\n", bSuccess);
2399 return bSuccess;
2403 /***********************************************************************
2404 * FTP_SendAccount (internal)
2408 * RETURNS
2409 * TRUE on success
2410 * FALSE on failure
2413 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
2415 INT nResCode;
2416 BOOL bSuccess = FALSE;
2418 TRACE("\n");
2419 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
2420 goto lend;
2422 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2423 if (nResCode)
2424 bSuccess = TRUE;
2425 else
2426 FTP_SetResponseError(nResCode);
2428 lend:
2429 return bSuccess;
2433 /***********************************************************************
2434 * FTP_SendStore (internal)
2436 * Send request to upload file to ftp server
2438 * RETURNS
2439 * TRUE on success
2440 * FALSE on failure
2443 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2445 INT nResCode;
2446 BOOL bSuccess = FALSE;
2448 TRACE("\n");
2449 if (!FTP_InitListenSocket(lpwfs))
2450 goto lend;
2452 if (!FTP_SendType(lpwfs, dwType))
2453 goto lend;
2455 if (!FTP_SendPortOrPasv(lpwfs))
2456 goto lend;
2458 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2459 goto lend;
2460 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2461 if (nResCode)
2463 if (nResCode == 150 || nResCode == 125)
2464 bSuccess = TRUE;
2465 else
2466 FTP_SetResponseError(nResCode);
2469 lend:
2470 if (!bSuccess && lpwfs->lstnSocket != -1)
2472 closesocket(lpwfs->lstnSocket);
2473 lpwfs->lstnSocket = -1;
2476 return bSuccess;
2480 /***********************************************************************
2481 * FTP_InitListenSocket (internal)
2483 * Create a socket to listen for server response
2485 * RETURNS
2486 * TRUE on success
2487 * FALSE on failure
2490 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
2492 BOOL bSuccess = FALSE;
2493 socklen_t namelen = sizeof(struct sockaddr_in);
2495 TRACE("\n");
2497 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2498 if (lpwfs->lstnSocket == -1)
2500 TRACE("Unable to create listening socket\n");
2501 goto lend;
2504 /* We obtain our ip addr from the name of the command channel socket */
2505 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2507 /* and get the system to assign us a port */
2508 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
2510 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
2512 TRACE("Unable to bind socket\n");
2513 goto lend;
2516 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2518 TRACE("listen failed\n");
2519 goto lend;
2522 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2523 bSuccess = TRUE;
2525 lend:
2526 if (!bSuccess && lpwfs->lstnSocket != -1)
2528 closesocket(lpwfs->lstnSocket);
2529 lpwfs->lstnSocket = -1;
2532 return bSuccess;
2536 /***********************************************************************
2537 * FTP_SendType (internal)
2539 * Tell server type of data being transferred
2541 * RETURNS
2542 * TRUE on success
2543 * FALSE on failure
2545 * W98SE doesn't cache the type that's currently set
2546 * (i.e. it sends it always),
2547 * so we probably don't want to do that either.
2549 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
2551 INT nResCode;
2552 WCHAR type[] = { 'I','\0' };
2553 BOOL bSuccess = FALSE;
2555 TRACE("\n");
2556 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2557 type[0] = 'A';
2559 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2560 goto lend;
2562 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2563 if (nResCode)
2565 if (nResCode == 2)
2566 bSuccess = TRUE;
2567 else
2568 FTP_SetResponseError(nResCode);
2571 lend:
2572 return bSuccess;
2576 #if 0 /* FIXME: should probably be used for FtpGetFileSize */
2577 /***********************************************************************
2578 * FTP_GetFileSize (internal)
2580 * Retrieves from the server the size of the given file
2582 * RETURNS
2583 * TRUE on success
2584 * FALSE on failure
2587 static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
2589 INT nResCode;
2590 BOOL bSuccess = FALSE;
2592 TRACE("\n");
2594 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2595 goto lend;
2597 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2598 if (nResCode)
2600 if (nResCode == 213) {
2601 /* Now parses the output to get the actual file size */
2602 int i;
2603 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2605 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2606 if (lpszResponseBuffer[i] == '\0') return FALSE;
2607 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2609 bSuccess = TRUE;
2610 } else {
2611 FTP_SetResponseError(nResCode);
2615 lend:
2616 return bSuccess;
2618 #endif
2621 /***********************************************************************
2622 * FTP_SendPort (internal)
2624 * Tell server which port to use
2626 * RETURNS
2627 * TRUE on success
2628 * FALSE on failure
2631 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
2633 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2634 INT nResCode;
2635 WCHAR szIPAddress[64];
2636 BOOL bSuccess = FALSE;
2637 TRACE("\n");
2639 sprintfW(szIPAddress, szIPFormat,
2640 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2641 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2642 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2643 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2644 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2645 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2647 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2648 goto lend;
2650 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2651 if (nResCode)
2653 if (nResCode == 200)
2654 bSuccess = TRUE;
2655 else
2656 FTP_SetResponseError(nResCode);
2659 lend:
2660 return bSuccess;
2664 /***********************************************************************
2665 * FTP_DoPassive (internal)
2667 * Tell server that we want to do passive transfers
2668 * and connect data socket
2670 * RETURNS
2671 * TRUE on success
2672 * FALSE on failure
2675 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
2677 INT nResCode;
2678 BOOL bSuccess = FALSE;
2680 TRACE("\n");
2681 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2682 goto lend;
2684 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2685 if (nResCode)
2687 if (nResCode == 227)
2689 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2690 LPSTR p;
2691 int f[6];
2692 int i;
2693 char *pAddr, *pPort;
2694 INT nsocket = -1;
2695 struct sockaddr_in dataSocketAddress;
2697 p = lpszResponseBuffer+4; /* skip status code */
2698 while (*p != '\0' && (*p < '0' || *p > '9')) p++;
2700 if (*p == '\0')
2702 ERR("no address found in response, aborting\n");
2703 goto lend;
2706 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2707 &f[4], &f[5]) != 6)
2709 ERR("unknown response address format '%s', aborting\n", p);
2710 goto lend;
2712 for (i=0; i < 6; i++)
2713 f[i] = f[i] & 0xff;
2715 dataSocketAddress = lpwfs->socketAddress;
2716 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2717 pPort = (char *)&(dataSocketAddress.sin_port);
2718 pAddr[0] = f[0];
2719 pAddr[1] = f[1];
2720 pAddr[2] = f[2];
2721 pAddr[3] = f[3];
2722 pPort[0] = f[4];
2723 pPort[1] = f[5];
2725 nsocket = socket(AF_INET,SOCK_STREAM,0);
2726 if (nsocket == -1)
2727 goto lend;
2729 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2731 ERR("can't connect passive FTP data port.\n");
2732 closesocket(nsocket);
2733 goto lend;
2735 lpwfs->pasvSocket = nsocket;
2736 bSuccess = TRUE;
2738 else
2739 FTP_SetResponseError(nResCode);
2742 lend:
2743 return bSuccess;
2747 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
2749 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2751 if (!FTP_DoPassive(lpwfs))
2752 return FALSE;
2754 else
2756 if (!FTP_SendPort(lpwfs))
2757 return FALSE;
2759 return TRUE;
2763 /***********************************************************************
2764 * FTP_GetDataSocket (internal)
2766 * Either accepts an incoming data socket connection from the server
2767 * or just returns the already opened socket after a PASV command
2768 * in case of passive FTP.
2771 * RETURNS
2772 * TRUE on success
2773 * FALSE on failure
2776 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
2778 struct sockaddr_in saddr;
2779 socklen_t addrlen = sizeof(struct sockaddr);
2781 TRACE("\n");
2782 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2784 *nDataSocket = lpwfs->pasvSocket;
2786 else
2788 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2789 closesocket(lpwfs->lstnSocket);
2790 lpwfs->lstnSocket = -1;
2792 return *nDataSocket != -1;
2796 /***********************************************************************
2797 * FTP_SendData (internal)
2799 * Send data to the server
2801 * RETURNS
2802 * TRUE on success
2803 * FALSE on failure
2806 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2808 BY_HANDLE_FILE_INFORMATION fi;
2809 DWORD nBytesRead = 0;
2810 DWORD nBytesSent = 0;
2811 DWORD nTotalSent = 0;
2812 DWORD nBytesToSend, nLen;
2813 int nRC = 1;
2814 time_t s_long_time, e_long_time;
2815 LONG nSeconds;
2816 CHAR *lpszBuffer;
2818 TRACE("\n");
2819 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2821 /* Get the size of the file. */
2822 GetFileInformationByHandle(hFile, &fi);
2823 time(&s_long_time);
2827 nBytesToSend = nBytesRead - nBytesSent;
2829 if (nBytesToSend <= 0)
2831 /* Read data from file. */
2832 nBytesSent = 0;
2833 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2834 ERR("Failed reading from file\n");
2836 if (nBytesRead > 0)
2837 nBytesToSend = nBytesRead;
2838 else
2839 break;
2842 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2843 DATA_PACKET_SIZE : nBytesToSend;
2844 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2846 if (nRC != -1)
2848 nBytesSent += nRC;
2849 nTotalSent += nRC;
2852 /* Do some computation to display the status. */
2853 time(&e_long_time);
2854 nSeconds = e_long_time - s_long_time;
2855 if( nSeconds / 60 > 0 )
2857 TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n",
2858 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2859 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2861 else
2863 TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n",
2864 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2865 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2867 } while (nRC != -1);
2869 TRACE("file transfer complete!\n");
2871 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2873 return nTotalSent;
2877 /***********************************************************************
2878 * FTP_SendRetrieve (internal)
2880 * Send request to retrieve a file
2882 * RETURNS
2883 * Number of bytes to be received on success
2884 * 0 on failure
2887 static BOOL FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2889 INT nResCode;
2890 BOOL ret;
2892 TRACE("\n");
2893 if (!(ret = FTP_InitListenSocket(lpwfs)))
2894 goto lend;
2896 if (!(ret = FTP_SendType(lpwfs, dwType)))
2897 goto lend;
2899 if (!(ret = FTP_SendPortOrPasv(lpwfs)))
2900 goto lend;
2902 if (!(ret = FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0)))
2903 goto lend;
2905 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2906 if ((nResCode != 125) && (nResCode != 150)) {
2907 /* That means that we got an error getting the file. */
2908 FTP_SetResponseError(nResCode);
2909 ret = FALSE;
2912 lend:
2913 if (!ret && lpwfs->lstnSocket != -1)
2915 closesocket(lpwfs->lstnSocket);
2916 lpwfs->lstnSocket = -1;
2919 return ret;
2923 /***********************************************************************
2924 * FTP_RetrieveData (internal)
2926 * Retrieve data from server
2928 * RETURNS
2929 * TRUE on success
2930 * FALSE on failure
2933 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2935 DWORD nBytesWritten;
2936 DWORD nBytesReceived = 0;
2937 INT nRC = 0;
2938 CHAR *lpszBuffer;
2940 TRACE("\n");
2942 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2943 if (NULL == lpszBuffer)
2945 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2946 return FALSE;
2949 while (nRC != -1)
2951 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2952 if (nRC != -1)
2954 /* other side closed socket. */
2955 if (nRC == 0)
2956 goto recv_end;
2957 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2958 nBytesReceived += nRC;
2962 TRACE("Data transfer complete\n");
2964 recv_end:
2965 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2967 return (nRC != -1);
2970 /***********************************************************************
2971 * FTP_CloseConnection (internal)
2973 * Close connections
2975 static void FTP_CloseConnection(LPWININETHANDLEHEADER hdr)
2977 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2979 TRACE("\n");
2981 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext,
2982 INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
2984 if (lpwfs->download_in_progress != NULL)
2985 lpwfs->download_in_progress->session_deleted = TRUE;
2987 if (lpwfs->sndSocket != -1)
2988 closesocket(lpwfs->sndSocket);
2990 if (lpwfs->lstnSocket != -1)
2991 closesocket(lpwfs->lstnSocket);
2993 if (lpwfs->pasvSocket != -1)
2994 closesocket(lpwfs->pasvSocket);
2996 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext,
2997 INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
3001 /***********************************************************************
3002 * FTP_CloseSessionHandle (internal)
3004 * Deallocate session handle
3006 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr)
3008 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
3010 TRACE("\n");
3012 WININET_Release(&lpwfs->lpAppInfo->hdr);
3014 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
3015 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
3016 HeapFree(GetProcessHeap(), 0, lpwfs);
3020 /***********************************************************************
3021 * FTP_FindNextFileW (Internal)
3023 * Continues a file search from a previous call to FindFirstFile
3025 * RETURNS
3026 * TRUE on success
3027 * FALSE on failure
3030 BOOL WINAPI FTP_FindNextFileW(LPWININETFTPFINDNEXTW lpwh, LPVOID lpvFindData)
3032 BOOL bSuccess = TRUE;
3033 LPWIN32_FIND_DATAW lpFindFileData;
3035 TRACE("index(%d) size(%d)\n", lpwh->index, lpwh->size);
3037 assert (lpwh->hdr.htype == WH_HFTPFINDNEXT);
3039 /* Clear any error information */
3040 INTERNET_SetLastError(0);
3042 lpFindFileData = (LPWIN32_FIND_DATAW) lpvFindData;
3043 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
3045 if (lpwh->index >= lpwh->size)
3047 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3048 bSuccess = FALSE;
3049 goto lend;
3052 FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
3053 lpwh->index++;
3055 TRACE("\nName: %s\nSize: %d\n", debugstr_w(lpFindFileData->cFileName), lpFindFileData->nFileSizeLow);
3057 lend:
3059 if (lpwh->hdr.dwFlags & INTERNET_FLAG_ASYNC)
3061 INTERNET_ASYNC_RESULT iar;
3063 iar.dwResult = (DWORD)bSuccess;
3064 iar.dwError = iar.dwError = bSuccess ? ERROR_SUCCESS :
3065 INTERNET_GetLastError();
3067 INTERNET_SendCallback(&lpwh->hdr, lpwh->hdr.dwContext,
3068 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
3069 sizeof(INTERNET_ASYNC_RESULT));
3072 return bSuccess;
3076 /***********************************************************************
3077 * FTP_CloseFindNextHandle (internal)
3079 * Deallocate session handle
3081 * RETURNS
3082 * TRUE on success
3083 * FALSE on failure
3086 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr)
3088 LPWININETFTPFINDNEXTW lpwfn = (LPWININETFTPFINDNEXTW) hdr;
3089 DWORD i;
3091 TRACE("\n");
3093 WININET_Release(&lpwfn->lpFtpSession->hdr);
3095 for (i = 0; i < lpwfn->size; i++)
3097 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
3100 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
3101 HeapFree(GetProcessHeap(), 0, lpwfn);
3104 /***********************************************************************
3105 * FTP_CloseFileTransferHandle (internal)
3107 * Closes the file transfer handle. This also 'cleans' the data queue of
3108 * the 'transfer complete' message (this is a bit of a hack though :-/ )
3111 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr)
3113 LPWININETFTPFILE lpwh = (LPWININETFTPFILE) hdr;
3114 LPWININETFTPSESSIONW lpwfs = lpwh->lpFtpSession;
3115 INT nResCode;
3117 TRACE("\n");
3119 WININET_Release(&lpwh->lpFtpSession->hdr);
3121 if (!lpwh->session_deleted)
3122 lpwfs->download_in_progress = NULL;
3124 if (lpwh->nDataSocket != -1)
3125 closesocket(lpwh->nDataSocket);
3127 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
3128 if (nResCode > 0 && nResCode != 226) WARN("server reports failed transfer\n");
3130 HeapFree(GetProcessHeap(), 0, lpwh);
3133 /***********************************************************************
3134 * FTP_ReceiveFileList (internal)
3136 * Read file list from server
3138 * RETURNS
3139 * Handle to file list on success
3140 * NULL on failure
3143 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3144 LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext)
3146 DWORD dwSize = 0;
3147 LPFILEPROPERTIESW lpafp = NULL;
3148 LPWININETFTPFINDNEXTW lpwfn = NULL;
3149 HINTERNET handle = 0;
3151 TRACE("(%p,%d,%s,%p,%08lx)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
3153 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
3155 if(lpFindFileData)
3156 FTP_ConvertFileProp(lpafp, lpFindFileData);
3158 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFTPFINDNEXTW));
3159 if (lpwfn)
3161 lpwfn->hdr.htype = WH_HFTPFINDNEXT;
3162 lpwfn->hdr.dwContext = dwContext;
3163 lpwfn->hdr.dwRefCount = 1;
3164 lpwfn->hdr.close_connection = NULL;
3165 lpwfn->hdr.destroy = FTP_CloseFindNextHandle;
3166 lpwfn->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
3167 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
3168 lpwfn->size = dwSize;
3169 lpwfn->lpafp = lpafp;
3171 WININET_AddRef( &lpwfs->hdr );
3172 lpwfn->lpFtpSession = lpwfs;
3173 list_add_head( &lpwfs->hdr.children, &lpwfn->hdr.entry );
3175 handle = WININET_AllocHandle( &lpwfn->hdr );
3179 if( lpwfn )
3180 WININET_Release( &lpwfn->hdr );
3182 TRACE("Matched %d files\n", dwSize);
3183 return handle;
3187 /***********************************************************************
3188 * FTP_ConvertFileProp (internal)
3190 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
3192 * RETURNS
3193 * TRUE on success
3194 * FALSE on failure
3197 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
3199 BOOL bSuccess = FALSE;
3201 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
3203 if (lpafp)
3205 /* Convert 'Unix' time to Windows time */
3206 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
3207 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
3208 lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime;
3209 lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime;
3211 /* Not all fields are filled in */
3212 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
3213 lpFindFileData->nFileSizeLow = lpafp->nSize;
3215 if (lpafp->bIsDirectory)
3216 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
3218 if (lpafp->lpszName)
3219 lstrcpynW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
3221 bSuccess = TRUE;
3224 return bSuccess;
3227 /***********************************************************************
3228 * FTP_ParseNextFile (internal)
3230 * Parse the next line in file listing
3232 * RETURNS
3233 * TRUE on success
3234 * FALSE on failure
3236 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
3238 static const char szSpace[] = " \t";
3239 DWORD nBufLen;
3240 char *pszLine;
3241 char *pszToken;
3242 char *pszTmp;
3243 BOOL found = FALSE;
3244 int i;
3246 lpfp->lpszName = NULL;
3247 do {
3248 if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
3249 return FALSE;
3251 pszToken = strtok(pszLine, szSpace);
3252 /* ls format
3253 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
3255 * For instance:
3256 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
3258 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
3259 if(!FTP_ParsePermission(pszToken, lpfp))
3260 lpfp->bIsDirectory = FALSE;
3261 for(i=0; i<=3; i++) {
3262 if(!(pszToken = strtok(NULL, szSpace)))
3263 break;
3265 if(!pszToken) continue;
3266 if(lpfp->bIsDirectory) {
3267 TRACE("Is directory\n");
3268 lpfp->nSize = 0;
3270 else {
3271 TRACE("Size: %s\n", pszToken);
3272 lpfp->nSize = atol(pszToken);
3275 lpfp->tmLastModified.tm_sec = 0;
3276 lpfp->tmLastModified.tm_min = 0;
3277 lpfp->tmLastModified.tm_hour = 0;
3278 lpfp->tmLastModified.tm_mday = 0;
3279 lpfp->tmLastModified.tm_mon = 0;
3280 lpfp->tmLastModified.tm_year = 0;
3282 /* Determine month */
3283 pszToken = strtok(NULL, szSpace);
3284 if(!pszToken) continue;
3285 if(strlen(pszToken) >= 3) {
3286 pszToken[3] = 0;
3287 if((pszTmp = StrStrIA(szMonths, pszToken)))
3288 lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
3290 /* Determine day */
3291 pszToken = strtok(NULL, szSpace);
3292 if(!pszToken) continue;
3293 lpfp->tmLastModified.tm_mday = atoi(pszToken);
3294 /* Determine time or year */
3295 pszToken = strtok(NULL, szSpace);
3296 if(!pszToken) continue;
3297 if((pszTmp = strchr(pszToken, ':'))) {
3298 struct tm* apTM;
3299 time_t aTime;
3300 *pszTmp = 0;
3301 pszTmp++;
3302 lpfp->tmLastModified.tm_min = atoi(pszTmp);
3303 lpfp->tmLastModified.tm_hour = atoi(pszToken);
3304 time(&aTime);
3305 apTM = localtime(&aTime);
3306 lpfp->tmLastModified.tm_year = apTM->tm_year;
3308 else {
3309 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
3310 lpfp->tmLastModified.tm_hour = 12;
3312 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3313 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3314 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3315 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3317 pszToken = strtok(NULL, szSpace);
3318 if(!pszToken) continue;
3319 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3320 TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
3322 /* NT way of parsing ... :
3324 07-13-03 08:55PM <DIR> sakpatch
3325 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
3327 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
3328 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
3330 sscanf(pszToken, "%d-%d-%d",
3331 &lpfp->tmLastModified.tm_mon,
3332 &lpfp->tmLastModified.tm_mday,
3333 &lpfp->tmLastModified.tm_year);
3335 /* Hacky and bad Y2K protection :-) */
3336 if (lpfp->tmLastModified.tm_year < 70)
3337 lpfp->tmLastModified.tm_year += 100;
3339 pszToken = strtok(NULL, szSpace);
3340 if(!pszToken) continue;
3341 sscanf(pszToken, "%d:%d",
3342 &lpfp->tmLastModified.tm_hour,
3343 &lpfp->tmLastModified.tm_min);
3344 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
3345 lpfp->tmLastModified.tm_hour += 12;
3347 lpfp->tmLastModified.tm_sec = 0;
3349 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3350 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3351 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3352 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3354 pszToken = strtok(NULL, szSpace);
3355 if(!pszToken) continue;
3356 if(!strcasecmp(pszToken, "<DIR>")) {
3357 lpfp->bIsDirectory = TRUE;
3358 lpfp->nSize = 0;
3359 TRACE("Is directory\n");
3361 else {
3362 lpfp->bIsDirectory = FALSE;
3363 lpfp->nSize = atol(pszToken);
3364 TRACE("Size: %d\n", lpfp->nSize);
3367 pszToken = strtok(NULL, szSpace);
3368 if(!pszToken) continue;
3369 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3370 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
3372 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
3373 else if(pszToken[0] == '+') {
3374 FIXME("EPLF Format not implemented\n");
3377 if(lpfp->lpszName) {
3378 if((lpszSearchFile == NULL) ||
3379 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
3380 found = TRUE;
3381 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
3383 else {
3384 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
3385 lpfp->lpszName = NULL;
3388 } while(!found);
3389 return TRUE;
3392 /***********************************************************************
3393 * FTP_ParseDirectory (internal)
3395 * Parse string of directory information
3397 * RETURNS
3398 * TRUE on success
3399 * FALSE on failure
3401 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3402 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
3404 BOOL bSuccess = TRUE;
3405 INT sizeFilePropArray = 500;/*20; */
3406 INT indexFilePropArray = -1;
3408 TRACE("\n");
3410 /* Allocate intial file properties array */
3411 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
3412 if (!*lpafp)
3413 return FALSE;
3415 do {
3416 if (indexFilePropArray+1 >= sizeFilePropArray)
3418 LPFILEPROPERTIESW tmpafp;
3420 sizeFilePropArray *= 2;
3421 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
3422 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
3423 if (NULL == tmpafp)
3425 bSuccess = FALSE;
3426 break;
3429 *lpafp = tmpafp;
3431 indexFilePropArray++;
3432 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
3434 if (bSuccess && indexFilePropArray)
3436 if (indexFilePropArray < sizeFilePropArray - 1)
3438 LPFILEPROPERTIESW tmpafp;
3440 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
3441 sizeof(FILEPROPERTIESW)*indexFilePropArray);
3442 if (NULL == tmpafp)
3443 *lpafp = tmpafp;
3445 *dwfp = indexFilePropArray;
3447 else
3449 HeapFree(GetProcessHeap(), 0, *lpafp);
3450 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3451 bSuccess = FALSE;
3454 return bSuccess;
3458 /***********************************************************************
3459 * FTP_ParsePermission (internal)
3461 * Parse permission string of directory information
3463 * RETURNS
3464 * TRUE on success
3465 * FALSE on failure
3468 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3470 BOOL bSuccess = TRUE;
3471 unsigned short nPermission = 0;
3472 INT nPos = 1;
3473 INT nLast = 9;
3475 TRACE("\n");
3476 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3478 bSuccess = FALSE;
3479 return bSuccess;
3482 lpfp->bIsDirectory = (*lpszPermission == 'd');
3485 switch (nPos)
3487 case 1:
3488 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3489 break;
3490 case 2:
3491 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3492 break;
3493 case 3:
3494 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3495 break;
3496 case 4:
3497 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3498 break;
3499 case 5:
3500 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3501 break;
3502 case 6:
3503 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3504 break;
3505 case 7:
3506 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3507 break;
3508 case 8:
3509 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3510 break;
3511 case 9:
3512 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3513 break;
3515 nPos++;
3516 }while (nPos <= nLast);
3518 lpfp->permissions = nPermission;
3519 return bSuccess;
3523 /***********************************************************************
3524 * FTP_SetResponseError (internal)
3526 * Set the appropriate error code for a given response from the server
3528 * RETURNS
3531 static DWORD FTP_SetResponseError(DWORD dwResponse)
3533 DWORD dwCode = 0;
3535 switch(dwResponse)
3537 case 425: /* Cannot open data connection. */
3538 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3539 break;
3541 case 426: /* Connection closed, transer aborted. */
3542 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3543 break;
3545 case 530: /* Not logged in. Login incorrect. */
3546 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3547 break;
3549 case 421: /* Service not available - Server may be shutting down. */
3550 case 450: /* File action not taken. File may be busy. */
3551 case 451: /* Action aborted. Server error. */
3552 case 452: /* Action not taken. Insufficient storage space on server. */
3553 case 500: /* Syntax error. Command unrecognized. */
3554 case 501: /* Syntax error. Error in parameters or arguments. */
3555 case 502: /* Command not implemented. */
3556 case 503: /* Bad sequence of commands. */
3557 case 504: /* Command not implemented for that parameter. */
3558 case 532: /* Need account for storing files */
3559 case 550: /* File action not taken. File not found or no access. */
3560 case 551: /* Requested action aborted. Page type unknown */
3561 case 552: /* Action aborted. Exceeded storage allocation */
3562 case 553: /* Action not taken. File name not allowed. */
3564 default:
3565 dwCode = ERROR_INTERNET_EXTENDED_ERROR;
3566 break;
3569 INTERNET_SetLastError(dwCode);
3570 return dwCode;