Remove trailing backslash.
[wine.git] / dlls / wininet / ftp.c
blobaf4605f888cfd2b2cb2ef65c67ac33f5e3a60c4d
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
123 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext);
124 BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
125 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket);
126 BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile);
127 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext);
128 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
129 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile);
130 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs);
131 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs);
132 BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs);
133 BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs);
134 BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType);
135 BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize);
136 BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs);
137 BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs);
138 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs);
139 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp);
140 BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW fileprop);
141 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
142 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp);
143 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
144 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext);
145 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);
256 /* Open file to be uploaded */
257 if (INVALID_HANDLE_VALUE ==
258 (hFile = CreateFileW(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
260 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND);
261 goto lend;
264 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
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;
343 LPWININETAPPINFOW hIC = NULL;
344 BOOL r = FALSE;
346 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
347 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
349 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
350 goto lend;
353 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
355 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
356 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
358 WORKREQUEST workRequest;
359 struct WORKREQ_FTPSETCURRENTDIRECTORYW *req;
361 workRequest.asyncall = FTPSETCURRENTDIRECTORYW;
362 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
363 req = &workRequest.u.FtpSetCurrentDirectoryW;
364 req->lpszDirectory = WININET_strdupW(lpszDirectory);
366 r = INTERNET_AsyncCall(&workRequest);
368 else
370 r = FTP_FtpSetCurrentDirectoryW(lpwfs, lpszDirectory);
373 lend:
374 if( lpwfs )
375 WININET_Release( &lpwfs->hdr );
377 return r;
381 /***********************************************************************
382 * FTP_FtpSetCurrentDirectoryW (Internal)
384 * Change the working directory on the FTP server
386 * RETURNS
387 * TRUE on success
388 * FALSE on failure
391 BOOL WINAPI FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
393 INT nResCode;
394 LPWININETAPPINFOW hIC = NULL;
395 DWORD bSuccess = FALSE;
397 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
399 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
401 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
402 return FALSE;
405 /* Clear any error information */
406 INTERNET_SetLastError(0);
408 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
409 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
410 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
411 goto lend;
413 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
415 if (nResCode)
417 if (nResCode == 250)
418 bSuccess = TRUE;
419 else
420 FTP_SetResponseError(nResCode);
423 lend:
424 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
426 INTERNET_ASYNC_RESULT iar;
428 iar.dwResult = (DWORD)bSuccess;
429 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
430 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
431 &iar, sizeof(INTERNET_ASYNC_RESULT));
433 return bSuccess;
437 /***********************************************************************
438 * FtpCreateDirectoryA (WININET.@)
440 * Create new directory on the FTP server
442 * RETURNS
443 * TRUE on success
444 * FALSE on failure
447 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
449 LPWSTR lpwzDirectory;
450 BOOL ret;
452 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
453 ret = FtpCreateDirectoryW(hConnect, lpwzDirectory);
454 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
455 return ret;
459 /***********************************************************************
460 * FtpCreateDirectoryW (WININET.@)
462 * Create new directory on the FTP server
464 * RETURNS
465 * TRUE on success
466 * FALSE on failure
469 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
471 LPWININETFTPSESSIONW lpwfs;
472 LPWININETAPPINFOW hIC = NULL;
473 BOOL r = FALSE;
475 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
476 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
478 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
479 goto lend;
482 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
483 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
485 WORKREQUEST workRequest;
486 struct WORKREQ_FTPCREATEDIRECTORYW *req;
488 workRequest.asyncall = FTPCREATEDIRECTORYW;
489 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
490 req = &workRequest.u.FtpCreateDirectoryW;
491 req->lpszDirectory = WININET_strdupW(lpszDirectory);
493 r = INTERNET_AsyncCall(&workRequest);
495 else
497 r = FTP_FtpCreateDirectoryW(lpwfs, lpszDirectory);
499 lend:
500 if( lpwfs )
501 WININET_Release( &lpwfs->hdr );
503 return r;
507 /***********************************************************************
508 * FTP_FtpCreateDirectoryW (Internal)
510 * Create new directory on the FTP server
512 * RETURNS
513 * TRUE on success
514 * FALSE on failure
517 BOOL WINAPI FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
519 INT nResCode;
520 BOOL bSuccess = FALSE;
521 LPWININETAPPINFOW hIC = NULL;
523 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
525 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
527 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
528 return FALSE;
531 /* Clear any error information */
532 INTERNET_SetLastError(0);
534 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
535 goto lend;
537 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
538 if (nResCode)
540 if (nResCode == 257)
541 bSuccess = TRUE;
542 else
543 FTP_SetResponseError(nResCode);
546 lend:
547 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
548 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
550 INTERNET_ASYNC_RESULT iar;
552 iar.dwResult = (DWORD)bSuccess;
553 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
554 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
555 &iar, sizeof(INTERNET_ASYNC_RESULT));
558 return bSuccess;
561 /***********************************************************************
562 * FtpFindFirstFileA (WININET.@)
564 * Search the specified directory
566 * RETURNS
567 * HINTERNET on success
568 * NULL on failure
571 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
572 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
574 LPWSTR lpwzSearchFile;
575 WIN32_FIND_DATAW wfd;
576 LPWIN32_FIND_DATAW lpFindFileDataW;
577 HINTERNET ret;
579 lpwzSearchFile = lpszSearchFile?WININET_strdup_AtoW(lpszSearchFile):NULL;
580 lpFindFileDataW = lpFindFileData?&wfd:NULL;
581 ret = FtpFindFirstFileW(hConnect, lpwzSearchFile, lpFindFileDataW, dwFlags, dwContext);
582 HeapFree(GetProcessHeap(), 0, lpwzSearchFile);
584 if(lpFindFileData) {
585 WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData);
587 return ret;
591 /***********************************************************************
592 * FtpFindFirstFileW (WININET.@)
594 * Search the specified directory
596 * RETURNS
597 * HINTERNET on success
598 * NULL on failure
601 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
602 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
604 LPWININETFTPSESSIONW lpwfs;
605 LPWININETAPPINFOW hIC = NULL;
606 HINTERNET r = NULL;
608 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
609 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
611 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
612 goto lend;
615 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
616 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
618 WORKREQUEST workRequest;
619 struct WORKREQ_FTPFINDFIRSTFILEW *req;
621 workRequest.asyncall = FTPFINDFIRSTFILEW;
622 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
623 req = &workRequest.u.FtpFindFirstFileW;
624 req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : WININET_strdupW(lpszSearchFile);
625 req->lpFindFileData = lpFindFileData;
626 req->dwFlags = dwFlags;
627 req->dwContext= dwContext;
629 INTERNET_AsyncCall(&workRequest);
630 r = NULL;
632 else
634 r = FTP_FtpFindFirstFileW(lpwfs, lpszSearchFile, lpFindFileData,
635 dwFlags, dwContext);
637 lend:
638 if( lpwfs )
639 WININET_Release( &lpwfs->hdr );
641 return r;
645 /***********************************************************************
646 * FTP_FtpFindFirstFileW (Internal)
648 * Search the specified directory
650 * RETURNS
651 * HINTERNET on success
652 * NULL on failure
655 HINTERNET WINAPI FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs,
656 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
658 INT nResCode;
659 LPWININETAPPINFOW hIC = NULL;
660 HINTERNET hFindNext = NULL;
662 TRACE("\n");
664 assert(WH_HFTPSESSION == lpwfs->hdr.htype);
666 /* Clear any error information */
667 INTERNET_SetLastError(0);
669 if (!FTP_InitListenSocket(lpwfs))
670 goto lend;
672 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
673 goto lend;
675 if (!FTP_SendPortOrPasv(lpwfs))
676 goto lend;
678 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
679 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, NULL,
680 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
681 goto lend;
683 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
684 if (nResCode)
686 if (nResCode == 125 || nResCode == 150)
688 INT nDataSocket;
690 /* Get data socket to server */
691 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
693 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpszSearchFile, lpFindFileData, dwContext);
694 closesocket(nDataSocket);
695 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
696 if (nResCode != 226 && nResCode != 250)
697 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
700 else
701 FTP_SetResponseError(nResCode);
704 lend:
705 if (lpwfs->lstnSocket != -1)
706 closesocket(lpwfs->lstnSocket);
708 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
710 INTERNET_ASYNC_RESULT iar;
712 if (hFindNext)
714 iar.dwResult = (DWORD)hFindNext;
715 iar.dwError = ERROR_SUCCESS;
716 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
717 &iar, sizeof(INTERNET_ASYNC_RESULT));
720 iar.dwResult = (DWORD)hFindNext;
721 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
722 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
723 &iar, sizeof(INTERNET_ASYNC_RESULT));
726 return hFindNext;
730 /***********************************************************************
731 * FtpGetCurrentDirectoryA (WININET.@)
733 * Retrieves the current directory
735 * RETURNS
736 * TRUE on success
737 * FALSE on failure
740 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
741 LPDWORD lpdwCurrentDirectory)
743 WCHAR dir[MAX_PATH];
744 DWORD len;
745 BOOL ret;
747 if(lpdwCurrentDirectory) len = *lpdwCurrentDirectory;
748 ret = FtpGetCurrentDirectoryW(hFtpSession, lpszCurrentDirectory?dir:NULL, lpdwCurrentDirectory?&len:NULL);
749 if(lpdwCurrentDirectory) {
750 *lpdwCurrentDirectory = len;
751 if(lpszCurrentDirectory)
752 WideCharToMultiByte(CP_ACP, 0, dir, len, lpszCurrentDirectory, *lpdwCurrentDirectory, NULL, NULL);
754 return ret;
758 /***********************************************************************
759 * FtpGetCurrentDirectoryW (WININET.@)
761 * Retrieves the current directory
763 * RETURNS
764 * TRUE on success
765 * FALSE on failure
768 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
769 LPDWORD lpdwCurrentDirectory)
771 LPWININETFTPSESSIONW lpwfs;
772 LPWININETAPPINFOW hIC = NULL;
773 BOOL r = FALSE;
775 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
777 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
778 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
780 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
781 goto lend;
784 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
785 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
787 WORKREQUEST workRequest;
788 struct WORKREQ_FTPGETCURRENTDIRECTORYW *req;
790 workRequest.asyncall = FTPGETCURRENTDIRECTORYW;
791 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
792 req = &workRequest.u.FtpGetCurrentDirectoryW;
793 req->lpszDirectory = lpszCurrentDirectory;
794 req->lpdwDirectory = lpdwCurrentDirectory;
796 r = INTERNET_AsyncCall(&workRequest);
798 else
800 r = FTP_FtpGetCurrentDirectoryW(lpwfs, lpszCurrentDirectory,
801 lpdwCurrentDirectory);
804 lend:
805 if( lpwfs )
806 WININET_Release( &lpwfs->hdr );
808 return r;
812 /***********************************************************************
813 * FTP_FtpGetCurrentDirectoryA (Internal)
815 * Retrieves the current directory
817 * RETURNS
818 * TRUE on success
819 * FALSE on failure
822 BOOL WINAPI FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszCurrentDirectory,
823 LPDWORD lpdwCurrentDirectory)
825 INT nResCode;
826 LPWININETAPPINFOW hIC = NULL;
827 DWORD bSuccess = FALSE;
829 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
831 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
833 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
834 return FALSE;
837 /* Clear any error information */
838 INTERNET_SetLastError(0);
840 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
842 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
843 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
844 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
845 goto lend;
847 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
848 if (nResCode)
850 if (nResCode == 257) /* Extract directory name */
852 DWORD firstpos, lastpos, len;
853 LPWSTR lpszResponseBuffer = WININET_strdup_AtoW(INTERNET_GetResponseBuffer());
855 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
857 if ('"' == lpszResponseBuffer[lastpos])
859 if (!firstpos)
860 firstpos = lastpos;
861 else
862 break;
866 len = lastpos - firstpos - 1;
867 lstrcpynW(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1], *lpdwCurrentDirectory);
868 HeapFree(GetProcessHeap(), 0, lpszResponseBuffer);
869 *lpdwCurrentDirectory = len;
870 bSuccess = TRUE;
872 else
873 FTP_SetResponseError(nResCode);
876 lend:
877 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
879 INTERNET_ASYNC_RESULT iar;
881 iar.dwResult = (DWORD)bSuccess;
882 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
883 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
884 &iar, sizeof(INTERNET_ASYNC_RESULT));
887 return (DWORD) bSuccess;
890 /***********************************************************************
891 * FtpOpenFileA (WININET.@)
893 * Open a remote file for writing or reading
895 * RETURNS
896 * HINTERNET handle on success
897 * NULL on failure
900 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
901 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
902 DWORD dwContext)
904 LPWSTR lpwzFileName;
905 HINTERNET ret;
907 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
908 ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext);
909 HeapFree(GetProcessHeap(), 0, lpwzFileName);
910 return ret;
914 /***********************************************************************
915 * FtpOpenFileW (WININET.@)
917 * Open a remote file for writing or reading
919 * RETURNS
920 * HINTERNET handle on success
921 * NULL on failure
924 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
925 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
926 DWORD dwContext)
928 LPWININETFTPSESSIONW lpwfs;
929 LPWININETAPPINFOW hIC = NULL;
930 HINTERNET r = NULL;
932 TRACE("(%p,%s,0x%08lx,0x%08lx,0x%08lx)\n", hFtpSession,
933 debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext);
935 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
936 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
938 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
939 goto lend;
942 if (lpwfs->download_in_progress != NULL) {
943 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
944 goto lend;
946 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
947 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
949 WORKREQUEST workRequest;
950 struct WORKREQ_FTPOPENFILEW *req;
952 workRequest.asyncall = FTPOPENFILEW;
953 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
954 req = &workRequest.u.FtpOpenFileW;
955 req->lpszFilename = WININET_strdupW(lpszFileName);
956 req->dwAccess = fdwAccess;
957 req->dwFlags = dwFlags;
958 req->dwContext = dwContext;
960 INTERNET_AsyncCall(&workRequest);
961 r = NULL;
963 else
965 r = FTP_FtpOpenFileW(lpwfs, lpszFileName, fdwAccess, dwFlags, dwContext);
968 lend:
969 if( lpwfs )
970 WININET_Release( &lpwfs->hdr );
972 return r;
976 /***********************************************************************
977 * FTP_FtpOpenFileW (Internal)
979 * Open a remote file for writing or reading
981 * RETURNS
982 * HINTERNET handle on success
983 * NULL on failure
986 HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs,
987 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
988 DWORD dwContext)
990 INT nDataSocket;
991 BOOL bSuccess = FALSE;
992 LPWININETFILE lpwh = NULL;
993 LPWININETAPPINFOW hIC = NULL;
994 HINTERNET handle = NULL;
996 TRACE("\n");
998 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1000 /* Clear any error information */
1001 INTERNET_SetLastError(0);
1003 if (GENERIC_READ == fdwAccess)
1005 /* Set up socket to retrieve data */
1006 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
1008 else if (GENERIC_WRITE == fdwAccess)
1010 /* Set up socket to send data */
1011 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
1014 /* Get data socket to server */
1015 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
1017 lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE));
1018 lpwh->hdr.htype = WH_HFILE;
1019 lpwh->hdr.dwFlags = dwFlags;
1020 lpwh->hdr.dwContext = dwContext;
1021 lpwh->hdr.lpwhparent = WININET_AddRef( &lpwfs->hdr );
1022 lpwh->hdr.dwRefCount = 1;
1023 lpwh->hdr.destroy = FTP_CloseFileTransferHandle;
1024 lpwh->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
1025 lpwh->nDataSocket = nDataSocket;
1026 lpwh->session_deleted = FALSE;
1028 handle = WININET_AllocHandle( &lpwh->hdr );
1029 if( !handle )
1030 goto lend;
1032 /* Indicate that a download is currently in progress */
1033 lpwfs->download_in_progress = lpwh;
1036 if (lpwfs->lstnSocket != -1)
1037 closesocket(lpwfs->lstnSocket);
1039 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1040 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1042 INTERNET_ASYNC_RESULT iar;
1044 if (lpwh)
1046 iar.dwResult = (DWORD)handle;
1047 iar.dwError = ERROR_SUCCESS;
1048 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
1049 &iar, sizeof(INTERNET_ASYNC_RESULT));
1052 iar.dwResult = (DWORD)bSuccess;
1053 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1054 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1055 &iar, sizeof(INTERNET_ASYNC_RESULT));
1058 lend:
1059 if( lpwh )
1060 WININET_Release( &lpwh->hdr );
1062 return handle;
1066 /***********************************************************************
1067 * FtpGetFileA (WININET.@)
1069 * Retrieve file from the FTP server
1071 * RETURNS
1072 * TRUE on success
1073 * FALSE on failure
1076 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1077 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1078 DWORD dwContext)
1080 LPWSTR lpwzRemoteFile;
1081 LPWSTR lpwzNewFile;
1082 BOOL ret;
1084 lpwzRemoteFile = lpszRemoteFile?WININET_strdup_AtoW(lpszRemoteFile):NULL;
1085 lpwzNewFile = lpszNewFile?WININET_strdup_AtoW(lpszNewFile):NULL;
1086 ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists,
1087 dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1088 HeapFree(GetProcessHeap(), 0, lpwzRemoteFile);
1089 HeapFree(GetProcessHeap(), 0, lpwzNewFile);
1090 return ret;
1094 /***********************************************************************
1095 * FtpGetFileW (WININET.@)
1097 * Retrieve file from the FTP server
1099 * RETURNS
1100 * TRUE on success
1101 * FALSE on failure
1104 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1105 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1106 DWORD dwContext)
1108 LPWININETFTPSESSIONW lpwfs;
1109 LPWININETAPPINFOW hIC = NULL;
1110 BOOL r = FALSE;
1112 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet );
1113 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1115 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1116 goto lend;
1119 if (lpwfs->download_in_progress != NULL) {
1120 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1121 goto lend;
1124 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1125 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1127 WORKREQUEST workRequest;
1128 struct WORKREQ_FTPGETFILEW *req;
1130 workRequest.asyncall = FTPGETFILEW;
1131 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1132 req = &workRequest.u.FtpGetFileW;
1133 req->lpszRemoteFile = WININET_strdupW(lpszRemoteFile);
1134 req->lpszNewFile = WININET_strdupW(lpszNewFile);
1135 req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1136 req->fFailIfExists = fFailIfExists;
1137 req->dwFlags = dwInternetFlags;
1138 req->dwContext = dwContext;
1140 r = INTERNET_AsyncCall(&workRequest);
1142 else
1144 r = FTP_FtpGetFileW(lpwfs, lpszRemoteFile, lpszNewFile,
1145 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1148 lend:
1149 if( lpwfs )
1150 WININET_Release( &lpwfs->hdr );
1152 return r;
1156 /***********************************************************************
1157 * FTP_FtpGetFileW (Internal)
1159 * Retrieve file from the FTP server
1161 * RETURNS
1162 * TRUE on success
1163 * FALSE on failure
1166 BOOL WINAPI FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1167 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1168 DWORD dwContext)
1170 DWORD nBytes;
1171 BOOL bSuccess = FALSE;
1172 HANDLE hFile;
1173 LPWININETAPPINFOW hIC = NULL;
1175 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile));
1177 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1179 /* Clear any error information */
1180 INTERNET_SetLastError(0);
1182 /* Ensure we can write to lpszNewfile by opening it */
1183 hFile = CreateFileW(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1184 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1185 if (INVALID_HANDLE_VALUE == hFile)
1186 goto lend;
1188 /* Set up socket to retrieve data */
1189 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
1191 if (nBytes > 0)
1193 INT nDataSocket;
1195 /* Get data socket to server */
1196 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1198 INT nResCode;
1200 /* Receive data */
1201 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
1202 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
1203 if (nResCode)
1205 if (nResCode == 226)
1206 bSuccess = TRUE;
1207 else
1208 FTP_SetResponseError(nResCode);
1210 closesocket(nDataSocket);
1214 lend:
1215 if (lpwfs->lstnSocket != -1)
1216 closesocket(lpwfs->lstnSocket);
1218 if (hFile)
1219 CloseHandle(hFile);
1221 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1222 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1224 INTERNET_ASYNC_RESULT iar;
1226 iar.dwResult = (DWORD)bSuccess;
1227 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1228 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1229 &iar, sizeof(INTERNET_ASYNC_RESULT));
1232 return bSuccess;
1235 /***********************************************************************
1236 * FtpGetFileSize (WININET.@)
1238 DWORD WINAPI FtpGetFileSize( HINTERNET hFile, LPDWORD lpdwFileSizeHigh )
1240 FIXME("(%p, %p)\n", hFile, lpdwFileSizeHigh);
1242 if (lpdwFileSizeHigh)
1243 *lpdwFileSizeHigh = 0;
1245 return 0;
1248 /***********************************************************************
1249 * FtpDeleteFileA (WININET.@)
1251 * Delete a file on the ftp server
1253 * RETURNS
1254 * TRUE on success
1255 * FALSE on failure
1258 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1260 LPWSTR lpwzFileName;
1261 BOOL ret;
1263 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1264 ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1265 HeapFree(GetProcessHeap(), 0, lpwzFileName);
1266 return ret;
1269 /***********************************************************************
1270 * FtpDeleteFileW (WININET.@)
1272 * Delete a file on the ftp server
1274 * RETURNS
1275 * TRUE on success
1276 * FALSE on failure
1279 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1281 LPWININETFTPSESSIONW lpwfs;
1282 LPWININETAPPINFOW hIC = NULL;
1283 BOOL r = FALSE;
1285 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1286 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1288 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1289 goto lend;
1292 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1293 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1295 WORKREQUEST workRequest;
1296 struct WORKREQ_FTPDELETEFILEW *req;
1298 workRequest.asyncall = FTPDELETEFILEW;
1299 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1300 req = &workRequest.u.FtpDeleteFileW;
1301 req->lpszFilename = WININET_strdupW(lpszFileName);
1303 r = INTERNET_AsyncCall(&workRequest);
1305 else
1307 r = FTP_FtpDeleteFileW(hFtpSession, lpszFileName);
1310 lend:
1311 if( lpwfs )
1312 WININET_Release( &lpwfs->hdr );
1314 return r;
1317 /***********************************************************************
1318 * FTP_FtpDeleteFileW (Internal)
1320 * Delete a file on the ftp server
1322 * RETURNS
1323 * TRUE on success
1324 * FALSE on failure
1327 BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName)
1329 INT nResCode;
1330 BOOL bSuccess = FALSE;
1331 LPWININETAPPINFOW hIC = NULL;
1333 TRACE("%p\n", lpwfs);
1335 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1337 /* Clear any error information */
1338 INTERNET_SetLastError(0);
1340 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1341 goto lend;
1343 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1344 if (nResCode)
1346 if (nResCode == 250)
1347 bSuccess = TRUE;
1348 else
1349 FTP_SetResponseError(nResCode);
1351 lend:
1352 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1353 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1355 INTERNET_ASYNC_RESULT iar;
1357 iar.dwResult = (DWORD)bSuccess;
1358 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1359 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1360 &iar, sizeof(INTERNET_ASYNC_RESULT));
1363 return bSuccess;
1367 /***********************************************************************
1368 * FtpRemoveDirectoryA (WININET.@)
1370 * Remove a directory on the ftp server
1372 * RETURNS
1373 * TRUE on success
1374 * FALSE on failure
1377 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1379 LPWSTR lpwzDirectory;
1380 BOOL ret;
1382 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
1383 ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1384 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
1385 return ret;
1388 /***********************************************************************
1389 * FtpRemoveDirectoryW (WININET.@)
1391 * Remove a directory on the ftp server
1393 * RETURNS
1394 * TRUE on success
1395 * FALSE on failure
1398 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1400 LPWININETFTPSESSIONW lpwfs;
1401 LPWININETAPPINFOW hIC = NULL;
1402 BOOL r = FALSE;
1404 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1405 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1407 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1408 goto lend;
1411 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1412 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1414 WORKREQUEST workRequest;
1415 struct WORKREQ_FTPREMOVEDIRECTORYW *req;
1417 workRequest.asyncall = FTPREMOVEDIRECTORYW;
1418 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1419 req = &workRequest.u.FtpRemoveDirectoryW;
1420 req->lpszDirectory = WININET_strdupW(lpszDirectory);
1422 r = INTERNET_AsyncCall(&workRequest);
1424 else
1426 r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory);
1429 lend:
1430 if( lpwfs )
1431 WININET_Release( &lpwfs->hdr );
1433 return r;
1436 /***********************************************************************
1437 * FTP_FtpRemoveDirectoryW (Internal)
1439 * Remove a directory on the ftp server
1441 * RETURNS
1442 * TRUE on success
1443 * FALSE on failure
1446 BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
1448 INT nResCode;
1449 BOOL bSuccess = FALSE;
1450 LPWININETAPPINFOW hIC = NULL;
1452 TRACE("\n");
1454 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1456 /* Clear any error information */
1457 INTERNET_SetLastError(0);
1459 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1460 goto lend;
1462 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1463 if (nResCode)
1465 if (nResCode == 250)
1466 bSuccess = TRUE;
1467 else
1468 FTP_SetResponseError(nResCode);
1471 lend:
1472 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1473 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1475 INTERNET_ASYNC_RESULT iar;
1477 iar.dwResult = (DWORD)bSuccess;
1478 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1479 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1480 &iar, sizeof(INTERNET_ASYNC_RESULT));
1483 return bSuccess;
1487 /***********************************************************************
1488 * FtpRenameFileA (WININET.@)
1490 * Rename a file on the ftp server
1492 * RETURNS
1493 * TRUE on success
1494 * FALSE on failure
1497 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1499 LPWSTR lpwzSrc;
1500 LPWSTR lpwzDest;
1501 BOOL ret;
1503 lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL;
1504 lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL;
1505 ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
1506 HeapFree(GetProcessHeap(), 0, lpwzSrc);
1507 HeapFree(GetProcessHeap(), 0, lpwzDest);
1508 return ret;
1511 /***********************************************************************
1512 * FtpRenameFileW (WININET.@)
1514 * Rename a file on the ftp server
1516 * RETURNS
1517 * TRUE on success
1518 * FALSE on failure
1521 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
1523 LPWININETFTPSESSIONW lpwfs;
1524 LPWININETAPPINFOW hIC = NULL;
1525 BOOL r = FALSE;
1527 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1528 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1530 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1531 goto lend;
1534 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1535 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1537 WORKREQUEST workRequest;
1538 struct WORKREQ_FTPRENAMEFILEW *req;
1540 workRequest.asyncall = FTPRENAMEFILEW;
1541 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1542 req = &workRequest.u.FtpRenameFileW;
1543 req->lpszSrcFile = WININET_strdupW(lpszSrc);
1544 req->lpszDestFile = WININET_strdupW(lpszDest);
1546 r = INTERNET_AsyncCall(&workRequest);
1548 else
1550 r = FTP_FtpRenameFileW(hFtpSession, lpszSrc, lpszDest);
1553 lend:
1554 if( lpwfs )
1555 WININET_Release( &lpwfs->hdr );
1557 return r;
1560 /***********************************************************************
1561 * FTP_FtpRenameFileA (Internal)
1563 * Rename a file on the ftp server
1565 * RETURNS
1566 * TRUE on success
1567 * FALSE on failure
1570 BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs,
1571 LPCWSTR lpszSrc, LPCWSTR lpszDest)
1573 INT nResCode;
1574 BOOL bSuccess = FALSE;
1575 LPWININETAPPINFOW hIC = NULL;
1577 TRACE("\n");
1579 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1581 /* Clear any error information */
1582 INTERNET_SetLastError(0);
1584 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1585 goto lend;
1587 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1588 if (nResCode == 350)
1590 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1591 goto lend;
1593 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1596 if (nResCode == 250)
1597 bSuccess = TRUE;
1598 else
1599 FTP_SetResponseError(nResCode);
1601 lend:
1602 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1603 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1605 INTERNET_ASYNC_RESULT iar;
1607 iar.dwResult = (DWORD)bSuccess;
1608 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1609 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1610 &iar, sizeof(INTERNET_ASYNC_RESULT));
1613 return bSuccess;
1616 /***********************************************************************
1617 * FtpCommandA (WININET.@)
1619 BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1620 LPCSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1622 FIXME("%p %d 0x%08lx %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1623 debugstr_a(lpszCommand), dwContext, phFtpCommand);
1625 return TRUE;
1628 /***********************************************************************
1629 * FtpCommandW (WININET.@)
1631 BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1632 LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1634 FIXME("%p %d 0x%08lx %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1635 debugstr_w(lpszCommand), dwContext, phFtpCommand);
1637 return TRUE;
1640 /***********************************************************************
1641 * FTP_Connect (internal)
1643 * Connect to a ftp server
1645 * RETURNS
1646 * HINTERNET a session handle on success
1647 * NULL on failure
1651 HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
1652 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1653 LPCWSTR lpszPassword, DWORD dwFlags, DWORD dwContext,
1654 DWORD dwInternalFlags)
1656 static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'};
1657 static const WCHAR szDefaultPassword[] = {'u','s','e','r','@','s','e','r','v','e','r','\0'};
1658 struct sockaddr_in socketAddr;
1659 struct hostent *phe = NULL;
1660 INT nsocket = -1;
1661 UINT sock_namelen;
1662 BOOL bSuccess = FALSE;
1663 LPWININETFTPSESSIONW lpwfs = NULL;
1664 HINTERNET handle = NULL;
1666 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1667 hIC, debugstr_w(lpszServerName),
1668 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
1670 assert( hIC->hdr.htype == WH_HINIT );
1672 if (NULL == lpszUserName && NULL != lpszPassword)
1674 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1675 goto lerror;
1678 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
1679 if (NULL == lpwfs)
1681 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1682 goto lerror;
1685 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1686 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1688 lpwfs->hdr.htype = WH_HFTPSESSION;
1689 lpwfs->hdr.lpwhparent = WININET_AddRef( &hIC->hdr );
1690 lpwfs->hdr.dwFlags = dwFlags;
1691 lpwfs->hdr.dwContext = dwContext;
1692 lpwfs->hdr.dwInternalFlags = dwInternalFlags;
1693 lpwfs->hdr.dwRefCount = 1;
1694 lpwfs->hdr.destroy = FTP_CloseSessionHandle;
1695 lpwfs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
1696 lpwfs->download_in_progress = NULL;
1698 handle = WININET_AllocHandle( &lpwfs->hdr );
1699 if( !handle )
1701 ERR("Failed to alloc handle\n");
1702 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1703 goto lerror;
1706 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1707 if(strchrW(hIC->lpszProxy, ' '))
1708 FIXME("Several proxies not implemented.\n");
1709 if(hIC->lpszProxyBypass)
1710 FIXME("Proxy bypass is ignored.\n");
1712 if ( !lpszUserName) {
1713 lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
1714 lpwfs->lpszPassword = WININET_strdupW(szDefaultPassword);
1716 else {
1717 lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
1718 lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
1721 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1722 if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
1724 INTERNET_ASYNC_RESULT iar;
1726 iar.dwResult = (DWORD)handle;
1727 iar.dwError = ERROR_SUCCESS;
1729 SendAsyncCallback(&hIC->hdr, dwContext,
1730 INTERNET_STATUS_HANDLE_CREATED, &iar,
1731 sizeof(INTERNET_ASYNC_RESULT));
1734 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1735 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1737 if (!GetAddress(lpszServerName, nServerPort, &phe, &socketAddr))
1739 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1740 goto lerror;
1743 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1744 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1746 nsocket = socket(AF_INET,SOCK_STREAM,0);
1747 if (nsocket == -1)
1749 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1750 goto lerror;
1753 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1754 &socketAddr, sizeof(struct sockaddr_in));
1756 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1758 ERR("Unable to connect (%s)\n", strerror(errno));
1759 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1761 else
1763 TRACE("Connected to server\n");
1764 lpwfs->sndSocket = nsocket;
1765 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1766 &socketAddr, sizeof(struct sockaddr_in));
1768 sock_namelen = sizeof(lpwfs->socketAddress);
1769 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1770 lpwfs->phostent = phe;
1772 if (FTP_ConnectToHost(lpwfs))
1774 TRACE("Successfully logged into server\n");
1775 bSuccess = TRUE;
1779 lerror:
1780 if (!bSuccess && nsocket == -1)
1781 closesocket(nsocket);
1783 if (!bSuccess && lpwfs)
1785 HeapFree(GetProcessHeap(), 0, lpwfs);
1786 WININET_FreeHandle( handle );
1787 lpwfs = NULL;
1790 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1792 INTERNET_ASYNC_RESULT iar;
1794 iar.dwResult = (DWORD)lpwfs;
1795 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1796 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1797 &iar, sizeof(INTERNET_ASYNC_RESULT));
1800 return handle;
1804 /***********************************************************************
1805 * FTP_ConnectToHost (internal)
1807 * Connect to a ftp server
1809 * RETURNS
1810 * TRUE on success
1811 * NULL on failure
1814 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
1816 INT nResCode;
1817 BOOL bSuccess = FALSE;
1819 TRACE("\n");
1820 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1822 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1823 goto lend;
1825 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1826 if (nResCode)
1828 /* Login successful... */
1829 if (nResCode == 230)
1830 bSuccess = TRUE;
1831 /* User name okay, need password... */
1832 else if (nResCode == 331)
1833 bSuccess = FTP_SendPassword(lpwfs);
1834 /* Need account for login... */
1835 else if (nResCode == 332)
1836 bSuccess = FTP_SendAccount(lpwfs);
1837 else
1838 FTP_SetResponseError(nResCode);
1841 TRACE("Returning %d\n", bSuccess);
1842 lend:
1843 return bSuccess;
1847 /***********************************************************************
1848 * FTP_SendCommandA (internal)
1850 * Send command to server
1852 * RETURNS
1853 * TRUE on success
1854 * NULL on failure
1857 static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1858 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
1860 DWORD len;
1861 CHAR *buf;
1862 DWORD nBytesSent = 0;
1863 int nRC = 0;
1864 DWORD dwParamLen;
1866 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1868 if (lpfnStatusCB)
1870 HINTERNET hHandle = WININET_FindHandle( hdr );
1871 if( hHandle )
1873 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1874 WININET_Release( hdr );
1878 dwParamLen = lpszParam?strlen(lpszParam)+1:0;
1879 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
1880 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1882 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1883 return FALSE;
1885 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
1886 dwParamLen ? lpszParam : "", szCRLF);
1888 TRACE("Sending (%s) len(%ld)\n", buf, len);
1889 while((nBytesSent < len) && (nRC != -1))
1891 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1892 nBytesSent += nRC;
1895 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
1897 if (lpfnStatusCB)
1899 HINTERNET hHandle = WININET_FindHandle( hdr );
1900 if( hHandle )
1902 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_REQUEST_SENT,
1903 &nBytesSent, sizeof(DWORD));
1904 WININET_Release( hdr );
1908 TRACE("Sent %ld bytes\n", nBytesSent);
1909 return (nRC != -1);
1912 /***********************************************************************
1913 * FTP_SendCommand (internal)
1915 * Send command to server
1917 * RETURNS
1918 * TRUE on success
1919 * NULL on failure
1922 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
1923 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
1925 BOOL ret;
1926 LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
1927 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
1928 HeapFree(GetProcessHeap(), 0, lpszParamA);
1929 return ret;
1932 /***********************************************************************
1933 * FTP_ReceiveResponse (internal)
1935 * Receive response from server
1937 * RETURNS
1938 * Reply code on success
1939 * 0 on failure
1942 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext)
1944 LPSTR lpszResponse = INTERNET_GetResponseBuffer();
1945 DWORD nRecv;
1946 INT rc = 0;
1947 char firstprefix[5];
1948 BOOL multiline = FALSE;
1949 LPWININETAPPINFOW hIC = NULL;
1951 TRACE("socket(%d) \n", lpwfs->sndSocket);
1953 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1954 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1956 while(1)
1958 if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
1959 goto lerror;
1961 if (nRecv >= 3)
1963 if(!multiline)
1965 if(lpszResponse[3] != '-')
1966 break;
1967 else
1968 { /* Start of multiline repsonse. Loop until we get "nnn " */
1969 multiline = TRUE;
1970 memcpy(firstprefix, lpszResponse, 3);
1971 firstprefix[3] = ' ';
1972 firstprefix[4] = '\0';
1975 else
1977 if(!memcmp(firstprefix, lpszResponse, 4))
1978 break;
1983 if (nRecv >= 3)
1985 rc = atoi(lpszResponse);
1987 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
1988 &nRecv, sizeof(DWORD));
1991 lerror:
1992 TRACE("return %d\n", rc);
1993 return rc;
1997 /***********************************************************************
1998 * FTP_SendPassword (internal)
2000 * Send password to ftp server
2002 * RETURNS
2003 * TRUE on success
2004 * NULL on failure
2007 BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
2009 INT nResCode;
2010 BOOL bSuccess = FALSE;
2012 TRACE("\n");
2013 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
2014 goto lend;
2016 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2017 if (nResCode)
2019 TRACE("Received reply code %d\n", nResCode);
2020 /* Login successful... */
2021 if (nResCode == 230)
2022 bSuccess = TRUE;
2023 /* Command not implemented, superfluous at the server site... */
2024 /* Need account for login... */
2025 else if (nResCode == 332)
2026 bSuccess = FTP_SendAccount(lpwfs);
2027 else
2028 FTP_SetResponseError(nResCode);
2031 lend:
2032 TRACE("Returning %d\n", bSuccess);
2033 return bSuccess;
2037 /***********************************************************************
2038 * FTP_SendAccount (internal)
2042 * RETURNS
2043 * TRUE on success
2044 * FALSE on failure
2047 BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
2049 INT nResCode;
2050 BOOL bSuccess = FALSE;
2052 TRACE("\n");
2053 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
2054 goto lend;
2056 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2057 if (nResCode)
2058 bSuccess = TRUE;
2059 else
2060 FTP_SetResponseError(nResCode);
2062 lend:
2063 return bSuccess;
2067 /***********************************************************************
2068 * FTP_SendStore (internal)
2070 * Send request to upload file to ftp server
2072 * RETURNS
2073 * TRUE on success
2074 * FALSE on failure
2077 BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2079 INT nResCode;
2080 BOOL bSuccess = FALSE;
2082 TRACE("\n");
2083 if (!FTP_InitListenSocket(lpwfs))
2084 goto lend;
2086 if (!FTP_SendType(lpwfs, dwType))
2087 goto lend;
2089 if (!FTP_SendPortOrPasv(lpwfs))
2090 goto lend;
2092 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2093 goto lend;
2094 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2095 if (nResCode)
2097 if (nResCode == 150)
2098 bSuccess = TRUE;
2099 else
2100 FTP_SetResponseError(nResCode);
2103 lend:
2104 if (!bSuccess && lpwfs->lstnSocket != -1)
2106 closesocket(lpwfs->lstnSocket);
2107 lpwfs->lstnSocket = -1;
2110 return bSuccess;
2114 /***********************************************************************
2115 * FTP_InitListenSocket (internal)
2117 * Create a socket to listen for server response
2119 * RETURNS
2120 * TRUE on success
2121 * FALSE on failure
2124 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
2126 BOOL bSuccess = FALSE;
2127 size_t namelen = sizeof(struct sockaddr_in);
2129 TRACE("\n");
2131 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2132 if (lpwfs->lstnSocket == -1)
2134 TRACE("Unable to create listening socket\n");
2135 goto lend;
2138 /* We obtain our ip addr from the name of the command channel socket */
2139 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2141 /* and get the system to assign us a port */
2142 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
2144 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
2146 TRACE("Unable to bind socket\n");
2147 goto lend;
2150 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2152 TRACE("listen failed\n");
2153 goto lend;
2156 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2157 bSuccess = TRUE;
2159 lend:
2160 if (!bSuccess && lpwfs->lstnSocket == -1)
2162 closesocket(lpwfs->lstnSocket);
2163 lpwfs->lstnSocket = -1;
2166 return bSuccess;
2170 /***********************************************************************
2171 * FTP_SendType (internal)
2173 * Tell server type of data being transferred
2175 * RETURNS
2176 * TRUE on success
2177 * FALSE on failure
2179 * W98SE doesn't cache the type that's currently set
2180 * (i.e. it sends it always),
2181 * so we probably don't want to do that either.
2183 BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
2185 INT nResCode;
2186 WCHAR type[] = { 'I','\0' };
2187 BOOL bSuccess = FALSE;
2189 TRACE("\n");
2190 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2191 type[0] = 'A';
2193 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2194 goto lend;
2196 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2197 if (nResCode)
2199 if (nResCode == 2)
2200 bSuccess = TRUE;
2201 else
2202 FTP_SetResponseError(nResCode);
2205 lend:
2206 return bSuccess;
2209 /***********************************************************************
2210 * FTP_GetFileSize (internal)
2212 * Retrieves from the server the size of the given file
2214 * RETURNS
2215 * TRUE on success
2216 * FALSE on failure
2219 BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
2221 INT nResCode;
2222 BOOL bSuccess = FALSE;
2224 TRACE("\n");
2226 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2227 goto lend;
2229 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2230 if (nResCode)
2232 if (nResCode == 213) {
2233 /* Now parses the output to get the actual file size */
2234 int i;
2235 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2237 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2238 if (lpszResponseBuffer[i] == '\0') return FALSE;
2239 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2241 bSuccess = TRUE;
2242 } else {
2243 FTP_SetResponseError(nResCode);
2247 lend:
2248 return bSuccess;
2252 /***********************************************************************
2253 * FTP_SendPort (internal)
2255 * Tell server which port to use
2257 * RETURNS
2258 * TRUE on success
2259 * FALSE on failure
2262 BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
2264 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2265 INT nResCode;
2266 WCHAR szIPAddress[64];
2267 BOOL bSuccess = FALSE;
2268 TRACE("\n");
2270 sprintfW(szIPAddress, szIPFormat,
2271 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2272 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2273 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2274 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2275 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2276 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2278 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2279 goto lend;
2281 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2282 if (nResCode)
2284 if (nResCode == 200)
2285 bSuccess = TRUE;
2286 else
2287 FTP_SetResponseError(nResCode);
2290 lend:
2291 return bSuccess;
2295 /***********************************************************************
2296 * FTP_DoPassive (internal)
2298 * Tell server that we want to do passive transfers
2299 * and connect data socket
2301 * RETURNS
2302 * TRUE on success
2303 * FALSE on failure
2306 BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
2308 INT nResCode;
2309 BOOL bSuccess = FALSE;
2311 TRACE("\n");
2312 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2313 goto lend;
2315 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2316 if (nResCode)
2318 if (nResCode == 227)
2320 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2321 LPSTR p;
2322 int f[6];
2323 int i;
2324 char *pAddr, *pPort;
2325 INT nsocket = -1;
2326 struct sockaddr_in dataSocketAddress;
2328 p = lpszResponseBuffer+4; /* skip status code */
2330 /* do a very strict check; we can improve that later. */
2332 if (strncmp(p, "Entering Passive Mode", 21))
2334 ERR("unknown response '%.*s', aborting\n", 21, p);
2335 goto lend;
2337 p += 21; /* skip string */
2338 if ((*p++ != ' ') || (*p++ != '('))
2340 ERR("unknown response format, aborting\n");
2341 goto lend;
2344 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2345 &f[4], &f[5]) != 6)
2347 ERR("unknown response address format '%s', aborting\n", p);
2348 goto lend;
2350 for (i=0; i < 6; i++)
2351 f[i] = f[i] & 0xff;
2353 dataSocketAddress = lpwfs->socketAddress;
2354 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2355 pPort = (char *)&(dataSocketAddress.sin_port);
2356 pAddr[0] = f[0];
2357 pAddr[1] = f[1];
2358 pAddr[2] = f[2];
2359 pAddr[3] = f[3];
2360 pPort[0] = f[4];
2361 pPort[1] = f[5];
2363 nsocket = socket(AF_INET,SOCK_STREAM,0);
2364 if (nsocket == -1)
2365 goto lend;
2367 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2369 ERR("can't connect passive FTP data port.\n");
2370 goto lend;
2372 lpwfs->pasvSocket = nsocket;
2373 bSuccess = TRUE;
2375 else
2376 FTP_SetResponseError(nResCode);
2379 lend:
2380 return bSuccess;
2384 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
2386 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2388 if (!FTP_DoPassive(lpwfs))
2389 return FALSE;
2391 else
2393 if (!FTP_SendPort(lpwfs))
2394 return FALSE;
2396 return TRUE;
2400 /***********************************************************************
2401 * FTP_GetDataSocket (internal)
2403 * Either accepts an incoming data socket connection from the server
2404 * or just returns the already opened socket after a PASV command
2405 * in case of passive FTP.
2408 * RETURNS
2409 * TRUE on success
2410 * FALSE on failure
2413 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
2415 struct sockaddr_in saddr;
2416 size_t addrlen = sizeof(struct sockaddr);
2418 TRACE("\n");
2419 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2421 *nDataSocket = lpwfs->pasvSocket;
2423 else
2425 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2426 closesocket(lpwfs->lstnSocket);
2427 lpwfs->lstnSocket = -1;
2429 return *nDataSocket != -1;
2433 /***********************************************************************
2434 * FTP_SendData (internal)
2436 * Send data to the server
2438 * RETURNS
2439 * TRUE on success
2440 * FALSE on failure
2443 BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2445 BY_HANDLE_FILE_INFORMATION fi;
2446 DWORD nBytesRead = 0;
2447 DWORD nBytesSent = 0;
2448 DWORD nTotalSent = 0;
2449 DWORD nBytesToSend, nLen;
2450 int nRC = 1;
2451 time_t s_long_time, e_long_time;
2452 LONG nSeconds;
2453 CHAR *lpszBuffer;
2455 TRACE("\n");
2456 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2457 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2459 /* Get the size of the file. */
2460 GetFileInformationByHandle(hFile, &fi);
2461 time(&s_long_time);
2465 nBytesToSend = nBytesRead - nBytesSent;
2467 if (nBytesToSend <= 0)
2469 /* Read data from file. */
2470 nBytesSent = 0;
2471 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2472 ERR("Failed reading from file\n");
2474 if (nBytesRead > 0)
2475 nBytesToSend = nBytesRead;
2476 else
2477 break;
2480 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2481 DATA_PACKET_SIZE : nBytesToSend;
2482 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2484 if (nRC != -1)
2486 nBytesSent += nRC;
2487 nTotalSent += nRC;
2490 /* Do some computation to display the status. */
2491 time(&e_long_time);
2492 nSeconds = e_long_time - s_long_time;
2493 if( nSeconds / 60 > 0 )
2495 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
2496 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2497 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2499 else
2501 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
2502 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2503 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2505 } while (nRC != -1);
2507 TRACE("file transfer complete!\n");
2509 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2511 return nTotalSent;
2515 /***********************************************************************
2516 * FTP_SendRetrieve (internal)
2518 * Send request to retrieve a file
2520 * RETURNS
2521 * Number of bytes to be received on success
2522 * 0 on failure
2525 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2527 INT nResCode;
2528 DWORD nResult = 0;
2530 TRACE("\n");
2531 if (!FTP_InitListenSocket(lpwfs))
2532 goto lend;
2534 if (!FTP_SendType(lpwfs, dwType))
2535 goto lend;
2537 if (!FTP_SendPortOrPasv(lpwfs))
2538 goto lend;
2540 if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2541 goto lend;
2543 TRACE("Waiting to receive %ld bytes\n", nResult);
2545 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2546 goto lend;
2548 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2549 if ((nResCode != 125) && (nResCode != 150)) {
2550 /* That means that we got an error getting the file. */
2551 nResult = 0;
2554 lend:
2555 if (0 == nResult && lpwfs->lstnSocket != -1)
2557 closesocket(lpwfs->lstnSocket);
2558 lpwfs->lstnSocket = -1;
2561 return nResult;
2565 /***********************************************************************
2566 * FTP_RetrieveData (internal)
2568 * Retrieve data from server
2570 * RETURNS
2571 * TRUE on success
2572 * FALSE on failure
2575 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2577 DWORD nBytesWritten;
2578 DWORD nBytesReceived = 0;
2579 INT nRC = 0;
2580 CHAR *lpszBuffer;
2582 TRACE("\n");
2584 if (INVALID_HANDLE_VALUE == hFile)
2585 return FALSE;
2587 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2588 if (NULL == lpszBuffer)
2590 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2591 return FALSE;
2594 while (nBytesReceived < nBytes && nRC != -1)
2596 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2597 if (nRC != -1)
2599 /* other side closed socket. */
2600 if (nRC == 0)
2601 goto recv_end;
2602 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2603 nBytesReceived += nRC;
2606 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
2607 nBytesReceived * 100 / nBytes);
2610 TRACE("Data transfer complete\n");
2611 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2613 recv_end:
2614 return (nRC != -1);
2618 /***********************************************************************
2619 * FTP_CloseSessionHandle (internal)
2621 * Deallocate session handle
2623 * RETURNS
2624 * TRUE on success
2625 * FALSE on failure
2628 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr)
2630 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2632 TRACE("\n");
2634 if (lpwfs->download_in_progress != NULL)
2635 lpwfs->download_in_progress->session_deleted = TRUE;
2637 if (lpwfs->sndSocket != -1)
2638 closesocket(lpwfs->sndSocket);
2640 if (lpwfs->lstnSocket != -1)
2641 closesocket(lpwfs->lstnSocket);
2643 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2644 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2645 HeapFree(GetProcessHeap(), 0, lpwfs);
2649 /***********************************************************************
2650 * FTP_CloseFindNextHandle (internal)
2652 * Deallocate session handle
2654 * RETURNS
2655 * TRUE on success
2656 * FALSE on failure
2659 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr)
2661 LPWININETFINDNEXTW lpwfn = (LPWININETFINDNEXTW) hdr;
2662 DWORD i;
2664 TRACE("\n");
2666 for (i = 0; i < lpwfn->size; i++)
2668 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2671 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2672 HeapFree(GetProcessHeap(), 0, lpwfn);
2675 /***********************************************************************
2676 * FTP_CloseFileTransferHandle (internal)
2678 * Closes the file transfer handle. This also 'cleans' the data queue of
2679 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2682 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr)
2684 LPWININETFILE lpwh = (LPWININETFILE) hdr;
2685 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) lpwh->hdr.lpwhparent;
2686 INT nResCode;
2688 TRACE("\n");
2690 if (!lpwh->session_deleted)
2691 lpwfs->download_in_progress = NULL;
2693 /* This just serves to flush the control socket of any spurrious lines written
2694 to it (like '226 Transfer complete.').
2696 Wonder what to do if the server sends us an error code though...
2698 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2700 if (lpwh->nDataSocket != -1)
2701 closesocket(lpwh->nDataSocket);
2703 HeapFree(GetProcessHeap(), 0, lpwh);
2706 /***********************************************************************
2707 * FTP_ReceiveFileList (internal)
2709 * Read file list from server
2711 * RETURNS
2712 * Handle to file list on success
2713 * NULL on failure
2716 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2717 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext)
2719 DWORD dwSize = 0;
2720 LPFILEPROPERTIESW lpafp = NULL;
2721 LPWININETFINDNEXTW lpwfn = NULL;
2722 HINTERNET handle = 0;
2724 TRACE("(%p,%d,%s,%p,%ld)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
2726 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
2728 if(lpFindFileData)
2729 FTP_ConvertFileProp(lpafp, lpFindFileData);
2731 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTW));
2732 if (lpwfn)
2734 lpwfn->hdr.htype = WH_HFINDNEXT;
2735 lpwfn->hdr.lpwhparent = WININET_AddRef( &lpwfs->hdr );
2736 lpwfn->hdr.dwContext = dwContext;
2737 lpwfn->hdr.dwRefCount = 1;
2738 lpwfn->hdr.destroy = FTP_CloseFindNextHandle;
2739 lpwfn->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
2740 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2741 lpwfn->size = dwSize;
2742 lpwfn->lpafp = lpafp;
2744 handle = WININET_AllocHandle( &lpwfn->hdr );
2748 if( lpwfn )
2749 WININET_Release( &lpwfn->hdr );
2751 TRACE("Matched %ld files\n", dwSize);
2752 return handle;
2756 /***********************************************************************
2757 * FTP_ConvertFileProp (internal)
2759 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
2761 * RETURNS
2762 * TRUE on success
2763 * FALSE on failure
2766 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
2768 BOOL bSuccess = FALSE;
2770 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
2772 if (lpafp)
2774 /* Convert 'Unix' time to Windows time */
2775 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
2776 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
2777 lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime;
2778 lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime;
2780 /* Not all fields are filled in */
2781 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2782 lpFindFileData->nFileSizeLow = lpafp->nSize;
2784 if (lpafp->bIsDirectory)
2785 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2787 if (lpafp->lpszName)
2788 lstrcpynW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2790 bSuccess = TRUE;
2793 return bSuccess;
2796 /***********************************************************************
2797 * FTP_ParseNextFile (internal)
2799 * Parse the next line in file listing
2801 * RETURNS
2802 * TRUE on success
2803 * FALSE on failure
2805 BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
2807 static const char szSpace[] = " \t";
2808 DWORD nBufLen;
2809 char *pszLine;
2810 char *pszToken;
2811 char *pszTmp;
2812 BOOL found = FALSE;
2813 int i;
2815 lpfp->lpszName = NULL;
2816 do {
2817 if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
2818 return FALSE;
2820 pszToken = strtok(pszLine, szSpace);
2821 /* ls format
2822 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2824 * For instance:
2825 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2827 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
2828 if(!FTP_ParsePermission(pszToken, lpfp))
2829 lpfp->bIsDirectory = FALSE;
2830 for(i=0; i<=3; i++) {
2831 if(!(pszToken = strtok(NULL, szSpace)))
2832 break;
2834 if(!pszToken) continue;
2835 if(lpfp->bIsDirectory) {
2836 TRACE("Is directory\n");
2837 lpfp->nSize = 0;
2839 else {
2840 TRACE("Size: %s\n", pszToken);
2841 lpfp->nSize = atol(pszToken);
2844 lpfp->tmLastModified.tm_sec = 0;
2845 lpfp->tmLastModified.tm_min = 0;
2846 lpfp->tmLastModified.tm_hour = 0;
2847 lpfp->tmLastModified.tm_mday = 0;
2848 lpfp->tmLastModified.tm_mon = 0;
2849 lpfp->tmLastModified.tm_year = 0;
2851 /* Determine month */
2852 pszToken = strtok(NULL, szSpace);
2853 if(!pszToken) continue;
2854 if(strlen(pszToken) >= 3) {
2855 pszToken[3] = 0;
2856 if((pszTmp = StrStrIA(szMonths, pszToken)))
2857 lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
2859 /* Determine day */
2860 pszToken = strtok(NULL, szSpace);
2861 if(!pszToken) continue;
2862 lpfp->tmLastModified.tm_mday = atoi(pszToken);
2863 /* Determine time or year */
2864 pszToken = strtok(NULL, szSpace);
2865 if(!pszToken) continue;
2866 if((pszTmp = strchr(pszToken, ':'))) {
2867 struct tm* apTM;
2868 time_t aTime;
2869 *pszTmp = 0;
2870 pszTmp++;
2871 lpfp->tmLastModified.tm_min = atoi(pszTmp);
2872 lpfp->tmLastModified.tm_hour = atoi(pszToken);
2873 time(&aTime);
2874 apTM = localtime(&aTime);
2875 lpfp->tmLastModified.tm_year = apTM->tm_year;
2877 else {
2878 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
2879 lpfp->tmLastModified.tm_hour = 12;
2881 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
2882 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
2883 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
2884 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
2886 pszToken = strtok(NULL, szSpace);
2887 if(!pszToken) continue;
2888 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
2889 TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
2891 /* NT way of parsing ... :
2893 07-13-03 08:55PM <DIR> sakpatch
2894 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
2896 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
2897 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
2899 sscanf(pszToken, "%d-%d-%d",
2900 &lpfp->tmLastModified.tm_mon,
2901 &lpfp->tmLastModified.tm_mday,
2902 &lpfp->tmLastModified.tm_year);
2904 /* Hacky and bad Y2K protection :-) */
2905 if (lpfp->tmLastModified.tm_year < 70)
2906 lpfp->tmLastModified.tm_year += 100;
2908 pszToken = strtok(NULL, szSpace);
2909 if(!pszToken) continue;
2910 sscanf(pszToken, "%d:%d",
2911 &lpfp->tmLastModified.tm_hour,
2912 &lpfp->tmLastModified.tm_min);
2913 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
2914 lpfp->tmLastModified.tm_hour += 12;
2916 lpfp->tmLastModified.tm_sec = 0;
2918 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
2919 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
2920 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
2921 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
2923 pszToken = strtok(NULL, szSpace);
2924 if(!pszToken) continue;
2925 if(!strcasecmp(pszToken, "<DIR>")) {
2926 lpfp->bIsDirectory = TRUE;
2927 lpfp->nSize = 0;
2928 TRACE("Is directory\n");
2930 else {
2931 lpfp->bIsDirectory = FALSE;
2932 lpfp->nSize = atol(pszToken);
2933 TRACE("Size: %ld\n", lpfp->nSize);
2936 pszToken = strtok(NULL, szSpace);
2937 if(!pszToken) continue;
2938 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
2939 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
2941 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
2942 else if(pszToken[0] == '+') {
2943 FIXME("EPLF Format not implemented\n");
2946 if(lpfp->lpszName) {
2947 if((lpszSearchFile == NULL) ||
2948 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
2949 found = TRUE;
2950 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
2952 else {
2953 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
2954 lpfp->lpszName = NULL;
2957 } while(!found);
2958 return TRUE;
2961 /***********************************************************************
2962 * FTP_ParseDirectory (internal)
2964 * Parse string of directory information
2966 * RETURNS
2967 * TRUE on success
2968 * FALSE on failure
2970 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2971 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
2973 BOOL bSuccess = TRUE;
2974 INT sizeFilePropArray = 500;/*20; */
2975 INT indexFilePropArray = -1;
2977 TRACE("\n");
2979 /* Allocate intial file properties array */
2980 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
2981 if (!*lpafp)
2982 return FALSE;
2984 do {
2985 if (indexFilePropArray+1 >= sizeFilePropArray)
2987 LPFILEPROPERTIESW tmpafp;
2989 sizeFilePropArray *= 2;
2990 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
2991 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
2992 if (NULL == tmpafp)
2994 bSuccess = FALSE;
2995 break;
2998 *lpafp = tmpafp;
3000 indexFilePropArray++;
3001 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
3003 if (bSuccess && indexFilePropArray)
3005 if (indexFilePropArray < sizeFilePropArray - 1)
3007 LPFILEPROPERTIESW tmpafp;
3009 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
3010 sizeof(FILEPROPERTIESW)*indexFilePropArray);
3011 if (NULL == tmpafp)
3012 *lpafp = tmpafp;
3014 *dwfp = indexFilePropArray;
3016 else
3018 HeapFree(GetProcessHeap(), 0, *lpafp);
3019 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3020 bSuccess = FALSE;
3023 return bSuccess;
3027 /***********************************************************************
3028 * FTP_ParsePermission (internal)
3030 * Parse permission string of directory information
3032 * RETURNS
3033 * TRUE on success
3034 * FALSE on failure
3037 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3039 BOOL bSuccess = TRUE;
3040 unsigned short nPermission = 0;
3041 INT nPos = 1;
3042 INT nLast = 9;
3044 TRACE("\n");
3045 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3047 bSuccess = FALSE;
3048 return bSuccess;
3051 lpfp->bIsDirectory = (*lpszPermission == 'd');
3054 switch (nPos)
3056 case 1:
3057 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3058 break;
3059 case 2:
3060 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3061 break;
3062 case 3:
3063 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3064 break;
3065 case 4:
3066 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3067 break;
3068 case 5:
3069 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3070 break;
3071 case 6:
3072 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3073 break;
3074 case 7:
3075 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3076 break;
3077 case 8:
3078 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3079 break;
3080 case 9:
3081 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3082 break;
3084 nPos++;
3085 }while (nPos <= nLast);
3087 lpfp->permissions = nPermission;
3088 return bSuccess;
3092 /***********************************************************************
3093 * FTP_SetResponseError (internal)
3095 * Set the appropriate error code for a given response from the server
3097 * RETURNS
3100 DWORD FTP_SetResponseError(DWORD dwResponse)
3102 DWORD dwCode = 0;
3104 switch(dwResponse)
3106 case 421: /* Service not available - Server may be shutting down. */
3107 dwCode = ERROR_INTERNET_TIMEOUT;
3108 break;
3110 case 425: /* Cannot open data connection. */
3111 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3112 break;
3114 case 426: /* Connection closed, transer aborted. */
3115 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3116 break;
3118 case 500: /* Syntax error. Command unrecognized. */
3119 case 501: /* Syntax error. Error in parameters or arguments. */
3120 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
3121 break;
3123 case 530: /* Not logged in. Login incorrect. */
3124 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3125 break;
3127 case 550: /* File action not taken. File not found or no access. */
3128 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
3129 break;
3131 case 450: /* File action not taken. File may be busy. */
3132 case 451: /* Action aborted. Server error. */
3133 case 452: /* Action not taken. Insufficient storage space on server. */
3134 case 502: /* Command not implemented. */
3135 case 503: /* Bad sequence of command. */
3136 case 504: /* Command not implemented for that parameter. */
3137 case 532: /* Need account for storing files */
3138 case 551: /* Requested action aborted. Page type unknown */
3139 case 552: /* Action aborted. Exceeded storage allocation */
3140 case 553: /* Action not taken. File name not allowed. */
3142 default:
3143 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
3144 break;
3147 INTERNET_SetLastError(dwCode);
3148 return dwCode;