msacm: Fix acmMetrics(ACM_METRIC_DRIVER_PRIORITY) return on error.
[wine/multimedia.git] / dlls / wininet / ftp.c
blobaa254f61cb28676eedc9ec8c1dcea0bc19b000db
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 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);
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 INT nsocket = -1;
1660 UINT sock_namelen;
1661 BOOL bSuccess = FALSE;
1662 LPWININETFTPSESSIONW lpwfs = NULL;
1663 HINTERNET handle = NULL;
1665 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1666 hIC, debugstr_w(lpszServerName),
1667 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
1669 assert( hIC->hdr.htype == WH_HINIT );
1671 if (NULL == lpszUserName && NULL != lpszPassword)
1673 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1674 goto lerror;
1677 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
1678 if (NULL == lpwfs)
1680 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1681 goto lerror;
1684 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1685 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1687 lpwfs->hdr.htype = WH_HFTPSESSION;
1688 lpwfs->hdr.lpwhparent = WININET_AddRef( &hIC->hdr );
1689 lpwfs->hdr.dwFlags = dwFlags;
1690 lpwfs->hdr.dwContext = dwContext;
1691 lpwfs->hdr.dwInternalFlags = dwInternalFlags;
1692 lpwfs->hdr.dwRefCount = 1;
1693 lpwfs->hdr.destroy = FTP_CloseSessionHandle;
1694 lpwfs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
1695 lpwfs->download_in_progress = NULL;
1697 handle = WININET_AllocHandle( &lpwfs->hdr );
1698 if( !handle )
1700 ERR("Failed to alloc handle\n");
1701 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1702 goto lerror;
1705 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1706 if(strchrW(hIC->lpszProxy, ' '))
1707 FIXME("Several proxies not implemented.\n");
1708 if(hIC->lpszProxyBypass)
1709 FIXME("Proxy bypass is ignored.\n");
1711 if ( !lpszUserName) {
1712 lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
1713 lpwfs->lpszPassword = WININET_strdupW(szDefaultPassword);
1715 else {
1716 lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
1717 lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
1720 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1721 if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
1723 INTERNET_ASYNC_RESULT iar;
1725 iar.dwResult = (DWORD)handle;
1726 iar.dwError = ERROR_SUCCESS;
1728 SendAsyncCallback(&hIC->hdr, dwContext,
1729 INTERNET_STATUS_HANDLE_CREATED, &iar,
1730 sizeof(INTERNET_ASYNC_RESULT));
1733 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1734 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1736 if (!GetAddress(lpszServerName, nServerPort, &socketAddr))
1738 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1739 goto lerror;
1742 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1743 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1745 nsocket = socket(AF_INET,SOCK_STREAM,0);
1746 if (nsocket == -1)
1748 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1749 goto lerror;
1752 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1753 &socketAddr, sizeof(struct sockaddr_in));
1755 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1757 ERR("Unable to connect (%s)\n", strerror(errno));
1758 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1760 else
1762 TRACE("Connected to server\n");
1763 lpwfs->sndSocket = nsocket;
1764 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1765 &socketAddr, sizeof(struct sockaddr_in));
1767 sock_namelen = sizeof(lpwfs->socketAddress);
1768 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1770 if (FTP_ConnectToHost(lpwfs))
1772 TRACE("Successfully logged into server\n");
1773 bSuccess = TRUE;
1777 lerror:
1778 if (!bSuccess && nsocket == -1)
1779 closesocket(nsocket);
1781 if (!bSuccess && lpwfs)
1783 HeapFree(GetProcessHeap(), 0, lpwfs);
1784 WININET_FreeHandle( handle );
1785 lpwfs = NULL;
1788 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1790 INTERNET_ASYNC_RESULT iar;
1792 iar.dwResult = (DWORD)lpwfs;
1793 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1794 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1795 &iar, sizeof(INTERNET_ASYNC_RESULT));
1798 return handle;
1802 /***********************************************************************
1803 * FTP_ConnectToHost (internal)
1805 * Connect to a ftp server
1807 * RETURNS
1808 * TRUE on success
1809 * NULL on failure
1812 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
1814 INT nResCode;
1815 BOOL bSuccess = FALSE;
1817 TRACE("\n");
1818 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1820 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1821 goto lend;
1823 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1824 if (nResCode)
1826 /* Login successful... */
1827 if (nResCode == 230)
1828 bSuccess = TRUE;
1829 /* User name okay, need password... */
1830 else if (nResCode == 331)
1831 bSuccess = FTP_SendPassword(lpwfs);
1832 /* Need account for login... */
1833 else if (nResCode == 332)
1834 bSuccess = FTP_SendAccount(lpwfs);
1835 else
1836 FTP_SetResponseError(nResCode);
1839 TRACE("Returning %d\n", bSuccess);
1840 lend:
1841 return bSuccess;
1845 /***********************************************************************
1846 * FTP_SendCommandA (internal)
1848 * Send command to server
1850 * RETURNS
1851 * TRUE on success
1852 * NULL on failure
1855 static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1856 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
1858 DWORD len;
1859 CHAR *buf;
1860 DWORD nBytesSent = 0;
1861 int nRC = 0;
1862 DWORD dwParamLen;
1864 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1866 if (lpfnStatusCB)
1868 HINTERNET hHandle = WININET_FindHandle( hdr );
1869 if( hHandle )
1871 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1872 WININET_Release( hdr );
1876 dwParamLen = lpszParam?strlen(lpszParam)+1:0;
1877 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
1878 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1880 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1881 return FALSE;
1883 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
1884 dwParamLen ? lpszParam : "", szCRLF);
1886 TRACE("Sending (%s) len(%ld)\n", buf, len);
1887 while((nBytesSent < len) && (nRC != -1))
1889 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1890 nBytesSent += nRC;
1893 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
1895 if (lpfnStatusCB)
1897 HINTERNET hHandle = WININET_FindHandle( hdr );
1898 if( hHandle )
1900 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_REQUEST_SENT,
1901 &nBytesSent, sizeof(DWORD));
1902 WININET_Release( hdr );
1906 TRACE("Sent %ld bytes\n", nBytesSent);
1907 return (nRC != -1);
1910 /***********************************************************************
1911 * FTP_SendCommand (internal)
1913 * Send command to server
1915 * RETURNS
1916 * TRUE on success
1917 * NULL on failure
1920 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
1921 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
1923 BOOL ret;
1924 LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
1925 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
1926 HeapFree(GetProcessHeap(), 0, lpszParamA);
1927 return ret;
1930 /***********************************************************************
1931 * FTP_ReceiveResponse (internal)
1933 * Receive response from server
1935 * RETURNS
1936 * Reply code on success
1937 * 0 on failure
1940 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext)
1942 LPSTR lpszResponse = INTERNET_GetResponseBuffer();
1943 DWORD nRecv;
1944 INT rc = 0;
1945 char firstprefix[5];
1946 BOOL multiline = FALSE;
1947 LPWININETAPPINFOW hIC = NULL;
1949 TRACE("socket(%d)\n", lpwfs->sndSocket);
1951 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1952 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1954 while(1)
1956 if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
1957 goto lerror;
1959 if (nRecv >= 3)
1961 if(!multiline)
1963 if(lpszResponse[3] != '-')
1964 break;
1965 else
1966 { /* Start of multiline repsonse. Loop until we get "nnn " */
1967 multiline = TRUE;
1968 memcpy(firstprefix, lpszResponse, 3);
1969 firstprefix[3] = ' ';
1970 firstprefix[4] = '\0';
1973 else
1975 if(!memcmp(firstprefix, lpszResponse, 4))
1976 break;
1981 if (nRecv >= 3)
1983 rc = atoi(lpszResponse);
1985 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
1986 &nRecv, sizeof(DWORD));
1989 lerror:
1990 TRACE("return %d\n", rc);
1991 return rc;
1995 /***********************************************************************
1996 * FTP_SendPassword (internal)
1998 * Send password to ftp server
2000 * RETURNS
2001 * TRUE on success
2002 * NULL on failure
2005 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
2007 INT nResCode;
2008 BOOL bSuccess = FALSE;
2010 TRACE("\n");
2011 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
2012 goto lend;
2014 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2015 if (nResCode)
2017 TRACE("Received reply code %d\n", nResCode);
2018 /* Login successful... */
2019 if (nResCode == 230)
2020 bSuccess = TRUE;
2021 /* Command not implemented, superfluous at the server site... */
2022 /* Need account for login... */
2023 else if (nResCode == 332)
2024 bSuccess = FTP_SendAccount(lpwfs);
2025 else
2026 FTP_SetResponseError(nResCode);
2029 lend:
2030 TRACE("Returning %d\n", bSuccess);
2031 return bSuccess;
2035 /***********************************************************************
2036 * FTP_SendAccount (internal)
2040 * RETURNS
2041 * TRUE on success
2042 * FALSE on failure
2045 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
2047 INT nResCode;
2048 BOOL bSuccess = FALSE;
2050 TRACE("\n");
2051 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
2052 goto lend;
2054 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2055 if (nResCode)
2056 bSuccess = TRUE;
2057 else
2058 FTP_SetResponseError(nResCode);
2060 lend:
2061 return bSuccess;
2065 /***********************************************************************
2066 * FTP_SendStore (internal)
2068 * Send request to upload file to ftp server
2070 * RETURNS
2071 * TRUE on success
2072 * FALSE on failure
2075 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2077 INT nResCode;
2078 BOOL bSuccess = FALSE;
2080 TRACE("\n");
2081 if (!FTP_InitListenSocket(lpwfs))
2082 goto lend;
2084 if (!FTP_SendType(lpwfs, dwType))
2085 goto lend;
2087 if (!FTP_SendPortOrPasv(lpwfs))
2088 goto lend;
2090 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2091 goto lend;
2092 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2093 if (nResCode)
2095 if (nResCode == 150)
2096 bSuccess = TRUE;
2097 else
2098 FTP_SetResponseError(nResCode);
2101 lend:
2102 if (!bSuccess && lpwfs->lstnSocket != -1)
2104 closesocket(lpwfs->lstnSocket);
2105 lpwfs->lstnSocket = -1;
2108 return bSuccess;
2112 /***********************************************************************
2113 * FTP_InitListenSocket (internal)
2115 * Create a socket to listen for server response
2117 * RETURNS
2118 * TRUE on success
2119 * FALSE on failure
2122 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
2124 BOOL bSuccess = FALSE;
2125 size_t namelen = sizeof(struct sockaddr_in);
2127 TRACE("\n");
2129 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2130 if (lpwfs->lstnSocket == -1)
2132 TRACE("Unable to create listening socket\n");
2133 goto lend;
2136 /* We obtain our ip addr from the name of the command channel socket */
2137 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2139 /* and get the system to assign us a port */
2140 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
2142 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
2144 TRACE("Unable to bind socket\n");
2145 goto lend;
2148 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2150 TRACE("listen failed\n");
2151 goto lend;
2154 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2155 bSuccess = TRUE;
2157 lend:
2158 if (!bSuccess && lpwfs->lstnSocket == -1)
2160 closesocket(lpwfs->lstnSocket);
2161 lpwfs->lstnSocket = -1;
2164 return bSuccess;
2168 /***********************************************************************
2169 * FTP_SendType (internal)
2171 * Tell server type of data being transferred
2173 * RETURNS
2174 * TRUE on success
2175 * FALSE on failure
2177 * W98SE doesn't cache the type that's currently set
2178 * (i.e. it sends it always),
2179 * so we probably don't want to do that either.
2181 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
2183 INT nResCode;
2184 WCHAR type[] = { 'I','\0' };
2185 BOOL bSuccess = FALSE;
2187 TRACE("\n");
2188 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2189 type[0] = 'A';
2191 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2192 goto lend;
2194 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2195 if (nResCode)
2197 if (nResCode == 2)
2198 bSuccess = TRUE;
2199 else
2200 FTP_SetResponseError(nResCode);
2203 lend:
2204 return bSuccess;
2207 /***********************************************************************
2208 * FTP_GetFileSize (internal)
2210 * Retrieves from the server the size of the given file
2212 * RETURNS
2213 * TRUE on success
2214 * FALSE on failure
2217 static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
2219 INT nResCode;
2220 BOOL bSuccess = FALSE;
2222 TRACE("\n");
2224 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2225 goto lend;
2227 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2228 if (nResCode)
2230 if (nResCode == 213) {
2231 /* Now parses the output to get the actual file size */
2232 int i;
2233 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2235 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2236 if (lpszResponseBuffer[i] == '\0') return FALSE;
2237 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2239 bSuccess = TRUE;
2240 } else {
2241 FTP_SetResponseError(nResCode);
2245 lend:
2246 return bSuccess;
2250 /***********************************************************************
2251 * FTP_SendPort (internal)
2253 * Tell server which port to use
2255 * RETURNS
2256 * TRUE on success
2257 * FALSE on failure
2260 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
2262 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2263 INT nResCode;
2264 WCHAR szIPAddress[64];
2265 BOOL bSuccess = FALSE;
2266 TRACE("\n");
2268 sprintfW(szIPAddress, szIPFormat,
2269 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2270 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2271 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2272 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2273 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2274 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2276 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2277 goto lend;
2279 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2280 if (nResCode)
2282 if (nResCode == 200)
2283 bSuccess = TRUE;
2284 else
2285 FTP_SetResponseError(nResCode);
2288 lend:
2289 return bSuccess;
2293 /***********************************************************************
2294 * FTP_DoPassive (internal)
2296 * Tell server that we want to do passive transfers
2297 * and connect data socket
2299 * RETURNS
2300 * TRUE on success
2301 * FALSE on failure
2304 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
2306 INT nResCode;
2307 BOOL bSuccess = FALSE;
2309 TRACE("\n");
2310 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2311 goto lend;
2313 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2314 if (nResCode)
2316 if (nResCode == 227)
2318 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2319 LPSTR p;
2320 int f[6];
2321 int i;
2322 char *pAddr, *pPort;
2323 INT nsocket = -1;
2324 struct sockaddr_in dataSocketAddress;
2326 p = lpszResponseBuffer+4; /* skip status code */
2328 /* do a very strict check; we can improve that later. */
2330 if (strncmp(p, "Entering Passive Mode", 21))
2332 ERR("unknown response '%.*s', aborting\n", 21, p);
2333 goto lend;
2335 p += 21; /* skip string */
2336 if ((*p++ != ' ') || (*p++ != '('))
2338 ERR("unknown response format, aborting\n");
2339 goto lend;
2342 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2343 &f[4], &f[5]) != 6)
2345 ERR("unknown response address format '%s', aborting\n", p);
2346 goto lend;
2348 for (i=0; i < 6; i++)
2349 f[i] = f[i] & 0xff;
2351 dataSocketAddress = lpwfs->socketAddress;
2352 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2353 pPort = (char *)&(dataSocketAddress.sin_port);
2354 pAddr[0] = f[0];
2355 pAddr[1] = f[1];
2356 pAddr[2] = f[2];
2357 pAddr[3] = f[3];
2358 pPort[0] = f[4];
2359 pPort[1] = f[5];
2361 nsocket = socket(AF_INET,SOCK_STREAM,0);
2362 if (nsocket == -1)
2363 goto lend;
2365 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2367 ERR("can't connect passive FTP data port.\n");
2368 goto lend;
2370 lpwfs->pasvSocket = nsocket;
2371 bSuccess = TRUE;
2373 else
2374 FTP_SetResponseError(nResCode);
2377 lend:
2378 return bSuccess;
2382 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
2384 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2386 if (!FTP_DoPassive(lpwfs))
2387 return FALSE;
2389 else
2391 if (!FTP_SendPort(lpwfs))
2392 return FALSE;
2394 return TRUE;
2398 /***********************************************************************
2399 * FTP_GetDataSocket (internal)
2401 * Either accepts an incoming data socket connection from the server
2402 * or just returns the already opened socket after a PASV command
2403 * in case of passive FTP.
2406 * RETURNS
2407 * TRUE on success
2408 * FALSE on failure
2411 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
2413 struct sockaddr_in saddr;
2414 size_t addrlen = sizeof(struct sockaddr);
2416 TRACE("\n");
2417 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2419 *nDataSocket = lpwfs->pasvSocket;
2421 else
2423 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2424 closesocket(lpwfs->lstnSocket);
2425 lpwfs->lstnSocket = -1;
2427 return *nDataSocket != -1;
2431 /***********************************************************************
2432 * FTP_SendData (internal)
2434 * Send data to the server
2436 * RETURNS
2437 * TRUE on success
2438 * FALSE on failure
2441 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2443 BY_HANDLE_FILE_INFORMATION fi;
2444 DWORD nBytesRead = 0;
2445 DWORD nBytesSent = 0;
2446 DWORD nTotalSent = 0;
2447 DWORD nBytesToSend, nLen;
2448 int nRC = 1;
2449 time_t s_long_time, e_long_time;
2450 LONG nSeconds;
2451 CHAR *lpszBuffer;
2453 TRACE("\n");
2454 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2455 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2457 /* Get the size of the file. */
2458 GetFileInformationByHandle(hFile, &fi);
2459 time(&s_long_time);
2463 nBytesToSend = nBytesRead - nBytesSent;
2465 if (nBytesToSend <= 0)
2467 /* Read data from file. */
2468 nBytesSent = 0;
2469 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2470 ERR("Failed reading from file\n");
2472 if (nBytesRead > 0)
2473 nBytesToSend = nBytesRead;
2474 else
2475 break;
2478 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2479 DATA_PACKET_SIZE : nBytesToSend;
2480 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2482 if (nRC != -1)
2484 nBytesSent += nRC;
2485 nTotalSent += nRC;
2488 /* Do some computation to display the status. */
2489 time(&e_long_time);
2490 nSeconds = e_long_time - s_long_time;
2491 if( nSeconds / 60 > 0 )
2493 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld min %ld sec estimated remaining time %ld sec\n",
2494 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2495 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2497 else
2499 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld sec estimated remaining time %ld sec\n",
2500 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2501 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2503 } while (nRC != -1);
2505 TRACE("file transfer complete!\n");
2507 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2509 return nTotalSent;
2513 /***********************************************************************
2514 * FTP_SendRetrieve (internal)
2516 * Send request to retrieve a file
2518 * RETURNS
2519 * Number of bytes to be received on success
2520 * 0 on failure
2523 static DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2525 INT nResCode;
2526 DWORD nResult = 0;
2528 TRACE("\n");
2529 if (!FTP_InitListenSocket(lpwfs))
2530 goto lend;
2532 if (!FTP_SendType(lpwfs, dwType))
2533 goto lend;
2535 if (!FTP_SendPortOrPasv(lpwfs))
2536 goto lend;
2538 if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2539 goto lend;
2541 TRACE("Waiting to receive %ld bytes\n", nResult);
2543 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2544 goto lend;
2546 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2547 if ((nResCode != 125) && (nResCode != 150)) {
2548 /* That means that we got an error getting the file. */
2549 nResult = 0;
2552 lend:
2553 if (0 == nResult && lpwfs->lstnSocket != -1)
2555 closesocket(lpwfs->lstnSocket);
2556 lpwfs->lstnSocket = -1;
2559 return nResult;
2563 /***********************************************************************
2564 * FTP_RetrieveData (internal)
2566 * Retrieve data from server
2568 * RETURNS
2569 * TRUE on success
2570 * FALSE on failure
2573 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2575 DWORD nBytesWritten;
2576 DWORD nBytesReceived = 0;
2577 INT nRC = 0;
2578 CHAR *lpszBuffer;
2580 TRACE("\n");
2582 if (INVALID_HANDLE_VALUE == hFile)
2583 return FALSE;
2585 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2586 if (NULL == lpszBuffer)
2588 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2589 return FALSE;
2592 while (nBytesReceived < nBytes && nRC != -1)
2594 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2595 if (nRC != -1)
2597 /* other side closed socket. */
2598 if (nRC == 0)
2599 goto recv_end;
2600 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2601 nBytesReceived += nRC;
2604 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
2605 nBytesReceived * 100 / nBytes);
2608 TRACE("Data transfer complete\n");
2609 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2611 recv_end:
2612 return (nRC != -1);
2616 /***********************************************************************
2617 * FTP_CloseSessionHandle (internal)
2619 * Deallocate session handle
2621 * RETURNS
2622 * TRUE on success
2623 * FALSE on failure
2626 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr)
2628 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2630 TRACE("\n");
2632 if (lpwfs->download_in_progress != NULL)
2633 lpwfs->download_in_progress->session_deleted = TRUE;
2635 if (lpwfs->sndSocket != -1)
2636 closesocket(lpwfs->sndSocket);
2638 if (lpwfs->lstnSocket != -1)
2639 closesocket(lpwfs->lstnSocket);
2641 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2642 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2643 HeapFree(GetProcessHeap(), 0, lpwfs);
2647 /***********************************************************************
2648 * FTP_CloseFindNextHandle (internal)
2650 * Deallocate session handle
2652 * RETURNS
2653 * TRUE on success
2654 * FALSE on failure
2657 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr)
2659 LPWININETFINDNEXTW lpwfn = (LPWININETFINDNEXTW) hdr;
2660 DWORD i;
2662 TRACE("\n");
2664 for (i = 0; i < lpwfn->size; i++)
2666 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2669 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2670 HeapFree(GetProcessHeap(), 0, lpwfn);
2673 /***********************************************************************
2674 * FTP_CloseFileTransferHandle (internal)
2676 * Closes the file transfer handle. This also 'cleans' the data queue of
2677 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2680 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr)
2682 LPWININETFILE lpwh = (LPWININETFILE) hdr;
2683 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) lpwh->hdr.lpwhparent;
2684 INT nResCode;
2686 TRACE("\n");
2688 if (!lpwh->session_deleted)
2689 lpwfs->download_in_progress = NULL;
2691 /* This just serves to flush the control socket of any spurrious lines written
2692 to it (like '226 Transfer complete.').
2694 Wonder what to do if the server sends us an error code though...
2696 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2698 if (lpwh->nDataSocket != -1)
2699 closesocket(lpwh->nDataSocket);
2701 HeapFree(GetProcessHeap(), 0, lpwh);
2704 /***********************************************************************
2705 * FTP_ReceiveFileList (internal)
2707 * Read file list from server
2709 * RETURNS
2710 * Handle to file list on success
2711 * NULL on failure
2714 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2715 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext)
2717 DWORD dwSize = 0;
2718 LPFILEPROPERTIESW lpafp = NULL;
2719 LPWININETFINDNEXTW lpwfn = NULL;
2720 HINTERNET handle = 0;
2722 TRACE("(%p,%d,%s,%p,%ld)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
2724 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
2726 if(lpFindFileData)
2727 FTP_ConvertFileProp(lpafp, lpFindFileData);
2729 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTW));
2730 if (lpwfn)
2732 lpwfn->hdr.htype = WH_HFINDNEXT;
2733 lpwfn->hdr.lpwhparent = WININET_AddRef( &lpwfs->hdr );
2734 lpwfn->hdr.dwContext = dwContext;
2735 lpwfn->hdr.dwRefCount = 1;
2736 lpwfn->hdr.destroy = FTP_CloseFindNextHandle;
2737 lpwfn->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
2738 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2739 lpwfn->size = dwSize;
2740 lpwfn->lpafp = lpafp;
2742 handle = WININET_AllocHandle( &lpwfn->hdr );
2746 if( lpwfn )
2747 WININET_Release( &lpwfn->hdr );
2749 TRACE("Matched %ld files\n", dwSize);
2750 return handle;
2754 /***********************************************************************
2755 * FTP_ConvertFileProp (internal)
2757 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
2759 * RETURNS
2760 * TRUE on success
2761 * FALSE on failure
2764 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
2766 BOOL bSuccess = FALSE;
2768 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
2770 if (lpafp)
2772 /* Convert 'Unix' time to Windows time */
2773 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
2774 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
2775 lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime;
2776 lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime;
2778 /* Not all fields are filled in */
2779 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2780 lpFindFileData->nFileSizeLow = lpafp->nSize;
2782 if (lpafp->bIsDirectory)
2783 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2785 if (lpafp->lpszName)
2786 lstrcpynW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2788 bSuccess = TRUE;
2791 return bSuccess;
2794 /***********************************************************************
2795 * FTP_ParseNextFile (internal)
2797 * Parse the next line in file listing
2799 * RETURNS
2800 * TRUE on success
2801 * FALSE on failure
2803 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
2805 static const char szSpace[] = " \t";
2806 DWORD nBufLen;
2807 char *pszLine;
2808 char *pszToken;
2809 char *pszTmp;
2810 BOOL found = FALSE;
2811 int i;
2813 lpfp->lpszName = NULL;
2814 do {
2815 if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
2816 return FALSE;
2818 pszToken = strtok(pszLine, szSpace);
2819 /* ls format
2820 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2822 * For instance:
2823 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2825 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
2826 if(!FTP_ParsePermission(pszToken, lpfp))
2827 lpfp->bIsDirectory = FALSE;
2828 for(i=0; i<=3; i++) {
2829 if(!(pszToken = strtok(NULL, szSpace)))
2830 break;
2832 if(!pszToken) continue;
2833 if(lpfp->bIsDirectory) {
2834 TRACE("Is directory\n");
2835 lpfp->nSize = 0;
2837 else {
2838 TRACE("Size: %s\n", pszToken);
2839 lpfp->nSize = atol(pszToken);
2842 lpfp->tmLastModified.tm_sec = 0;
2843 lpfp->tmLastModified.tm_min = 0;
2844 lpfp->tmLastModified.tm_hour = 0;
2845 lpfp->tmLastModified.tm_mday = 0;
2846 lpfp->tmLastModified.tm_mon = 0;
2847 lpfp->tmLastModified.tm_year = 0;
2849 /* Determine month */
2850 pszToken = strtok(NULL, szSpace);
2851 if(!pszToken) continue;
2852 if(strlen(pszToken) >= 3) {
2853 pszToken[3] = 0;
2854 if((pszTmp = StrStrIA(szMonths, pszToken)))
2855 lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
2857 /* Determine day */
2858 pszToken = strtok(NULL, szSpace);
2859 if(!pszToken) continue;
2860 lpfp->tmLastModified.tm_mday = atoi(pszToken);
2861 /* Determine time or year */
2862 pszToken = strtok(NULL, szSpace);
2863 if(!pszToken) continue;
2864 if((pszTmp = strchr(pszToken, ':'))) {
2865 struct tm* apTM;
2866 time_t aTime;
2867 *pszTmp = 0;
2868 pszTmp++;
2869 lpfp->tmLastModified.tm_min = atoi(pszTmp);
2870 lpfp->tmLastModified.tm_hour = atoi(pszToken);
2871 time(&aTime);
2872 apTM = localtime(&aTime);
2873 lpfp->tmLastModified.tm_year = apTM->tm_year;
2875 else {
2876 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
2877 lpfp->tmLastModified.tm_hour = 12;
2879 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
2880 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
2881 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
2882 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
2884 pszToken = strtok(NULL, szSpace);
2885 if(!pszToken) continue;
2886 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
2887 TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
2889 /* NT way of parsing ... :
2891 07-13-03 08:55PM <DIR> sakpatch
2892 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
2894 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
2895 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
2897 sscanf(pszToken, "%d-%d-%d",
2898 &lpfp->tmLastModified.tm_mon,
2899 &lpfp->tmLastModified.tm_mday,
2900 &lpfp->tmLastModified.tm_year);
2902 /* Hacky and bad Y2K protection :-) */
2903 if (lpfp->tmLastModified.tm_year < 70)
2904 lpfp->tmLastModified.tm_year += 100;
2906 pszToken = strtok(NULL, szSpace);
2907 if(!pszToken) continue;
2908 sscanf(pszToken, "%d:%d",
2909 &lpfp->tmLastModified.tm_hour,
2910 &lpfp->tmLastModified.tm_min);
2911 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
2912 lpfp->tmLastModified.tm_hour += 12;
2914 lpfp->tmLastModified.tm_sec = 0;
2916 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
2917 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
2918 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
2919 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
2921 pszToken = strtok(NULL, szSpace);
2922 if(!pszToken) continue;
2923 if(!strcasecmp(pszToken, "<DIR>")) {
2924 lpfp->bIsDirectory = TRUE;
2925 lpfp->nSize = 0;
2926 TRACE("Is directory\n");
2928 else {
2929 lpfp->bIsDirectory = FALSE;
2930 lpfp->nSize = atol(pszToken);
2931 TRACE("Size: %ld\n", lpfp->nSize);
2934 pszToken = strtok(NULL, szSpace);
2935 if(!pszToken) continue;
2936 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
2937 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
2939 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
2940 else if(pszToken[0] == '+') {
2941 FIXME("EPLF Format not implemented\n");
2944 if(lpfp->lpszName) {
2945 if((lpszSearchFile == NULL) ||
2946 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
2947 found = TRUE;
2948 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
2950 else {
2951 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
2952 lpfp->lpszName = NULL;
2955 } while(!found);
2956 return TRUE;
2959 /***********************************************************************
2960 * FTP_ParseDirectory (internal)
2962 * Parse string of directory information
2964 * RETURNS
2965 * TRUE on success
2966 * FALSE on failure
2968 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2969 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
2971 BOOL bSuccess = TRUE;
2972 INT sizeFilePropArray = 500;/*20; */
2973 INT indexFilePropArray = -1;
2975 TRACE("\n");
2977 /* Allocate intial file properties array */
2978 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
2979 if (!*lpafp)
2980 return FALSE;
2982 do {
2983 if (indexFilePropArray+1 >= sizeFilePropArray)
2985 LPFILEPROPERTIESW tmpafp;
2987 sizeFilePropArray *= 2;
2988 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
2989 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
2990 if (NULL == tmpafp)
2992 bSuccess = FALSE;
2993 break;
2996 *lpafp = tmpafp;
2998 indexFilePropArray++;
2999 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
3001 if (bSuccess && indexFilePropArray)
3003 if (indexFilePropArray < sizeFilePropArray - 1)
3005 LPFILEPROPERTIESW tmpafp;
3007 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
3008 sizeof(FILEPROPERTIESW)*indexFilePropArray);
3009 if (NULL == tmpafp)
3010 *lpafp = tmpafp;
3012 *dwfp = indexFilePropArray;
3014 else
3016 HeapFree(GetProcessHeap(), 0, *lpafp);
3017 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3018 bSuccess = FALSE;
3021 return bSuccess;
3025 /***********************************************************************
3026 * FTP_ParsePermission (internal)
3028 * Parse permission string of directory information
3030 * RETURNS
3031 * TRUE on success
3032 * FALSE on failure
3035 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3037 BOOL bSuccess = TRUE;
3038 unsigned short nPermission = 0;
3039 INT nPos = 1;
3040 INT nLast = 9;
3042 TRACE("\n");
3043 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3045 bSuccess = FALSE;
3046 return bSuccess;
3049 lpfp->bIsDirectory = (*lpszPermission == 'd');
3052 switch (nPos)
3054 case 1:
3055 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3056 break;
3057 case 2:
3058 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3059 break;
3060 case 3:
3061 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3062 break;
3063 case 4:
3064 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3065 break;
3066 case 5:
3067 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3068 break;
3069 case 6:
3070 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3071 break;
3072 case 7:
3073 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3074 break;
3075 case 8:
3076 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3077 break;
3078 case 9:
3079 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3080 break;
3082 nPos++;
3083 }while (nPos <= nLast);
3085 lpfp->permissions = nPermission;
3086 return bSuccess;
3090 /***********************************************************************
3091 * FTP_SetResponseError (internal)
3093 * Set the appropriate error code for a given response from the server
3095 * RETURNS
3098 static DWORD FTP_SetResponseError(DWORD dwResponse)
3100 DWORD dwCode = 0;
3102 switch(dwResponse)
3104 case 421: /* Service not available - Server may be shutting down. */
3105 dwCode = ERROR_INTERNET_TIMEOUT;
3106 break;
3108 case 425: /* Cannot open data connection. */
3109 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3110 break;
3112 case 426: /* Connection closed, transer aborted. */
3113 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3114 break;
3116 case 500: /* Syntax error. Command unrecognized. */
3117 case 501: /* Syntax error. Error in parameters or arguments. */
3118 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
3119 break;
3121 case 530: /* Not logged in. Login incorrect. */
3122 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3123 break;
3125 case 550: /* File action not taken. File not found or no access. */
3126 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
3127 break;
3129 case 450: /* File action not taken. File may be busy. */
3130 case 451: /* Action aborted. Server error. */
3131 case 452: /* Action not taken. Insufficient storage space on server. */
3132 case 502: /* Command not implemented. */
3133 case 503: /* Bad sequence of command. */
3134 case 504: /* Command not implemented for that parameter. */
3135 case 532: /* Need account for storing files */
3136 case 551: /* Requested action aborted. Page type unknown */
3137 case 552: /* Action aborted. Exceeded storage allocation */
3138 case 553: /* Action not taken. File name not allowed. */
3140 default:
3141 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
3142 break;
3145 INTERNET_SetLastError(dwCode);
3146 return dwCode;