Don't use ".previous" for Cygwin build.
[wine/multimedia.git] / dlls / wininet / ftp.c
blobb7ddb2b9a019fd05f83fa8c6a1bf3e3815a3614b
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(&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 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 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 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)
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 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 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 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)
880 INTERNET_ASYNC_RESULT iar;
882 iar.dwResult = (DWORD)bSuccess;
883 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
884 SendAsyncCallback(&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->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
1026 lpwh->nDataSocket = nDataSocket;
1027 lpwh->session_deleted = FALSE;
1029 handle = WININET_AllocHandle( &lpwh->hdr );
1030 if( !handle )
1031 goto lend;
1033 /* Indicate that a download is currently in progress */
1034 lpwfs->download_in_progress = lpwh;
1037 if (lpwfs->lstnSocket != -1)
1038 closesocket(lpwfs->lstnSocket);
1040 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1041 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1043 INTERNET_ASYNC_RESULT iar;
1045 if (lpwh)
1047 iar.dwResult = (DWORD)handle;
1048 iar.dwError = ERROR_SUCCESS;
1049 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
1050 &iar, sizeof(INTERNET_ASYNC_RESULT));
1053 iar.dwResult = (DWORD)bSuccess;
1054 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1055 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1056 &iar, sizeof(INTERNET_ASYNC_RESULT));
1059 lend:
1060 if( lpwh )
1061 WININET_Release( &lpwh->hdr );
1063 return handle;
1067 /***********************************************************************
1068 * FtpGetFileA (WININET.@)
1070 * Retrieve file from the FTP server
1072 * RETURNS
1073 * TRUE on success
1074 * FALSE on failure
1077 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1078 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1079 DWORD dwContext)
1081 LPWSTR lpwzRemoteFile;
1082 LPWSTR lpwzNewFile;
1083 BOOL ret;
1085 lpwzRemoteFile = lpszRemoteFile?WININET_strdup_AtoW(lpszRemoteFile):NULL;
1086 lpwzNewFile = lpszNewFile?WININET_strdup_AtoW(lpszNewFile):NULL;
1087 ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists,
1088 dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1089 if(lpwzRemoteFile) HeapFree(GetProcessHeap(), 0, lpwzRemoteFile);
1090 if(lpwzNewFile) HeapFree(GetProcessHeap(), 0, lpwzNewFile);
1091 return ret;
1095 /***********************************************************************
1096 * FtpGetFileW (WININET.@)
1098 * Retrieve file from the FTP server
1100 * RETURNS
1101 * TRUE on success
1102 * FALSE on failure
1105 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1106 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1107 DWORD dwContext)
1109 LPWININETFTPSESSIONW lpwfs;
1110 LPWININETAPPINFOW hIC = NULL;
1111 BOOL r = FALSE;
1113 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet );
1114 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1116 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1117 goto lend;
1120 if (lpwfs->download_in_progress != NULL) {
1121 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1122 goto lend;
1125 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1126 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1128 WORKREQUEST workRequest;
1129 struct WORKREQ_FTPGETFILEW *req;
1131 workRequest.asyncall = FTPGETFILEW;
1132 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1133 req = &workRequest.u.FtpGetFileW;
1134 req->lpszRemoteFile = WININET_strdupW(lpszRemoteFile);
1135 req->lpszNewFile = WININET_strdupW(lpszNewFile);
1136 req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1137 req->fFailIfExists = fFailIfExists;
1138 req->dwFlags = dwInternetFlags;
1139 req->dwContext = dwContext;
1141 r = INTERNET_AsyncCall(&workRequest);
1143 else
1145 r = FTP_FtpGetFileW(lpwfs, lpszRemoteFile, lpszNewFile,
1146 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1149 lend:
1150 if( lpwfs )
1151 WININET_Release( &lpwfs->hdr );
1153 return r;
1157 /***********************************************************************
1158 * FTP_FtpGetFileW (Internal)
1160 * Retrieve file from the FTP server
1162 * RETURNS
1163 * TRUE on success
1164 * FALSE on failure
1167 BOOL WINAPI FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1168 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1169 DWORD dwContext)
1171 DWORD nBytes;
1172 BOOL bSuccess = FALSE;
1173 HANDLE hFile;
1174 LPWININETAPPINFOW hIC = NULL;
1176 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile));
1178 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1180 /* Clear any error information */
1181 INTERNET_SetLastError(0);
1183 /* Ensure we can write to lpszNewfile by opening it */
1184 hFile = CreateFileW(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1185 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1186 if (INVALID_HANDLE_VALUE == hFile)
1187 goto lend;
1189 /* Set up socket to retrieve data */
1190 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
1192 if (nBytes > 0)
1194 INT nDataSocket;
1196 /* Get data socket to server */
1197 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1199 INT nResCode;
1201 /* Receive data */
1202 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
1203 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
1204 if (nResCode)
1206 if (nResCode == 226)
1207 bSuccess = TRUE;
1208 else
1209 FTP_SetResponseError(nResCode);
1211 closesocket(nDataSocket);
1215 lend:
1216 if (lpwfs->lstnSocket != -1)
1217 closesocket(lpwfs->lstnSocket);
1219 if (hFile)
1220 CloseHandle(hFile);
1222 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1223 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1225 INTERNET_ASYNC_RESULT iar;
1227 iar.dwResult = (DWORD)bSuccess;
1228 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1229 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1230 &iar, sizeof(INTERNET_ASYNC_RESULT));
1233 return bSuccess;
1237 /***********************************************************************
1238 * FtpDeleteFileA (WININET.@)
1240 * Delete a file on the ftp server
1242 * RETURNS
1243 * TRUE on success
1244 * FALSE on failure
1247 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1249 LPWSTR lpwzFileName;
1250 BOOL ret;
1252 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1253 ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1254 if(lpwzFileName) HeapFree(GetProcessHeap(), 0, lpwzFileName);
1255 return ret;
1258 /***********************************************************************
1259 * FtpDeleteFileW (WININET.@)
1261 * Delete a file on the ftp server
1263 * RETURNS
1264 * TRUE on success
1265 * FALSE on failure
1268 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1270 LPWININETFTPSESSIONW lpwfs;
1271 LPWININETAPPINFOW hIC = NULL;
1272 BOOL r = FALSE;
1274 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1275 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1277 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1278 goto lend;
1281 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1282 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1284 WORKREQUEST workRequest;
1285 struct WORKREQ_FTPDELETEFILEW *req;
1287 workRequest.asyncall = FTPDELETEFILEW;
1288 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1289 req = &workRequest.u.FtpDeleteFileW;
1290 req->lpszFilename = WININET_strdupW(lpszFileName);
1292 r = INTERNET_AsyncCall(&workRequest);
1294 else
1296 r = FTP_FtpDeleteFileW(hFtpSession, lpszFileName);
1299 lend:
1300 if( lpwfs )
1301 WININET_Release( &lpwfs->hdr );
1303 return r;
1306 /***********************************************************************
1307 * FTP_FtpDeleteFileW (Internal)
1309 * Delete a file on the ftp server
1311 * RETURNS
1312 * TRUE on success
1313 * FALSE on failure
1316 BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName)
1318 INT nResCode;
1319 BOOL bSuccess = FALSE;
1320 LPWININETAPPINFOW hIC = NULL;
1322 TRACE("%p\n", lpwfs);
1324 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1326 /* Clear any error information */
1327 INTERNET_SetLastError(0);
1329 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1330 goto lend;
1332 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1333 if (nResCode)
1335 if (nResCode == 250)
1336 bSuccess = TRUE;
1337 else
1338 FTP_SetResponseError(nResCode);
1340 lend:
1341 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1342 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1344 INTERNET_ASYNC_RESULT iar;
1346 iar.dwResult = (DWORD)bSuccess;
1347 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1348 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1349 &iar, sizeof(INTERNET_ASYNC_RESULT));
1352 return bSuccess;
1356 /***********************************************************************
1357 * FtpRemoveDirectoryA (WININET.@)
1359 * Remove a directory on the ftp server
1361 * RETURNS
1362 * TRUE on success
1363 * FALSE on failure
1366 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1368 LPWSTR lpwzDirectory;
1369 BOOL ret;
1371 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
1372 ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1373 if(lpwzDirectory) HeapFree(GetProcessHeap(), 0, lpwzDirectory);
1374 return ret;
1377 /***********************************************************************
1378 * FtpRemoveDirectoryW (WININET.@)
1380 * Remove a directory on the ftp server
1382 * RETURNS
1383 * TRUE on success
1384 * FALSE on failure
1387 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1389 LPWININETFTPSESSIONW lpwfs;
1390 LPWININETAPPINFOW hIC = NULL;
1391 BOOL r = FALSE;
1393 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1394 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1396 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1397 goto lend;
1400 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1401 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1403 WORKREQUEST workRequest;
1404 struct WORKREQ_FTPREMOVEDIRECTORYW *req;
1406 workRequest.asyncall = FTPREMOVEDIRECTORYW;
1407 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1408 req = &workRequest.u.FtpRemoveDirectoryW;
1409 req->lpszDirectory = WININET_strdupW(lpszDirectory);
1411 r = INTERNET_AsyncCall(&workRequest);
1413 else
1415 r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory);
1418 lend:
1419 if( lpwfs )
1420 WININET_Release( &lpwfs->hdr );
1422 return r;
1425 /***********************************************************************
1426 * FTP_FtpRemoveDirectoryW (Internal)
1428 * Remove a directory on the ftp server
1430 * RETURNS
1431 * TRUE on success
1432 * FALSE on failure
1435 BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
1437 INT nResCode;
1438 BOOL bSuccess = FALSE;
1439 LPWININETAPPINFOW hIC = NULL;
1441 TRACE("\n");
1443 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1445 /* Clear any error information */
1446 INTERNET_SetLastError(0);
1448 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1449 goto lend;
1451 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1452 if (nResCode)
1454 if (nResCode == 250)
1455 bSuccess = TRUE;
1456 else
1457 FTP_SetResponseError(nResCode);
1460 lend:
1461 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1462 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1464 INTERNET_ASYNC_RESULT iar;
1466 iar.dwResult = (DWORD)bSuccess;
1467 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1468 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1469 &iar, sizeof(INTERNET_ASYNC_RESULT));
1472 return bSuccess;
1476 /***********************************************************************
1477 * FtpRenameFileA (WININET.@)
1479 * Rename a file on the ftp server
1481 * RETURNS
1482 * TRUE on success
1483 * FALSE on failure
1486 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1488 LPWSTR lpwzSrc;
1489 LPWSTR lpwzDest;
1490 BOOL ret;
1492 lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL;
1493 lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL;
1494 ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
1495 if(lpwzSrc) HeapFree(GetProcessHeap(), 0, lpwzSrc);
1496 if(lpwzDest) HeapFree(GetProcessHeap(), 0, lpwzDest);
1497 return ret;
1500 /***********************************************************************
1501 * FtpRenameFileW (WININET.@)
1503 * Rename a file on the ftp server
1505 * RETURNS
1506 * TRUE on success
1507 * FALSE on failure
1510 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
1512 LPWININETFTPSESSIONW lpwfs;
1513 LPWININETAPPINFOW hIC = NULL;
1514 BOOL r = FALSE;
1516 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1517 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1519 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1520 goto lend;
1523 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1524 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1526 WORKREQUEST workRequest;
1527 struct WORKREQ_FTPRENAMEFILEW *req;
1529 workRequest.asyncall = FTPRENAMEFILEW;
1530 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1531 req = &workRequest.u.FtpRenameFileW;
1532 req->lpszSrcFile = WININET_strdupW(lpszSrc);
1533 req->lpszDestFile = WININET_strdupW(lpszDest);
1535 r = INTERNET_AsyncCall(&workRequest);
1537 else
1539 r = FTP_FtpRenameFileW(hFtpSession, lpszSrc, lpszDest);
1542 lend:
1543 if( lpwfs )
1544 WININET_Release( &lpwfs->hdr );
1546 return r;
1549 /***********************************************************************
1550 * FTP_FtpRenameFileA (Internal)
1552 * Rename a file on the ftp server
1554 * RETURNS
1555 * TRUE on success
1556 * FALSE on failure
1559 BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs,
1560 LPCWSTR lpszSrc, LPCWSTR lpszDest)
1562 INT nResCode;
1563 BOOL bSuccess = FALSE;
1564 LPWININETAPPINFOW hIC = NULL;
1566 TRACE("\n");
1568 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1570 /* Clear any error information */
1571 INTERNET_SetLastError(0);
1573 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1574 goto lend;
1576 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1577 if (nResCode == 350)
1579 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1580 goto lend;
1582 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1585 if (nResCode == 250)
1586 bSuccess = TRUE;
1587 else
1588 FTP_SetResponseError(nResCode);
1590 lend:
1591 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1592 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1594 INTERNET_ASYNC_RESULT iar;
1596 iar.dwResult = (DWORD)bSuccess;
1597 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1598 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1599 &iar, sizeof(INTERNET_ASYNC_RESULT));
1602 return bSuccess;
1606 /***********************************************************************
1607 * FTP_Connect (internal)
1609 * Connect to a ftp server
1611 * RETURNS
1612 * HINTERNET a session handle on success
1613 * NULL on failure
1617 HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
1618 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1619 LPCWSTR lpszPassword, DWORD dwFlags, DWORD dwContext,
1620 DWORD dwInternalFlags)
1622 static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'};
1623 static const WCHAR szDefaultPassword[] = {'u','s','e','r','@','s','e','r','v','e','r','\0'};
1624 struct sockaddr_in socketAddr;
1625 struct hostent *phe = NULL;
1626 INT nsocket = -1, sock_namelen;
1627 BOOL bSuccess = FALSE;
1628 LPWININETFTPSESSIONW lpwfs = NULL;
1629 HINTERNET handle = NULL;
1631 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1632 hIC, debugstr_w(lpszServerName),
1633 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
1635 assert( hIC->hdr.htype == WH_HINIT );
1637 if (NULL == lpszUserName && NULL != lpszPassword)
1639 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1640 goto lerror;
1643 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
1644 if (NULL == lpwfs)
1646 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1647 goto lerror;
1650 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1651 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1653 lpwfs->hdr.htype = WH_HFTPSESSION;
1654 lpwfs->hdr.lpwhparent = WININET_AddRef( &hIC->hdr );
1655 lpwfs->hdr.dwFlags = dwFlags;
1656 lpwfs->hdr.dwContext = dwContext;
1657 lpwfs->hdr.dwInternalFlags = dwInternalFlags;
1658 lpwfs->hdr.dwRefCount = 1;
1659 lpwfs->hdr.destroy = FTP_CloseSessionHandle;
1660 lpwfs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
1661 lpwfs->download_in_progress = NULL;
1663 handle = WININET_AllocHandle( &lpwfs->hdr );
1664 if( !handle )
1666 ERR("Failed to alloc handle\n");
1667 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1668 goto lerror;
1671 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1672 if(strchrW(hIC->lpszProxy, ' '))
1673 FIXME("Several proxies not implemented.\n");
1674 if(hIC->lpszProxyBypass)
1675 FIXME("Proxy bypass is ignored.\n");
1677 if ( !lpszUserName) {
1678 lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
1679 lpwfs->lpszPassword = WININET_strdupW(szDefaultPassword);
1681 else {
1682 lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
1683 lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
1686 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1687 if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
1689 INTERNET_ASYNC_RESULT iar;
1691 iar.dwResult = (DWORD)handle;
1692 iar.dwError = ERROR_SUCCESS;
1694 SendAsyncCallback(&hIC->hdr, dwContext,
1695 INTERNET_STATUS_HANDLE_CREATED, &iar,
1696 sizeof(INTERNET_ASYNC_RESULT));
1699 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1700 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1702 if (!GetAddress(lpszServerName, nServerPort, &phe, &socketAddr))
1704 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1705 goto lerror;
1708 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1709 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1711 nsocket = socket(AF_INET,SOCK_STREAM,0);
1712 if (nsocket == -1)
1714 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1715 goto lerror;
1718 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1719 &socketAddr, sizeof(struct sockaddr_in));
1721 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1723 ERR("Unable to connect (%s)\n", strerror(errno));
1724 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1726 else
1728 TRACE("Connected to server\n");
1729 lpwfs->sndSocket = nsocket;
1730 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1731 &socketAddr, sizeof(struct sockaddr_in));
1733 sock_namelen = sizeof(lpwfs->socketAddress);
1734 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1735 lpwfs->phostent = phe;
1737 if (FTP_ConnectToHost(lpwfs))
1739 TRACE("Successfully logged into server\n");
1740 bSuccess = TRUE;
1744 lerror:
1745 if (!bSuccess && nsocket == -1)
1746 closesocket(nsocket);
1748 if (!bSuccess && lpwfs)
1750 HeapFree(GetProcessHeap(), 0, lpwfs);
1751 WININET_FreeHandle( handle );
1752 lpwfs = NULL;
1755 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1757 INTERNET_ASYNC_RESULT iar;
1759 iar.dwResult = (DWORD)lpwfs;
1760 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1761 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1762 &iar, sizeof(INTERNET_ASYNC_RESULT));
1765 return handle;
1769 /***********************************************************************
1770 * FTP_ConnectToHost (internal)
1772 * Connect to a ftp server
1774 * RETURNS
1775 * TRUE on success
1776 * NULL on failure
1779 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
1781 INT nResCode;
1782 BOOL bSuccess = FALSE;
1784 TRACE("\n");
1785 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1787 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1788 goto lend;
1790 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1791 if (nResCode)
1793 /* Login successful... */
1794 if (nResCode == 230)
1795 bSuccess = TRUE;
1796 /* User name okay, need password... */
1797 else if (nResCode == 331)
1798 bSuccess = FTP_SendPassword(lpwfs);
1799 /* Need account for login... */
1800 else if (nResCode == 332)
1801 bSuccess = FTP_SendAccount(lpwfs);
1802 else
1803 FTP_SetResponseError(nResCode);
1806 TRACE("Returning %d\n", bSuccess);
1807 lend:
1808 return bSuccess;
1812 /***********************************************************************
1813 * FTP_SendCommandA (internal)
1815 * Send command to server
1817 * RETURNS
1818 * TRUE on success
1819 * NULL on failure
1822 BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1823 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
1825 DWORD len;
1826 CHAR *buf;
1827 DWORD nBytesSent = 0;
1828 int nRC = 0;
1829 DWORD dwParamLen;
1831 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1833 if (lpfnStatusCB)
1835 HINTERNET hHandle = WININET_FindHandle( hdr );
1836 if( hHandle )
1838 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1839 WININET_Release( hdr );
1843 dwParamLen = lpszParam?strlen(lpszParam)+1:0;
1844 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
1845 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1847 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1848 return FALSE;
1850 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
1851 dwParamLen ? lpszParam : "", szCRLF);
1853 TRACE("Sending (%s) len(%ld)\n", buf, len);
1854 while((nBytesSent < len) && (nRC != -1))
1856 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1857 nBytesSent += nRC;
1860 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
1862 if (lpfnStatusCB)
1864 HINTERNET hHandle = WININET_FindHandle( hdr );
1865 if( hHandle )
1867 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_REQUEST_SENT,
1868 &nBytesSent, sizeof(DWORD));
1869 WININET_Release( hdr );
1873 TRACE("Sent %ld bytes\n", nBytesSent);
1874 return (nRC != -1);
1877 /***********************************************************************
1878 * FTP_SendCommand (internal)
1880 * Send command to server
1882 * RETURNS
1883 * TRUE on success
1884 * NULL on failure
1887 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
1888 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
1890 BOOL ret;
1891 LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
1892 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
1893 HeapFree(GetProcessHeap(), 0, lpszParamA);
1894 return ret;
1897 /***********************************************************************
1898 * FTP_ReceiveResponse (internal)
1900 * Receive response from server
1902 * RETURNS
1903 * Reply code on success
1904 * 0 on failure
1907 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext)
1909 LPSTR lpszResponse = INTERNET_GetResponseBuffer();
1910 DWORD nRecv;
1911 INT rc = 0;
1912 char firstprefix[5];
1913 BOOL multiline = FALSE;
1914 LPWININETAPPINFOW hIC = NULL;
1916 TRACE("socket(%d) \n", lpwfs->sndSocket);
1918 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1919 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1921 while(1)
1923 if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
1924 goto lerror;
1926 if (nRecv >= 3)
1928 if(!multiline)
1930 if(lpszResponse[3] != '-')
1931 break;
1932 else
1933 { /* Start of multiline repsonse. Loop until we get "nnn " */
1934 multiline = TRUE;
1935 memcpy(firstprefix, lpszResponse, 3);
1936 firstprefix[3] = ' ';
1937 firstprefix[4] = '\0';
1940 else
1942 if(!memcmp(firstprefix, lpszResponse, 4))
1943 break;
1948 if (nRecv >= 3)
1950 rc = atoi(lpszResponse);
1952 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
1953 &nRecv, sizeof(DWORD));
1956 lerror:
1957 TRACE("return %d\n", rc);
1958 return rc;
1962 /***********************************************************************
1963 * FTP_SendPassword (internal)
1965 * Send password to ftp server
1967 * RETURNS
1968 * TRUE on success
1969 * NULL on failure
1972 BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
1974 INT nResCode;
1975 BOOL bSuccess = FALSE;
1977 TRACE("\n");
1978 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
1979 goto lend;
1981 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1982 if (nResCode)
1984 TRACE("Received reply code %d\n", nResCode);
1985 /* Login successful... */
1986 if (nResCode == 230)
1987 bSuccess = TRUE;
1988 /* Command not implemented, superfluous at the server site... */
1989 /* Need account for login... */
1990 else if (nResCode == 332)
1991 bSuccess = FTP_SendAccount(lpwfs);
1992 else
1993 FTP_SetResponseError(nResCode);
1996 lend:
1997 TRACE("Returning %d\n", bSuccess);
1998 return bSuccess;
2002 /***********************************************************************
2003 * FTP_SendAccount (internal)
2007 * RETURNS
2008 * TRUE on success
2009 * FALSE on failure
2012 BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
2014 INT nResCode;
2015 BOOL bSuccess = FALSE;
2017 TRACE("\n");
2018 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
2019 goto lend;
2021 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2022 if (nResCode)
2023 bSuccess = TRUE;
2024 else
2025 FTP_SetResponseError(nResCode);
2027 lend:
2028 return bSuccess;
2032 /***********************************************************************
2033 * FTP_SendStore (internal)
2035 * Send request to upload file to ftp server
2037 * RETURNS
2038 * TRUE on success
2039 * FALSE on failure
2042 BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2044 INT nResCode;
2045 BOOL bSuccess = FALSE;
2047 TRACE("\n");
2048 if (!FTP_InitListenSocket(lpwfs))
2049 goto lend;
2051 if (!FTP_SendType(lpwfs, dwType))
2052 goto lend;
2054 if (!FTP_SendPortOrPasv(lpwfs))
2055 goto lend;
2057 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2058 goto lend;
2059 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2060 if (nResCode)
2062 if (nResCode == 150)
2063 bSuccess = TRUE;
2064 else
2065 FTP_SetResponseError(nResCode);
2068 lend:
2069 if (!bSuccess && lpwfs->lstnSocket != -1)
2071 closesocket(lpwfs->lstnSocket);
2072 lpwfs->lstnSocket = -1;
2075 return bSuccess;
2079 /***********************************************************************
2080 * FTP_InitListenSocket (internal)
2082 * Create a socket to listen for server response
2084 * RETURNS
2085 * TRUE on success
2086 * FALSE on failure
2089 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
2091 BOOL bSuccess = FALSE;
2092 size_t namelen = sizeof(struct sockaddr_in);
2094 TRACE("\n");
2096 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2097 if (lpwfs->lstnSocket == -1)
2099 TRACE("Unable to create listening socket\n");
2100 goto lend;
2103 /* We obtain our ip addr from the name of the command channel socket */
2104 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2106 /* and get the system to assign us a port */
2107 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
2109 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
2111 TRACE("Unable to bind socket\n");
2112 goto lend;
2115 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2117 TRACE("listen failed\n");
2118 goto lend;
2121 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2122 bSuccess = TRUE;
2124 lend:
2125 if (!bSuccess && lpwfs->lstnSocket == -1)
2127 closesocket(lpwfs->lstnSocket);
2128 lpwfs->lstnSocket = -1;
2131 return bSuccess;
2135 /***********************************************************************
2136 * FTP_SendType (internal)
2138 * Tell server type of data being transferred
2140 * RETURNS
2141 * TRUE on success
2142 * FALSE on failure
2144 * W98SE doesn't cache the type that's currently set
2145 * (i.e. it sends it always),
2146 * so we probably don't want to do that either.
2148 BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
2150 INT nResCode;
2151 WCHAR type[] = { 'I','\0' };
2152 BOOL bSuccess = FALSE;
2154 TRACE("\n");
2155 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2156 type[0] = 'A';
2158 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2159 goto lend;
2161 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2162 if (nResCode)
2164 if (nResCode == 2)
2165 bSuccess = TRUE;
2166 else
2167 FTP_SetResponseError(nResCode);
2170 lend:
2171 return bSuccess;
2174 /***********************************************************************
2175 * FTP_GetFileSize (internal)
2177 * Retrieves from the server the size of the given file
2179 * RETURNS
2180 * TRUE on success
2181 * FALSE on failure
2184 BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
2186 INT nResCode;
2187 BOOL bSuccess = FALSE;
2189 TRACE("\n");
2191 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2192 goto lend;
2194 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2195 if (nResCode)
2197 if (nResCode == 213) {
2198 /* Now parses the output to get the actual file size */
2199 int i;
2200 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2202 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2203 if (lpszResponseBuffer[i] == '\0') return FALSE;
2204 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2206 bSuccess = TRUE;
2207 } else {
2208 FTP_SetResponseError(nResCode);
2212 lend:
2213 return bSuccess;
2217 /***********************************************************************
2218 * FTP_SendPort (internal)
2220 * Tell server which port to use
2222 * RETURNS
2223 * TRUE on success
2224 * FALSE on failure
2227 BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
2229 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2230 INT nResCode;
2231 WCHAR szIPAddress[64];
2232 BOOL bSuccess = FALSE;
2233 TRACE("\n");
2235 sprintfW(szIPAddress, szIPFormat,
2236 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2237 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2238 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2239 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2240 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2241 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2243 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2244 goto lend;
2246 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2247 if (nResCode)
2249 if (nResCode == 200)
2250 bSuccess = TRUE;
2251 else
2252 FTP_SetResponseError(nResCode);
2255 lend:
2256 return bSuccess;
2260 /***********************************************************************
2261 * FTP_DoPassive (internal)
2263 * Tell server that we want to do passive transfers
2264 * and connect data socket
2266 * RETURNS
2267 * TRUE on success
2268 * FALSE on failure
2271 BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
2273 INT nResCode;
2274 BOOL bSuccess = FALSE;
2276 TRACE("\n");
2277 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2278 goto lend;
2280 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2281 if (nResCode)
2283 if (nResCode == 227)
2285 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2286 LPSTR p;
2287 int f[6];
2288 int i;
2289 char *pAddr, *pPort;
2290 INT nsocket = -1;
2291 struct sockaddr_in dataSocketAddress;
2293 p = lpszResponseBuffer+4; /* skip status code */
2295 /* do a very strict check; we can improve that later. */
2297 if (strncmp(p, "Entering Passive Mode", 21))
2299 ERR("unknown response '%.*s', aborting\n", 21, p);
2300 goto lend;
2302 p += 21; /* skip string */
2303 if ((*p++ != ' ') || (*p++ != '('))
2305 ERR("unknown response format, aborting\n");
2306 goto lend;
2309 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2310 &f[4], &f[5]) != 6)
2312 ERR("unknown response address format '%s', aborting\n", p);
2313 goto lend;
2315 for (i=0; i < 6; i++)
2316 f[i] = f[i] & 0xff;
2318 dataSocketAddress = lpwfs->socketAddress;
2319 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2320 pPort = (char *)&(dataSocketAddress.sin_port);
2321 pAddr[0] = f[0];
2322 pAddr[1] = f[1];
2323 pAddr[2] = f[2];
2324 pAddr[3] = f[3];
2325 pPort[0] = f[4];
2326 pPort[1] = f[5];
2328 nsocket = socket(AF_INET,SOCK_STREAM,0);
2329 if (nsocket == -1)
2330 goto lend;
2332 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2334 ERR("can't connect passive FTP data port.\n");
2335 goto lend;
2337 lpwfs->pasvSocket = nsocket;
2338 bSuccess = TRUE;
2340 else
2341 FTP_SetResponseError(nResCode);
2344 lend:
2345 return bSuccess;
2349 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
2351 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2353 if (!FTP_DoPassive(lpwfs))
2354 return FALSE;
2356 else
2358 if (!FTP_SendPort(lpwfs))
2359 return FALSE;
2361 return TRUE;
2365 /***********************************************************************
2366 * FTP_GetDataSocket (internal)
2368 * Either accepts an incoming data socket connection from the server
2369 * or just returns the already opened socket after a PASV command
2370 * in case of passive FTP.
2373 * RETURNS
2374 * TRUE on success
2375 * FALSE on failure
2378 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
2380 struct sockaddr_in saddr;
2381 size_t addrlen = sizeof(struct sockaddr);
2383 TRACE("\n");
2384 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2386 *nDataSocket = lpwfs->pasvSocket;
2388 else
2390 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2391 closesocket(lpwfs->lstnSocket);
2392 lpwfs->lstnSocket = -1;
2394 return *nDataSocket != -1;
2398 /***********************************************************************
2399 * FTP_SendData (internal)
2401 * Send data to the server
2403 * RETURNS
2404 * TRUE on success
2405 * FALSE on failure
2408 BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2410 BY_HANDLE_FILE_INFORMATION fi;
2411 DWORD nBytesRead = 0;
2412 DWORD nBytesSent = 0;
2413 DWORD nTotalSent = 0;
2414 DWORD nBytesToSend, nLen;
2415 int nRC = 1;
2416 time_t s_long_time, e_long_time;
2417 LONG nSeconds;
2418 CHAR *lpszBuffer;
2420 TRACE("\n");
2421 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2422 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2424 /* Get the size of the file. */
2425 GetFileInformationByHandle(hFile, &fi);
2426 time(&s_long_time);
2430 nBytesToSend = nBytesRead - nBytesSent;
2432 if (nBytesToSend <= 0)
2434 /* Read data from file. */
2435 nBytesSent = 0;
2436 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2437 ERR("Failed reading from file\n");
2439 if (nBytesRead > 0)
2440 nBytesToSend = nBytesRead;
2441 else
2442 break;
2445 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2446 DATA_PACKET_SIZE : nBytesToSend;
2447 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2449 if (nRC != -1)
2451 nBytesSent += nRC;
2452 nTotalSent += nRC;
2455 /* Do some computation to display the status. */
2456 time(&e_long_time);
2457 nSeconds = e_long_time - s_long_time;
2458 if( nSeconds / 60 > 0 )
2460 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
2461 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2462 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2464 else
2466 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
2467 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2468 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2470 } while (nRC != -1);
2472 TRACE("file transfer complete!\n");
2474 if(lpszBuffer != NULL)
2475 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2477 return nTotalSent;
2481 /***********************************************************************
2482 * FTP_SendRetrieve (internal)
2484 * Send request to retrieve a file
2486 * RETURNS
2487 * Number of bytes to be received on success
2488 * 0 on failure
2491 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2493 INT nResCode;
2494 DWORD nResult = 0;
2496 TRACE("\n");
2497 if (!FTP_InitListenSocket(lpwfs))
2498 goto lend;
2500 if (!FTP_SendType(lpwfs, dwType))
2501 goto lend;
2503 if (!FTP_SendPortOrPasv(lpwfs))
2504 goto lend;
2506 if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2507 goto lend;
2509 TRACE("Waiting to receive %ld bytes\n", nResult);
2511 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2512 goto lend;
2514 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2515 if ((nResCode != 125) && (nResCode != 150)) {
2516 /* That means that we got an error getting the file. */
2517 nResult = 0;
2520 lend:
2521 if (0 == nResult && lpwfs->lstnSocket != -1)
2523 closesocket(lpwfs->lstnSocket);
2524 lpwfs->lstnSocket = -1;
2527 return nResult;
2531 /***********************************************************************
2532 * FTP_RetrieveData (internal)
2534 * Retrieve data from server
2536 * RETURNS
2537 * TRUE on success
2538 * FALSE on failure
2541 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2543 DWORD nBytesWritten;
2544 DWORD nBytesReceived = 0;
2545 INT nRC = 0;
2546 CHAR *lpszBuffer;
2548 TRACE("\n");
2550 if (INVALID_HANDLE_VALUE == hFile)
2551 return FALSE;
2553 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2554 if (NULL == lpszBuffer)
2556 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2557 return FALSE;
2560 while (nBytesReceived < nBytes && nRC != -1)
2562 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2563 if (nRC != -1)
2565 /* other side closed socket. */
2566 if (nRC == 0)
2567 goto recv_end;
2568 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2569 nBytesReceived += nRC;
2572 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
2573 nBytesReceived * 100 / nBytes);
2576 TRACE("Data transfer complete\n");
2577 if (NULL != lpszBuffer)
2578 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2580 recv_end:
2581 return (nRC != -1);
2585 /***********************************************************************
2586 * FTP_CloseSessionHandle (internal)
2588 * Deallocate session handle
2590 * RETURNS
2591 * TRUE on success
2592 * FALSE on failure
2595 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr)
2597 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2599 TRACE("\n");
2601 if (lpwfs->download_in_progress != NULL)
2602 lpwfs->download_in_progress->session_deleted = TRUE;
2604 if (lpwfs->sndSocket != -1)
2605 closesocket(lpwfs->sndSocket);
2607 if (lpwfs->lstnSocket != -1)
2608 closesocket(lpwfs->lstnSocket);
2610 if (lpwfs->lpszPassword)
2611 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2613 if (lpwfs->lpszUserName)
2614 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2616 HeapFree(GetProcessHeap(), 0, lpwfs);
2620 /***********************************************************************
2621 * FTP_CloseFindNextHandle (internal)
2623 * Deallocate session handle
2625 * RETURNS
2626 * TRUE on success
2627 * FALSE on failure
2630 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr)
2632 LPWININETFINDNEXTW lpwfn = (LPWININETFINDNEXTW) hdr;
2633 DWORD i;
2635 TRACE("\n");
2637 for (i = 0; i < lpwfn->size; i++)
2639 if (NULL != lpwfn->lpafp[i].lpszName)
2640 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2643 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2644 HeapFree(GetProcessHeap(), 0, lpwfn);
2647 /***********************************************************************
2648 * FTP_CloseFileTransferHandle (internal)
2650 * Closes the file transfer handle. This also 'cleans' the data queue of
2651 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2654 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr)
2656 LPWININETFILE lpwh = (LPWININETFILE) hdr;
2657 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) lpwh->hdr.lpwhparent;
2658 INT nResCode;
2660 TRACE("\n");
2662 if (!lpwh->session_deleted)
2663 lpwfs->download_in_progress = NULL;
2665 /* This just serves to flush the control socket of any spurrious lines written
2666 to it (like '226 Transfer complete.').
2668 Wonder what to do if the server sends us an error code though...
2670 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2672 if (lpwh->nDataSocket != -1)
2673 closesocket(lpwh->nDataSocket);
2675 HeapFree(GetProcessHeap(), 0, lpwh);
2678 /***********************************************************************
2679 * FTP_ReceiveFileList (internal)
2681 * Read file list from server
2683 * RETURNS
2684 * Handle to file list on success
2685 * NULL on failure
2688 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2689 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext)
2691 DWORD dwSize = 0;
2692 LPFILEPROPERTIESW lpafp = NULL;
2693 LPWININETFINDNEXTW lpwfn = NULL;
2694 HINTERNET handle = 0;
2696 TRACE("(%p,%d,%s,%p,%ld)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
2698 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
2700 if(lpFindFileData)
2701 FTP_ConvertFileProp(lpafp, lpFindFileData);
2703 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTW));
2704 if (lpwfn)
2706 lpwfn->hdr.htype = WH_HFINDNEXT;
2707 lpwfn->hdr.lpwhparent = WININET_AddRef( &lpwfs->hdr );
2708 lpwfn->hdr.dwContext = dwContext;
2709 lpwfn->hdr.dwRefCount = 1;
2710 lpwfn->hdr.destroy = FTP_CloseFindNextHandle;
2711 lpwfn->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
2712 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2713 lpwfn->size = dwSize;
2714 lpwfn->lpafp = lpafp;
2716 handle = WININET_AllocHandle( &lpwfn->hdr );
2720 if( lpwfn )
2721 WININET_Release( &lpwfn->hdr );
2723 TRACE("Matched %ld files\n", dwSize);
2724 return handle;
2728 /***********************************************************************
2729 * FTP_ConvertFileProp (internal)
2731 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
2733 * RETURNS
2734 * TRUE on success
2735 * FALSE on failure
2738 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
2740 BOOL bSuccess = FALSE;
2742 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
2744 if (lpafp)
2746 /* Convert 'Unix' time to Windows time */
2747 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
2748 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
2749 lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime;
2750 lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime;
2752 /* Not all fields are filled in */
2753 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2754 lpFindFileData->nFileSizeLow = lpafp->nSize;
2756 if (lpafp->bIsDirectory)
2757 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2759 if (lpafp->lpszName)
2760 strncpyW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2762 bSuccess = TRUE;
2765 return bSuccess;
2768 /***********************************************************************
2769 * FTP_ParseNextFile (internal)
2771 * Parse the next line in file listing
2773 * RETURNS
2774 * TRUE on success
2775 * FALSE on failure
2777 BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
2779 static const char szSpace[] = " \t";
2780 DWORD nBufLen;
2781 char *pszLine;
2782 char *pszToken;
2783 char *pszTmp;
2784 BOOL found = FALSE;
2785 int i;
2787 lpfp->lpszName = NULL;
2788 do {
2789 if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
2790 return FALSE;
2792 pszToken = strtok(pszLine, szSpace);
2793 /* ls format
2794 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2796 * For instance:
2797 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2799 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
2800 if(!FTP_ParsePermission(pszToken, lpfp))
2801 lpfp->bIsDirectory = FALSE;
2802 for(i=0; i<=3; i++) {
2803 if(!(pszToken = strtok(NULL, szSpace)))
2804 break;
2806 if(!pszToken) continue;
2807 if(lpfp->bIsDirectory) {
2808 TRACE("Is directory\n");
2809 lpfp->nSize = 0;
2811 else {
2812 TRACE("Size: %s\n", pszToken);
2813 lpfp->nSize = atol(pszToken);
2816 lpfp->tmLastModified.tm_sec = 0;
2817 lpfp->tmLastModified.tm_min = 0;
2818 lpfp->tmLastModified.tm_hour = 0;
2819 lpfp->tmLastModified.tm_mday = 0;
2820 lpfp->tmLastModified.tm_mon = 0;
2821 lpfp->tmLastModified.tm_year = 0;
2823 /* Determine month */
2824 pszToken = strtok(NULL, szSpace);
2825 if(!pszToken) continue;
2826 if(strlen(pszToken) >= 3) {
2827 pszToken[3] = 0;
2828 if((pszTmp = StrStrIA(szMonths, pszToken)))
2829 lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
2831 /* Determine day */
2832 pszToken = strtok(NULL, szSpace);
2833 if(!pszToken) continue;
2834 lpfp->tmLastModified.tm_mday = atoi(pszToken);
2835 /* Determine time or year */
2836 pszToken = strtok(NULL, szSpace);
2837 if(!pszToken) continue;
2838 if((pszTmp = strchr(pszToken, ':'))) {
2839 struct tm* apTM;
2840 time_t aTime;
2841 *pszTmp = 0;
2842 pszTmp++;
2843 lpfp->tmLastModified.tm_min = atoi(pszTmp);
2844 lpfp->tmLastModified.tm_hour = atoi(pszToken);
2845 time(&aTime);
2846 apTM = localtime(&aTime);
2847 lpfp->tmLastModified.tm_year = apTM->tm_year;
2849 else {
2850 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
2851 lpfp->tmLastModified.tm_hour = 12;
2853 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
2854 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
2855 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
2856 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
2858 pszToken = strtok(NULL, szSpace);
2859 if(!pszToken) continue;
2860 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
2861 TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
2863 /* NT way of parsing ... :
2865 07-13-03 08:55PM <DIR> sakpatch
2866 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
2868 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
2869 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
2871 sscanf(pszToken, "%d-%d-%d",
2872 &lpfp->tmLastModified.tm_mon,
2873 &lpfp->tmLastModified.tm_mday,
2874 &lpfp->tmLastModified.tm_year);
2876 /* Hacky and bad Y2K protection :-) */
2877 if (lpfp->tmLastModified.tm_year < 70)
2878 lpfp->tmLastModified.tm_year += 100;
2880 pszToken = strtok(NULL, szSpace);
2881 if(!pszToken) continue;
2882 sscanf(pszToken, "%d:%d",
2883 &lpfp->tmLastModified.tm_hour,
2884 &lpfp->tmLastModified.tm_min);
2885 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
2886 lpfp->tmLastModified.tm_hour += 12;
2888 lpfp->tmLastModified.tm_sec = 0;
2890 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
2891 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
2892 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
2893 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
2895 pszToken = strtok(NULL, szSpace);
2896 if(!pszToken) continue;
2897 if(!strcasecmp(pszToken, "<DIR>")) {
2898 lpfp->bIsDirectory = TRUE;
2899 lpfp->nSize = 0;
2900 TRACE("Is directory\n");
2902 else {
2903 lpfp->bIsDirectory = FALSE;
2904 lpfp->nSize = atol(pszToken);
2905 TRACE("Size: %ld\n", lpfp->nSize);
2908 pszToken = strtok(NULL, szSpace);
2909 if(!pszToken) continue;
2910 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
2911 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
2913 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
2914 else if(pszToken[0] == '+') {
2915 FIXME("EPLF Format not implemented\n");
2918 if(lpfp->lpszName) {
2919 if((lpszSearchFile == NULL) ||
2920 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
2921 found = TRUE;
2922 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
2924 else {
2925 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
2926 lpfp->lpszName = NULL;
2929 } while(!found);
2930 return TRUE;
2933 /***********************************************************************
2934 * FTP_ParseDirectory (internal)
2936 * Parse string of directory information
2938 * RETURNS
2939 * TRUE on success
2940 * FALSE on failure
2942 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2943 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
2945 BOOL bSuccess = TRUE;
2946 INT sizeFilePropArray = 500;/*20; */
2947 INT indexFilePropArray = -1;
2949 TRACE("\n");
2951 /* Allocate intial file properties array */
2952 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
2953 if (!*lpafp)
2954 return FALSE;
2956 do {
2957 if (indexFilePropArray+1 >= sizeFilePropArray)
2959 LPFILEPROPERTIESW tmpafp;
2961 sizeFilePropArray *= 2;
2962 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
2963 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
2964 if (NULL == tmpafp)
2966 bSuccess = FALSE;
2967 break;
2970 *lpafp = tmpafp;
2972 indexFilePropArray++;
2973 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
2975 if (bSuccess && indexFilePropArray)
2977 if (indexFilePropArray < sizeFilePropArray - 1)
2979 LPFILEPROPERTIESW tmpafp;
2981 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
2982 sizeof(FILEPROPERTIESW)*indexFilePropArray);
2983 if (NULL == tmpafp)
2984 *lpafp = tmpafp;
2986 *dwfp = indexFilePropArray;
2988 else
2990 HeapFree(GetProcessHeap(), 0, *lpafp);
2991 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2992 bSuccess = FALSE;
2995 return bSuccess;
2999 /***********************************************************************
3000 * FTP_ParsePermission (internal)
3002 * Parse permission string of directory information
3004 * RETURNS
3005 * TRUE on success
3006 * FALSE on failure
3009 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3011 BOOL bSuccess = TRUE;
3012 unsigned short nPermission = 0;
3013 INT nPos = 1;
3014 INT nLast = 9;
3016 TRACE("\n");
3017 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3019 bSuccess = FALSE;
3020 return bSuccess;
3023 lpfp->bIsDirectory = (*lpszPermission == 'd');
3026 switch (nPos)
3028 case 1:
3029 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3030 break;
3031 case 2:
3032 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3033 break;
3034 case 3:
3035 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3036 break;
3037 case 4:
3038 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3039 break;
3040 case 5:
3041 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3042 break;
3043 case 6:
3044 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3045 break;
3046 case 7:
3047 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3048 break;
3049 case 8:
3050 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3051 break;
3052 case 9:
3053 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3054 break;
3056 nPos++;
3057 }while (nPos <= nLast);
3059 lpfp->permissions = nPermission;
3060 return bSuccess;
3064 /***********************************************************************
3065 * FTP_SetResponseError (internal)
3067 * Set the appropriate error code for a given response from the server
3069 * RETURNS
3072 DWORD FTP_SetResponseError(DWORD dwResponse)
3074 DWORD dwCode = 0;
3076 switch(dwResponse)
3078 case 421: /* Service not available - Server may be shutting down. */
3079 dwCode = ERROR_INTERNET_TIMEOUT;
3080 break;
3082 case 425: /* Cannot open data connection. */
3083 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3084 break;
3086 case 426: /* Connection closed, transer aborted. */
3087 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3088 break;
3090 case 500: /* Syntax error. Command unrecognized. */
3091 case 501: /* Syntax error. Error in parameters or arguments. */
3092 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
3093 break;
3095 case 530: /* Not logged in. Login incorrect. */
3096 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3097 break;
3099 case 550: /* File action not taken. File not found or no access. */
3100 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
3101 break;
3103 case 450: /* File action not taken. File may be busy. */
3104 case 451: /* Action aborted. Server error. */
3105 case 452: /* Action not taken. Insufficient storage space on server. */
3106 case 502: /* Command not implemented. */
3107 case 503: /* Bad sequence of command. */
3108 case 504: /* Command not implemented for that parameter. */
3109 case 532: /* Need account for storing files */
3110 case 551: /* Requested action aborted. Page type unknown */
3111 case 552: /* Action aborted. Exceeded storage allocation */
3112 case 553: /* Action not taken. File name not allowed. */
3114 default:
3115 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
3116 break;
3119 INTERNET_SetLastError(dwCode);
3120 return dwCode;