Fix a bug in passing parameters to CFn_WMInitDialog and CFn_WMCommand
[wine/hacks.git] / dlls / wininet / ftp.c
blobd1a8ec6af38ef79428855ae6cf7a5b9f128f652e
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 if(lpwzLocalFile) HeapFree(GetProcessHeap(), 0, lpwzLocalFile);
169 if(lpwzNewRemoteFile) 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(hIC, &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 close(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 close(lpwfs->lstnSocket);
291 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
293 INTERNET_ASYNC_RESULT iar;
295 iar.dwResult = (DWORD)bSuccess;
296 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
297 SendAsyncCallback(hIC, &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 if(lpwzDirectory) 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 hIC->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 && hIC->lpfnStatusCB)
426 INTERNET_ASYNC_RESULT iar;
428 iar.dwResult = (DWORD)bSuccess;
429 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
430 SendAsyncCallback(hIC, &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 if(lpwzDirectory) 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 && hIC->lpfnStatusCB)
550 INTERNET_ASYNC_RESULT iar;
552 iar.dwResult = (DWORD)bSuccess;
553 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
554 SendAsyncCallback(hIC, &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 if(lpwzSearchFile) 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 hIC->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 close(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 close(lpwfs->lstnSocket);
708 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
710 INTERNET_ASYNC_RESULT iar;
712 if (hFindNext)
714 iar.dwResult = (DWORD)hFindNext;
715 iar.dwError = ERROR_SUCCESS;
716 SendAsyncCallback(hIC, &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(hIC, &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 hIC->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 strncpyW(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1],
868 len < *lpdwCurrentDirectory ? len : *lpdwCurrentDirectory);
869 HeapFree(GetProcessHeap(), 0, lpszResponseBuffer);
870 *lpdwCurrentDirectory = len;
871 bSuccess = TRUE;
873 else
874 FTP_SetResponseError(nResCode);
877 lend:
878 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
880 INTERNET_ASYNC_RESULT iar;
882 iar.dwResult = (DWORD)bSuccess;
883 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
884 SendAsyncCallback(hIC, &lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
885 &iar, sizeof(INTERNET_ASYNC_RESULT));
888 return (DWORD) bSuccess;
891 /***********************************************************************
892 * FtpOpenFileA (WININET.@)
894 * Open a remote file for writing or reading
896 * RETURNS
897 * HINTERNET handle on success
898 * NULL on failure
901 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
902 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
903 DWORD dwContext)
905 LPWSTR lpwzFileName;
906 HINTERNET ret;
908 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
909 ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext);
910 if(lpwzFileName) HeapFree(GetProcessHeap(), 0, lpwzFileName);
911 return ret;
915 /***********************************************************************
916 * FtpOpenFileW (WININET.@)
918 * Open a remote file for writing or reading
920 * RETURNS
921 * HINTERNET handle on success
922 * NULL on failure
925 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
926 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
927 DWORD dwContext)
929 LPWININETFTPSESSIONW lpwfs;
930 LPWININETAPPINFOW hIC = NULL;
931 HINTERNET r = NULL;
933 TRACE("(%p,%s,0x%08lx,0x%08lx,0x%08lx)\n", hFtpSession,
934 debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext);
936 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
937 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
939 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
940 goto lend;
943 if (lpwfs->download_in_progress != NULL) {
944 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
945 goto lend;
947 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
948 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
950 WORKREQUEST workRequest;
951 struct WORKREQ_FTPOPENFILEW *req;
953 workRequest.asyncall = FTPOPENFILEW;
954 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
955 req = &workRequest.u.FtpOpenFileW;
956 req->lpszFilename = WININET_strdupW(lpszFileName);
957 req->dwAccess = fdwAccess;
958 req->dwFlags = dwFlags;
959 req->dwContext = dwContext;
961 INTERNET_AsyncCall(&workRequest);
962 r = NULL;
964 else
966 r = FTP_FtpOpenFileW(lpwfs, lpszFileName, fdwAccess, dwFlags, dwContext);
969 lend:
970 if( lpwfs )
971 WININET_Release( &lpwfs->hdr );
973 return r;
977 /***********************************************************************
978 * FTP_FtpOpenFileW (Internal)
980 * Open a remote file for writing or reading
982 * RETURNS
983 * HINTERNET handle on success
984 * NULL on failure
987 HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs,
988 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
989 DWORD dwContext)
991 INT nDataSocket;
992 BOOL bSuccess = FALSE;
993 LPWININETFILE lpwh = NULL;
994 LPWININETAPPINFOW hIC = NULL;
995 HINTERNET handle = NULL;
997 TRACE("\n");
999 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1001 /* Clear any error information */
1002 INTERNET_SetLastError(0);
1004 if (GENERIC_READ == fdwAccess)
1006 /* Set up socket to retrieve data */
1007 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
1009 else if (GENERIC_WRITE == fdwAccess)
1011 /* Set up socket to send data */
1012 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
1015 /* Get data socket to server */
1016 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
1018 lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE));
1019 lpwh->hdr.htype = WH_HFILE;
1020 lpwh->hdr.dwFlags = dwFlags;
1021 lpwh->hdr.dwContext = dwContext;
1022 lpwh->hdr.lpwhparent = WININET_AddRef( &lpwfs->hdr );
1023 lpwh->hdr.dwRefCount = 1;
1024 lpwh->hdr.destroy = FTP_CloseFileTransferHandle;
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 close(lpwfs->lstnSocket);
1039 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1040 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1042 INTERNET_ASYNC_RESULT iar;
1044 if (lpwh)
1046 iar.dwResult = (DWORD)handle;
1047 iar.dwError = ERROR_SUCCESS;
1048 SendAsyncCallback(hIC, &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(hIC, &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 if(lpwzRemoteFile) HeapFree(GetProcessHeap(), 0, lpwzRemoteFile);
1089 if(lpwzNewFile) 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 close(nDataSocket);
1214 lend:
1215 if (lpwfs->lstnSocket != -1)
1216 close(lpwfs->lstnSocket);
1218 if (hFile)
1219 CloseHandle(hFile);
1221 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1222 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1224 INTERNET_ASYNC_RESULT iar;
1226 iar.dwResult = (DWORD)bSuccess;
1227 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1228 SendAsyncCallback(hIC, &lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1229 &iar, sizeof(INTERNET_ASYNC_RESULT));
1232 return bSuccess;
1236 /***********************************************************************
1237 * FtpDeleteFileA (WININET.@)
1239 * Delete a file on the ftp server
1241 * RETURNS
1242 * TRUE on success
1243 * FALSE on failure
1246 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1248 LPWSTR lpwzFileName;
1249 BOOL ret;
1251 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1252 ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1253 if(lpwzFileName) HeapFree(GetProcessHeap(), 0, lpwzFileName);
1254 return ret;
1257 /***********************************************************************
1258 * FtpDeleteFileW (WININET.@)
1260 * Delete a file on the ftp server
1262 * RETURNS
1263 * TRUE on success
1264 * FALSE on failure
1267 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1269 LPWININETFTPSESSIONW lpwfs;
1270 LPWININETAPPINFOW hIC = NULL;
1271 BOOL r = FALSE;
1273 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1274 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1276 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1277 goto lend;
1280 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1281 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1283 WORKREQUEST workRequest;
1284 struct WORKREQ_FTPDELETEFILEW *req;
1286 workRequest.asyncall = FTPDELETEFILEW;
1287 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1288 req = &workRequest.u.FtpDeleteFileW;
1289 req->lpszFilename = WININET_strdupW(lpszFileName);
1291 r = INTERNET_AsyncCall(&workRequest);
1293 else
1295 r = FTP_FtpDeleteFileW(hFtpSession, lpszFileName);
1298 lend:
1299 if( lpwfs )
1300 WININET_Release( &lpwfs->hdr );
1302 return r;
1305 /***********************************************************************
1306 * FTP_FtpDeleteFileW (Internal)
1308 * Delete a file on the ftp server
1310 * RETURNS
1311 * TRUE on success
1312 * FALSE on failure
1315 BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName)
1317 INT nResCode;
1318 BOOL bSuccess = FALSE;
1319 LPWININETAPPINFOW hIC = NULL;
1321 TRACE("%p\n", lpwfs);
1323 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1325 /* Clear any error information */
1326 INTERNET_SetLastError(0);
1328 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1329 goto lend;
1331 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1332 if (nResCode)
1334 if (nResCode == 250)
1335 bSuccess = TRUE;
1336 else
1337 FTP_SetResponseError(nResCode);
1339 lend:
1340 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1341 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1343 INTERNET_ASYNC_RESULT iar;
1345 iar.dwResult = (DWORD)bSuccess;
1346 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1347 SendAsyncCallback(hIC, &lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1348 &iar, sizeof(INTERNET_ASYNC_RESULT));
1351 return bSuccess;
1355 /***********************************************************************
1356 * FtpRemoveDirectoryA (WININET.@)
1358 * Remove a directory on the ftp server
1360 * RETURNS
1361 * TRUE on success
1362 * FALSE on failure
1365 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1367 LPWSTR lpwzDirectory;
1368 BOOL ret;
1370 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
1371 ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1372 if(lpwzDirectory) HeapFree(GetProcessHeap(), 0, lpwzDirectory);
1373 return ret;
1376 /***********************************************************************
1377 * FtpRemoveDirectoryW (WININET.@)
1379 * Remove a directory on the ftp server
1381 * RETURNS
1382 * TRUE on success
1383 * FALSE on failure
1386 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1388 LPWININETFTPSESSIONW lpwfs;
1389 LPWININETAPPINFOW hIC = NULL;
1390 BOOL r = FALSE;
1392 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1393 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1395 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1396 goto lend;
1399 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1400 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1402 WORKREQUEST workRequest;
1403 struct WORKREQ_FTPREMOVEDIRECTORYW *req;
1405 workRequest.asyncall = FTPREMOVEDIRECTORYW;
1406 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1407 req = &workRequest.u.FtpRemoveDirectoryW;
1408 req->lpszDirectory = WININET_strdupW(lpszDirectory);
1410 r = INTERNET_AsyncCall(&workRequest);
1412 else
1414 r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory);
1417 lend:
1418 if( lpwfs )
1419 WININET_Release( &lpwfs->hdr );
1421 return r;
1424 /***********************************************************************
1425 * FTP_FtpRemoveDirectoryW (Internal)
1427 * Remove a directory on the ftp server
1429 * RETURNS
1430 * TRUE on success
1431 * FALSE on failure
1434 BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
1436 INT nResCode;
1437 BOOL bSuccess = FALSE;
1438 LPWININETAPPINFOW hIC = NULL;
1440 TRACE("\n");
1442 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1444 /* Clear any error information */
1445 INTERNET_SetLastError(0);
1447 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1448 goto lend;
1450 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1451 if (nResCode)
1453 if (nResCode == 250)
1454 bSuccess = TRUE;
1455 else
1456 FTP_SetResponseError(nResCode);
1459 lend:
1460 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1461 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1463 INTERNET_ASYNC_RESULT iar;
1465 iar.dwResult = (DWORD)bSuccess;
1466 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1467 SendAsyncCallback(hIC, &lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1468 &iar, sizeof(INTERNET_ASYNC_RESULT));
1471 return bSuccess;
1475 /***********************************************************************
1476 * FtpRenameFileA (WININET.@)
1478 * Rename a file on the ftp server
1480 * RETURNS
1481 * TRUE on success
1482 * FALSE on failure
1485 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1487 LPWSTR lpwzSrc;
1488 LPWSTR lpwzDest;
1489 BOOL ret;
1491 lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL;
1492 lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL;
1493 ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
1494 if(lpwzSrc) HeapFree(GetProcessHeap(), 0, lpwzSrc);
1495 if(lpwzDest) HeapFree(GetProcessHeap(), 0, lpwzDest);
1496 return ret;
1499 /***********************************************************************
1500 * FtpRenameFileW (WININET.@)
1502 * Rename a file on the ftp server
1504 * RETURNS
1505 * TRUE on success
1506 * FALSE on failure
1509 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
1511 LPWININETFTPSESSIONW lpwfs;
1512 LPWININETAPPINFOW hIC = NULL;
1513 BOOL r = FALSE;
1515 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1516 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1518 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1519 goto lend;
1522 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1523 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1525 WORKREQUEST workRequest;
1526 struct WORKREQ_FTPRENAMEFILEW *req;
1528 workRequest.asyncall = FTPRENAMEFILEW;
1529 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1530 req = &workRequest.u.FtpRenameFileW;
1531 req->lpszSrcFile = WININET_strdupW(lpszSrc);
1532 req->lpszDestFile = WININET_strdupW(lpszDest);
1534 r = INTERNET_AsyncCall(&workRequest);
1536 else
1538 r = FTP_FtpRenameFileW(hFtpSession, lpszSrc, lpszDest);
1541 lend:
1542 if( lpwfs )
1543 WININET_Release( &lpwfs->hdr );
1545 return r;
1548 /***********************************************************************
1549 * FTP_FtpRenameFileA (Internal)
1551 * Rename a file on the ftp server
1553 * RETURNS
1554 * TRUE on success
1555 * FALSE on failure
1558 BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs,
1559 LPCWSTR lpszSrc, LPCWSTR lpszDest)
1561 INT nResCode;
1562 BOOL bSuccess = FALSE;
1563 LPWININETAPPINFOW hIC = NULL;
1565 TRACE("\n");
1567 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1569 /* Clear any error information */
1570 INTERNET_SetLastError(0);
1572 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1573 goto lend;
1575 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1576 if (nResCode == 350)
1578 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1579 goto lend;
1581 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1584 if (nResCode == 250)
1585 bSuccess = TRUE;
1586 else
1587 FTP_SetResponseError(nResCode);
1589 lend:
1590 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1591 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1593 INTERNET_ASYNC_RESULT iar;
1595 iar.dwResult = (DWORD)bSuccess;
1596 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1597 SendAsyncCallback(hIC, &lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1598 &iar, sizeof(INTERNET_ASYNC_RESULT));
1601 return bSuccess;
1605 /***********************************************************************
1606 * FTP_Connect (internal)
1608 * Connect to a ftp server
1610 * RETURNS
1611 * HINTERNET a session handle on success
1612 * NULL on failure
1616 HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
1617 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1618 LPCWSTR lpszPassword, DWORD dwFlags, DWORD dwContext,
1619 DWORD dwInternalFlags)
1621 static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'};
1622 static const WCHAR szDefaultPassword[] = {'u','s','e','r','@','s','e','r','v','e','r','\0'};
1623 struct sockaddr_in socketAddr;
1624 struct hostent *phe = NULL;
1625 INT nsocket = -1, sock_namelen;
1626 BOOL bSuccess = FALSE;
1627 LPWININETFTPSESSIONW lpwfs = NULL;
1628 HINTERNET handle = NULL;
1630 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1631 hIC, debugstr_w(lpszServerName),
1632 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
1634 assert( hIC->hdr.htype != WH_HINIT );
1636 if (NULL == lpszUserName && NULL != lpszPassword)
1638 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1639 goto lerror;
1642 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
1643 if (NULL == lpwfs)
1645 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1646 goto lerror;
1649 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1650 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1652 lpwfs->hdr.htype = WH_HFTPSESSION;
1653 lpwfs->hdr.lpwhparent = WININET_AddRef( &hIC->hdr );
1654 lpwfs->hdr.dwFlags = dwFlags;
1655 lpwfs->hdr.dwContext = dwContext;
1656 lpwfs->hdr.dwInternalFlags = dwInternalFlags;
1657 lpwfs->hdr.dwRefCount = 1;
1658 lpwfs->hdr.destroy = FTP_CloseSessionHandle;
1659 lpwfs->download_in_progress = NULL;
1661 handle = WININET_AllocHandle( &lpwfs->hdr );
1662 if( !handle )
1664 ERR("Failed to alloc handle\n");
1665 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1666 goto lerror;
1669 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1670 if(strchrW(hIC->lpszProxy, ' '))
1671 FIXME("Several proxies not implemented.\n");
1672 if(hIC->lpszProxyBypass)
1673 FIXME("Proxy bypass is ignored.\n");
1675 if ( !lpszUserName) {
1676 lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
1677 lpwfs->lpszPassword = WININET_strdupW(szDefaultPassword);
1679 else {
1680 lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
1681 lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
1684 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1685 if (hIC->lpfnStatusCB && !(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
1687 INTERNET_ASYNC_RESULT iar;
1689 iar.dwResult = (DWORD)handle;
1690 iar.dwError = ERROR_SUCCESS;
1692 SendAsyncCallback(hIC, &hIC->hdr, dwContext,
1693 INTERNET_STATUS_HANDLE_CREATED, &iar,
1694 sizeof(INTERNET_ASYNC_RESULT));
1697 SendAsyncCallback(hIC, &hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1698 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1700 if (!GetAddress(lpszServerName, nServerPort, &phe, &socketAddr))
1702 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1703 goto lerror;
1706 SendAsyncCallback(hIC, &hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1707 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1709 nsocket = socket(AF_INET,SOCK_STREAM,0);
1710 if (nsocket == -1)
1712 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1713 goto lerror;
1716 SendAsyncCallback(hIC, &hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1717 &socketAddr, sizeof(struct sockaddr_in));
1719 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1721 ERR("Unable to connect (%s)\n", strerror(errno));
1722 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1724 else
1726 TRACE("Connected to server\n");
1727 lpwfs->sndSocket = nsocket;
1728 SendAsyncCallback(hIC, &hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1729 &socketAddr, sizeof(struct sockaddr_in));
1731 sock_namelen = sizeof(lpwfs->socketAddress);
1732 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1733 lpwfs->phostent = phe;
1735 if (FTP_ConnectToHost(lpwfs))
1737 TRACE("Successfully logged into server\n");
1738 bSuccess = TRUE;
1742 lerror:
1743 if (!bSuccess && nsocket == -1)
1744 close(nsocket);
1746 if (!bSuccess && lpwfs)
1748 HeapFree(GetProcessHeap(), 0, lpwfs);
1749 WININET_FreeHandle( handle );
1750 lpwfs = NULL;
1753 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1755 INTERNET_ASYNC_RESULT iar;
1757 iar.dwResult = (DWORD)lpwfs;
1758 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1759 SendAsyncCallback(hIC, &hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1760 &iar, sizeof(INTERNET_ASYNC_RESULT));
1763 return handle;
1767 /***********************************************************************
1768 * FTP_ConnectToHost (internal)
1770 * Connect to a ftp server
1772 * RETURNS
1773 * TRUE on success
1774 * NULL on failure
1777 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
1779 INT nResCode;
1780 BOOL bSuccess = FALSE;
1782 TRACE("\n");
1783 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1785 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1786 goto lend;
1788 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1789 if (nResCode)
1791 /* Login successful... */
1792 if (nResCode == 230)
1793 bSuccess = TRUE;
1794 /* User name okay, need password... */
1795 else if (nResCode == 331)
1796 bSuccess = FTP_SendPassword(lpwfs);
1797 /* Need account for login... */
1798 else if (nResCode == 332)
1799 bSuccess = FTP_SendAccount(lpwfs);
1800 else
1801 FTP_SetResponseError(nResCode);
1804 TRACE("Returning %d\n", bSuccess);
1805 lend:
1806 return bSuccess;
1810 /***********************************************************************
1811 * FTP_SendCommandA (internal)
1813 * Send command to server
1815 * RETURNS
1816 * TRUE on success
1817 * NULL on failure
1820 BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1821 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
1823 DWORD len;
1824 CHAR *buf;
1825 DWORD nBytesSent = 0;
1826 int nRC = 0;
1827 DWORD dwParamLen;
1829 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1831 if (lpfnStatusCB)
1833 HINTERNET hHandle = WININET_FindHandle( hdr );
1834 if( hHandle )
1836 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1837 WININET_Release( hdr );
1841 dwParamLen = lpszParam?strlen(lpszParam)+1:0;
1842 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
1843 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1845 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1846 return FALSE;
1848 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
1849 dwParamLen ? lpszParam : "", szCRLF);
1851 TRACE("Sending (%s) len(%ld)\n", buf, len);
1852 while((nBytesSent < len) && (nRC != -1))
1854 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1855 nBytesSent += nRC;
1858 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
1860 if (lpfnStatusCB)
1862 HINTERNET hHandle = WININET_FindHandle( hdr );
1863 if( hHandle )
1865 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_REQUEST_SENT,
1866 &nBytesSent, sizeof(DWORD));
1867 WININET_Release( hdr );
1871 TRACE("Sent %ld bytes\n", nBytesSent);
1872 return (nRC != -1);
1875 /***********************************************************************
1876 * FTP_SendCommand (internal)
1878 * Send command to server
1880 * RETURNS
1881 * TRUE on success
1882 * NULL on failure
1885 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
1886 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
1888 BOOL ret;
1889 LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
1890 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
1891 HeapFree(GetProcessHeap(), 0, lpszParamA);
1892 return ret;
1895 /***********************************************************************
1896 * FTP_ReceiveResponse (internal)
1898 * Receive response from server
1900 * RETURNS
1901 * Reply code on success
1902 * 0 on failure
1905 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext)
1907 LPSTR lpszResponse = INTERNET_GetResponseBuffer();
1908 DWORD nRecv;
1909 INT rc = 0;
1910 char firstprefix[5];
1911 BOOL multiline = FALSE;
1912 LPWININETAPPINFOW hIC = NULL;
1914 TRACE("socket(%d) \n", lpwfs->sndSocket);
1916 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1917 SendAsyncCallback(hIC, &lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1919 while(1)
1921 if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
1922 goto lerror;
1924 if (nRecv >= 3)
1926 if(!multiline)
1928 if(lpszResponse[3] != '-')
1929 break;
1930 else
1931 { /* Start of multiline repsonse. Loop until we get "nnn " */
1932 multiline = TRUE;
1933 memcpy(firstprefix, lpszResponse, 3);
1934 firstprefix[3] = ' ';
1935 firstprefix[4] = '\0';
1938 else
1940 if(!memcmp(firstprefix, lpszResponse, 4))
1941 break;
1946 if (nRecv >= 3)
1948 rc = atoi(lpszResponse);
1950 SendAsyncCallback(hIC, &lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
1951 &nRecv, sizeof(DWORD));
1954 lerror:
1955 TRACE("return %d\n", rc);
1956 return rc;
1960 /***********************************************************************
1961 * FTP_SendPassword (internal)
1963 * Send password to ftp server
1965 * RETURNS
1966 * TRUE on success
1967 * NULL on failure
1970 BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
1972 INT nResCode;
1973 BOOL bSuccess = FALSE;
1975 TRACE("\n");
1976 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
1977 goto lend;
1979 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1980 if (nResCode)
1982 TRACE("Received reply code %d\n", nResCode);
1983 /* Login successful... */
1984 if (nResCode == 230)
1985 bSuccess = TRUE;
1986 /* Command not implemented, superfluous at the server site... */
1987 /* Need account for login... */
1988 else if (nResCode == 332)
1989 bSuccess = FTP_SendAccount(lpwfs);
1990 else
1991 FTP_SetResponseError(nResCode);
1994 lend:
1995 TRACE("Returning %d\n", bSuccess);
1996 return bSuccess;
2000 /***********************************************************************
2001 * FTP_SendAccount (internal)
2005 * RETURNS
2006 * TRUE on success
2007 * FALSE on failure
2010 BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
2012 INT nResCode;
2013 BOOL bSuccess = FALSE;
2015 TRACE("\n");
2016 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
2017 goto lend;
2019 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2020 if (nResCode)
2021 bSuccess = TRUE;
2022 else
2023 FTP_SetResponseError(nResCode);
2025 lend:
2026 return bSuccess;
2030 /***********************************************************************
2031 * FTP_SendStore (internal)
2033 * Send request to upload file to ftp server
2035 * RETURNS
2036 * TRUE on success
2037 * FALSE on failure
2040 BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2042 INT nResCode;
2043 BOOL bSuccess = FALSE;
2045 TRACE("\n");
2046 if (!FTP_InitListenSocket(lpwfs))
2047 goto lend;
2049 if (!FTP_SendType(lpwfs, dwType))
2050 goto lend;
2052 if (!FTP_SendPortOrPasv(lpwfs))
2053 goto lend;
2055 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2056 goto lend;
2057 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2058 if (nResCode)
2060 if (nResCode == 150)
2061 bSuccess = TRUE;
2062 else
2063 FTP_SetResponseError(nResCode);
2066 lend:
2067 if (!bSuccess && lpwfs->lstnSocket != -1)
2069 close(lpwfs->lstnSocket);
2070 lpwfs->lstnSocket = -1;
2073 return bSuccess;
2077 /***********************************************************************
2078 * FTP_InitListenSocket (internal)
2080 * Create a socket to listen for server response
2082 * RETURNS
2083 * TRUE on success
2084 * FALSE on failure
2087 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
2089 BOOL bSuccess = FALSE;
2090 size_t namelen = sizeof(struct sockaddr_in);
2092 TRACE("\n");
2094 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2095 if (lpwfs->lstnSocket == -1)
2097 TRACE("Unable to create listening socket\n");
2098 goto lend;
2101 /* We obtain our ip addr from the name of the command channel socket */
2102 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2104 /* and get the system to assign us a port */
2105 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
2107 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
2109 TRACE("Unable to bind socket\n");
2110 goto lend;
2113 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2115 TRACE("listen failed\n");
2116 goto lend;
2119 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2120 bSuccess = TRUE;
2122 lend:
2123 if (!bSuccess && lpwfs->lstnSocket == -1)
2125 close(lpwfs->lstnSocket);
2126 lpwfs->lstnSocket = -1;
2129 return bSuccess;
2133 /***********************************************************************
2134 * FTP_SendType (internal)
2136 * Tell server type of data being transferred
2138 * RETURNS
2139 * TRUE on success
2140 * FALSE on failure
2142 * W98SE doesn't cache the type that's currently set
2143 * (i.e. it sends it always),
2144 * so we probably don't want to do that either.
2146 BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
2148 INT nResCode;
2149 WCHAR type[] = { 'I','\0' };
2150 BOOL bSuccess = FALSE;
2152 TRACE("\n");
2153 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2154 type[0] = 'A';
2156 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2157 goto lend;
2159 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2160 if (nResCode)
2162 if (nResCode == 2)
2163 bSuccess = TRUE;
2164 else
2165 FTP_SetResponseError(nResCode);
2168 lend:
2169 return bSuccess;
2172 /***********************************************************************
2173 * FTP_GetFileSize (internal)
2175 * Retrieves from the server the size of the given file
2177 * RETURNS
2178 * TRUE on success
2179 * FALSE on failure
2182 BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
2184 INT nResCode;
2185 BOOL bSuccess = FALSE;
2187 TRACE("\n");
2189 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2190 goto lend;
2192 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2193 if (nResCode)
2195 if (nResCode == 213) {
2196 /* Now parses the output to get the actual file size */
2197 int i;
2198 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2200 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2201 if (lpszResponseBuffer[i] == '\0') return FALSE;
2202 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2204 bSuccess = TRUE;
2205 } else {
2206 FTP_SetResponseError(nResCode);
2210 lend:
2211 return bSuccess;
2215 /***********************************************************************
2216 * FTP_SendPort (internal)
2218 * Tell server which port to use
2220 * RETURNS
2221 * TRUE on success
2222 * FALSE on failure
2225 BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
2227 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2228 INT nResCode;
2229 WCHAR szIPAddress[64];
2230 BOOL bSuccess = FALSE;
2231 TRACE("\n");
2233 sprintfW(szIPAddress, szIPFormat,
2234 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2235 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2236 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2237 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2238 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2239 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2241 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2242 goto lend;
2244 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2245 if (nResCode)
2247 if (nResCode == 200)
2248 bSuccess = TRUE;
2249 else
2250 FTP_SetResponseError(nResCode);
2253 lend:
2254 return bSuccess;
2258 /***********************************************************************
2259 * FTP_DoPassive (internal)
2261 * Tell server that we want to do passive transfers
2262 * and connect data socket
2264 * RETURNS
2265 * TRUE on success
2266 * FALSE on failure
2269 BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
2271 INT nResCode;
2272 BOOL bSuccess = FALSE;
2274 TRACE("\n");
2275 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2276 goto lend;
2278 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2279 if (nResCode)
2281 if (nResCode == 227)
2283 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2284 LPSTR p;
2285 int f[6];
2286 int i;
2287 char *pAddr, *pPort;
2288 INT nsocket = -1;
2289 struct sockaddr_in dataSocketAddress;
2291 p = lpszResponseBuffer+4; /* skip status code */
2293 /* do a very strict check; we can improve that later. */
2295 if (strncmp(p, "Entering Passive Mode", 21))
2297 ERR("unknown response '%.*s', aborting\n", 21, p);
2298 goto lend;
2300 p += 21; /* skip string */
2301 if ((*p++ != ' ') || (*p++ != '('))
2303 ERR("unknown response format, aborting\n");
2304 goto lend;
2307 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2308 &f[4], &f[5]) != 6)
2310 ERR("unknown response address format '%s', aborting\n", p);
2311 goto lend;
2313 for (i=0; i < 6; i++)
2314 f[i] = f[i] & 0xff;
2316 dataSocketAddress = lpwfs->socketAddress;
2317 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2318 pPort = (char *)&(dataSocketAddress.sin_port);
2319 pAddr[0] = f[0];
2320 pAddr[1] = f[1];
2321 pAddr[2] = f[2];
2322 pAddr[3] = f[3];
2323 pPort[0] = f[4];
2324 pPort[1] = f[5];
2326 nsocket = socket(AF_INET,SOCK_STREAM,0);
2327 if (nsocket == -1)
2328 goto lend;
2330 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2332 ERR("can't connect passive FTP data port.\n");
2333 goto lend;
2335 lpwfs->pasvSocket = nsocket;
2336 bSuccess = TRUE;
2338 else
2339 FTP_SetResponseError(nResCode);
2342 lend:
2343 return bSuccess;
2347 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
2349 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2351 if (!FTP_DoPassive(lpwfs))
2352 return FALSE;
2354 else
2356 if (!FTP_SendPort(lpwfs))
2357 return FALSE;
2359 return TRUE;
2363 /***********************************************************************
2364 * FTP_GetDataSocket (internal)
2366 * Either accepts an incoming data socket connection from the server
2367 * or just returns the already opened socket after a PASV command
2368 * in case of passive FTP.
2371 * RETURNS
2372 * TRUE on success
2373 * FALSE on failure
2376 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
2378 struct sockaddr_in saddr;
2379 size_t addrlen = sizeof(struct sockaddr);
2381 TRACE("\n");
2382 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2384 *nDataSocket = lpwfs->pasvSocket;
2386 else
2388 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2389 close(lpwfs->lstnSocket);
2390 lpwfs->lstnSocket = -1;
2392 return *nDataSocket != -1;
2396 /***********************************************************************
2397 * FTP_SendData (internal)
2399 * Send data to the server
2401 * RETURNS
2402 * TRUE on success
2403 * FALSE on failure
2406 BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2408 BY_HANDLE_FILE_INFORMATION fi;
2409 DWORD nBytesRead = 0;
2410 DWORD nBytesSent = 0;
2411 DWORD nTotalSent = 0;
2412 DWORD nBytesToSend, nLen;
2413 int nRC = 1;
2414 time_t s_long_time, e_long_time;
2415 LONG nSeconds;
2416 CHAR *lpszBuffer;
2418 TRACE("\n");
2419 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2420 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2422 /* Get the size of the file. */
2423 GetFileInformationByHandle(hFile, &fi);
2424 time(&s_long_time);
2428 nBytesToSend = nBytesRead - nBytesSent;
2430 if (nBytesToSend <= 0)
2432 /* Read data from file. */
2433 nBytesSent = 0;
2434 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2435 ERR("Failed reading from file\n");
2437 if (nBytesRead > 0)
2438 nBytesToSend = nBytesRead;
2439 else
2440 break;
2443 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2444 DATA_PACKET_SIZE : nBytesToSend;
2445 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2447 if (nRC != -1)
2449 nBytesSent += nRC;
2450 nTotalSent += nRC;
2453 /* Do some computation to display the status. */
2454 time(&e_long_time);
2455 nSeconds = e_long_time - s_long_time;
2456 if( nSeconds / 60 > 0 )
2458 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
2459 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2460 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2462 else
2464 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
2465 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2466 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2468 } while (nRC != -1);
2470 TRACE("file transfer complete!\n");
2472 if(lpszBuffer != NULL)
2473 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2475 return nTotalSent;
2479 /***********************************************************************
2480 * FTP_SendRetrieve (internal)
2482 * Send request to retrieve a file
2484 * RETURNS
2485 * Number of bytes to be received on success
2486 * 0 on failure
2489 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2491 INT nResCode;
2492 DWORD nResult = 0;
2494 TRACE("\n");
2495 if (!FTP_InitListenSocket(lpwfs))
2496 goto lend;
2498 if (!FTP_SendType(lpwfs, dwType))
2499 goto lend;
2501 if (!FTP_SendPortOrPasv(lpwfs))
2502 goto lend;
2504 if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2505 goto lend;
2507 TRACE("Waiting to receive %ld bytes\n", nResult);
2509 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2510 goto lend;
2512 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2513 if ((nResCode != 125) && (nResCode != 150)) {
2514 /* That means that we got an error getting the file. */
2515 nResult = 0;
2518 lend:
2519 if (0 == nResult && lpwfs->lstnSocket != -1)
2521 close(lpwfs->lstnSocket);
2522 lpwfs->lstnSocket = -1;
2525 return nResult;
2529 /***********************************************************************
2530 * FTP_RetrieveData (internal)
2532 * Retrieve data from server
2534 * RETURNS
2535 * TRUE on success
2536 * FALSE on failure
2539 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2541 DWORD nBytesWritten;
2542 DWORD nBytesReceived = 0;
2543 INT nRC = 0;
2544 CHAR *lpszBuffer;
2546 TRACE("\n");
2548 if (INVALID_HANDLE_VALUE == hFile)
2549 return FALSE;
2551 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2552 if (NULL == lpszBuffer)
2554 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2555 return FALSE;
2558 while (nBytesReceived < nBytes && nRC != -1)
2560 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2561 if (nRC != -1)
2563 /* other side closed socket. */
2564 if (nRC == 0)
2565 goto recv_end;
2566 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2567 nBytesReceived += nRC;
2570 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
2571 nBytesReceived * 100 / nBytes);
2574 TRACE("Data transfer complete\n");
2575 if (NULL != lpszBuffer)
2576 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2578 recv_end:
2579 return (nRC != -1);
2583 /***********************************************************************
2584 * FTP_CloseSessionHandle (internal)
2586 * Deallocate session handle
2588 * RETURNS
2589 * TRUE on success
2590 * FALSE on failure
2593 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr)
2595 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2597 TRACE("\n");
2599 if (lpwfs->download_in_progress != NULL)
2600 lpwfs->download_in_progress->session_deleted = TRUE;
2602 if (lpwfs->sndSocket != -1)
2603 close(lpwfs->sndSocket);
2605 if (lpwfs->lstnSocket != -1)
2606 close(lpwfs->lstnSocket);
2608 if (lpwfs->lpszPassword)
2609 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2611 if (lpwfs->lpszUserName)
2612 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2614 HeapFree(GetProcessHeap(), 0, lpwfs);
2618 /***********************************************************************
2619 * FTP_CloseFindNextHandle (internal)
2621 * Deallocate session handle
2623 * RETURNS
2624 * TRUE on success
2625 * FALSE on failure
2628 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr)
2630 LPWININETFINDNEXTW lpwfn = (LPWININETFINDNEXTW) hdr;
2631 DWORD i;
2633 TRACE("\n");
2635 for (i = 0; i < lpwfn->size; i++)
2637 if (NULL != lpwfn->lpafp[i].lpszName)
2638 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2641 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2642 HeapFree(GetProcessHeap(), 0, lpwfn);
2645 /***********************************************************************
2646 * FTP_CloseFileTransferHandle (internal)
2648 * Closes the file transfer handle. This also 'cleans' the data queue of
2649 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2652 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr)
2654 LPWININETFILE lpwh = (LPWININETFILE) hdr;
2655 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) lpwh->hdr.lpwhparent;
2656 INT nResCode;
2658 TRACE("\n");
2660 if (!lpwh->session_deleted)
2661 lpwfs->download_in_progress = NULL;
2663 /* This just serves to flush the control socket of any spurrious lines written
2664 to it (like '226 Transfer complete.').
2666 Wonder what to do if the server sends us an error code though...
2668 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2670 if (lpwh->nDataSocket != -1)
2671 close(lpwh->nDataSocket);
2673 HeapFree(GetProcessHeap(), 0, lpwh);
2676 /***********************************************************************
2677 * FTP_ReceiveFileList (internal)
2679 * Read file list from server
2681 * RETURNS
2682 * Handle to file list on success
2683 * NULL on failure
2686 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2687 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext)
2689 DWORD dwSize = 0;
2690 LPFILEPROPERTIESW lpafp = NULL;
2691 LPWININETFINDNEXTW lpwfn = NULL;
2692 HINTERNET handle = 0;
2694 TRACE("(%p,%d,%s,%p,%ld)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
2696 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
2698 if(lpFindFileData)
2699 FTP_ConvertFileProp(lpafp, lpFindFileData);
2701 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTW));
2702 if (lpwfn)
2704 lpwfn->hdr.htype = WH_HFINDNEXT;
2705 lpwfn->hdr.lpwhparent = WININET_AddRef( &lpwfs->hdr );
2706 lpwfn->hdr.dwContext = dwContext;
2707 lpwfn->hdr.dwRefCount = 1;
2708 lpwfn->hdr.destroy = FTP_CloseFindNextHandle;
2709 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2710 lpwfn->size = dwSize;
2711 lpwfn->lpafp = lpafp;
2713 handle = WININET_AllocHandle( &lpwfn->hdr );
2717 if( lpwfn )
2718 WININET_Release( &lpwfn->hdr );
2720 TRACE("Matched %ld files\n", dwSize);
2721 return handle;
2725 /***********************************************************************
2726 * FTP_ConvertFileProp (internal)
2728 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
2730 * RETURNS
2731 * TRUE on success
2732 * FALSE on failure
2735 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
2737 BOOL bSuccess = FALSE;
2739 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
2741 if (lpafp)
2743 /* Convert 'Unix' time to Windows time */
2744 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
2745 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
2747 /* Not all fields are filled in */
2748 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2749 lpFindFileData->nFileSizeLow = lpafp->nSize;
2751 if (lpafp->bIsDirectory)
2752 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2754 if (lpafp->lpszName)
2755 strncpyW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2757 bSuccess = TRUE;
2760 return bSuccess;
2763 /***********************************************************************
2764 * FTP_ParseNextFile (internal)
2766 * Parse the next line in file listing
2768 * RETURNS
2769 * TRUE on success
2770 * FALSE on failure
2772 BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
2774 static const char szSpace[] = " \t";
2775 DWORD nBufLen;
2776 char *pszLine;
2777 char *pszToken;
2778 char *pszTmp;
2779 BOOL found = FALSE;
2780 int i;
2782 lpfp->lpszName = NULL;
2783 do {
2784 if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
2785 return FALSE;
2787 pszToken = strtok(pszLine, szSpace);
2788 /* ls format
2789 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2791 * For instance:
2792 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2794 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
2795 if(!FTP_ParsePermission(pszToken, lpfp))
2796 lpfp->bIsDirectory = FALSE;
2797 for(i=0; i<=3; i++) {
2798 if(!(pszToken = strtok(NULL, szSpace)))
2799 break;
2801 if(!pszToken) continue;
2802 if(lpfp->bIsDirectory) {
2803 TRACE("Is directory\n");
2804 lpfp->nSize = 0;
2806 else {
2807 TRACE("Size: %s\n", pszToken);
2808 lpfp->nSize = atol(pszToken);
2811 lpfp->tmLastModified.tm_sec = 0;
2812 lpfp->tmLastModified.tm_min = 0;
2813 lpfp->tmLastModified.tm_hour = 0;
2814 lpfp->tmLastModified.tm_mday = 0;
2815 lpfp->tmLastModified.tm_mon = 0;
2816 lpfp->tmLastModified.tm_year = 0;
2818 /* Determine month */
2819 pszToken = strtok(NULL, szSpace);
2820 if(!pszToken) continue;
2821 if(strlen(pszToken) >= 3) {
2822 pszToken[3] = 0;
2823 if((pszTmp = StrStrIA(szMonths, pszToken)))
2824 lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
2826 /* Determine day */
2827 pszToken = strtok(NULL, szSpace);
2828 if(!pszToken) continue;
2829 lpfp->tmLastModified.tm_mday = atoi(pszToken);
2830 /* Determine time or year */
2831 pszToken = strtok(NULL, szSpace);
2832 if(!pszToken) continue;
2833 if((pszTmp = strchr(pszToken, ':'))) {
2834 struct tm* apTM;
2835 time_t aTime;
2836 *pszTmp = 0;
2837 pszTmp++;
2838 lpfp->tmLastModified.tm_min = atoi(pszTmp);
2839 lpfp->tmLastModified.tm_hour = atoi(pszToken);
2840 time(&aTime);
2841 apTM = localtime(&aTime);
2842 lpfp->tmLastModified.tm_year = apTM->tm_year;
2844 else {
2845 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
2846 lpfp->tmLastModified.tm_hour = 12;
2848 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
2849 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
2850 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
2851 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
2853 pszToken = strtok(NULL, szSpace);
2854 if(!pszToken) continue;
2855 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
2856 TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
2858 /* NT way of parsing ... :
2860 07-13-03 08:55PM <DIR> sakpatch
2861 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
2863 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
2864 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
2866 sscanf(pszToken, "%d-%d-%d",
2867 &lpfp->tmLastModified.tm_mon,
2868 &lpfp->tmLastModified.tm_mday,
2869 &lpfp->tmLastModified.tm_year);
2871 /* Hacky and bad Y2K protection :-) */
2872 if (lpfp->tmLastModified.tm_year < 70)
2873 lpfp->tmLastModified.tm_year += 100;
2875 pszToken = strtok(NULL, szSpace);
2876 if(!pszToken) continue;
2877 sscanf(pszToken, "%d:%d",
2878 &lpfp->tmLastModified.tm_hour,
2879 &lpfp->tmLastModified.tm_min);
2880 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
2881 lpfp->tmLastModified.tm_hour += 12;
2883 lpfp->tmLastModified.tm_sec = 0;
2885 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
2886 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
2887 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
2888 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
2890 pszToken = strtok(NULL, szSpace);
2891 if(!pszToken) continue;
2892 if(!strcasecmp(pszToken, "<DIR>")) {
2893 lpfp->bIsDirectory = TRUE;
2894 lpfp->nSize = 0;
2895 TRACE("Is directory\n");
2897 else {
2898 lpfp->bIsDirectory = FALSE;
2899 lpfp->nSize = atol(pszToken);
2900 TRACE("Size: %ld\n", lpfp->nSize);
2903 pszToken = strtok(NULL, szSpace);
2904 if(!pszToken) continue;
2905 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
2906 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
2908 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
2909 else if(pszToken[0] == '+') {
2910 FIXME("EPLF Format not implemented\n");
2913 if(lpfp->lpszName) {
2914 if((lpszSearchFile == NULL) ||
2915 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
2916 found = TRUE;
2917 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
2919 else {
2920 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
2921 lpfp->lpszName = NULL;
2924 } while(!found);
2925 return TRUE;
2928 /***********************************************************************
2929 * FTP_ParseDirectory (internal)
2931 * Parse string of directory information
2933 * RETURNS
2934 * TRUE on success
2935 * FALSE on failure
2937 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2938 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
2940 BOOL bSuccess = TRUE;
2941 INT sizeFilePropArray = 500;/*20; */
2942 INT indexFilePropArray = -1;
2944 TRACE("\n");
2946 /* Allocate intial file properties array */
2947 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
2948 if (!*lpafp)
2949 return FALSE;
2951 do {
2952 if (indexFilePropArray+1 >= sizeFilePropArray)
2954 LPFILEPROPERTIESW tmpafp;
2956 sizeFilePropArray *= 2;
2957 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
2958 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
2959 if (NULL == tmpafp)
2961 bSuccess = FALSE;
2962 break;
2965 *lpafp = tmpafp;
2967 indexFilePropArray++;
2968 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
2970 if (bSuccess && indexFilePropArray)
2972 if (indexFilePropArray < sizeFilePropArray - 1)
2974 LPFILEPROPERTIESW tmpafp;
2976 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
2977 sizeof(FILEPROPERTIESW)*indexFilePropArray);
2978 if (NULL == tmpafp)
2979 *lpafp = tmpafp;
2981 *dwfp = indexFilePropArray;
2983 else
2985 HeapFree(GetProcessHeap(), 0, *lpafp);
2986 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2987 bSuccess = FALSE;
2990 return bSuccess;
2994 /***********************************************************************
2995 * FTP_ParsePermission (internal)
2997 * Parse permission string of directory information
2999 * RETURNS
3000 * TRUE on success
3001 * FALSE on failure
3004 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3006 BOOL bSuccess = TRUE;
3007 unsigned short nPermission = 0;
3008 INT nPos = 1;
3009 INT nLast = 9;
3011 TRACE("\n");
3012 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3014 bSuccess = FALSE;
3015 return bSuccess;
3018 lpfp->bIsDirectory = (*lpszPermission == 'd');
3021 switch (nPos)
3023 case 1:
3024 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3025 break;
3026 case 2:
3027 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3028 break;
3029 case 3:
3030 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3031 break;
3032 case 4:
3033 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3034 break;
3035 case 5:
3036 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3037 break;
3038 case 6:
3039 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3040 break;
3041 case 7:
3042 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3043 break;
3044 case 8:
3045 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3046 break;
3047 case 9:
3048 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3049 break;
3051 nPos++;
3052 }while (nPos <= nLast);
3054 lpfp->permissions = nPermission;
3055 return bSuccess;
3059 /***********************************************************************
3060 * FTP_SetResponseError (internal)
3062 * Set the appropriate error code for a given response from the server
3064 * RETURNS
3067 DWORD FTP_SetResponseError(DWORD dwResponse)
3069 DWORD dwCode = 0;
3071 switch(dwResponse)
3073 case 421: /* Service not available - Server may be shutting down. */
3074 dwCode = ERROR_INTERNET_TIMEOUT;
3075 break;
3077 case 425: /* Cannot open data connection. */
3078 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3079 break;
3081 case 426: /* Connection closed, transer aborted. */
3082 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3083 break;
3085 case 500: /* Syntax error. Command unrecognized. */
3086 case 501: /* Syntax error. Error in parameters or arguments. */
3087 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
3088 break;
3090 case 530: /* Not logged in. Login incorrect. */
3091 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3092 break;
3094 case 550: /* File action not taken. File not found or no access. */
3095 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
3096 break;
3098 case 450: /* File action not taken. File may be busy. */
3099 case 451: /* Action aborted. Server error. */
3100 case 452: /* Action not taken. Insufficient storage space on server. */
3101 case 502: /* Command not implemented. */
3102 case 503: /* Bad sequence of command. */
3103 case 504: /* Command not implemented for that parameter. */
3104 case 532: /* Need account for storing files */
3105 case 551: /* Requested action aborted. Page type unknown */
3106 case 552: /* Action aborted. Exceeded storage allocation */
3107 case 553: /* Action not taken. File name not allowed. */
3109 default:
3110 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
3111 break;
3114 INTERNET_SetLastError(dwCode);
3115 return dwCode;