wininet: ftp: 125 is an acceptable response code for the STORE command.
[wine/multimedia.git] / dlls / wininet / ftp.c
blob828f1e596fdf8871a25bb4b405394cfbc4da5760
1 /*
2 * WININET - Ftp implementation
4 * Copyright 1999 Corel Corporation
5 * Copyright 2004 Mike McCormack for CodeWeavers
6 * Copyright 2004 Kevin Koltzau
8 * Ulrich Czekalla
9 * Noureddine Jemmali
11 * Copyright 2000 Andreas Mohr
12 * Copyright 2002 Jaco Greeff
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "config.h"
30 #include "wine/port.h"
32 #include <errno.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/types.h>
38 #ifdef HAVE_SYS_SOCKET_H
39 # include <sys/socket.h>
40 #endif
41 #ifdef HAVE_UNISTD_H
42 # include <unistd.h>
43 #endif
44 #include <time.h>
45 #include <assert.h>
47 #include "windef.h"
48 #include "winbase.h"
49 #include "wingdi.h"
50 #include "winuser.h"
51 #include "wininet.h"
52 #include "winnls.h"
53 #include "winerror.h"
54 #include "winreg.h"
55 #include "winternl.h"
56 #include "shlwapi.h"
58 #include "wine/debug.h"
59 #include "internet.h"
61 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
63 #define DATA_PACKET_SIZE 0x2000
64 #define szCRLF "\r\n"
65 #define MAX_BACKLOG 5
67 typedef enum {
68 /* FTP commands with arguments. */
69 FTP_CMD_ACCT,
70 FTP_CMD_CWD,
71 FTP_CMD_DELE,
72 FTP_CMD_MKD,
73 FTP_CMD_PASS,
74 FTP_CMD_PORT,
75 FTP_CMD_RETR,
76 FTP_CMD_RMD,
77 FTP_CMD_RNFR,
78 FTP_CMD_RNTO,
79 FTP_CMD_STOR,
80 FTP_CMD_TYPE,
81 FTP_CMD_USER,
82 FTP_CMD_SIZE,
84 /* FTP commands without arguments. */
85 FTP_CMD_ABOR,
86 FTP_CMD_LIST,
87 FTP_CMD_NLST,
88 FTP_CMD_PASV,
89 FTP_CMD_PWD,
90 FTP_CMD_QUIT,
91 } FTP_COMMAND;
93 static const CHAR *szFtpCommands[] = {
94 "ACCT",
95 "CWD",
96 "DELE",
97 "MKD",
98 "PASS",
99 "PORT",
100 "RETR",
101 "RMD",
102 "RNFR",
103 "RNTO",
104 "STOR",
105 "TYPE",
106 "USER",
107 "SIZE",
108 "ABOR",
109 "LIST",
110 "NLST",
111 "PASV",
112 "PWD",
113 "QUIT",
116 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
117 static const WCHAR szNoAccount[] = {'n','o','a','c','c','o','u','n','t','\0'};
119 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr);
120 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr);
121 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr);
122 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
123 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext);
124 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
125 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket);
126 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile);
127 static INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext);
128 static DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
129 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile);
130 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs);
131 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs);
132 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs);
133 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs);
134 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType);
135 static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize);
136 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs);
137 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs);
138 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs);
139 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp);
140 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW fileprop);
141 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
142 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp);
143 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
144 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext);
145 static DWORD FTP_SetResponseError(DWORD dwResponse);
147 /***********************************************************************
148 * FtpPutFileA (WININET.@)
150 * Uploads a file to the FTP server
152 * RETURNS
153 * TRUE on success
154 * FALSE on failure
157 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
158 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
160 LPWSTR lpwzLocalFile;
161 LPWSTR lpwzNewRemoteFile;
162 BOOL ret;
164 lpwzLocalFile = lpszLocalFile?WININET_strdup_AtoW(lpszLocalFile):NULL;
165 lpwzNewRemoteFile = lpszNewRemoteFile?WININET_strdup_AtoW(lpszNewRemoteFile):NULL;
166 ret = FtpPutFileW(hConnect, lpwzLocalFile, lpwzNewRemoteFile,
167 dwFlags, dwContext);
168 HeapFree(GetProcessHeap(), 0, lpwzLocalFile);
169 HeapFree(GetProcessHeap(), 0, lpwzNewRemoteFile);
170 return ret;
173 /***********************************************************************
174 * FtpPutFileW (WININET.@)
176 * Uploads a file to the FTP server
178 * RETURNS
179 * TRUE on success
180 * FALSE on failure
183 BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile,
184 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
186 LPWININETFTPSESSIONW lpwfs;
187 LPWININETAPPINFOW hIC = NULL;
188 BOOL r = FALSE;
190 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
191 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
193 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
194 goto lend;
197 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
198 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
200 WORKREQUEST workRequest;
201 struct WORKREQ_FTPPUTFILEW *req = &workRequest.u.FtpPutFileW;
203 workRequest.asyncall = FTPPUTFILEW;
204 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
205 req->lpszLocalFile = WININET_strdupW(lpszLocalFile);
206 req->lpszNewRemoteFile = WININET_strdupW(lpszNewRemoteFile);
207 req->dwFlags = dwFlags;
208 req->dwContext = dwContext;
210 r = INTERNET_AsyncCall(&workRequest);
212 else
214 r = FTP_FtpPutFileW(lpwfs, lpszLocalFile,
215 lpszNewRemoteFile, dwFlags, dwContext);
218 lend:
219 if( lpwfs )
220 WININET_Release( &lpwfs->hdr );
222 return r;
225 /***********************************************************************
226 * FTP_FtpPutFileW (Internal)
228 * Uploads a file to the FTP server
230 * RETURNS
231 * TRUE on success
232 * FALSE on failure
235 BOOL WINAPI FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile,
236 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
238 HANDLE hFile = NULL;
239 BOOL bSuccess = FALSE;
240 LPWININETAPPINFOW hIC = NULL;
241 INT nResCode;
243 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", debugstr_w(lpszLocalFile), debugstr_w(lpszNewRemoteFile));
245 if (!lpszLocalFile || !lpszNewRemoteFile)
247 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
248 return FALSE;
251 assert( WH_HFTPSESSION == lpwfs->hdr.htype);
253 /* Clear any error information */
254 INTERNET_SetLastError(0);
255 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
257 /* Open file to be uploaded */
258 if (INVALID_HANDLE_VALUE ==
259 (hFile = CreateFileW(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
261 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND);
262 goto lend;
265 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
267 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
269 INT nDataSocket;
271 /* Get data socket to server */
272 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
274 FTP_SendData(lpwfs, nDataSocket, hFile);
275 closesocket(nDataSocket);
276 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
277 if (nResCode)
279 if (nResCode == 226)
280 bSuccess = TRUE;
281 else
282 FTP_SetResponseError(nResCode);
287 lend:
288 if (lpwfs->lstnSocket != -1)
289 closesocket(lpwfs->lstnSocket);
291 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
293 INTERNET_ASYNC_RESULT iar;
295 iar.dwResult = (DWORD)bSuccess;
296 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
297 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
298 &iar, sizeof(INTERNET_ASYNC_RESULT));
301 if (hFile)
302 CloseHandle(hFile);
304 return bSuccess;
308 /***********************************************************************
309 * FtpSetCurrentDirectoryA (WININET.@)
311 * Change the working directory on the FTP server
313 * RETURNS
314 * TRUE on success
315 * FALSE on failure
318 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
320 LPWSTR lpwzDirectory;
321 BOOL ret;
323 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
324 ret = FtpSetCurrentDirectoryW(hConnect, lpwzDirectory);
325 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
326 return ret;
330 /***********************************************************************
331 * FtpSetCurrentDirectoryW (WININET.@)
333 * Change the working directory on the FTP server
335 * RETURNS
336 * TRUE on success
337 * FALSE on failure
340 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
342 LPWININETFTPSESSIONW lpwfs = NULL;
343 LPWININETAPPINFOW hIC = NULL;
344 BOOL r = FALSE;
346 if (!lpszDirectory)
348 SetLastError(ERROR_INVALID_PARAMETER);
349 goto lend;
352 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
353 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
355 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
356 goto lend;
359 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
361 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
362 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
364 WORKREQUEST workRequest;
365 struct WORKREQ_FTPSETCURRENTDIRECTORYW *req;
367 workRequest.asyncall = FTPSETCURRENTDIRECTORYW;
368 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
369 req = &workRequest.u.FtpSetCurrentDirectoryW;
370 req->lpszDirectory = WININET_strdupW(lpszDirectory);
372 r = INTERNET_AsyncCall(&workRequest);
374 else
376 r = FTP_FtpSetCurrentDirectoryW(lpwfs, lpszDirectory);
379 lend:
380 if( lpwfs )
381 WININET_Release( &lpwfs->hdr );
383 return r;
387 /***********************************************************************
388 * FTP_FtpSetCurrentDirectoryW (Internal)
390 * Change the working directory on the FTP server
392 * RETURNS
393 * TRUE on success
394 * FALSE on failure
397 BOOL WINAPI FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
399 INT nResCode;
400 LPWININETAPPINFOW hIC = NULL;
401 DWORD bSuccess = FALSE;
403 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
405 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
407 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
408 return FALSE;
411 /* Clear any error information */
412 INTERNET_SetLastError(0);
414 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
415 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
416 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
417 goto lend;
419 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
421 if (nResCode)
423 if (nResCode == 250)
424 bSuccess = TRUE;
425 else
426 FTP_SetResponseError(nResCode);
429 lend:
430 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
432 INTERNET_ASYNC_RESULT iar;
434 iar.dwResult = (DWORD)bSuccess;
435 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
436 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
437 &iar, sizeof(INTERNET_ASYNC_RESULT));
439 return bSuccess;
443 /***********************************************************************
444 * FtpCreateDirectoryA (WININET.@)
446 * Create new directory on the FTP server
448 * RETURNS
449 * TRUE on success
450 * FALSE on failure
453 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
455 LPWSTR lpwzDirectory;
456 BOOL ret;
458 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
459 ret = FtpCreateDirectoryW(hConnect, lpwzDirectory);
460 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
461 return ret;
465 /***********************************************************************
466 * FtpCreateDirectoryW (WININET.@)
468 * Create new directory on the FTP server
470 * RETURNS
471 * TRUE on success
472 * FALSE on failure
475 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
477 LPWININETFTPSESSIONW lpwfs;
478 LPWININETAPPINFOW hIC = NULL;
479 BOOL r = FALSE;
481 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
482 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
484 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
485 goto lend;
488 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
489 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
491 WORKREQUEST workRequest;
492 struct WORKREQ_FTPCREATEDIRECTORYW *req;
494 workRequest.asyncall = FTPCREATEDIRECTORYW;
495 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
496 req = &workRequest.u.FtpCreateDirectoryW;
497 req->lpszDirectory = WININET_strdupW(lpszDirectory);
499 r = INTERNET_AsyncCall(&workRequest);
501 else
503 r = FTP_FtpCreateDirectoryW(lpwfs, lpszDirectory);
505 lend:
506 if( lpwfs )
507 WININET_Release( &lpwfs->hdr );
509 return r;
513 /***********************************************************************
514 * FTP_FtpCreateDirectoryW (Internal)
516 * Create new directory on the FTP server
518 * RETURNS
519 * TRUE on success
520 * FALSE on failure
523 BOOL WINAPI FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
525 INT nResCode;
526 BOOL bSuccess = FALSE;
527 LPWININETAPPINFOW hIC = NULL;
529 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
531 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
533 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
534 return FALSE;
537 /* Clear any error information */
538 INTERNET_SetLastError(0);
540 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
541 goto lend;
543 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
544 if (nResCode)
546 if (nResCode == 257)
547 bSuccess = TRUE;
548 else
549 FTP_SetResponseError(nResCode);
552 lend:
553 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
554 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
556 INTERNET_ASYNC_RESULT iar;
558 iar.dwResult = (DWORD)bSuccess;
559 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
560 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
561 &iar, sizeof(INTERNET_ASYNC_RESULT));
564 return bSuccess;
567 /***********************************************************************
568 * FtpFindFirstFileA (WININET.@)
570 * Search the specified directory
572 * RETURNS
573 * HINTERNET on success
574 * NULL on failure
577 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
578 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
580 LPWSTR lpwzSearchFile;
581 WIN32_FIND_DATAW wfd;
582 LPWIN32_FIND_DATAW lpFindFileDataW;
583 HINTERNET ret;
585 lpwzSearchFile = lpszSearchFile?WININET_strdup_AtoW(lpszSearchFile):NULL;
586 lpFindFileDataW = lpFindFileData?&wfd:NULL;
587 ret = FtpFindFirstFileW(hConnect, lpwzSearchFile, lpFindFileDataW, dwFlags, dwContext);
588 HeapFree(GetProcessHeap(), 0, lpwzSearchFile);
590 if(lpFindFileData) {
591 WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData);
593 return ret;
597 /***********************************************************************
598 * FtpFindFirstFileW (WININET.@)
600 * Search the specified directory
602 * RETURNS
603 * HINTERNET on success
604 * NULL on failure
607 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
608 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
610 LPWININETFTPSESSIONW lpwfs;
611 LPWININETAPPINFOW hIC = NULL;
612 HINTERNET r = NULL;
614 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
615 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
617 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
618 goto lend;
621 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
622 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
624 WORKREQUEST workRequest;
625 struct WORKREQ_FTPFINDFIRSTFILEW *req;
627 workRequest.asyncall = FTPFINDFIRSTFILEW;
628 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
629 req = &workRequest.u.FtpFindFirstFileW;
630 req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : WININET_strdupW(lpszSearchFile);
631 req->lpFindFileData = lpFindFileData;
632 req->dwFlags = dwFlags;
633 req->dwContext= dwContext;
635 INTERNET_AsyncCall(&workRequest);
636 r = NULL;
638 else
640 r = FTP_FtpFindFirstFileW(lpwfs, lpszSearchFile, lpFindFileData,
641 dwFlags, dwContext);
643 lend:
644 if( lpwfs )
645 WININET_Release( &lpwfs->hdr );
647 return r;
651 /***********************************************************************
652 * FTP_FtpFindFirstFileW (Internal)
654 * Search the specified directory
656 * RETURNS
657 * HINTERNET on success
658 * NULL on failure
661 HINTERNET WINAPI FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs,
662 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
664 INT nResCode;
665 LPWININETAPPINFOW hIC = NULL;
666 HINTERNET hFindNext = NULL;
668 TRACE("\n");
670 assert(WH_HFTPSESSION == lpwfs->hdr.htype);
672 /* Clear any error information */
673 INTERNET_SetLastError(0);
675 if (!FTP_InitListenSocket(lpwfs))
676 goto lend;
678 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
679 goto lend;
681 if (!FTP_SendPortOrPasv(lpwfs))
682 goto lend;
684 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
685 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, NULL,
686 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
687 goto lend;
689 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
690 if (nResCode)
692 if (nResCode == 125 || nResCode == 150)
694 INT nDataSocket;
696 /* Get data socket to server */
697 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
699 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpszSearchFile, lpFindFileData, dwContext);
700 closesocket(nDataSocket);
701 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
702 if (nResCode != 226 && nResCode != 250)
703 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
706 else
707 FTP_SetResponseError(nResCode);
710 lend:
711 if (lpwfs->lstnSocket != -1)
712 closesocket(lpwfs->lstnSocket);
714 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
716 INTERNET_ASYNC_RESULT iar;
718 if (hFindNext)
720 iar.dwResult = (DWORD)hFindNext;
721 iar.dwError = ERROR_SUCCESS;
722 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
723 &iar, sizeof(INTERNET_ASYNC_RESULT));
726 iar.dwResult = (DWORD)hFindNext;
727 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
728 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
729 &iar, sizeof(INTERNET_ASYNC_RESULT));
732 return hFindNext;
736 /***********************************************************************
737 * FtpGetCurrentDirectoryA (WININET.@)
739 * Retrieves the current directory
741 * RETURNS
742 * TRUE on success
743 * FALSE on failure
746 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
747 LPDWORD lpdwCurrentDirectory)
749 WCHAR dir[MAX_PATH];
750 DWORD len;
751 BOOL ret;
753 if(lpdwCurrentDirectory) len = *lpdwCurrentDirectory;
754 ret = FtpGetCurrentDirectoryW(hFtpSession, lpszCurrentDirectory?dir:NULL, lpdwCurrentDirectory?&len:NULL);
755 if(lpdwCurrentDirectory) {
756 *lpdwCurrentDirectory = len;
757 if(lpszCurrentDirectory)
758 WideCharToMultiByte(CP_ACP, 0, dir, len, lpszCurrentDirectory, *lpdwCurrentDirectory, NULL, NULL);
760 return ret;
764 /***********************************************************************
765 * FtpGetCurrentDirectoryW (WININET.@)
767 * Retrieves the current directory
769 * RETURNS
770 * TRUE on success
771 * FALSE on failure
774 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
775 LPDWORD lpdwCurrentDirectory)
777 LPWININETFTPSESSIONW lpwfs;
778 LPWININETAPPINFOW hIC = NULL;
779 BOOL r = FALSE;
781 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
783 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
784 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
786 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
787 goto lend;
790 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
791 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
793 WORKREQUEST workRequest;
794 struct WORKREQ_FTPGETCURRENTDIRECTORYW *req;
796 workRequest.asyncall = FTPGETCURRENTDIRECTORYW;
797 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
798 req = &workRequest.u.FtpGetCurrentDirectoryW;
799 req->lpszDirectory = lpszCurrentDirectory;
800 req->lpdwDirectory = lpdwCurrentDirectory;
802 r = INTERNET_AsyncCall(&workRequest);
804 else
806 r = FTP_FtpGetCurrentDirectoryW(lpwfs, lpszCurrentDirectory,
807 lpdwCurrentDirectory);
810 lend:
811 if( lpwfs )
812 WININET_Release( &lpwfs->hdr );
814 return r;
818 /***********************************************************************
819 * FTP_FtpGetCurrentDirectoryA (Internal)
821 * Retrieves the current directory
823 * RETURNS
824 * TRUE on success
825 * FALSE on failure
828 BOOL WINAPI FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszCurrentDirectory,
829 LPDWORD lpdwCurrentDirectory)
831 INT nResCode;
832 LPWININETAPPINFOW hIC = NULL;
833 DWORD bSuccess = FALSE;
835 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
837 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
839 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
840 return FALSE;
843 /* Clear any error information */
844 INTERNET_SetLastError(0);
846 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
848 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
849 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
850 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
851 goto lend;
853 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
854 if (nResCode)
856 if (nResCode == 257) /* Extract directory name */
858 DWORD firstpos, lastpos, len;
859 LPWSTR lpszResponseBuffer = WININET_strdup_AtoW(INTERNET_GetResponseBuffer());
861 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
863 if ('"' == lpszResponseBuffer[lastpos])
865 if (!firstpos)
866 firstpos = lastpos;
867 else
868 break;
872 len = lastpos - firstpos - 1;
873 lstrcpynW(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1], *lpdwCurrentDirectory);
874 HeapFree(GetProcessHeap(), 0, lpszResponseBuffer);
875 *lpdwCurrentDirectory = len;
876 bSuccess = TRUE;
878 else
879 FTP_SetResponseError(nResCode);
882 lend:
883 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
885 INTERNET_ASYNC_RESULT iar;
887 iar.dwResult = (DWORD)bSuccess;
888 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
889 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
890 &iar, sizeof(INTERNET_ASYNC_RESULT));
893 return (DWORD) bSuccess;
896 /***********************************************************************
897 * FtpOpenFileA (WININET.@)
899 * Open a remote file for writing or reading
901 * RETURNS
902 * HINTERNET handle on success
903 * NULL on failure
906 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
907 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
908 DWORD dwContext)
910 LPWSTR lpwzFileName;
911 HINTERNET ret;
913 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
914 ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext);
915 HeapFree(GetProcessHeap(), 0, lpwzFileName);
916 return ret;
920 /***********************************************************************
921 * FtpOpenFileW (WININET.@)
923 * Open a remote file for writing or reading
925 * RETURNS
926 * HINTERNET handle on success
927 * NULL on failure
930 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
931 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
932 DWORD dwContext)
934 LPWININETFTPSESSIONW lpwfs;
935 LPWININETAPPINFOW hIC = NULL;
936 HINTERNET r = NULL;
938 TRACE("(%p,%s,0x%08lx,0x%08lx,0x%08lx)\n", hFtpSession,
939 debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext);
941 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
942 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
944 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
945 goto lend;
948 if (lpwfs->download_in_progress != NULL) {
949 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
950 goto lend;
952 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
953 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
955 WORKREQUEST workRequest;
956 struct WORKREQ_FTPOPENFILEW *req;
958 workRequest.asyncall = FTPOPENFILEW;
959 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
960 req = &workRequest.u.FtpOpenFileW;
961 req->lpszFilename = WININET_strdupW(lpszFileName);
962 req->dwAccess = fdwAccess;
963 req->dwFlags = dwFlags;
964 req->dwContext = dwContext;
966 INTERNET_AsyncCall(&workRequest);
967 r = NULL;
969 else
971 r = FTP_FtpOpenFileW(lpwfs, lpszFileName, fdwAccess, dwFlags, dwContext);
974 lend:
975 if( lpwfs )
976 WININET_Release( &lpwfs->hdr );
978 return r;
982 /***********************************************************************
983 * FTP_FtpOpenFileW (Internal)
985 * Open a remote file for writing or reading
987 * RETURNS
988 * HINTERNET handle on success
989 * NULL on failure
992 HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs,
993 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
994 DWORD dwContext)
996 INT nDataSocket;
997 BOOL bSuccess = FALSE;
998 LPWININETFILE lpwh = NULL;
999 LPWININETAPPINFOW hIC = NULL;
1000 HINTERNET handle = NULL;
1002 TRACE("\n");
1004 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1006 /* Clear any error information */
1007 INTERNET_SetLastError(0);
1009 if (GENERIC_READ == fdwAccess)
1011 /* Set up socket to retrieve data */
1012 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
1014 else if (GENERIC_WRITE == fdwAccess)
1016 /* Set up socket to send data */
1017 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
1020 /* Get data socket to server */
1021 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
1023 lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE));
1024 lpwh->hdr.htype = WH_HFILE;
1025 lpwh->hdr.dwFlags = dwFlags;
1026 lpwh->hdr.dwContext = dwContext;
1027 lpwh->hdr.lpwhparent = WININET_AddRef( &lpwfs->hdr );
1028 lpwh->hdr.dwRefCount = 1;
1029 lpwh->hdr.destroy = FTP_CloseFileTransferHandle;
1030 lpwh->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
1031 lpwh->nDataSocket = nDataSocket;
1032 lpwh->session_deleted = FALSE;
1034 handle = WININET_AllocHandle( &lpwh->hdr );
1035 if( !handle )
1036 goto lend;
1038 /* Indicate that a download is currently in progress */
1039 lpwfs->download_in_progress = lpwh;
1042 if (lpwfs->lstnSocket != -1)
1043 closesocket(lpwfs->lstnSocket);
1045 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1046 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1048 INTERNET_ASYNC_RESULT iar;
1050 if (lpwh)
1052 iar.dwResult = (DWORD)handle;
1053 iar.dwError = ERROR_SUCCESS;
1054 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
1055 &iar, sizeof(INTERNET_ASYNC_RESULT));
1058 iar.dwResult = (DWORD)bSuccess;
1059 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1060 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1061 &iar, sizeof(INTERNET_ASYNC_RESULT));
1064 lend:
1065 if( lpwh )
1066 WININET_Release( &lpwh->hdr );
1068 return handle;
1072 /***********************************************************************
1073 * FtpGetFileA (WININET.@)
1075 * Retrieve file from the FTP server
1077 * RETURNS
1078 * TRUE on success
1079 * FALSE on failure
1082 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1083 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1084 DWORD dwContext)
1086 LPWSTR lpwzRemoteFile;
1087 LPWSTR lpwzNewFile;
1088 BOOL ret;
1090 lpwzRemoteFile = lpszRemoteFile?WININET_strdup_AtoW(lpszRemoteFile):NULL;
1091 lpwzNewFile = lpszNewFile?WININET_strdup_AtoW(lpszNewFile):NULL;
1092 ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists,
1093 dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1094 HeapFree(GetProcessHeap(), 0, lpwzRemoteFile);
1095 HeapFree(GetProcessHeap(), 0, lpwzNewFile);
1096 return ret;
1100 /***********************************************************************
1101 * FtpGetFileW (WININET.@)
1103 * Retrieve file from the FTP server
1105 * RETURNS
1106 * TRUE on success
1107 * FALSE on failure
1110 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1111 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1112 DWORD dwContext)
1114 LPWININETFTPSESSIONW lpwfs;
1115 LPWININETAPPINFOW hIC = NULL;
1116 BOOL r = FALSE;
1118 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet );
1119 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1121 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1122 goto lend;
1125 if (lpwfs->download_in_progress != NULL) {
1126 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1127 goto lend;
1130 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1131 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1133 WORKREQUEST workRequest;
1134 struct WORKREQ_FTPGETFILEW *req;
1136 workRequest.asyncall = FTPGETFILEW;
1137 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1138 req = &workRequest.u.FtpGetFileW;
1139 req->lpszRemoteFile = WININET_strdupW(lpszRemoteFile);
1140 req->lpszNewFile = WININET_strdupW(lpszNewFile);
1141 req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1142 req->fFailIfExists = fFailIfExists;
1143 req->dwFlags = dwInternetFlags;
1144 req->dwContext = dwContext;
1146 r = INTERNET_AsyncCall(&workRequest);
1148 else
1150 r = FTP_FtpGetFileW(lpwfs, lpszRemoteFile, lpszNewFile,
1151 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1154 lend:
1155 if( lpwfs )
1156 WININET_Release( &lpwfs->hdr );
1158 return r;
1162 /***********************************************************************
1163 * FTP_FtpGetFileW (Internal)
1165 * Retrieve file from the FTP server
1167 * RETURNS
1168 * TRUE on success
1169 * FALSE on failure
1172 BOOL WINAPI FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1173 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1174 DWORD dwContext)
1176 DWORD nBytes;
1177 BOOL bSuccess = FALSE;
1178 HANDLE hFile;
1179 LPWININETAPPINFOW hIC = NULL;
1181 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile));
1183 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1185 /* Clear any error information */
1186 INTERNET_SetLastError(0);
1188 /* Ensure we can write to lpszNewfile by opening it */
1189 hFile = CreateFileW(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1190 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1191 if (INVALID_HANDLE_VALUE == hFile)
1192 goto lend;
1194 /* Set up socket to retrieve data */
1195 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
1197 if (nBytes > 0)
1199 INT nDataSocket;
1201 /* Get data socket to server */
1202 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1204 INT nResCode;
1206 /* Receive data */
1207 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
1208 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
1209 if (nResCode)
1211 if (nResCode == 226)
1212 bSuccess = TRUE;
1213 else
1214 FTP_SetResponseError(nResCode);
1216 closesocket(nDataSocket);
1220 lend:
1221 if (lpwfs->lstnSocket != -1)
1222 closesocket(lpwfs->lstnSocket);
1224 if (hFile)
1225 CloseHandle(hFile);
1227 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1228 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1230 INTERNET_ASYNC_RESULT iar;
1232 iar.dwResult = (DWORD)bSuccess;
1233 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1234 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1235 &iar, sizeof(INTERNET_ASYNC_RESULT));
1238 return bSuccess;
1241 /***********************************************************************
1242 * FtpGetFileSize (WININET.@)
1244 DWORD WINAPI FtpGetFileSize( HINTERNET hFile, LPDWORD lpdwFileSizeHigh )
1246 FIXME("(%p, %p)\n", hFile, lpdwFileSizeHigh);
1248 if (lpdwFileSizeHigh)
1249 *lpdwFileSizeHigh = 0;
1251 return 0;
1254 /***********************************************************************
1255 * FtpDeleteFileA (WININET.@)
1257 * Delete a file on the ftp server
1259 * RETURNS
1260 * TRUE on success
1261 * FALSE on failure
1264 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1266 LPWSTR lpwzFileName;
1267 BOOL ret;
1269 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1270 ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1271 HeapFree(GetProcessHeap(), 0, lpwzFileName);
1272 return ret;
1275 /***********************************************************************
1276 * FtpDeleteFileW (WININET.@)
1278 * Delete a file on the ftp server
1280 * RETURNS
1281 * TRUE on success
1282 * FALSE on failure
1285 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1287 LPWININETFTPSESSIONW lpwfs;
1288 LPWININETAPPINFOW hIC = NULL;
1289 BOOL r = FALSE;
1291 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1292 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1294 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1295 goto lend;
1298 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1299 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1301 WORKREQUEST workRequest;
1302 struct WORKREQ_FTPDELETEFILEW *req;
1304 workRequest.asyncall = FTPDELETEFILEW;
1305 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1306 req = &workRequest.u.FtpDeleteFileW;
1307 req->lpszFilename = WININET_strdupW(lpszFileName);
1309 r = INTERNET_AsyncCall(&workRequest);
1311 else
1313 r = FTP_FtpDeleteFileW(hFtpSession, lpszFileName);
1316 lend:
1317 if( lpwfs )
1318 WININET_Release( &lpwfs->hdr );
1320 return r;
1323 /***********************************************************************
1324 * FTP_FtpDeleteFileW (Internal)
1326 * Delete a file on the ftp server
1328 * RETURNS
1329 * TRUE on success
1330 * FALSE on failure
1333 BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName)
1335 INT nResCode;
1336 BOOL bSuccess = FALSE;
1337 LPWININETAPPINFOW hIC = NULL;
1339 TRACE("%p\n", lpwfs);
1341 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1343 /* Clear any error information */
1344 INTERNET_SetLastError(0);
1346 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1347 goto lend;
1349 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1350 if (nResCode)
1352 if (nResCode == 250)
1353 bSuccess = TRUE;
1354 else
1355 FTP_SetResponseError(nResCode);
1357 lend:
1358 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1359 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1361 INTERNET_ASYNC_RESULT iar;
1363 iar.dwResult = (DWORD)bSuccess;
1364 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1365 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1366 &iar, sizeof(INTERNET_ASYNC_RESULT));
1369 return bSuccess;
1373 /***********************************************************************
1374 * FtpRemoveDirectoryA (WININET.@)
1376 * Remove a directory on the ftp server
1378 * RETURNS
1379 * TRUE on success
1380 * FALSE on failure
1383 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1385 LPWSTR lpwzDirectory;
1386 BOOL ret;
1388 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
1389 ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1390 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
1391 return ret;
1394 /***********************************************************************
1395 * FtpRemoveDirectoryW (WININET.@)
1397 * Remove a directory on the ftp server
1399 * RETURNS
1400 * TRUE on success
1401 * FALSE on failure
1404 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1406 LPWININETFTPSESSIONW lpwfs;
1407 LPWININETAPPINFOW hIC = NULL;
1408 BOOL r = FALSE;
1410 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1411 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1413 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1414 goto lend;
1417 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1418 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1420 WORKREQUEST workRequest;
1421 struct WORKREQ_FTPREMOVEDIRECTORYW *req;
1423 workRequest.asyncall = FTPREMOVEDIRECTORYW;
1424 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1425 req = &workRequest.u.FtpRemoveDirectoryW;
1426 req->lpszDirectory = WININET_strdupW(lpszDirectory);
1428 r = INTERNET_AsyncCall(&workRequest);
1430 else
1432 r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory);
1435 lend:
1436 if( lpwfs )
1437 WININET_Release( &lpwfs->hdr );
1439 return r;
1442 /***********************************************************************
1443 * FTP_FtpRemoveDirectoryW (Internal)
1445 * Remove a directory on the ftp server
1447 * RETURNS
1448 * TRUE on success
1449 * FALSE on failure
1452 BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
1454 INT nResCode;
1455 BOOL bSuccess = FALSE;
1456 LPWININETAPPINFOW hIC = NULL;
1458 TRACE("\n");
1460 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1462 /* Clear any error information */
1463 INTERNET_SetLastError(0);
1465 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1466 goto lend;
1468 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1469 if (nResCode)
1471 if (nResCode == 250)
1472 bSuccess = TRUE;
1473 else
1474 FTP_SetResponseError(nResCode);
1477 lend:
1478 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1479 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1481 INTERNET_ASYNC_RESULT iar;
1483 iar.dwResult = (DWORD)bSuccess;
1484 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1485 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1486 &iar, sizeof(INTERNET_ASYNC_RESULT));
1489 return bSuccess;
1493 /***********************************************************************
1494 * FtpRenameFileA (WININET.@)
1496 * Rename a file on the ftp server
1498 * RETURNS
1499 * TRUE on success
1500 * FALSE on failure
1503 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1505 LPWSTR lpwzSrc;
1506 LPWSTR lpwzDest;
1507 BOOL ret;
1509 lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL;
1510 lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL;
1511 ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
1512 HeapFree(GetProcessHeap(), 0, lpwzSrc);
1513 HeapFree(GetProcessHeap(), 0, lpwzDest);
1514 return ret;
1517 /***********************************************************************
1518 * FtpRenameFileW (WININET.@)
1520 * Rename a file on the ftp server
1522 * RETURNS
1523 * TRUE on success
1524 * FALSE on failure
1527 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
1529 LPWININETFTPSESSIONW lpwfs;
1530 LPWININETAPPINFOW hIC = NULL;
1531 BOOL r = FALSE;
1533 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1534 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1536 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1537 goto lend;
1540 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1541 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1543 WORKREQUEST workRequest;
1544 struct WORKREQ_FTPRENAMEFILEW *req;
1546 workRequest.asyncall = FTPRENAMEFILEW;
1547 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1548 req = &workRequest.u.FtpRenameFileW;
1549 req->lpszSrcFile = WININET_strdupW(lpszSrc);
1550 req->lpszDestFile = WININET_strdupW(lpszDest);
1552 r = INTERNET_AsyncCall(&workRequest);
1554 else
1556 r = FTP_FtpRenameFileW(hFtpSession, lpszSrc, lpszDest);
1559 lend:
1560 if( lpwfs )
1561 WININET_Release( &lpwfs->hdr );
1563 return r;
1566 /***********************************************************************
1567 * FTP_FtpRenameFileA (Internal)
1569 * Rename a file on the ftp server
1571 * RETURNS
1572 * TRUE on success
1573 * FALSE on failure
1576 BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs,
1577 LPCWSTR lpszSrc, LPCWSTR lpszDest)
1579 INT nResCode;
1580 BOOL bSuccess = FALSE;
1581 LPWININETAPPINFOW hIC = NULL;
1583 TRACE("\n");
1585 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1587 /* Clear any error information */
1588 INTERNET_SetLastError(0);
1590 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1591 goto lend;
1593 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1594 if (nResCode == 350)
1596 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1597 goto lend;
1599 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1602 if (nResCode == 250)
1603 bSuccess = TRUE;
1604 else
1605 FTP_SetResponseError(nResCode);
1607 lend:
1608 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1609 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1611 INTERNET_ASYNC_RESULT iar;
1613 iar.dwResult = (DWORD)bSuccess;
1614 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1615 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1616 &iar, sizeof(INTERNET_ASYNC_RESULT));
1619 return bSuccess;
1622 /***********************************************************************
1623 * FtpCommandA (WININET.@)
1625 BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1626 LPCSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1628 FIXME("%p %d 0x%08lx %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1629 debugstr_a(lpszCommand), dwContext, phFtpCommand);
1631 return TRUE;
1634 /***********************************************************************
1635 * FtpCommandW (WININET.@)
1637 BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1638 LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1640 FIXME("%p %d 0x%08lx %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1641 debugstr_w(lpszCommand), dwContext, phFtpCommand);
1643 return TRUE;
1646 /***********************************************************************
1647 * FTP_Connect (internal)
1649 * Connect to a ftp server
1651 * RETURNS
1652 * HINTERNET a session handle on success
1653 * NULL on failure
1657 HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
1658 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1659 LPCWSTR lpszPassword, DWORD dwFlags, DWORD dwContext,
1660 DWORD dwInternalFlags)
1662 static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'};
1663 static const WCHAR szDefaultPassword[] = {'u','s','e','r','@','s','e','r','v','e','r','\0'};
1664 struct sockaddr_in socketAddr;
1665 INT nsocket = -1;
1666 UINT sock_namelen;
1667 BOOL bSuccess = FALSE;
1668 LPWININETFTPSESSIONW lpwfs = NULL;
1669 HINTERNET handle = NULL;
1671 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1672 hIC, debugstr_w(lpszServerName),
1673 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
1675 assert( hIC->hdr.htype == WH_HINIT );
1677 if (NULL == lpszUserName && NULL != lpszPassword)
1679 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1680 goto lerror;
1683 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
1684 if (NULL == lpwfs)
1686 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1687 goto lerror;
1690 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1691 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1693 lpwfs->hdr.htype = WH_HFTPSESSION;
1694 lpwfs->hdr.lpwhparent = WININET_AddRef( &hIC->hdr );
1695 lpwfs->hdr.dwFlags = dwFlags;
1696 lpwfs->hdr.dwContext = dwContext;
1697 lpwfs->hdr.dwInternalFlags = dwInternalFlags;
1698 lpwfs->hdr.dwRefCount = 1;
1699 lpwfs->hdr.destroy = FTP_CloseSessionHandle;
1700 lpwfs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
1701 lpwfs->download_in_progress = NULL;
1703 handle = WININET_AllocHandle( &lpwfs->hdr );
1704 if( !handle )
1706 ERR("Failed to alloc handle\n");
1707 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1708 goto lerror;
1711 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1712 if(strchrW(hIC->lpszProxy, ' '))
1713 FIXME("Several proxies not implemented.\n");
1714 if(hIC->lpszProxyBypass)
1715 FIXME("Proxy bypass is ignored.\n");
1717 if ( !lpszUserName) {
1718 lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
1719 lpwfs->lpszPassword = WININET_strdupW(szDefaultPassword);
1721 else {
1722 lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
1723 lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
1726 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1727 if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
1729 INTERNET_ASYNC_RESULT iar;
1731 iar.dwResult = (DWORD)handle;
1732 iar.dwError = ERROR_SUCCESS;
1734 SendAsyncCallback(&hIC->hdr, dwContext,
1735 INTERNET_STATUS_HANDLE_CREATED, &iar,
1736 sizeof(INTERNET_ASYNC_RESULT));
1739 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1740 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1742 if (!GetAddress(lpszServerName, nServerPort, &socketAddr))
1744 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1745 goto lerror;
1748 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1749 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1751 nsocket = socket(AF_INET,SOCK_STREAM,0);
1752 if (nsocket == -1)
1754 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1755 goto lerror;
1758 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1759 &socketAddr, sizeof(struct sockaddr_in));
1761 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1763 ERR("Unable to connect (%s)\n", strerror(errno));
1764 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1766 else
1768 TRACE("Connected to server\n");
1769 lpwfs->sndSocket = nsocket;
1770 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1771 &socketAddr, sizeof(struct sockaddr_in));
1773 sock_namelen = sizeof(lpwfs->socketAddress);
1774 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1776 if (FTP_ConnectToHost(lpwfs))
1778 TRACE("Successfully logged into server\n");
1779 bSuccess = TRUE;
1783 lerror:
1784 if (!bSuccess && nsocket == -1)
1785 closesocket(nsocket);
1787 if (!bSuccess && lpwfs)
1789 HeapFree(GetProcessHeap(), 0, lpwfs);
1790 WININET_FreeHandle( handle );
1791 lpwfs = NULL;
1794 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1796 INTERNET_ASYNC_RESULT iar;
1798 iar.dwResult = (DWORD)lpwfs;
1799 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1800 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1801 &iar, sizeof(INTERNET_ASYNC_RESULT));
1804 return handle;
1808 /***********************************************************************
1809 * FTP_ConnectToHost (internal)
1811 * Connect to a ftp server
1813 * RETURNS
1814 * TRUE on success
1815 * NULL on failure
1818 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
1820 INT nResCode;
1821 BOOL bSuccess = FALSE;
1823 TRACE("\n");
1824 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1826 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1827 goto lend;
1829 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1830 if (nResCode)
1832 /* Login successful... */
1833 if (nResCode == 230)
1834 bSuccess = TRUE;
1835 /* User name okay, need password... */
1836 else if (nResCode == 331)
1837 bSuccess = FTP_SendPassword(lpwfs);
1838 /* Need account for login... */
1839 else if (nResCode == 332)
1840 bSuccess = FTP_SendAccount(lpwfs);
1841 else
1842 FTP_SetResponseError(nResCode);
1845 TRACE("Returning %d\n", bSuccess);
1846 lend:
1847 return bSuccess;
1851 /***********************************************************************
1852 * FTP_SendCommandA (internal)
1854 * Send command to server
1856 * RETURNS
1857 * TRUE on success
1858 * NULL on failure
1861 static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1862 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
1864 DWORD len;
1865 CHAR *buf;
1866 DWORD nBytesSent = 0;
1867 int nRC = 0;
1868 DWORD dwParamLen;
1870 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1872 if (lpfnStatusCB)
1874 HINTERNET hHandle = WININET_FindHandle( hdr );
1875 if( hHandle )
1877 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1878 WININET_Release( hdr );
1882 dwParamLen = lpszParam?strlen(lpszParam)+1:0;
1883 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
1884 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1886 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1887 return FALSE;
1889 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
1890 dwParamLen ? lpszParam : "", szCRLF);
1892 TRACE("Sending (%s) len(%ld)\n", buf, len);
1893 while((nBytesSent < len) && (nRC != -1))
1895 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1896 nBytesSent += nRC;
1899 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
1901 if (lpfnStatusCB)
1903 HINTERNET hHandle = WININET_FindHandle( hdr );
1904 if( hHandle )
1906 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_REQUEST_SENT,
1907 &nBytesSent, sizeof(DWORD));
1908 WININET_Release( hdr );
1912 TRACE("Sent %ld bytes\n", nBytesSent);
1913 return (nRC != -1);
1916 /***********************************************************************
1917 * FTP_SendCommand (internal)
1919 * Send command to server
1921 * RETURNS
1922 * TRUE on success
1923 * NULL on failure
1926 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
1927 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
1929 BOOL ret;
1930 LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
1931 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
1932 HeapFree(GetProcessHeap(), 0, lpszParamA);
1933 return ret;
1936 /***********************************************************************
1937 * FTP_ReceiveResponse (internal)
1939 * Receive response from server
1941 * RETURNS
1942 * Reply code on success
1943 * 0 on failure
1946 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext)
1948 LPSTR lpszResponse = INTERNET_GetResponseBuffer();
1949 DWORD nRecv;
1950 INT rc = 0;
1951 char firstprefix[5];
1952 BOOL multiline = FALSE;
1953 LPWININETAPPINFOW hIC = NULL;
1955 TRACE("socket(%d)\n", lpwfs->sndSocket);
1957 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1958 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1960 while(1)
1962 if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
1963 goto lerror;
1965 if (nRecv >= 3)
1967 if(!multiline)
1969 if(lpszResponse[3] != '-')
1970 break;
1971 else
1972 { /* Start of multiline repsonse. Loop until we get "nnn " */
1973 multiline = TRUE;
1974 memcpy(firstprefix, lpszResponse, 3);
1975 firstprefix[3] = ' ';
1976 firstprefix[4] = '\0';
1979 else
1981 if(!memcmp(firstprefix, lpszResponse, 4))
1982 break;
1987 if (nRecv >= 3)
1989 rc = atoi(lpszResponse);
1991 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
1992 &nRecv, sizeof(DWORD));
1995 lerror:
1996 TRACE("return %d\n", rc);
1997 return rc;
2001 /***********************************************************************
2002 * FTP_SendPassword (internal)
2004 * Send password to ftp server
2006 * RETURNS
2007 * TRUE on success
2008 * NULL on failure
2011 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
2013 INT nResCode;
2014 BOOL bSuccess = FALSE;
2016 TRACE("\n");
2017 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
2018 goto lend;
2020 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2021 if (nResCode)
2023 TRACE("Received reply code %d\n", nResCode);
2024 /* Login successful... */
2025 if (nResCode == 230)
2026 bSuccess = TRUE;
2027 /* Command not implemented, superfluous at the server site... */
2028 /* Need account for login... */
2029 else if (nResCode == 332)
2030 bSuccess = FTP_SendAccount(lpwfs);
2031 else
2032 FTP_SetResponseError(nResCode);
2035 lend:
2036 TRACE("Returning %d\n", bSuccess);
2037 return bSuccess;
2041 /***********************************************************************
2042 * FTP_SendAccount (internal)
2046 * RETURNS
2047 * TRUE on success
2048 * FALSE on failure
2051 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
2053 INT nResCode;
2054 BOOL bSuccess = FALSE;
2056 TRACE("\n");
2057 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
2058 goto lend;
2060 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2061 if (nResCode)
2062 bSuccess = TRUE;
2063 else
2064 FTP_SetResponseError(nResCode);
2066 lend:
2067 return bSuccess;
2071 /***********************************************************************
2072 * FTP_SendStore (internal)
2074 * Send request to upload file to ftp server
2076 * RETURNS
2077 * TRUE on success
2078 * FALSE on failure
2081 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2083 INT nResCode;
2084 BOOL bSuccess = FALSE;
2086 TRACE("\n");
2087 if (!FTP_InitListenSocket(lpwfs))
2088 goto lend;
2090 if (!FTP_SendType(lpwfs, dwType))
2091 goto lend;
2093 if (!FTP_SendPortOrPasv(lpwfs))
2094 goto lend;
2096 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2097 goto lend;
2098 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2099 if (nResCode)
2101 if (nResCode == 150 || nResCode == 125)
2102 bSuccess = TRUE;
2103 else
2104 FTP_SetResponseError(nResCode);
2107 lend:
2108 if (!bSuccess && lpwfs->lstnSocket != -1)
2110 closesocket(lpwfs->lstnSocket);
2111 lpwfs->lstnSocket = -1;
2114 return bSuccess;
2118 /***********************************************************************
2119 * FTP_InitListenSocket (internal)
2121 * Create a socket to listen for server response
2123 * RETURNS
2124 * TRUE on success
2125 * FALSE on failure
2128 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
2130 BOOL bSuccess = FALSE;
2131 size_t namelen = sizeof(struct sockaddr_in);
2133 TRACE("\n");
2135 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2136 if (lpwfs->lstnSocket == -1)
2138 TRACE("Unable to create listening socket\n");
2139 goto lend;
2142 /* We obtain our ip addr from the name of the command channel socket */
2143 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2145 /* and get the system to assign us a port */
2146 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
2148 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
2150 TRACE("Unable to bind socket\n");
2151 goto lend;
2154 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2156 TRACE("listen failed\n");
2157 goto lend;
2160 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2161 bSuccess = TRUE;
2163 lend:
2164 if (!bSuccess && lpwfs->lstnSocket == -1)
2166 closesocket(lpwfs->lstnSocket);
2167 lpwfs->lstnSocket = -1;
2170 return bSuccess;
2174 /***********************************************************************
2175 * FTP_SendType (internal)
2177 * Tell server type of data being transferred
2179 * RETURNS
2180 * TRUE on success
2181 * FALSE on failure
2183 * W98SE doesn't cache the type that's currently set
2184 * (i.e. it sends it always),
2185 * so we probably don't want to do that either.
2187 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
2189 INT nResCode;
2190 WCHAR type[] = { 'I','\0' };
2191 BOOL bSuccess = FALSE;
2193 TRACE("\n");
2194 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2195 type[0] = 'A';
2197 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2198 goto lend;
2200 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2201 if (nResCode)
2203 if (nResCode == 2)
2204 bSuccess = TRUE;
2205 else
2206 FTP_SetResponseError(nResCode);
2209 lend:
2210 return bSuccess;
2213 /***********************************************************************
2214 * FTP_GetFileSize (internal)
2216 * Retrieves from the server the size of the given file
2218 * RETURNS
2219 * TRUE on success
2220 * FALSE on failure
2223 static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
2225 INT nResCode;
2226 BOOL bSuccess = FALSE;
2228 TRACE("\n");
2230 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2231 goto lend;
2233 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2234 if (nResCode)
2236 if (nResCode == 213) {
2237 /* Now parses the output to get the actual file size */
2238 int i;
2239 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2241 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2242 if (lpszResponseBuffer[i] == '\0') return FALSE;
2243 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2245 bSuccess = TRUE;
2246 } else {
2247 FTP_SetResponseError(nResCode);
2251 lend:
2252 return bSuccess;
2256 /***********************************************************************
2257 * FTP_SendPort (internal)
2259 * Tell server which port to use
2261 * RETURNS
2262 * TRUE on success
2263 * FALSE on failure
2266 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
2268 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2269 INT nResCode;
2270 WCHAR szIPAddress[64];
2271 BOOL bSuccess = FALSE;
2272 TRACE("\n");
2274 sprintfW(szIPAddress, szIPFormat,
2275 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2276 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2277 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2278 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2279 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2280 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2282 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2283 goto lend;
2285 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2286 if (nResCode)
2288 if (nResCode == 200)
2289 bSuccess = TRUE;
2290 else
2291 FTP_SetResponseError(nResCode);
2294 lend:
2295 return bSuccess;
2299 /***********************************************************************
2300 * FTP_DoPassive (internal)
2302 * Tell server that we want to do passive transfers
2303 * and connect data socket
2305 * RETURNS
2306 * TRUE on success
2307 * FALSE on failure
2310 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
2312 INT nResCode;
2313 BOOL bSuccess = FALSE;
2315 TRACE("\n");
2316 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2317 goto lend;
2319 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2320 if (nResCode)
2322 if (nResCode == 227)
2324 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2325 LPSTR p;
2326 int f[6];
2327 int i;
2328 char *pAddr, *pPort;
2329 INT nsocket = -1;
2330 struct sockaddr_in dataSocketAddress;
2332 p = lpszResponseBuffer+4; /* skip status code */
2334 /* do a very strict check; we can improve that later. */
2336 if (strncmp(p, "Entering Passive Mode", 21))
2338 ERR("unknown response '%.*s', aborting\n", 21, p);
2339 goto lend;
2341 p += 21; /* skip string */
2342 if ((*p++ != ' ') || (*p++ != '('))
2344 ERR("unknown response format, aborting\n");
2345 goto lend;
2348 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2349 &f[4], &f[5]) != 6)
2351 ERR("unknown response address format '%s', aborting\n", p);
2352 goto lend;
2354 for (i=0; i < 6; i++)
2355 f[i] = f[i] & 0xff;
2357 dataSocketAddress = lpwfs->socketAddress;
2358 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2359 pPort = (char *)&(dataSocketAddress.sin_port);
2360 pAddr[0] = f[0];
2361 pAddr[1] = f[1];
2362 pAddr[2] = f[2];
2363 pAddr[3] = f[3];
2364 pPort[0] = f[4];
2365 pPort[1] = f[5];
2367 nsocket = socket(AF_INET,SOCK_STREAM,0);
2368 if (nsocket == -1)
2369 goto lend;
2371 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2373 ERR("can't connect passive FTP data port.\n");
2374 goto lend;
2376 lpwfs->pasvSocket = nsocket;
2377 bSuccess = TRUE;
2379 else
2380 FTP_SetResponseError(nResCode);
2383 lend:
2384 return bSuccess;
2388 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
2390 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2392 if (!FTP_DoPassive(lpwfs))
2393 return FALSE;
2395 else
2397 if (!FTP_SendPort(lpwfs))
2398 return FALSE;
2400 return TRUE;
2404 /***********************************************************************
2405 * FTP_GetDataSocket (internal)
2407 * Either accepts an incoming data socket connection from the server
2408 * or just returns the already opened socket after a PASV command
2409 * in case of passive FTP.
2412 * RETURNS
2413 * TRUE on success
2414 * FALSE on failure
2417 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
2419 struct sockaddr_in saddr;
2420 size_t addrlen = sizeof(struct sockaddr);
2422 TRACE("\n");
2423 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2425 *nDataSocket = lpwfs->pasvSocket;
2427 else
2429 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2430 closesocket(lpwfs->lstnSocket);
2431 lpwfs->lstnSocket = -1;
2433 return *nDataSocket != -1;
2437 /***********************************************************************
2438 * FTP_SendData (internal)
2440 * Send data to the server
2442 * RETURNS
2443 * TRUE on success
2444 * FALSE on failure
2447 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2449 BY_HANDLE_FILE_INFORMATION fi;
2450 DWORD nBytesRead = 0;
2451 DWORD nBytesSent = 0;
2452 DWORD nTotalSent = 0;
2453 DWORD nBytesToSend, nLen;
2454 int nRC = 1;
2455 time_t s_long_time, e_long_time;
2456 LONG nSeconds;
2457 CHAR *lpszBuffer;
2459 TRACE("\n");
2460 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2461 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2463 /* Get the size of the file. */
2464 GetFileInformationByHandle(hFile, &fi);
2465 time(&s_long_time);
2469 nBytesToSend = nBytesRead - nBytesSent;
2471 if (nBytesToSend <= 0)
2473 /* Read data from file. */
2474 nBytesSent = 0;
2475 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2476 ERR("Failed reading from file\n");
2478 if (nBytesRead > 0)
2479 nBytesToSend = nBytesRead;
2480 else
2481 break;
2484 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2485 DATA_PACKET_SIZE : nBytesToSend;
2486 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2488 if (nRC != -1)
2490 nBytesSent += nRC;
2491 nTotalSent += nRC;
2494 /* Do some computation to display the status. */
2495 time(&e_long_time);
2496 nSeconds = e_long_time - s_long_time;
2497 if( nSeconds / 60 > 0 )
2499 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld min %ld sec estimated remaining time %ld sec\n",
2500 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2501 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2503 else
2505 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld sec estimated remaining time %ld sec\n",
2506 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2507 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2509 } while (nRC != -1);
2511 TRACE("file transfer complete!\n");
2513 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2515 return nTotalSent;
2519 /***********************************************************************
2520 * FTP_SendRetrieve (internal)
2522 * Send request to retrieve a file
2524 * RETURNS
2525 * Number of bytes to be received on success
2526 * 0 on failure
2529 static DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2531 INT nResCode;
2532 DWORD nResult = 0;
2534 TRACE("\n");
2535 if (!FTP_InitListenSocket(lpwfs))
2536 goto lend;
2538 if (!FTP_SendType(lpwfs, dwType))
2539 goto lend;
2541 if (!FTP_SendPortOrPasv(lpwfs))
2542 goto lend;
2544 if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2545 goto lend;
2547 TRACE("Waiting to receive %ld bytes\n", nResult);
2549 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2550 goto lend;
2552 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2553 if ((nResCode != 125) && (nResCode != 150)) {
2554 /* That means that we got an error getting the file. */
2555 nResult = 0;
2558 lend:
2559 if (0 == nResult && lpwfs->lstnSocket != -1)
2561 closesocket(lpwfs->lstnSocket);
2562 lpwfs->lstnSocket = -1;
2565 return nResult;
2569 /***********************************************************************
2570 * FTP_RetrieveData (internal)
2572 * Retrieve data from server
2574 * RETURNS
2575 * TRUE on success
2576 * FALSE on failure
2579 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2581 DWORD nBytesWritten;
2582 DWORD nBytesReceived = 0;
2583 INT nRC = 0;
2584 CHAR *lpszBuffer;
2586 TRACE("\n");
2588 if (INVALID_HANDLE_VALUE == hFile)
2589 return FALSE;
2591 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2592 if (NULL == lpszBuffer)
2594 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2595 return FALSE;
2598 while (nBytesReceived < nBytes && nRC != -1)
2600 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2601 if (nRC != -1)
2603 /* other side closed socket. */
2604 if (nRC == 0)
2605 goto recv_end;
2606 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2607 nBytesReceived += nRC;
2610 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
2611 nBytesReceived * 100 / nBytes);
2614 TRACE("Data transfer complete\n");
2615 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2617 recv_end:
2618 return (nRC != -1);
2622 /***********************************************************************
2623 * FTP_CloseSessionHandle (internal)
2625 * Deallocate session handle
2627 * RETURNS
2628 * TRUE on success
2629 * FALSE on failure
2632 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr)
2634 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2636 TRACE("\n");
2638 if (lpwfs->download_in_progress != NULL)
2639 lpwfs->download_in_progress->session_deleted = TRUE;
2641 if (lpwfs->sndSocket != -1)
2642 closesocket(lpwfs->sndSocket);
2644 if (lpwfs->lstnSocket != -1)
2645 closesocket(lpwfs->lstnSocket);
2647 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2648 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2649 HeapFree(GetProcessHeap(), 0, lpwfs);
2653 /***********************************************************************
2654 * FTP_CloseFindNextHandle (internal)
2656 * Deallocate session handle
2658 * RETURNS
2659 * TRUE on success
2660 * FALSE on failure
2663 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr)
2665 LPWININETFINDNEXTW lpwfn = (LPWININETFINDNEXTW) hdr;
2666 DWORD i;
2668 TRACE("\n");
2670 for (i = 0; i < lpwfn->size; i++)
2672 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2675 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2676 HeapFree(GetProcessHeap(), 0, lpwfn);
2679 /***********************************************************************
2680 * FTP_CloseFileTransferHandle (internal)
2682 * Closes the file transfer handle. This also 'cleans' the data queue of
2683 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2686 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr)
2688 LPWININETFILE lpwh = (LPWININETFILE) hdr;
2689 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) lpwh->hdr.lpwhparent;
2690 INT nResCode;
2692 TRACE("\n");
2694 if (!lpwh->session_deleted)
2695 lpwfs->download_in_progress = NULL;
2697 /* This just serves to flush the control socket of any spurrious lines written
2698 to it (like '226 Transfer complete.').
2700 Wonder what to do if the server sends us an error code though...
2702 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2704 if (lpwh->nDataSocket != -1)
2705 closesocket(lpwh->nDataSocket);
2707 HeapFree(GetProcessHeap(), 0, lpwh);
2710 /***********************************************************************
2711 * FTP_ReceiveFileList (internal)
2713 * Read file list from server
2715 * RETURNS
2716 * Handle to file list on success
2717 * NULL on failure
2720 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2721 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext)
2723 DWORD dwSize = 0;
2724 LPFILEPROPERTIESW lpafp = NULL;
2725 LPWININETFINDNEXTW lpwfn = NULL;
2726 HINTERNET handle = 0;
2728 TRACE("(%p,%d,%s,%p,%ld)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
2730 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
2732 if(lpFindFileData)
2733 FTP_ConvertFileProp(lpafp, lpFindFileData);
2735 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTW));
2736 if (lpwfn)
2738 lpwfn->hdr.htype = WH_HFINDNEXT;
2739 lpwfn->hdr.lpwhparent = WININET_AddRef( &lpwfs->hdr );
2740 lpwfn->hdr.dwContext = dwContext;
2741 lpwfn->hdr.dwRefCount = 1;
2742 lpwfn->hdr.destroy = FTP_CloseFindNextHandle;
2743 lpwfn->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
2744 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2745 lpwfn->size = dwSize;
2746 lpwfn->lpafp = lpafp;
2748 handle = WININET_AllocHandle( &lpwfn->hdr );
2752 if( lpwfn )
2753 WININET_Release( &lpwfn->hdr );
2755 TRACE("Matched %ld files\n", dwSize);
2756 return handle;
2760 /***********************************************************************
2761 * FTP_ConvertFileProp (internal)
2763 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
2765 * RETURNS
2766 * TRUE on success
2767 * FALSE on failure
2770 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
2772 BOOL bSuccess = FALSE;
2774 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
2776 if (lpafp)
2778 /* Convert 'Unix' time to Windows time */
2779 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
2780 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
2781 lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime;
2782 lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime;
2784 /* Not all fields are filled in */
2785 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2786 lpFindFileData->nFileSizeLow = lpafp->nSize;
2788 if (lpafp->bIsDirectory)
2789 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2791 if (lpafp->lpszName)
2792 lstrcpynW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2794 bSuccess = TRUE;
2797 return bSuccess;
2800 /***********************************************************************
2801 * FTP_ParseNextFile (internal)
2803 * Parse the next line in file listing
2805 * RETURNS
2806 * TRUE on success
2807 * FALSE on failure
2809 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
2811 static const char szSpace[] = " \t";
2812 DWORD nBufLen;
2813 char *pszLine;
2814 char *pszToken;
2815 char *pszTmp;
2816 BOOL found = FALSE;
2817 int i;
2819 lpfp->lpszName = NULL;
2820 do {
2821 if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
2822 return FALSE;
2824 pszToken = strtok(pszLine, szSpace);
2825 /* ls format
2826 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2828 * For instance:
2829 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2831 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
2832 if(!FTP_ParsePermission(pszToken, lpfp))
2833 lpfp->bIsDirectory = FALSE;
2834 for(i=0; i<=3; i++) {
2835 if(!(pszToken = strtok(NULL, szSpace)))
2836 break;
2838 if(!pszToken) continue;
2839 if(lpfp->bIsDirectory) {
2840 TRACE("Is directory\n");
2841 lpfp->nSize = 0;
2843 else {
2844 TRACE("Size: %s\n", pszToken);
2845 lpfp->nSize = atol(pszToken);
2848 lpfp->tmLastModified.tm_sec = 0;
2849 lpfp->tmLastModified.tm_min = 0;
2850 lpfp->tmLastModified.tm_hour = 0;
2851 lpfp->tmLastModified.tm_mday = 0;
2852 lpfp->tmLastModified.tm_mon = 0;
2853 lpfp->tmLastModified.tm_year = 0;
2855 /* Determine month */
2856 pszToken = strtok(NULL, szSpace);
2857 if(!pszToken) continue;
2858 if(strlen(pszToken) >= 3) {
2859 pszToken[3] = 0;
2860 if((pszTmp = StrStrIA(szMonths, pszToken)))
2861 lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
2863 /* Determine day */
2864 pszToken = strtok(NULL, szSpace);
2865 if(!pszToken) continue;
2866 lpfp->tmLastModified.tm_mday = atoi(pszToken);
2867 /* Determine time or year */
2868 pszToken = strtok(NULL, szSpace);
2869 if(!pszToken) continue;
2870 if((pszTmp = strchr(pszToken, ':'))) {
2871 struct tm* apTM;
2872 time_t aTime;
2873 *pszTmp = 0;
2874 pszTmp++;
2875 lpfp->tmLastModified.tm_min = atoi(pszTmp);
2876 lpfp->tmLastModified.tm_hour = atoi(pszToken);
2877 time(&aTime);
2878 apTM = localtime(&aTime);
2879 lpfp->tmLastModified.tm_year = apTM->tm_year;
2881 else {
2882 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
2883 lpfp->tmLastModified.tm_hour = 12;
2885 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
2886 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
2887 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
2888 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
2890 pszToken = strtok(NULL, szSpace);
2891 if(!pszToken) continue;
2892 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
2893 TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
2895 /* NT way of parsing ... :
2897 07-13-03 08:55PM <DIR> sakpatch
2898 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
2900 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
2901 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
2903 sscanf(pszToken, "%d-%d-%d",
2904 &lpfp->tmLastModified.tm_mon,
2905 &lpfp->tmLastModified.tm_mday,
2906 &lpfp->tmLastModified.tm_year);
2908 /* Hacky and bad Y2K protection :-) */
2909 if (lpfp->tmLastModified.tm_year < 70)
2910 lpfp->tmLastModified.tm_year += 100;
2912 pszToken = strtok(NULL, szSpace);
2913 if(!pszToken) continue;
2914 sscanf(pszToken, "%d:%d",
2915 &lpfp->tmLastModified.tm_hour,
2916 &lpfp->tmLastModified.tm_min);
2917 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
2918 lpfp->tmLastModified.tm_hour += 12;
2920 lpfp->tmLastModified.tm_sec = 0;
2922 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
2923 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
2924 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
2925 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
2927 pszToken = strtok(NULL, szSpace);
2928 if(!pszToken) continue;
2929 if(!strcasecmp(pszToken, "<DIR>")) {
2930 lpfp->bIsDirectory = TRUE;
2931 lpfp->nSize = 0;
2932 TRACE("Is directory\n");
2934 else {
2935 lpfp->bIsDirectory = FALSE;
2936 lpfp->nSize = atol(pszToken);
2937 TRACE("Size: %ld\n", lpfp->nSize);
2940 pszToken = strtok(NULL, szSpace);
2941 if(!pszToken) continue;
2942 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
2943 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
2945 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
2946 else if(pszToken[0] == '+') {
2947 FIXME("EPLF Format not implemented\n");
2950 if(lpfp->lpszName) {
2951 if((lpszSearchFile == NULL) ||
2952 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
2953 found = TRUE;
2954 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
2956 else {
2957 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
2958 lpfp->lpszName = NULL;
2961 } while(!found);
2962 return TRUE;
2965 /***********************************************************************
2966 * FTP_ParseDirectory (internal)
2968 * Parse string of directory information
2970 * RETURNS
2971 * TRUE on success
2972 * FALSE on failure
2974 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2975 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
2977 BOOL bSuccess = TRUE;
2978 INT sizeFilePropArray = 500;/*20; */
2979 INT indexFilePropArray = -1;
2981 TRACE("\n");
2983 /* Allocate intial file properties array */
2984 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
2985 if (!*lpafp)
2986 return FALSE;
2988 do {
2989 if (indexFilePropArray+1 >= sizeFilePropArray)
2991 LPFILEPROPERTIESW tmpafp;
2993 sizeFilePropArray *= 2;
2994 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
2995 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
2996 if (NULL == tmpafp)
2998 bSuccess = FALSE;
2999 break;
3002 *lpafp = tmpafp;
3004 indexFilePropArray++;
3005 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
3007 if (bSuccess && indexFilePropArray)
3009 if (indexFilePropArray < sizeFilePropArray - 1)
3011 LPFILEPROPERTIESW tmpafp;
3013 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
3014 sizeof(FILEPROPERTIESW)*indexFilePropArray);
3015 if (NULL == tmpafp)
3016 *lpafp = tmpafp;
3018 *dwfp = indexFilePropArray;
3020 else
3022 HeapFree(GetProcessHeap(), 0, *lpafp);
3023 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3024 bSuccess = FALSE;
3027 return bSuccess;
3031 /***********************************************************************
3032 * FTP_ParsePermission (internal)
3034 * Parse permission string of directory information
3036 * RETURNS
3037 * TRUE on success
3038 * FALSE on failure
3041 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3043 BOOL bSuccess = TRUE;
3044 unsigned short nPermission = 0;
3045 INT nPos = 1;
3046 INT nLast = 9;
3048 TRACE("\n");
3049 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3051 bSuccess = FALSE;
3052 return bSuccess;
3055 lpfp->bIsDirectory = (*lpszPermission == 'd');
3058 switch (nPos)
3060 case 1:
3061 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3062 break;
3063 case 2:
3064 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3065 break;
3066 case 3:
3067 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3068 break;
3069 case 4:
3070 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3071 break;
3072 case 5:
3073 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3074 break;
3075 case 6:
3076 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3077 break;
3078 case 7:
3079 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3080 break;
3081 case 8:
3082 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3083 break;
3084 case 9:
3085 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3086 break;
3088 nPos++;
3089 }while (nPos <= nLast);
3091 lpfp->permissions = nPermission;
3092 return bSuccess;
3096 /***********************************************************************
3097 * FTP_SetResponseError (internal)
3099 * Set the appropriate error code for a given response from the server
3101 * RETURNS
3104 static DWORD FTP_SetResponseError(DWORD dwResponse)
3106 DWORD dwCode = 0;
3108 switch(dwResponse)
3110 case 421: /* Service not available - Server may be shutting down. */
3111 dwCode = ERROR_INTERNET_TIMEOUT;
3112 break;
3114 case 425: /* Cannot open data connection. */
3115 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3116 break;
3118 case 426: /* Connection closed, transer aborted. */
3119 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3120 break;
3122 case 500: /* Syntax error. Command unrecognized. */
3123 case 501: /* Syntax error. Error in parameters or arguments. */
3124 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
3125 break;
3127 case 530: /* Not logged in. Login incorrect. */
3128 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3129 break;
3131 case 550: /* File action not taken. File not found or no access. */
3132 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
3133 break;
3135 case 450: /* File action not taken. File may be busy. */
3136 case 451: /* Action aborted. Server error. */
3137 case 452: /* Action not taken. Insufficient storage space on server. */
3138 case 502: /* Command not implemented. */
3139 case 503: /* Bad sequence of command. */
3140 case 504: /* Command not implemented for that parameter. */
3141 case 532: /* Need account for storing files */
3142 case 551: /* Requested action aborted. Page type unknown */
3143 case 552: /* Action aborted. Exceeded storage allocation */
3144 case 553: /* Action not taken. File name not allowed. */
3146 default:
3147 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
3148 break;
3151 INTERNET_SetLastError(dwCode);
3152 return dwCode;