Handle CBR_BLOCK in EXECUTE and ADVISE DDE transactions.
[wine/hacks.git] / dlls / wininet / ftp.c
blob8161f01be3629e542b6633bc8a4c67a828f2c1d5
1 /*
2 * WININET - Ftp implementation
4 * Copyright 1999 Corel Corporation
5 * Copyright 2004 Mike McCormack for CodeWeavers
6 * Copyright 2004 Kevin Koltzau
8 * Ulrich Czekalla
9 * Noureddine Jemmali
11 * Copyright 2000 Andreas Mohr
12 * Copyright 2002 Jaco Greeff
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "config.h"
30 #include "wine/port.h"
32 #include <errno.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/types.h>
38 #ifdef HAVE_SYS_SOCKET_H
39 # include <sys/socket.h>
40 #endif
41 #ifdef HAVE_UNISTD_H
42 # include <unistd.h>
43 #endif
44 #include <time.h>
45 #include <assert.h>
47 #include "windef.h"
48 #include "winbase.h"
49 #include "wingdi.h"
50 #include "winuser.h"
51 #include "wininet.h"
52 #include "winnls.h"
53 #include "winerror.h"
54 #include "winreg.h"
55 #include "winternl.h"
56 #include "shlwapi.h"
58 #include "wine/debug.h"
59 #include "internet.h"
61 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
63 #define DATA_PACKET_SIZE 0x2000
64 #define szCRLF "\r\n"
65 #define MAX_BACKLOG 5
67 typedef enum {
68 /* FTP commands with arguments. */
69 FTP_CMD_ACCT,
70 FTP_CMD_CWD,
71 FTP_CMD_DELE,
72 FTP_CMD_MKD,
73 FTP_CMD_PASS,
74 FTP_CMD_PORT,
75 FTP_CMD_RETR,
76 FTP_CMD_RMD,
77 FTP_CMD_RNFR,
78 FTP_CMD_RNTO,
79 FTP_CMD_STOR,
80 FTP_CMD_TYPE,
81 FTP_CMD_USER,
82 FTP_CMD_SIZE,
84 /* FTP commands without arguments. */
85 FTP_CMD_ABOR,
86 FTP_CMD_LIST,
87 FTP_CMD_NLST,
88 FTP_CMD_PASV,
89 FTP_CMD_PWD,
90 FTP_CMD_QUIT,
91 } FTP_COMMAND;
93 static const CHAR *szFtpCommands[] = {
94 "ACCT",
95 "CWD",
96 "DELE",
97 "MKD",
98 "PASS",
99 "PORT",
100 "RETR",
101 "RMD",
102 "RNFR",
103 "RNTO",
104 "STOR",
105 "TYPE",
106 "USER",
107 "SIZE",
108 "ABOR",
109 "LIST",
110 "NLST",
111 "PASV",
112 "PWD",
113 "QUIT",
116 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
117 static const WCHAR szNoAccount[] = {'n','o','a','c','c','o','u','n','t','\0'};
119 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr);
120 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr);
121 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr);
122 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
123 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext);
124 BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
125 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket);
126 BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile);
127 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext);
128 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
129 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile);
130 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs);
131 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs);
132 BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs);
133 BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs);
134 BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType);
135 BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize);
136 BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs);
137 BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs);
138 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs);
139 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp);
140 BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW fileprop);
141 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
142 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp);
143 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
144 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext);
145 DWORD FTP_SetResponseError(DWORD dwResponse);
147 /***********************************************************************
148 * FtpPutFileA (WININET.@)
150 * Uploads a file to the FTP server
152 * RETURNS
153 * TRUE on success
154 * FALSE on failure
157 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
158 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
160 LPWSTR lpwzLocalFile;
161 LPWSTR lpwzNewRemoteFile;
162 BOOL ret;
164 lpwzLocalFile = lpszLocalFile?WININET_strdup_AtoW(lpszLocalFile):NULL;
165 lpwzNewRemoteFile = lpszNewRemoteFile?WININET_strdup_AtoW(lpszNewRemoteFile):NULL;
166 ret = FtpPutFileW(hConnect, lpwzLocalFile, lpwzNewRemoteFile,
167 dwFlags, dwContext);
168 HeapFree(GetProcessHeap(), 0, lpwzLocalFile);
169 HeapFree(GetProcessHeap(), 0, lpwzNewRemoteFile);
170 return ret;
173 /***********************************************************************
174 * FtpPutFileW (WININET.@)
176 * Uploads a file to the FTP server
178 * RETURNS
179 * TRUE on success
180 * FALSE on failure
183 BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile,
184 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
186 LPWININETFTPSESSIONW lpwfs;
187 LPWININETAPPINFOW hIC = NULL;
188 BOOL r = FALSE;
190 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
191 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
193 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
194 goto lend;
197 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
198 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
200 WORKREQUEST workRequest;
201 struct WORKREQ_FTPPUTFILEW *req = &workRequest.u.FtpPutFileW;
203 workRequest.asyncall = FTPPUTFILEW;
204 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
205 req->lpszLocalFile = WININET_strdupW(lpszLocalFile);
206 req->lpszNewRemoteFile = WININET_strdupW(lpszNewRemoteFile);
207 req->dwFlags = dwFlags;
208 req->dwContext = dwContext;
210 r = INTERNET_AsyncCall(&workRequest);
212 else
214 r = FTP_FtpPutFileW(lpwfs, lpszLocalFile,
215 lpszNewRemoteFile, dwFlags, dwContext);
218 lend:
219 if( lpwfs )
220 WININET_Release( &lpwfs->hdr );
222 return r;
225 /***********************************************************************
226 * FTP_FtpPutFileW (Internal)
228 * Uploads a file to the FTP server
230 * RETURNS
231 * TRUE on success
232 * FALSE on failure
235 BOOL WINAPI FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile,
236 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
238 HANDLE hFile = NULL;
239 BOOL bSuccess = FALSE;
240 LPWININETAPPINFOW hIC = NULL;
241 INT nResCode;
243 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", debugstr_w(lpszLocalFile), debugstr_w(lpszNewRemoteFile));
245 if (!lpszLocalFile || !lpszNewRemoteFile)
247 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
248 return FALSE;
251 assert( WH_HFTPSESSION == lpwfs->hdr.htype);
253 /* Clear any error information */
254 INTERNET_SetLastError(0);
256 /* Open file to be uploaded */
257 if (INVALID_HANDLE_VALUE ==
258 (hFile = CreateFileW(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
260 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND);
261 goto lend;
264 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
265 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
267 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
269 INT nDataSocket;
271 /* Get data socket to server */
272 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
274 FTP_SendData(lpwfs, nDataSocket, hFile);
275 closesocket(nDataSocket);
276 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
277 if (nResCode)
279 if (nResCode == 226)
280 bSuccess = TRUE;
281 else
282 FTP_SetResponseError(nResCode);
287 lend:
288 if (lpwfs->lstnSocket != -1)
289 closesocket(lpwfs->lstnSocket);
291 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
293 INTERNET_ASYNC_RESULT iar;
295 iar.dwResult = (DWORD)bSuccess;
296 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
297 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
298 &iar, sizeof(INTERNET_ASYNC_RESULT));
301 if (hFile)
302 CloseHandle(hFile);
304 return bSuccess;
308 /***********************************************************************
309 * FtpSetCurrentDirectoryA (WININET.@)
311 * Change the working directory on the FTP server
313 * RETURNS
314 * TRUE on success
315 * FALSE on failure
318 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
320 LPWSTR lpwzDirectory;
321 BOOL ret;
323 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
324 ret = FtpSetCurrentDirectoryW(hConnect, lpwzDirectory);
325 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
326 return ret;
330 /***********************************************************************
331 * FtpSetCurrentDirectoryW (WININET.@)
333 * Change the working directory on the FTP server
335 * RETURNS
336 * TRUE on success
337 * FALSE on failure
340 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
342 LPWININETFTPSESSIONW lpwfs;
343 LPWININETAPPINFOW hIC = NULL;
344 BOOL r = FALSE;
346 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
347 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
349 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
350 goto lend;
353 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
355 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
356 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
358 WORKREQUEST workRequest;
359 struct WORKREQ_FTPSETCURRENTDIRECTORYW *req;
361 workRequest.asyncall = FTPSETCURRENTDIRECTORYW;
362 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
363 req = &workRequest.u.FtpSetCurrentDirectoryW;
364 req->lpszDirectory = WININET_strdupW(lpszDirectory);
366 r = INTERNET_AsyncCall(&workRequest);
368 else
370 r = FTP_FtpSetCurrentDirectoryW(lpwfs, lpszDirectory);
373 lend:
374 if( lpwfs )
375 WININET_Release( &lpwfs->hdr );
377 return r;
381 /***********************************************************************
382 * FTP_FtpSetCurrentDirectoryW (Internal)
384 * Change the working directory on the FTP server
386 * RETURNS
387 * TRUE on success
388 * FALSE on failure
391 BOOL WINAPI FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
393 INT nResCode;
394 LPWININETAPPINFOW hIC = NULL;
395 DWORD bSuccess = FALSE;
397 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
399 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
401 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
402 return FALSE;
405 /* Clear any error information */
406 INTERNET_SetLastError(0);
408 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
409 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
410 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
411 goto lend;
413 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
415 if (nResCode)
417 if (nResCode == 250)
418 bSuccess = TRUE;
419 else
420 FTP_SetResponseError(nResCode);
423 lend:
424 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
426 INTERNET_ASYNC_RESULT iar;
428 iar.dwResult = (DWORD)bSuccess;
429 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
430 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
431 &iar, sizeof(INTERNET_ASYNC_RESULT));
433 return bSuccess;
437 /***********************************************************************
438 * FtpCreateDirectoryA (WININET.@)
440 * Create new directory on the FTP server
442 * RETURNS
443 * TRUE on success
444 * FALSE on failure
447 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
449 LPWSTR lpwzDirectory;
450 BOOL ret;
452 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
453 ret = FtpCreateDirectoryW(hConnect, lpwzDirectory);
454 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
455 return ret;
459 /***********************************************************************
460 * FtpCreateDirectoryW (WININET.@)
462 * Create new directory on the FTP server
464 * RETURNS
465 * TRUE on success
466 * FALSE on failure
469 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
471 LPWININETFTPSESSIONW lpwfs;
472 LPWININETAPPINFOW hIC = NULL;
473 BOOL r = FALSE;
475 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
476 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
478 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
479 goto lend;
482 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
483 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
485 WORKREQUEST workRequest;
486 struct WORKREQ_FTPCREATEDIRECTORYW *req;
488 workRequest.asyncall = FTPCREATEDIRECTORYW;
489 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
490 req = &workRequest.u.FtpCreateDirectoryW;
491 req->lpszDirectory = WININET_strdupW(lpszDirectory);
493 r = INTERNET_AsyncCall(&workRequest);
495 else
497 r = FTP_FtpCreateDirectoryW(lpwfs, lpszDirectory);
499 lend:
500 if( lpwfs )
501 WININET_Release( &lpwfs->hdr );
503 return r;
507 /***********************************************************************
508 * FTP_FtpCreateDirectoryW (Internal)
510 * Create new directory on the FTP server
512 * RETURNS
513 * TRUE on success
514 * FALSE on failure
517 BOOL WINAPI FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
519 INT nResCode;
520 BOOL bSuccess = FALSE;
521 LPWININETAPPINFOW hIC = NULL;
523 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
525 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
527 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
528 return FALSE;
531 /* Clear any error information */
532 INTERNET_SetLastError(0);
534 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
535 goto lend;
537 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
538 if (nResCode)
540 if (nResCode == 257)
541 bSuccess = TRUE;
542 else
543 FTP_SetResponseError(nResCode);
546 lend:
547 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
548 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
550 INTERNET_ASYNC_RESULT iar;
552 iar.dwResult = (DWORD)bSuccess;
553 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
554 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
555 &iar, sizeof(INTERNET_ASYNC_RESULT));
558 return bSuccess;
561 /***********************************************************************
562 * FtpFindFirstFileA (WININET.@)
564 * Search the specified directory
566 * RETURNS
567 * HINTERNET on success
568 * NULL on failure
571 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
572 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
574 LPWSTR lpwzSearchFile;
575 WIN32_FIND_DATAW wfd;
576 LPWIN32_FIND_DATAW lpFindFileDataW;
577 HINTERNET ret;
579 lpwzSearchFile = lpszSearchFile?WININET_strdup_AtoW(lpszSearchFile):NULL;
580 lpFindFileDataW = lpFindFileData?&wfd:NULL;
581 ret = FtpFindFirstFileW(hConnect, lpwzSearchFile, lpFindFileDataW, dwFlags, dwContext);
582 HeapFree(GetProcessHeap(), 0, lpwzSearchFile);
584 if(lpFindFileData) {
585 WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData);
587 return ret;
591 /***********************************************************************
592 * FtpFindFirstFileW (WININET.@)
594 * Search the specified directory
596 * RETURNS
597 * HINTERNET on success
598 * NULL on failure
601 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
602 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
604 LPWININETFTPSESSIONW lpwfs;
605 LPWININETAPPINFOW hIC = NULL;
606 HINTERNET r = NULL;
608 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
609 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
611 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
612 goto lend;
615 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
616 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
618 WORKREQUEST workRequest;
619 struct WORKREQ_FTPFINDFIRSTFILEW *req;
621 workRequest.asyncall = FTPFINDFIRSTFILEW;
622 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
623 req = &workRequest.u.FtpFindFirstFileW;
624 req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : WININET_strdupW(lpszSearchFile);
625 req->lpFindFileData = lpFindFileData;
626 req->dwFlags = dwFlags;
627 req->dwContext= dwContext;
629 INTERNET_AsyncCall(&workRequest);
630 r = NULL;
632 else
634 r = FTP_FtpFindFirstFileW(lpwfs, lpszSearchFile, lpFindFileData,
635 dwFlags, dwContext);
637 lend:
638 if( lpwfs )
639 WININET_Release( &lpwfs->hdr );
641 return r;
645 /***********************************************************************
646 * FTP_FtpFindFirstFileW (Internal)
648 * Search the specified directory
650 * RETURNS
651 * HINTERNET on success
652 * NULL on failure
655 HINTERNET WINAPI FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs,
656 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
658 INT nResCode;
659 LPWININETAPPINFOW hIC = NULL;
660 HINTERNET hFindNext = NULL;
662 TRACE("\n");
664 assert(WH_HFTPSESSION == lpwfs->hdr.htype);
666 /* Clear any error information */
667 INTERNET_SetLastError(0);
669 if (!FTP_InitListenSocket(lpwfs))
670 goto lend;
672 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
673 goto lend;
675 if (!FTP_SendPortOrPasv(lpwfs))
676 goto lend;
678 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
679 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, NULL,
680 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
681 goto lend;
683 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
684 if (nResCode)
686 if (nResCode == 125 || nResCode == 150)
688 INT nDataSocket;
690 /* Get data socket to server */
691 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
693 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpszSearchFile, lpFindFileData, dwContext);
694 closesocket(nDataSocket);
695 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
696 if (nResCode != 226 && nResCode != 250)
697 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
700 else
701 FTP_SetResponseError(nResCode);
704 lend:
705 if (lpwfs->lstnSocket != -1)
706 closesocket(lpwfs->lstnSocket);
708 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
710 INTERNET_ASYNC_RESULT iar;
712 if (hFindNext)
714 iar.dwResult = (DWORD)hFindNext;
715 iar.dwError = ERROR_SUCCESS;
716 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
717 &iar, sizeof(INTERNET_ASYNC_RESULT));
720 iar.dwResult = (DWORD)hFindNext;
721 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
722 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
723 &iar, sizeof(INTERNET_ASYNC_RESULT));
726 return hFindNext;
730 /***********************************************************************
731 * FtpGetCurrentDirectoryA (WININET.@)
733 * Retrieves the current directory
735 * RETURNS
736 * TRUE on success
737 * FALSE on failure
740 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
741 LPDWORD lpdwCurrentDirectory)
743 WCHAR dir[MAX_PATH];
744 DWORD len;
745 BOOL ret;
747 if(lpdwCurrentDirectory) len = *lpdwCurrentDirectory;
748 ret = FtpGetCurrentDirectoryW(hFtpSession, lpszCurrentDirectory?dir:NULL, lpdwCurrentDirectory?&len:NULL);
749 if(lpdwCurrentDirectory) {
750 *lpdwCurrentDirectory = len;
751 if(lpszCurrentDirectory)
752 WideCharToMultiByte(CP_ACP, 0, dir, len, lpszCurrentDirectory, *lpdwCurrentDirectory, NULL, NULL);
754 return ret;
758 /***********************************************************************
759 * FtpGetCurrentDirectoryW (WININET.@)
761 * Retrieves the current directory
763 * RETURNS
764 * TRUE on success
765 * FALSE on failure
768 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
769 LPDWORD lpdwCurrentDirectory)
771 LPWININETFTPSESSIONW lpwfs;
772 LPWININETAPPINFOW hIC = NULL;
773 BOOL r = FALSE;
775 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
777 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
778 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
780 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
781 goto lend;
784 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
785 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
787 WORKREQUEST workRequest;
788 struct WORKREQ_FTPGETCURRENTDIRECTORYW *req;
790 workRequest.asyncall = FTPGETCURRENTDIRECTORYW;
791 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
792 req = &workRequest.u.FtpGetCurrentDirectoryW;
793 req->lpszDirectory = lpszCurrentDirectory;
794 req->lpdwDirectory = lpdwCurrentDirectory;
796 r = INTERNET_AsyncCall(&workRequest);
798 else
800 r = FTP_FtpGetCurrentDirectoryW(lpwfs, lpszCurrentDirectory,
801 lpdwCurrentDirectory);
804 lend:
805 if( lpwfs )
806 WININET_Release( &lpwfs->hdr );
808 return r;
812 /***********************************************************************
813 * FTP_FtpGetCurrentDirectoryA (Internal)
815 * Retrieves the current directory
817 * RETURNS
818 * TRUE on success
819 * FALSE on failure
822 BOOL WINAPI FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszCurrentDirectory,
823 LPDWORD lpdwCurrentDirectory)
825 INT nResCode;
826 LPWININETAPPINFOW hIC = NULL;
827 DWORD bSuccess = FALSE;
829 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
831 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
833 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
834 return FALSE;
837 /* Clear any error information */
838 INTERNET_SetLastError(0);
840 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
842 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
843 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
844 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
845 goto lend;
847 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
848 if (nResCode)
850 if (nResCode == 257) /* Extract directory name */
852 DWORD firstpos, lastpos, len;
853 LPWSTR lpszResponseBuffer = WININET_strdup_AtoW(INTERNET_GetResponseBuffer());
855 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
857 if ('"' == lpszResponseBuffer[lastpos])
859 if (!firstpos)
860 firstpos = lastpos;
861 else
862 break;
866 len = lastpos - firstpos - 1;
867 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 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 HeapFree(GetProcessHeap(), 0, lpwzRemoteFile);
1090 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 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 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 HeapFree(GetProcessHeap(), 0, lpwzSrc);
1496 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 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2476 return nTotalSent;
2480 /***********************************************************************
2481 * FTP_SendRetrieve (internal)
2483 * Send request to retrieve a file
2485 * RETURNS
2486 * Number of bytes to be received on success
2487 * 0 on failure
2490 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2492 INT nResCode;
2493 DWORD nResult = 0;
2495 TRACE("\n");
2496 if (!FTP_InitListenSocket(lpwfs))
2497 goto lend;
2499 if (!FTP_SendType(lpwfs, dwType))
2500 goto lend;
2502 if (!FTP_SendPortOrPasv(lpwfs))
2503 goto lend;
2505 if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2506 goto lend;
2508 TRACE("Waiting to receive %ld bytes\n", nResult);
2510 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2511 goto lend;
2513 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2514 if ((nResCode != 125) && (nResCode != 150)) {
2515 /* That means that we got an error getting the file. */
2516 nResult = 0;
2519 lend:
2520 if (0 == nResult && lpwfs->lstnSocket != -1)
2522 closesocket(lpwfs->lstnSocket);
2523 lpwfs->lstnSocket = -1;
2526 return nResult;
2530 /***********************************************************************
2531 * FTP_RetrieveData (internal)
2533 * Retrieve data from server
2535 * RETURNS
2536 * TRUE on success
2537 * FALSE on failure
2540 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2542 DWORD nBytesWritten;
2543 DWORD nBytesReceived = 0;
2544 INT nRC = 0;
2545 CHAR *lpszBuffer;
2547 TRACE("\n");
2549 if (INVALID_HANDLE_VALUE == hFile)
2550 return FALSE;
2552 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2553 if (NULL == lpszBuffer)
2555 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2556 return FALSE;
2559 while (nBytesReceived < nBytes && nRC != -1)
2561 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2562 if (nRC != -1)
2564 /* other side closed socket. */
2565 if (nRC == 0)
2566 goto recv_end;
2567 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2568 nBytesReceived += nRC;
2571 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
2572 nBytesReceived * 100 / nBytes);
2575 TRACE("Data transfer complete\n");
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 closesocket(lpwfs->sndSocket);
2605 if (lpwfs->lstnSocket != -1)
2606 closesocket(lpwfs->lstnSocket);
2608 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2609 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2610 HeapFree(GetProcessHeap(), 0, lpwfs);
2614 /***********************************************************************
2615 * FTP_CloseFindNextHandle (internal)
2617 * Deallocate session handle
2619 * RETURNS
2620 * TRUE on success
2621 * FALSE on failure
2624 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr)
2626 LPWININETFINDNEXTW lpwfn = (LPWININETFINDNEXTW) hdr;
2627 DWORD i;
2629 TRACE("\n");
2631 for (i = 0; i < lpwfn->size; i++)
2633 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2636 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2637 HeapFree(GetProcessHeap(), 0, lpwfn);
2640 /***********************************************************************
2641 * FTP_CloseFileTransferHandle (internal)
2643 * Closes the file transfer handle. This also 'cleans' the data queue of
2644 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2647 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr)
2649 LPWININETFILE lpwh = (LPWININETFILE) hdr;
2650 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) lpwh->hdr.lpwhparent;
2651 INT nResCode;
2653 TRACE("\n");
2655 if (!lpwh->session_deleted)
2656 lpwfs->download_in_progress = NULL;
2658 /* This just serves to flush the control socket of any spurrious lines written
2659 to it (like '226 Transfer complete.').
2661 Wonder what to do if the server sends us an error code though...
2663 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2665 if (lpwh->nDataSocket != -1)
2666 closesocket(lpwh->nDataSocket);
2668 HeapFree(GetProcessHeap(), 0, lpwh);
2671 /***********************************************************************
2672 * FTP_ReceiveFileList (internal)
2674 * Read file list from server
2676 * RETURNS
2677 * Handle to file list on success
2678 * NULL on failure
2681 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2682 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext)
2684 DWORD dwSize = 0;
2685 LPFILEPROPERTIESW lpafp = NULL;
2686 LPWININETFINDNEXTW lpwfn = NULL;
2687 HINTERNET handle = 0;
2689 TRACE("(%p,%d,%s,%p,%ld)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
2691 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
2693 if(lpFindFileData)
2694 FTP_ConvertFileProp(lpafp, lpFindFileData);
2696 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTW));
2697 if (lpwfn)
2699 lpwfn->hdr.htype = WH_HFINDNEXT;
2700 lpwfn->hdr.lpwhparent = WININET_AddRef( &lpwfs->hdr );
2701 lpwfn->hdr.dwContext = dwContext;
2702 lpwfn->hdr.dwRefCount = 1;
2703 lpwfn->hdr.destroy = FTP_CloseFindNextHandle;
2704 lpwfn->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
2705 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2706 lpwfn->size = dwSize;
2707 lpwfn->lpafp = lpafp;
2709 handle = WININET_AllocHandle( &lpwfn->hdr );
2713 if( lpwfn )
2714 WININET_Release( &lpwfn->hdr );
2716 TRACE("Matched %ld files\n", dwSize);
2717 return handle;
2721 /***********************************************************************
2722 * FTP_ConvertFileProp (internal)
2724 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
2726 * RETURNS
2727 * TRUE on success
2728 * FALSE on failure
2731 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
2733 BOOL bSuccess = FALSE;
2735 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
2737 if (lpafp)
2739 /* Convert 'Unix' time to Windows time */
2740 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
2741 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
2742 lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime;
2743 lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime;
2745 /* Not all fields are filled in */
2746 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2747 lpFindFileData->nFileSizeLow = lpafp->nSize;
2749 if (lpafp->bIsDirectory)
2750 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2752 if (lpafp->lpszName)
2753 strncpyW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2755 bSuccess = TRUE;
2758 return bSuccess;
2761 /***********************************************************************
2762 * FTP_ParseNextFile (internal)
2764 * Parse the next line in file listing
2766 * RETURNS
2767 * TRUE on success
2768 * FALSE on failure
2770 BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
2772 static const char szSpace[] = " \t";
2773 DWORD nBufLen;
2774 char *pszLine;
2775 char *pszToken;
2776 char *pszTmp;
2777 BOOL found = FALSE;
2778 int i;
2780 lpfp->lpszName = NULL;
2781 do {
2782 if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
2783 return FALSE;
2785 pszToken = strtok(pszLine, szSpace);
2786 /* ls format
2787 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2789 * For instance:
2790 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2792 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
2793 if(!FTP_ParsePermission(pszToken, lpfp))
2794 lpfp->bIsDirectory = FALSE;
2795 for(i=0; i<=3; i++) {
2796 if(!(pszToken = strtok(NULL, szSpace)))
2797 break;
2799 if(!pszToken) continue;
2800 if(lpfp->bIsDirectory) {
2801 TRACE("Is directory\n");
2802 lpfp->nSize = 0;
2804 else {
2805 TRACE("Size: %s\n", pszToken);
2806 lpfp->nSize = atol(pszToken);
2809 lpfp->tmLastModified.tm_sec = 0;
2810 lpfp->tmLastModified.tm_min = 0;
2811 lpfp->tmLastModified.tm_hour = 0;
2812 lpfp->tmLastModified.tm_mday = 0;
2813 lpfp->tmLastModified.tm_mon = 0;
2814 lpfp->tmLastModified.tm_year = 0;
2816 /* Determine month */
2817 pszToken = strtok(NULL, szSpace);
2818 if(!pszToken) continue;
2819 if(strlen(pszToken) >= 3) {
2820 pszToken[3] = 0;
2821 if((pszTmp = StrStrIA(szMonths, pszToken)))
2822 lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
2824 /* Determine day */
2825 pszToken = strtok(NULL, szSpace);
2826 if(!pszToken) continue;
2827 lpfp->tmLastModified.tm_mday = atoi(pszToken);
2828 /* Determine time or year */
2829 pszToken = strtok(NULL, szSpace);
2830 if(!pszToken) continue;
2831 if((pszTmp = strchr(pszToken, ':'))) {
2832 struct tm* apTM;
2833 time_t aTime;
2834 *pszTmp = 0;
2835 pszTmp++;
2836 lpfp->tmLastModified.tm_min = atoi(pszTmp);
2837 lpfp->tmLastModified.tm_hour = atoi(pszToken);
2838 time(&aTime);
2839 apTM = localtime(&aTime);
2840 lpfp->tmLastModified.tm_year = apTM->tm_year;
2842 else {
2843 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
2844 lpfp->tmLastModified.tm_hour = 12;
2846 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
2847 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
2848 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
2849 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
2851 pszToken = strtok(NULL, szSpace);
2852 if(!pszToken) continue;
2853 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
2854 TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
2856 /* NT way of parsing ... :
2858 07-13-03 08:55PM <DIR> sakpatch
2859 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
2861 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
2862 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
2864 sscanf(pszToken, "%d-%d-%d",
2865 &lpfp->tmLastModified.tm_mon,
2866 &lpfp->tmLastModified.tm_mday,
2867 &lpfp->tmLastModified.tm_year);
2869 /* Hacky and bad Y2K protection :-) */
2870 if (lpfp->tmLastModified.tm_year < 70)
2871 lpfp->tmLastModified.tm_year += 100;
2873 pszToken = strtok(NULL, szSpace);
2874 if(!pszToken) continue;
2875 sscanf(pszToken, "%d:%d",
2876 &lpfp->tmLastModified.tm_hour,
2877 &lpfp->tmLastModified.tm_min);
2878 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
2879 lpfp->tmLastModified.tm_hour += 12;
2881 lpfp->tmLastModified.tm_sec = 0;
2883 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
2884 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
2885 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
2886 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
2888 pszToken = strtok(NULL, szSpace);
2889 if(!pszToken) continue;
2890 if(!strcasecmp(pszToken, "<DIR>")) {
2891 lpfp->bIsDirectory = TRUE;
2892 lpfp->nSize = 0;
2893 TRACE("Is directory\n");
2895 else {
2896 lpfp->bIsDirectory = FALSE;
2897 lpfp->nSize = atol(pszToken);
2898 TRACE("Size: %ld\n", lpfp->nSize);
2901 pszToken = strtok(NULL, szSpace);
2902 if(!pszToken) continue;
2903 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
2904 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
2906 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
2907 else if(pszToken[0] == '+') {
2908 FIXME("EPLF Format not implemented\n");
2911 if(lpfp->lpszName) {
2912 if((lpszSearchFile == NULL) ||
2913 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
2914 found = TRUE;
2915 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
2917 else {
2918 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
2919 lpfp->lpszName = NULL;
2922 } while(!found);
2923 return TRUE;
2926 /***********************************************************************
2927 * FTP_ParseDirectory (internal)
2929 * Parse string of directory information
2931 * RETURNS
2932 * TRUE on success
2933 * FALSE on failure
2935 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2936 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
2938 BOOL bSuccess = TRUE;
2939 INT sizeFilePropArray = 500;/*20; */
2940 INT indexFilePropArray = -1;
2942 TRACE("\n");
2944 /* Allocate intial file properties array */
2945 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
2946 if (!*lpafp)
2947 return FALSE;
2949 do {
2950 if (indexFilePropArray+1 >= sizeFilePropArray)
2952 LPFILEPROPERTIESW tmpafp;
2954 sizeFilePropArray *= 2;
2955 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
2956 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
2957 if (NULL == tmpafp)
2959 bSuccess = FALSE;
2960 break;
2963 *lpafp = tmpafp;
2965 indexFilePropArray++;
2966 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
2968 if (bSuccess && indexFilePropArray)
2970 if (indexFilePropArray < sizeFilePropArray - 1)
2972 LPFILEPROPERTIESW tmpafp;
2974 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
2975 sizeof(FILEPROPERTIESW)*indexFilePropArray);
2976 if (NULL == tmpafp)
2977 *lpafp = tmpafp;
2979 *dwfp = indexFilePropArray;
2981 else
2983 HeapFree(GetProcessHeap(), 0, *lpafp);
2984 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2985 bSuccess = FALSE;
2988 return bSuccess;
2992 /***********************************************************************
2993 * FTP_ParsePermission (internal)
2995 * Parse permission string of directory information
2997 * RETURNS
2998 * TRUE on success
2999 * FALSE on failure
3002 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3004 BOOL bSuccess = TRUE;
3005 unsigned short nPermission = 0;
3006 INT nPos = 1;
3007 INT nLast = 9;
3009 TRACE("\n");
3010 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3012 bSuccess = FALSE;
3013 return bSuccess;
3016 lpfp->bIsDirectory = (*lpszPermission == 'd');
3019 switch (nPos)
3021 case 1:
3022 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3023 break;
3024 case 2:
3025 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3026 break;
3027 case 3:
3028 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3029 break;
3030 case 4:
3031 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3032 break;
3033 case 5:
3034 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3035 break;
3036 case 6:
3037 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3038 break;
3039 case 7:
3040 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3041 break;
3042 case 8:
3043 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3044 break;
3045 case 9:
3046 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3047 break;
3049 nPos++;
3050 }while (nPos <= nLast);
3052 lpfp->permissions = nPermission;
3053 return bSuccess;
3057 /***********************************************************************
3058 * FTP_SetResponseError (internal)
3060 * Set the appropriate error code for a given response from the server
3062 * RETURNS
3065 DWORD FTP_SetResponseError(DWORD dwResponse)
3067 DWORD dwCode = 0;
3069 switch(dwResponse)
3071 case 421: /* Service not available - Server may be shutting down. */
3072 dwCode = ERROR_INTERNET_TIMEOUT;
3073 break;
3075 case 425: /* Cannot open data connection. */
3076 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3077 break;
3079 case 426: /* Connection closed, transer aborted. */
3080 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3081 break;
3083 case 500: /* Syntax error. Command unrecognized. */
3084 case 501: /* Syntax error. Error in parameters or arguments. */
3085 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
3086 break;
3088 case 530: /* Not logged in. Login incorrect. */
3089 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3090 break;
3092 case 550: /* File action not taken. File not found or no access. */
3093 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
3094 break;
3096 case 450: /* File action not taken. File may be busy. */
3097 case 451: /* Action aborted. Server error. */
3098 case 452: /* Action not taken. Insufficient storage space on server. */
3099 case 502: /* Command not implemented. */
3100 case 503: /* Bad sequence of command. */
3101 case 504: /* Command not implemented for that parameter. */
3102 case 532: /* Need account for storing files */
3103 case 551: /* Requested action aborted. Page type unknown */
3104 case 552: /* Action aborted. Exceeded storage allocation */
3105 case 553: /* Action not taken. File name not allowed. */
3107 default:
3108 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
3109 break;
3112 INTERNET_SetLastError(dwCode);
3113 return dwCode;