Fix HttpQueryInfo(HTTP_QUERY_RAW_HEADERS*) so that it returns the
[wine/hacks.git] / dlls / wininet / ftp.c
blob16cefa76983038eb85dbf23811bbb02247cc5ede
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>
46 #include "windef.h"
47 #include "winbase.h"
48 #include "wingdi.h"
49 #include "winuser.h"
50 #include "wininet.h"
51 #include "winnls.h"
52 #include "winerror.h"
53 #include "winreg.h"
54 #include "winternl.h"
55 #include "shlwapi.h"
57 #include "wine/debug.h"
58 #include "internet.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
62 #define DATA_PACKET_SIZE 0x2000
63 #define szCRLF "\r\n"
64 #define MAX_BACKLOG 5
66 typedef enum {
67 /* FTP commands with arguments. */
68 FTP_CMD_ACCT,
69 FTP_CMD_CWD,
70 FTP_CMD_DELE,
71 FTP_CMD_MKD,
72 FTP_CMD_PASS,
73 FTP_CMD_PORT,
74 FTP_CMD_RETR,
75 FTP_CMD_RMD,
76 FTP_CMD_RNFR,
77 FTP_CMD_RNTO,
78 FTP_CMD_STOR,
79 FTP_CMD_TYPE,
80 FTP_CMD_USER,
81 FTP_CMD_SIZE,
83 /* FTP commands without arguments. */
84 FTP_CMD_ABOR,
85 FTP_CMD_LIST,
86 FTP_CMD_NLST,
87 FTP_CMD_PASV,
88 FTP_CMD_PWD,
89 FTP_CMD_QUIT,
90 } FTP_COMMAND;
92 static const CHAR *szFtpCommands[] = {
93 "ACCT",
94 "CWD",
95 "DELE",
96 "MKD",
97 "PASS",
98 "PORT",
99 "RETR",
100 "RMD",
101 "RNFR",
102 "RNTO",
103 "STOR",
104 "TYPE",
105 "USER",
106 "SIZE",
107 "ABOR",
108 "LIST",
109 "NLST",
110 "PASV",
111 "PWD",
112 "QUIT",
115 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
116 static const WCHAR szNoAccount[] = {'n','o','a','c','c','o','u','n','t','\0'};
118 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
119 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
120 BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
121 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket);
122 BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile);
123 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext);
124 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
125 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile);
126 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs);
127 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs);
128 BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs);
129 BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs);
130 BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType);
131 BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize);
132 BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs);
133 BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs);
134 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs);
135 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp);
136 BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW fileprop);
137 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
138 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp);
139 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
140 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext);
141 DWORD FTP_SetResponseError(DWORD dwResponse);
143 /***********************************************************************
144 * FtpPutFileA (WININET.@)
146 * Uploads a file to the FTP server
148 * RETURNS
149 * TRUE on success
150 * FALSE on failure
153 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
154 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
156 LPWSTR lpwzLocalFile;
157 LPWSTR lpwzNewRemoteFile;
158 BOOL ret;
160 lpwzLocalFile = lpszLocalFile?WININET_strdup_AtoW(lpszLocalFile):NULL;
161 lpwzNewRemoteFile = lpszNewRemoteFile?WININET_strdup_AtoW(lpszNewRemoteFile):NULL;
162 ret = FtpPutFileW(hConnect, lpwzLocalFile, lpwzNewRemoteFile,
163 dwFlags, dwContext);
164 if(lpwzLocalFile) HeapFree(GetProcessHeap(), 0, lpwzLocalFile);
165 if(lpwzNewRemoteFile) HeapFree(GetProcessHeap(), 0, lpwzNewRemoteFile);
166 return ret;
169 /***********************************************************************
170 * FtpPutFileW (WININET.@)
172 * Uploads a file to the FTP server
174 * RETURNS
175 * TRUE on success
176 * FALSE on failure
179 BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile,
180 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
182 LPWININETFTPSESSIONW lpwfs;
183 LPWININETAPPINFOW hIC = NULL;
185 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
186 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
188 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
189 return FALSE;
192 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
193 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
195 WORKREQUEST workRequest;
196 struct WORKREQ_FTPPUTFILEW *req = &workRequest.u.FtpPutFileW;
198 workRequest.asyncall = FTPPUTFILEW;
199 workRequest.handle = hConnect;
200 req->lpszLocalFile = WININET_strdupW(lpszLocalFile);
201 req->lpszNewRemoteFile = WININET_strdupW(lpszNewRemoteFile);
202 req->dwFlags = dwFlags;
203 req->dwContext = dwContext;
205 return INTERNET_AsyncCall(&workRequest);
207 else
209 return FTP_FtpPutFileW(hConnect, lpszLocalFile,
210 lpszNewRemoteFile, dwFlags, dwContext);
214 /***********************************************************************
215 * FTP_FtpPutFileW (Internal)
217 * Uploads a file to the FTP server
219 * RETURNS
220 * TRUE on success
221 * FALSE on failure
224 BOOL WINAPI FTP_FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile,
225 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
227 HANDLE hFile = NULL;
228 BOOL bSuccess = FALSE;
229 LPWININETAPPINFOW hIC = NULL;
230 LPWININETFTPSESSIONW lpwfs;
231 INT nResCode;
233 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", debugstr_w(lpszLocalFile), debugstr_w(lpszNewRemoteFile));
235 if (!lpszLocalFile || !lpszNewRemoteFile)
237 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
238 return FALSE;
241 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
242 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
244 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
245 return FALSE;
248 /* Clear any error information */
249 INTERNET_SetLastError(0);
251 /* Open file to be uploaded */
252 if (INVALID_HANDLE_VALUE ==
253 (hFile = CreateFileW(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
255 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND);
256 goto lend;
259 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
260 SendAsyncCallback(hIC, hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
262 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
264 INT nDataSocket;
266 /* Get data socket to server */
267 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
269 FTP_SendData(lpwfs, nDataSocket, hFile);
270 close(nDataSocket);
271 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
272 if (nResCode)
274 if (nResCode == 226)
275 bSuccess = TRUE;
276 else
277 FTP_SetResponseError(nResCode);
282 lend:
283 if (lpwfs->lstnSocket != -1)
284 close(lpwfs->lstnSocket);
286 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
288 INTERNET_ASYNC_RESULT iar;
290 iar.dwResult = (DWORD)bSuccess;
291 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
292 SendAsyncCallback(hIC, hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
293 &iar, sizeof(INTERNET_ASYNC_RESULT));
296 if (hFile)
297 CloseHandle(hFile);
299 return bSuccess;
303 /***********************************************************************
304 * FtpSetCurrentDirectoryA (WININET.@)
306 * Change the working directory on the FTP server
308 * RETURNS
309 * TRUE on success
310 * FALSE on failure
313 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
315 LPWSTR lpwzDirectory;
316 BOOL ret;
318 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
319 ret = FtpSetCurrentDirectoryW(hConnect, lpwzDirectory);
320 if(lpwzDirectory) HeapFree(GetProcessHeap(), 0, lpwzDirectory);
321 return ret;
325 /***********************************************************************
326 * FtpSetCurrentDirectoryW (WININET.@)
328 * Change the working directory on the FTP server
330 * RETURNS
331 * TRUE on success
332 * FALSE on failure
335 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
337 LPWININETFTPSESSIONW lpwfs;
338 LPWININETAPPINFOW hIC = NULL;
340 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
341 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
343 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
344 return FALSE;
347 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
349 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
350 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
352 WORKREQUEST workRequest;
353 struct WORKREQ_FTPSETCURRENTDIRECTORYW *req;
355 workRequest.asyncall = FTPSETCURRENTDIRECTORYW;
356 workRequest.handle = hConnect;
357 req = &workRequest.u.FtpSetCurrentDirectoryW;
358 req->lpszDirectory = WININET_strdupW(lpszDirectory);
360 return INTERNET_AsyncCall(&workRequest);
362 else
364 return FTP_FtpSetCurrentDirectoryW(hConnect, lpszDirectory);
369 /***********************************************************************
370 * FTP_FtpSetCurrentDirectoryW (Internal)
372 * Change the working directory on the FTP server
374 * RETURNS
375 * TRUE on success
376 * FALSE on failure
379 BOOL WINAPI FTP_FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
381 INT nResCode;
382 LPWININETFTPSESSIONW lpwfs;
383 LPWININETAPPINFOW hIC = NULL;
384 DWORD bSuccess = FALSE;
386 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
388 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
389 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
391 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
392 return FALSE;
395 /* Clear any error information */
396 INTERNET_SetLastError(0);
398 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
399 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
400 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
401 goto lend;
403 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
405 if (nResCode)
407 if (nResCode == 250)
408 bSuccess = TRUE;
409 else
410 FTP_SetResponseError(nResCode);
413 lend:
414 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
416 INTERNET_ASYNC_RESULT iar;
418 iar.dwResult = (DWORD)bSuccess;
419 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
420 SendAsyncCallback(hIC, hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
421 &iar, sizeof(INTERNET_ASYNC_RESULT));
423 return bSuccess;
427 /***********************************************************************
428 * FtpCreateDirectoryA (WININET.@)
430 * Create new directory on the FTP server
432 * RETURNS
433 * TRUE on success
434 * FALSE on failure
437 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
439 LPWSTR lpwzDirectory;
440 BOOL ret;
442 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
443 ret = FtpCreateDirectoryW(hConnect, lpwzDirectory);
444 if(lpwzDirectory) HeapFree(GetProcessHeap(), 0, lpwzDirectory);
445 return ret;
449 /***********************************************************************
450 * FtpCreateDirectoryW (WININET.@)
452 * Create new directory on the FTP server
454 * RETURNS
455 * TRUE on success
456 * FALSE on failure
459 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
461 LPWININETFTPSESSIONW lpwfs;
462 LPWININETAPPINFOW hIC = NULL;
464 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
465 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
467 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
468 return FALSE;
471 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
472 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
474 WORKREQUEST workRequest;
475 struct WORKREQ_FTPCREATEDIRECTORYW *req;
477 workRequest.asyncall = FTPCREATEDIRECTORYW;
478 workRequest.handle = hConnect;
479 req = &workRequest.u.FtpCreateDirectoryW;
480 req->lpszDirectory = WININET_strdupW(lpszDirectory);
482 return INTERNET_AsyncCall(&workRequest);
484 else
486 return FTP_FtpCreateDirectoryW(hConnect, lpszDirectory);
491 /***********************************************************************
492 * FTP_FtpCreateDirectoryW (Internal)
494 * Create new directory on the FTP server
496 * RETURNS
497 * TRUE on success
498 * FALSE on failure
501 BOOL WINAPI FTP_FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
503 INT nResCode;
504 BOOL bSuccess = FALSE;
505 LPWININETAPPINFOW hIC = NULL;
506 LPWININETFTPSESSIONW lpwfs;
508 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
510 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
511 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
513 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
514 return FALSE;
517 /* Clear any error information */
518 INTERNET_SetLastError(0);
520 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
521 goto lend;
523 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
524 if (nResCode)
526 if (nResCode == 257)
527 bSuccess = TRUE;
528 else
529 FTP_SetResponseError(nResCode);
532 lend:
533 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
534 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
536 INTERNET_ASYNC_RESULT iar;
538 iar.dwResult = (DWORD)bSuccess;
539 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
540 SendAsyncCallback(hIC, hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
541 &iar, sizeof(INTERNET_ASYNC_RESULT));
544 return bSuccess;
547 /***********************************************************************
548 * FtpFindFirstFileA (WININET.@)
550 * Search the specified directory
552 * RETURNS
553 * HINTERNET on success
554 * NULL on failure
557 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
558 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
560 LPWSTR lpwzSearchFile;
561 WIN32_FIND_DATAW wfd;
562 LPWIN32_FIND_DATAW lpFindFileDataW;
563 HINTERNET ret;
565 lpwzSearchFile = lpszSearchFile?WININET_strdup_AtoW(lpszSearchFile):NULL;
566 lpFindFileDataW = lpFindFileData?&wfd:NULL;
567 ret = FtpFindFirstFileW(hConnect, lpwzSearchFile, lpFindFileDataW, dwFlags, dwContext);
568 if(lpwzSearchFile) HeapFree(GetProcessHeap(), 0, lpwzSearchFile);
570 if(lpFindFileData) {
571 WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData);
573 return ret;
577 /***********************************************************************
578 * FtpFindFirstFileW (WININET.@)
580 * Search the specified directory
582 * RETURNS
583 * HINTERNET on success
584 * NULL on failure
587 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
588 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
590 LPWININETFTPSESSIONW lpwfs;
591 LPWININETAPPINFOW hIC = NULL;
593 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
594 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
596 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
597 return FALSE;
600 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
601 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
603 WORKREQUEST workRequest;
604 struct WORKREQ_FTPFINDFIRSTFILEW *req;
606 workRequest.asyncall = FTPFINDFIRSTFILEW;
607 workRequest.handle = hConnect;
608 req = &workRequest.u.FtpFindFirstFileW;
609 req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : WININET_strdupW(lpszSearchFile);
610 req->lpFindFileData = lpFindFileData;
611 req->dwFlags = dwFlags;
612 req->dwContext= dwContext;
614 INTERNET_AsyncCall(&workRequest);
615 return NULL;
617 else
619 return FTP_FtpFindFirstFileW(hConnect, lpszSearchFile, lpFindFileData,
620 dwFlags, dwContext);
625 /***********************************************************************
626 * FTP_FtpFindFirstFileW (Internal)
628 * Search the specified directory
630 * RETURNS
631 * HINTERNET on success
632 * NULL on failure
635 HINTERNET WINAPI FTP_FtpFindFirstFileW(HINTERNET hConnect,
636 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
638 INT nResCode;
639 LPWININETAPPINFOW hIC = NULL;
640 LPWININETFTPSESSIONW lpwfs;
641 HINTERNET hFindNext = NULL;
643 TRACE("\n");
645 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
646 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
648 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
649 return FALSE;
652 /* Clear any error information */
653 INTERNET_SetLastError(0);
655 if (!FTP_InitListenSocket(lpwfs))
656 goto lend;
658 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
659 goto lend;
661 if (!FTP_SendPortOrPasv(lpwfs))
662 goto lend;
664 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
665 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, NULL,
666 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
667 goto lend;
669 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
670 if (nResCode)
672 if (nResCode == 125 || nResCode == 150)
674 INT nDataSocket;
676 /* Get data socket to server */
677 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
679 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpszSearchFile, lpFindFileData, dwContext);
680 close(nDataSocket);
681 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
682 if (nResCode != 226 && nResCode != 250)
683 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
686 else
687 FTP_SetResponseError(nResCode);
690 lend:
691 if (lpwfs->lstnSocket != -1)
692 close(lpwfs->lstnSocket);
694 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
696 INTERNET_ASYNC_RESULT iar;
698 if (hFindNext)
700 iar.dwResult = (DWORD)hFindNext;
701 iar.dwError = ERROR_SUCCESS;
702 SendAsyncCallback(hIC, hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
703 &iar, sizeof(INTERNET_ASYNC_RESULT));
706 iar.dwResult = (DWORD)hFindNext;
707 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
708 SendAsyncCallback(hIC, hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
709 &iar, sizeof(INTERNET_ASYNC_RESULT));
712 return hFindNext;
716 /***********************************************************************
717 * FtpGetCurrentDirectoryA (WININET.@)
719 * Retrieves the current directory
721 * RETURNS
722 * TRUE on success
723 * FALSE on failure
726 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
727 LPDWORD lpdwCurrentDirectory)
729 WCHAR dir[MAX_PATH];
730 DWORD len;
731 BOOL ret;
733 if(lpdwCurrentDirectory) len = *lpdwCurrentDirectory;
734 ret = FtpGetCurrentDirectoryW(hFtpSession, lpszCurrentDirectory?dir:NULL, lpdwCurrentDirectory?&len:NULL);
735 if(lpdwCurrentDirectory) {
736 *lpdwCurrentDirectory = len;
737 if(lpszCurrentDirectory)
738 WideCharToMultiByte(CP_ACP, 0, dir, len, lpszCurrentDirectory, *lpdwCurrentDirectory, NULL, NULL);
740 return ret;
744 /***********************************************************************
745 * FtpGetCurrentDirectoryW (WININET.@)
747 * Retrieves the current directory
749 * RETURNS
750 * TRUE on success
751 * FALSE on failure
754 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
755 LPDWORD lpdwCurrentDirectory)
757 LPWININETFTPSESSIONW lpwfs;
758 LPWININETAPPINFOW hIC = NULL;
760 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
762 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
763 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
765 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
766 return FALSE;
769 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
770 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
772 WORKREQUEST workRequest;
773 struct WORKREQ_FTPGETCURRENTDIRECTORYW *req;
775 workRequest.asyncall = FTPGETCURRENTDIRECTORYW;
776 workRequest.handle = hFtpSession;
777 req = &workRequest.u.FtpGetCurrentDirectoryW;
778 req->lpszDirectory = lpszCurrentDirectory;
779 req->lpdwDirectory = lpdwCurrentDirectory;
781 return INTERNET_AsyncCall(&workRequest);
783 else
785 return FTP_FtpGetCurrentDirectoryW(hFtpSession, lpszCurrentDirectory,
786 lpdwCurrentDirectory);
791 /***********************************************************************
792 * FTP_FtpGetCurrentDirectoryA (Internal)
794 * Retrieves the current directory
796 * RETURNS
797 * TRUE on success
798 * FALSE on failure
801 BOOL WINAPI FTP_FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
802 LPDWORD lpdwCurrentDirectory)
804 INT nResCode;
805 LPWININETFTPSESSIONW lpwfs;
806 LPWININETAPPINFOW hIC = NULL;
807 DWORD bSuccess = FALSE;
809 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
811 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
812 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
814 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
815 return FALSE;
818 /* Clear any error information */
819 INTERNET_SetLastError(0);
821 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
823 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
824 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
825 hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext))
826 goto lend;
828 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
829 if (nResCode)
831 if (nResCode == 257) /* Extract directory name */
833 INT firstpos, lastpos, len;
834 LPWSTR lpszResponseBuffer = WININET_strdup_AtoW(INTERNET_GetResponseBuffer());
836 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
838 if ('"' == lpszResponseBuffer[lastpos])
840 if (!firstpos)
841 firstpos = lastpos;
842 else
843 break;
847 len = lastpos - firstpos - 1;
848 strncpyW(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1],
849 len < *lpdwCurrentDirectory ? len : *lpdwCurrentDirectory);
850 HeapFree(GetProcessHeap(), 0, lpszResponseBuffer);
851 *lpdwCurrentDirectory = len;
852 bSuccess = TRUE;
854 else
855 FTP_SetResponseError(nResCode);
858 lend:
859 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
861 INTERNET_ASYNC_RESULT iar;
863 iar.dwResult = (DWORD)bSuccess;
864 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
865 SendAsyncCallback(hIC, hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
866 &iar, sizeof(INTERNET_ASYNC_RESULT));
869 return (DWORD) bSuccess;
872 /***********************************************************************
873 * FtpOpenFileA (WININET.@)
875 * Open a remote file for writing or reading
877 * RETURNS
878 * HINTERNET handle on success
879 * NULL on failure
882 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
883 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
884 DWORD dwContext)
886 LPWSTR lpwzFileName;
887 HINTERNET ret;
889 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
890 ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext);
891 if(lpwzFileName) HeapFree(GetProcessHeap(), 0, lpwzFileName);
892 return ret;
896 /***********************************************************************
897 * FtpOpenFileW (WININET.@)
899 * Open a remote file for writing or reading
901 * RETURNS
902 * HINTERNET handle on success
903 * NULL on failure
906 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
907 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
908 DWORD dwContext)
910 LPWININETFTPSESSIONW lpwfs;
911 LPWININETAPPINFOW hIC = NULL;
913 TRACE("(%p,%s,0x%08lx,0x%08lx,0x%08lx)\n", hFtpSession,
914 debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext);
916 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
917 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
919 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
920 return FALSE;
923 if (lpwfs->download_in_progress != NULL) {
924 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
925 return FALSE;
927 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
928 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
930 WORKREQUEST workRequest;
931 struct WORKREQ_FTPOPENFILEW *req;
933 workRequest.asyncall = FTPOPENFILEW;
934 workRequest.handle = hFtpSession;
935 req = &workRequest.u.FtpOpenFileW;
936 req->lpszFilename = WININET_strdupW(lpszFileName);
937 req->dwAccess = fdwAccess;
938 req->dwFlags = dwFlags;
939 req->dwContext = dwContext;
941 INTERNET_AsyncCall(&workRequest);
942 return NULL;
944 else
946 return FTP_FtpOpenFileW(hFtpSession, lpszFileName, fdwAccess, dwFlags, dwContext);
951 /***********************************************************************
952 * FTP_FtpOpenFileW (Internal)
954 * Open a remote file for writing or reading
956 * RETURNS
957 * HINTERNET handle on success
958 * NULL on failure
961 HINTERNET FTP_FtpOpenFileW(HINTERNET hFtpSession,
962 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
963 DWORD dwContext)
965 INT nDataSocket;
966 BOOL bSuccess = FALSE;
967 LPWININETFILE lpwh = NULL;
968 LPWININETAPPINFOW hIC = NULL;
969 LPWININETFTPSESSIONW lpwfs;
970 HINTERNET handle = NULL;
972 TRACE("\n");
974 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
975 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
977 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
978 return FALSE;
981 /* Clear any error information */
982 INTERNET_SetLastError(0);
984 if (GENERIC_READ == fdwAccess)
986 /* Set up socket to retrieve data */
987 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
989 else if (GENERIC_WRITE == fdwAccess)
991 /* Set up socket to send data */
992 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
995 /* Get data socket to server */
996 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
998 lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE));
999 handle = WININET_AllocHandle( &lpwh->hdr );
1000 lpwh->hdr.htype = WH_HFILE;
1001 lpwh->hdr.dwFlags = dwFlags;
1002 lpwh->hdr.dwContext = dwContext;
1003 lpwh->hdr.lpwhparent = &lpwfs->hdr;
1004 lpwh->nDataSocket = nDataSocket;
1005 lpwh->session_deleted = FALSE;
1007 /* Indicate that a download is currently in progress */
1008 lpwfs->download_in_progress = lpwh;
1011 if (lpwfs->lstnSocket != -1)
1012 close(lpwfs->lstnSocket);
1014 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1015 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1017 INTERNET_ASYNC_RESULT iar;
1019 if (lpwh)
1021 iar.dwResult = (DWORD)handle;
1022 iar.dwError = ERROR_SUCCESS;
1023 SendAsyncCallback(hIC, hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
1024 &iar, sizeof(INTERNET_ASYNC_RESULT));
1027 iar.dwResult = (DWORD)bSuccess;
1028 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1029 SendAsyncCallback(hIC, hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1030 &iar, sizeof(INTERNET_ASYNC_RESULT));
1033 return handle;
1037 /***********************************************************************
1038 * FtpGetFileA (WININET.@)
1040 * Retrieve file from the FTP server
1042 * RETURNS
1043 * TRUE on success
1044 * FALSE on failure
1047 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1048 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1049 DWORD dwContext)
1051 LPWSTR lpwzRemoteFile;
1052 LPWSTR lpwzNewFile;
1053 BOOL ret;
1055 lpwzRemoteFile = lpszRemoteFile?WININET_strdup_AtoW(lpszRemoteFile):NULL;
1056 lpwzNewFile = lpszNewFile?WININET_strdup_AtoW(lpszNewFile):NULL;
1057 ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists,
1058 dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1059 if(lpwzRemoteFile) HeapFree(GetProcessHeap(), 0, lpwzRemoteFile);
1060 if(lpwzNewFile) HeapFree(GetProcessHeap(), 0, lpwzNewFile);
1061 return ret;
1065 /***********************************************************************
1066 * FtpGetFileW (WININET.@)
1068 * Retrieve file from the FTP server
1070 * RETURNS
1071 * TRUE on success
1072 * FALSE on failure
1075 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1076 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1077 DWORD dwContext)
1079 LPWININETFTPSESSIONW lpwfs;
1080 LPWININETAPPINFOW hIC = NULL;
1082 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet );
1083 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1085 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1086 return FALSE;
1089 if (lpwfs->download_in_progress != NULL) {
1090 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1091 return FALSE;
1094 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1095 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1097 WORKREQUEST workRequest;
1098 struct WORKREQ_FTPGETFILEW *req;
1100 workRequest.asyncall = FTPGETFILEW;
1101 workRequest.handle = hInternet;
1102 req = &workRequest.u.FtpGetFileW;
1103 req->lpszRemoteFile = WININET_strdupW(lpszRemoteFile);
1104 req->lpszNewFile = WININET_strdupW(lpszNewFile);
1105 req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1106 req->fFailIfExists = fFailIfExists;
1107 req->dwFlags = dwInternetFlags;
1108 req->dwContext = dwContext;
1110 return INTERNET_AsyncCall(&workRequest);
1112 else
1114 return FTP_FtpGetFileW(hInternet, lpszRemoteFile, lpszNewFile,
1115 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1120 /***********************************************************************
1121 * FTP_FtpGetFileW (Internal)
1123 * Retrieve file from the FTP server
1125 * RETURNS
1126 * TRUE on success
1127 * FALSE on failure
1130 BOOL WINAPI FTP_FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1131 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1132 DWORD dwContext)
1134 DWORD nBytes;
1135 BOOL bSuccess = FALSE;
1136 HANDLE hFile;
1137 LPWININETAPPINFOW hIC = NULL;
1138 LPWININETFTPSESSIONW lpwfs;
1140 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile));
1142 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet );
1143 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1145 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1146 return FALSE;
1149 /* Clear any error information */
1150 INTERNET_SetLastError(0);
1152 /* Ensure we can write to lpszNewfile by opening it */
1153 hFile = CreateFileW(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1154 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1155 if (INVALID_HANDLE_VALUE == hFile)
1156 goto lend;
1158 /* Set up socket to retrieve data */
1159 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
1161 if (nBytes > 0)
1163 INT nDataSocket;
1165 /* Get data socket to server */
1166 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1168 INT nResCode;
1170 /* Receive data */
1171 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
1172 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
1173 if (nResCode)
1175 if (nResCode == 226)
1176 bSuccess = TRUE;
1177 else
1178 FTP_SetResponseError(nResCode);
1180 close(nDataSocket);
1184 lend:
1185 if (lpwfs->lstnSocket != -1)
1186 close(lpwfs->lstnSocket);
1188 if (hFile)
1189 CloseHandle(hFile);
1191 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1192 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1194 INTERNET_ASYNC_RESULT iar;
1196 iar.dwResult = (DWORD)bSuccess;
1197 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1198 SendAsyncCallback(hIC, hInternet, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1199 &iar, sizeof(INTERNET_ASYNC_RESULT));
1202 return bSuccess;
1206 /***********************************************************************
1207 * FtpDeleteFileA (WININET.@)
1209 * Delete a file on the ftp server
1211 * RETURNS
1212 * TRUE on success
1213 * FALSE on failure
1216 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1218 LPWSTR lpwzFileName;
1219 BOOL ret;
1221 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1222 ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1223 if(lpwzFileName) HeapFree(GetProcessHeap(), 0, lpwzFileName);
1224 return ret;
1227 /***********************************************************************
1228 * FtpDeleteFileW (WININET.@)
1230 * Delete a file on the ftp server
1232 * RETURNS
1233 * TRUE on success
1234 * FALSE on failure
1237 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1239 LPWININETFTPSESSIONW lpwfs;
1240 LPWININETAPPINFOW hIC = NULL;
1242 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1243 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1245 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1246 return FALSE;
1249 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1250 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1252 WORKREQUEST workRequest;
1253 struct WORKREQ_FTPDELETEFILEW *req;
1255 workRequest.asyncall = FTPDELETEFILEW;
1256 workRequest.handle = hFtpSession;
1257 req = &workRequest.u.FtpDeleteFileW;
1258 req->lpszFilename = WININET_strdupW(lpszFileName);
1260 return INTERNET_AsyncCall(&workRequest);
1262 else
1264 return FTP_FtpDeleteFileW(hFtpSession, lpszFileName);
1268 /***********************************************************************
1269 * FTP_FtpDeleteFileW (Internal)
1271 * Delete a file on the ftp server
1273 * RETURNS
1274 * TRUE on success
1275 * FALSE on failure
1278 BOOL FTP_FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1280 INT nResCode;
1281 BOOL bSuccess = FALSE;
1282 LPWININETAPPINFOW hIC = NULL;
1283 LPWININETFTPSESSIONW lpwfs;
1285 TRACE("0x%08lx\n", (ULONG) hFtpSession);
1287 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1288 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1290 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1291 return FALSE;
1294 /* Clear any error information */
1295 INTERNET_SetLastError(0);
1297 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1298 goto lend;
1300 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1301 if (nResCode)
1303 if (nResCode == 250)
1304 bSuccess = TRUE;
1305 else
1306 FTP_SetResponseError(nResCode);
1308 lend:
1309 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1310 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1312 INTERNET_ASYNC_RESULT iar;
1314 iar.dwResult = (DWORD)bSuccess;
1315 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1316 SendAsyncCallback(hIC, hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1317 &iar, sizeof(INTERNET_ASYNC_RESULT));
1320 return bSuccess;
1324 /***********************************************************************
1325 * FtpRemoveDirectoryA (WININET.@)
1327 * Remove a directory on the ftp server
1329 * RETURNS
1330 * TRUE on success
1331 * FALSE on failure
1334 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1336 LPWSTR lpwzDirectory;
1337 BOOL ret;
1339 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
1340 ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1341 if(lpwzDirectory) HeapFree(GetProcessHeap(), 0, lpwzDirectory);
1342 return ret;
1345 /***********************************************************************
1346 * FtpRemoveDirectoryW (WININET.@)
1348 * Remove a directory on the ftp server
1350 * RETURNS
1351 * TRUE on success
1352 * FALSE on failure
1355 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1357 LPWININETFTPSESSIONW lpwfs;
1358 LPWININETAPPINFOW hIC = NULL;
1360 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1361 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1363 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1364 return FALSE;
1367 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1368 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1370 WORKREQUEST workRequest;
1371 struct WORKREQ_FTPREMOVEDIRECTORYW *req;
1373 workRequest.asyncall = FTPREMOVEDIRECTORYW;
1374 workRequest.handle = hFtpSession;
1375 req = &workRequest.u.FtpRemoveDirectoryW;
1376 req->lpszDirectory = WININET_strdupW(lpszDirectory);
1378 return INTERNET_AsyncCall(&workRequest);
1380 else
1382 return FTP_FtpRemoveDirectoryW(hFtpSession, lpszDirectory);
1386 /***********************************************************************
1387 * FTP_FtpRemoveDirectoryW (Internal)
1389 * Remove a directory on the ftp server
1391 * RETURNS
1392 * TRUE on success
1393 * FALSE on failure
1396 BOOL FTP_FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1398 INT nResCode;
1399 BOOL bSuccess = FALSE;
1400 LPWININETAPPINFOW hIC = NULL;
1401 LPWININETFTPSESSIONW lpwfs;
1403 TRACE("\n");
1405 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1406 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1408 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1409 return FALSE;
1412 /* Clear any error information */
1413 INTERNET_SetLastError(0);
1415 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1416 goto lend;
1418 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1419 if (nResCode)
1421 if (nResCode == 250)
1422 bSuccess = TRUE;
1423 else
1424 FTP_SetResponseError(nResCode);
1427 lend:
1428 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1429 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1431 INTERNET_ASYNC_RESULT iar;
1433 iar.dwResult = (DWORD)bSuccess;
1434 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1435 SendAsyncCallback(hIC, hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1436 &iar, sizeof(INTERNET_ASYNC_RESULT));
1439 return bSuccess;
1443 /***********************************************************************
1444 * FtpRenameFileA (WININET.@)
1446 * Rename a file on the ftp server
1448 * RETURNS
1449 * TRUE on success
1450 * FALSE on failure
1453 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1455 LPWSTR lpwzSrc;
1456 LPWSTR lpwzDest;
1457 BOOL ret;
1459 lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL;
1460 lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL;
1461 ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
1462 if(lpwzSrc) HeapFree(GetProcessHeap(), 0, lpwzSrc);
1463 if(lpwzDest) HeapFree(GetProcessHeap(), 0, lpwzDest);
1464 return ret;
1467 /***********************************************************************
1468 * FtpRenameFileW (WININET.@)
1470 * Rename a file on the ftp server
1472 * RETURNS
1473 * TRUE on success
1474 * FALSE on failure
1477 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
1479 LPWININETFTPSESSIONW lpwfs;
1480 LPWININETAPPINFOW hIC = NULL;
1482 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1483 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1485 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1486 return FALSE;
1489 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1490 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1492 WORKREQUEST workRequest;
1493 struct WORKREQ_FTPRENAMEFILEW *req;
1495 workRequest.asyncall = FTPRENAMEFILEW;
1496 workRequest.handle = hFtpSession;
1497 req = &workRequest.u.FtpRenameFileW;
1498 req->lpszSrcFile = WININET_strdupW(lpszSrc);
1499 req->lpszDestFile = WININET_strdupW(lpszDest);
1501 return INTERNET_AsyncCall(&workRequest);
1503 else
1505 return FTP_FtpRenameFileW(hFtpSession, lpszSrc, lpszDest);
1509 /***********************************************************************
1510 * FTP_FtpRenameFileA (Internal)
1512 * Rename a file on the ftp server
1514 * RETURNS
1515 * TRUE on success
1516 * FALSE on failure
1519 BOOL FTP_FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
1521 INT nResCode;
1522 BOOL bSuccess = FALSE;
1523 LPWININETAPPINFOW hIC = NULL;
1524 LPWININETFTPSESSIONW lpwfs;
1526 TRACE("\n");
1528 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1529 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1531 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1532 return FALSE;
1535 /* Clear any error information */
1536 INTERNET_SetLastError(0);
1538 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1539 goto lend;
1541 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1542 if (nResCode == 350)
1544 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1545 goto lend;
1547 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1550 if (nResCode == 250)
1551 bSuccess = TRUE;
1552 else
1553 FTP_SetResponseError(nResCode);
1555 lend:
1556 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1557 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1559 INTERNET_ASYNC_RESULT iar;
1561 iar.dwResult = (DWORD)bSuccess;
1562 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1563 SendAsyncCallback(hIC, hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1564 &iar, sizeof(INTERNET_ASYNC_RESULT));
1567 return bSuccess;
1571 /***********************************************************************
1572 * FTP_Connect (internal)
1574 * Connect to a ftp server
1576 * RETURNS
1577 * HINTERNET a session handle on success
1578 * NULL on failure
1582 HINTERNET FTP_Connect(HINTERNET hInternet, LPCWSTR lpszServerName,
1583 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1584 LPCWSTR lpszPassword, DWORD dwFlags, DWORD dwContext,
1585 DWORD dwInternalFlags)
1587 static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'};
1588 static const WCHAR szDefaultPassword[] = {'u','s','e','r','@','s','e','r','v','e','r','\0'};
1589 struct sockaddr_in socketAddr;
1590 struct hostent *phe = NULL;
1591 INT nsocket = -1, sock_namelen;
1592 LPWININETAPPINFOW hIC = NULL;
1593 BOOL bSuccess = FALSE;
1594 LPWININETFTPSESSIONW lpwfs = NULL;
1595 HINTERNET handle = NULL;
1597 TRACE("0x%08lx Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1598 (ULONG) hInternet, debugstr_w(lpszServerName),
1599 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
1601 hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
1602 if ( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) )
1603 goto lerror;
1605 if (NULL == lpszUserName && NULL != lpszPassword)
1607 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1608 goto lerror;
1611 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
1612 if (NULL == lpwfs)
1614 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1615 goto lerror;
1618 handle = WININET_AllocHandle( &lpwfs->hdr );
1619 if( !handle )
1621 ERR("Failed to alloc handle\n");
1622 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1623 goto lerror;
1626 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1627 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1629 lpwfs->hdr.htype = WH_HFTPSESSION;
1630 lpwfs->hdr.lpwhparent = &hIC->hdr;
1631 lpwfs->hdr.dwFlags = dwFlags;
1632 lpwfs->hdr.dwContext = dwContext;
1633 lpwfs->hdr.dwInternalFlags = dwInternalFlags;
1634 lpwfs->download_in_progress = NULL;
1635 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1636 if(strchrW(hIC->lpszProxy, ' '))
1637 FIXME("Several proxies not implemented.\n");
1638 if(hIC->lpszProxyBypass)
1639 FIXME("Proxy bypass is ignored.\n");
1641 if ( !lpszUserName) {
1642 lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
1643 lpwfs->lpszPassword = WININET_strdupW(szDefaultPassword);
1645 else {
1646 lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
1647 lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
1650 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1651 if (hIC->lpfnStatusCB && !(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
1653 INTERNET_ASYNC_RESULT iar;
1655 iar.dwResult = (DWORD)handle;
1656 iar.dwError = ERROR_SUCCESS;
1658 SendAsyncCallback(hIC, hInternet, dwContext,
1659 INTERNET_STATUS_HANDLE_CREATED, &iar,
1660 sizeof(INTERNET_ASYNC_RESULT));
1663 SendAsyncCallback(hIC, hInternet, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1664 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1666 if (!GetAddress(lpszServerName, nServerPort, &phe, &socketAddr))
1668 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1669 goto lerror;
1672 SendAsyncCallback(hIC, hInternet, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1673 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1675 nsocket = socket(AF_INET,SOCK_STREAM,0);
1676 if (nsocket == -1)
1678 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1679 goto lerror;
1682 SendAsyncCallback(hIC, hInternet, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1683 &socketAddr, sizeof(struct sockaddr_in));
1685 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1687 ERR("Unable to connect (%s)\n", strerror(errno));
1688 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1690 else
1692 TRACE("Connected to server\n");
1693 lpwfs->sndSocket = nsocket;
1694 SendAsyncCallback(hIC, hInternet, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1695 &socketAddr, sizeof(struct sockaddr_in));
1697 sock_namelen = sizeof(lpwfs->socketAddress);
1698 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1699 lpwfs->phostent = phe;
1701 if (FTP_ConnectToHost(lpwfs))
1703 TRACE("Successfully logged into server\n");
1704 bSuccess = TRUE;
1708 lerror:
1709 if (!bSuccess && nsocket == -1)
1710 close(nsocket);
1712 if (!bSuccess && lpwfs)
1714 HeapFree(GetProcessHeap(), 0, lpwfs);
1715 WININET_FreeHandle( handle );
1716 lpwfs = NULL;
1719 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1721 INTERNET_ASYNC_RESULT iar;
1723 iar.dwResult = (DWORD)lpwfs;
1724 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1725 SendAsyncCallback(hIC, hInternet, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1726 &iar, sizeof(INTERNET_ASYNC_RESULT));
1729 return handle;
1733 /***********************************************************************
1734 * FTP_ConnectToHost (internal)
1736 * Connect to a ftp server
1738 * RETURNS
1739 * TRUE on success
1740 * NULL on failure
1743 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
1745 INT nResCode;
1746 BOOL bSuccess = FALSE;
1748 TRACE("\n");
1749 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1751 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1752 goto lend;
1754 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1755 if (nResCode)
1757 /* Login successful... */
1758 if (nResCode == 230)
1759 bSuccess = TRUE;
1760 /* User name okay, need password... */
1761 else if (nResCode == 331)
1762 bSuccess = FTP_SendPassword(lpwfs);
1763 /* Need account for login... */
1764 else if (nResCode == 332)
1765 bSuccess = FTP_SendAccount(lpwfs);
1766 else
1767 FTP_SetResponseError(nResCode);
1770 TRACE("Returning %d\n", bSuccess);
1771 lend:
1772 return bSuccess;
1776 /***********************************************************************
1777 * FTP_SendCommandA (internal)
1779 * Send command to server
1781 * RETURNS
1782 * TRUE on success
1783 * NULL on failure
1786 BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1787 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1789 DWORD len;
1790 CHAR *buf;
1791 DWORD nBytesSent = 0;
1792 DWORD nRC = 0;
1793 DWORD dwParamLen;
1795 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1797 if (lpfnStatusCB)
1798 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1800 dwParamLen = lpszParam?strlen(lpszParam)+1:0;
1801 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
1802 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1804 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1805 return FALSE;
1807 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
1808 dwParamLen ? lpszParam : "", szCRLF);
1810 TRACE("Sending (%s) len(%ld)\n", buf, len);
1811 while((nBytesSent < len) && (nRC != -1))
1813 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1814 nBytesSent += nRC;
1817 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
1819 if (lpfnStatusCB)
1820 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_REQUEST_SENT,
1821 &nBytesSent, sizeof(DWORD));
1823 TRACE("Sent %ld bytes\n", nBytesSent);
1824 return (nRC != -1);
1827 /***********************************************************************
1828 * FTP_SendCommand (internal)
1830 * Send command to server
1832 * RETURNS
1833 * TRUE on success
1834 * NULL on failure
1837 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
1838 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1840 BOOL ret;
1841 LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
1842 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hHandle, dwContext);
1843 HeapFree(GetProcessHeap(), 0, lpszParamA);
1844 return ret;
1847 /***********************************************************************
1848 * FTP_ReceiveResponse (internal)
1850 * Receive response from server
1852 * RETURNS
1853 * Reply code on success
1854 * 0 on failure
1857 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext)
1859 LPSTR lpszResponse = INTERNET_GetResponseBuffer();
1860 DWORD nRecv;
1861 INT rc = 0;
1862 char firstprefix[5];
1863 BOOL multiline = FALSE;
1864 LPWININETAPPINFOW hIC = NULL;
1865 HINTERNET hHandle;
1867 TRACE("socket(%d) \n", lpwfs->sndSocket);
1869 hHandle = WININET_FindHandle(&lpwfs->hdr);
1870 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1871 SendAsyncCallback(hIC, hHandle, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1873 while(1)
1875 if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
1876 goto lerror;
1878 if (nRecv >= 3)
1880 if(!multiline)
1882 if(lpszResponse[3] != '-')
1883 break;
1884 else
1885 { /* Start of multiline repsonse. Loop until we get "nnn " */
1886 multiline = TRUE;
1887 memcpy(firstprefix, lpszResponse, 3);
1888 firstprefix[3] = ' ';
1889 firstprefix[4] = '\0';
1892 else
1894 if(!memcmp(firstprefix, lpszResponse, 4))
1895 break;
1900 if (nRecv >= 3)
1902 rc = atoi(lpszResponse);
1904 SendAsyncCallback(hIC, hHandle, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
1905 &nRecv, sizeof(DWORD));
1908 lerror:
1909 TRACE("return %d\n", rc);
1910 return rc;
1914 /***********************************************************************
1915 * FTP_SendPassword (internal)
1917 * Send password to ftp server
1919 * RETURNS
1920 * TRUE on success
1921 * NULL on failure
1924 BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
1926 INT nResCode;
1927 BOOL bSuccess = FALSE;
1929 TRACE("\n");
1930 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
1931 goto lend;
1933 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1934 if (nResCode)
1936 TRACE("Received reply code %d\n", nResCode);
1937 /* Login successful... */
1938 if (nResCode == 230)
1939 bSuccess = TRUE;
1940 /* Command not implemented, superfluous at the server site... */
1941 /* Need account for login... */
1942 else if (nResCode == 332)
1943 bSuccess = FTP_SendAccount(lpwfs);
1944 else
1945 FTP_SetResponseError(nResCode);
1948 lend:
1949 TRACE("Returning %d\n", bSuccess);
1950 return bSuccess;
1954 /***********************************************************************
1955 * FTP_SendAccount (internal)
1959 * RETURNS
1960 * TRUE on success
1961 * FALSE on failure
1964 BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
1966 INT nResCode;
1967 BOOL bSuccess = FALSE;
1969 TRACE("\n");
1970 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
1971 goto lend;
1973 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1974 if (nResCode)
1975 bSuccess = TRUE;
1976 else
1977 FTP_SetResponseError(nResCode);
1979 lend:
1980 return bSuccess;
1984 /***********************************************************************
1985 * FTP_SendStore (internal)
1987 * Send request to upload file to ftp server
1989 * RETURNS
1990 * TRUE on success
1991 * FALSE on failure
1994 BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
1996 INT nResCode;
1997 BOOL bSuccess = FALSE;
1999 TRACE("\n");
2000 if (!FTP_InitListenSocket(lpwfs))
2001 goto lend;
2003 if (!FTP_SendType(lpwfs, dwType))
2004 goto lend;
2006 if (!FTP_SendPortOrPasv(lpwfs))
2007 goto lend;
2009 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2010 goto lend;
2011 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2012 if (nResCode)
2014 if (nResCode == 150)
2015 bSuccess = TRUE;
2016 else
2017 FTP_SetResponseError(nResCode);
2020 lend:
2021 if (!bSuccess && lpwfs->lstnSocket != -1)
2023 close(lpwfs->lstnSocket);
2024 lpwfs->lstnSocket = -1;
2027 return bSuccess;
2031 /***********************************************************************
2032 * FTP_InitListenSocket (internal)
2034 * Create a socket to listen for server response
2036 * RETURNS
2037 * TRUE on success
2038 * FALSE on failure
2041 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
2043 BOOL bSuccess = FALSE;
2044 size_t namelen = sizeof(struct sockaddr_in);
2046 TRACE("\n");
2048 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2049 if (lpwfs->lstnSocket == -1)
2051 TRACE("Unable to create listening socket\n");
2052 goto lend;
2055 /* We obtain our ip addr from the name of the command channel socket */
2056 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2058 /* and get the system to assign us a port */
2059 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
2061 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
2063 TRACE("Unable to bind socket\n");
2064 goto lend;
2067 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2069 TRACE("listen failed\n");
2070 goto lend;
2073 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2074 bSuccess = TRUE;
2076 lend:
2077 if (!bSuccess && lpwfs->lstnSocket == -1)
2079 close(lpwfs->lstnSocket);
2080 lpwfs->lstnSocket = -1;
2083 return bSuccess;
2087 /***********************************************************************
2088 * FTP_SendType (internal)
2090 * Tell server type of data being transferred
2092 * RETURNS
2093 * TRUE on success
2094 * FALSE on failure
2096 * W98SE doesn't cache the type that's currently set
2097 * (i.e. it sends it always),
2098 * so we probably don't want to do that either.
2100 BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
2102 INT nResCode;
2103 WCHAR type[] = { 'I','\0' };
2104 BOOL bSuccess = FALSE;
2106 TRACE("\n");
2107 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2108 type[0] = 'A';
2110 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2111 goto lend;
2113 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2114 if (nResCode)
2116 if (nResCode == 2)
2117 bSuccess = TRUE;
2118 else
2119 FTP_SetResponseError(nResCode);
2122 lend:
2123 return bSuccess;
2126 /***********************************************************************
2127 * FTP_GetFileSize (internal)
2129 * Retrieves from the server the size of the given file
2131 * RETURNS
2132 * TRUE on success
2133 * FALSE on failure
2136 BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
2138 INT nResCode;
2139 BOOL bSuccess = FALSE;
2141 TRACE("\n");
2143 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2144 goto lend;
2146 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2147 if (nResCode)
2149 if (nResCode == 213) {
2150 /* Now parses the output to get the actual file size */
2151 int i;
2152 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2154 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2155 if (lpszResponseBuffer[i] == '\0') return FALSE;
2156 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2158 bSuccess = TRUE;
2159 } else {
2160 FTP_SetResponseError(nResCode);
2164 lend:
2165 return bSuccess;
2169 /***********************************************************************
2170 * FTP_SendPort (internal)
2172 * Tell server which port to use
2174 * RETURNS
2175 * TRUE on success
2176 * FALSE on failure
2179 BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
2181 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2182 INT nResCode;
2183 WCHAR szIPAddress[64];
2184 BOOL bSuccess = FALSE;
2185 TRACE("\n");
2187 sprintfW(szIPAddress, szIPFormat,
2188 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2189 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2190 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2191 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2192 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2193 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2195 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2196 goto lend;
2198 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2199 if (nResCode)
2201 if (nResCode == 200)
2202 bSuccess = TRUE;
2203 else
2204 FTP_SetResponseError(nResCode);
2207 lend:
2208 return bSuccess;
2212 /***********************************************************************
2213 * FTP_DoPassive (internal)
2215 * Tell server that we want to do passive transfers
2216 * and connect data socket
2218 * RETURNS
2219 * TRUE on success
2220 * FALSE on failure
2223 BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
2225 INT nResCode;
2226 BOOL bSuccess = FALSE;
2228 TRACE("\n");
2229 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2230 goto lend;
2232 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2233 if (nResCode)
2235 if (nResCode == 227)
2237 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2238 LPSTR p;
2239 int f[6];
2240 int i;
2241 char *pAddr, *pPort;
2242 INT nsocket = -1;
2243 struct sockaddr_in dataSocketAddress;
2245 p = lpszResponseBuffer+4; /* skip status code */
2247 /* do a very strict check; we can improve that later. */
2249 if (strncmp(p, "Entering Passive Mode", 21))
2251 ERR("unknown response '%.*s', aborting\n", 21, p);
2252 goto lend;
2254 p += 21; /* skip string */
2255 if ((*p++ != ' ') || (*p++ != '('))
2257 ERR("unknown response format, aborting\n");
2258 goto lend;
2261 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2262 &f[4], &f[5]) != 6)
2264 ERR("unknown response address format '%s', aborting\n", p);
2265 goto lend;
2267 for (i=0; i < 6; i++)
2268 f[i] = f[i] & 0xff;
2270 dataSocketAddress = lpwfs->socketAddress;
2271 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2272 pPort = (char *)&(dataSocketAddress.sin_port);
2273 pAddr[0] = f[0];
2274 pAddr[1] = f[1];
2275 pAddr[2] = f[2];
2276 pAddr[3] = f[3];
2277 pPort[0] = f[4];
2278 pPort[1] = f[5];
2280 nsocket = socket(AF_INET,SOCK_STREAM,0);
2281 if (nsocket == -1)
2282 goto lend;
2284 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2286 ERR("can't connect passive FTP data port.\n");
2287 goto lend;
2289 lpwfs->pasvSocket = nsocket;
2290 bSuccess = TRUE;
2292 else
2293 FTP_SetResponseError(nResCode);
2296 lend:
2297 return bSuccess;
2301 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
2303 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2305 if (!FTP_DoPassive(lpwfs))
2306 return FALSE;
2308 else
2310 if (!FTP_SendPort(lpwfs))
2311 return FALSE;
2313 return TRUE;
2317 /***********************************************************************
2318 * FTP_GetDataSocket (internal)
2320 * Either accepts an incoming data socket connection from the server
2321 * or just returns the already opened socket after a PASV command
2322 * in case of passive FTP.
2325 * RETURNS
2326 * TRUE on success
2327 * FALSE on failure
2330 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
2332 struct sockaddr_in saddr;
2333 size_t addrlen = sizeof(struct sockaddr);
2335 TRACE("\n");
2336 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2338 *nDataSocket = lpwfs->pasvSocket;
2340 else
2342 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2343 close(lpwfs->lstnSocket);
2344 lpwfs->lstnSocket = -1;
2346 return *nDataSocket != -1;
2350 /***********************************************************************
2351 * FTP_SendData (internal)
2353 * Send data to the server
2355 * RETURNS
2356 * TRUE on success
2357 * FALSE on failure
2360 BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2362 BY_HANDLE_FILE_INFORMATION fi;
2363 DWORD nBytesRead = 0;
2364 DWORD nBytesSent = 0;
2365 DWORD nTotalSent = 0;
2366 DWORD nBytesToSend, nLen, nRC = 1;
2367 time_t s_long_time, e_long_time;
2368 LONG nSeconds;
2369 CHAR *lpszBuffer;
2371 TRACE("\n");
2372 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2373 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2375 /* Get the size of the file. */
2376 GetFileInformationByHandle(hFile, &fi);
2377 time(&s_long_time);
2381 nBytesToSend = nBytesRead - nBytesSent;
2383 if (nBytesToSend <= 0)
2385 /* Read data from file. */
2386 nBytesSent = 0;
2387 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2388 ERR("Failed reading from file\n");
2390 if (nBytesRead > 0)
2391 nBytesToSend = nBytesRead;
2392 else
2393 break;
2396 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2397 DATA_PACKET_SIZE : nBytesToSend;
2398 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2400 if (nRC != -1)
2402 nBytesSent += nRC;
2403 nTotalSent += nRC;
2406 /* Do some computation to display the status. */
2407 time(&e_long_time);
2408 nSeconds = e_long_time - s_long_time;
2409 if( nSeconds / 60 > 0 )
2411 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
2412 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2413 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2415 else
2417 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
2418 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2419 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2421 } while (nRC != -1);
2423 TRACE("file transfer complete!\n");
2425 if(lpszBuffer != NULL)
2426 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2428 return nTotalSent;
2432 /***********************************************************************
2433 * FTP_SendRetrieve (internal)
2435 * Send request to retrieve a file
2437 * RETURNS
2438 * Number of bytes to be received on success
2439 * 0 on failure
2442 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2444 INT nResCode;
2445 DWORD nResult = 0;
2447 TRACE("\n");
2448 if (!FTP_InitListenSocket(lpwfs))
2449 goto lend;
2451 if (!FTP_SendType(lpwfs, dwType))
2452 goto lend;
2454 if (!FTP_SendPortOrPasv(lpwfs))
2455 goto lend;
2457 if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2458 goto lend;
2460 TRACE("Waiting to receive %ld bytes\n", nResult);
2462 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2463 goto lend;
2465 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2466 if ((nResCode != 125) && (nResCode != 150)) {
2467 /* That means that we got an error getting the file. */
2468 nResult = 0;
2471 lend:
2472 if (0 == nResult && lpwfs->lstnSocket != -1)
2474 close(lpwfs->lstnSocket);
2475 lpwfs->lstnSocket = -1;
2478 return nResult;
2482 /***********************************************************************
2483 * FTP_RetrieveData (internal)
2485 * Retrieve data from server
2487 * RETURNS
2488 * TRUE on success
2489 * FALSE on failure
2492 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2494 DWORD nBytesWritten;
2495 DWORD nBytesReceived = 0;
2496 INT nRC = 0;
2497 CHAR *lpszBuffer;
2499 TRACE("\n");
2501 if (INVALID_HANDLE_VALUE == hFile)
2502 return FALSE;
2504 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2505 if (NULL == lpszBuffer)
2507 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2508 return FALSE;
2511 while (nBytesReceived < nBytes && nRC != -1)
2513 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2514 if (nRC != -1)
2516 /* other side closed socket. */
2517 if (nRC == 0)
2518 goto recv_end;
2519 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2520 nBytesReceived += nRC;
2523 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
2524 nBytesReceived * 100 / nBytes);
2527 TRACE("Data transfer complete\n");
2528 if (NULL != lpszBuffer)
2529 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2531 recv_end:
2532 return (nRC != -1);
2536 /***********************************************************************
2537 * FTP_CloseSessionHandle (internal)
2539 * Deallocate session handle
2541 * RETURNS
2542 * TRUE on success
2543 * FALSE on failure
2546 BOOL FTP_CloseSessionHandle(LPWININETFTPSESSIONW lpwfs)
2548 TRACE("\n");
2550 if (lpwfs->download_in_progress != NULL)
2551 lpwfs->download_in_progress->session_deleted = TRUE;
2553 if (lpwfs->sndSocket != -1)
2554 close(lpwfs->sndSocket);
2556 if (lpwfs->lstnSocket != -1)
2557 close(lpwfs->lstnSocket);
2559 if (lpwfs->lpszPassword)
2560 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2562 if (lpwfs->lpszUserName)
2563 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2565 HeapFree(GetProcessHeap(), 0, lpwfs);
2567 return TRUE;
2571 /***********************************************************************
2572 * FTP_CloseFindNextHandle (internal)
2574 * Deallocate session handle
2576 * RETURNS
2577 * TRUE on success
2578 * FALSE on failure
2581 BOOL FTP_CloseFindNextHandle(LPWININETFINDNEXTW lpwfn)
2583 INT i;
2585 TRACE("\n");
2587 for (i = 0; i < lpwfn->size; i++)
2589 if (NULL != lpwfn->lpafp[i].lpszName)
2590 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2593 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2594 HeapFree(GetProcessHeap(), 0, lpwfn);
2596 return TRUE;
2599 /***********************************************************************
2600 * FTP_CloseFileTransferHandle (internal)
2602 * Closes the file transfer handle. This also 'cleans' the data queue of
2603 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2605 * RETURNS
2606 * TRUE on success
2607 * FALSE on failure
2610 BOOL FTP_CloseFileTransferHandle(LPWININETFILE lpwh)
2612 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) lpwh->hdr.lpwhparent;
2613 INT nResCode;
2614 HINTERNET handle;
2616 TRACE("\n");
2618 if (!lpwh->session_deleted)
2619 lpwfs->download_in_progress = NULL;
2621 /* This just serves to flush the control socket of any spurrious lines written
2622 to it (like '226 Transfer complete.').
2624 Wonder what to do if the server sends us an error code though...
2626 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2628 if (lpwh->nDataSocket != -1)
2629 close(lpwh->nDataSocket);
2631 HeapFree(GetProcessHeap(), 0, lpwh);
2633 /* If this handle was opened with InternetOpenUrl, we need to close the parent to prevent
2634 a memory leek
2636 if(lpwfs->hdr.dwInternalFlags & INET_OPENURL)
2638 handle = WININET_FindHandle( &lpwfs->hdr );
2639 InternetCloseHandle(handle);
2641 return TRUE;
2644 /***********************************************************************
2645 * FTP_ReceiveFileList (internal)
2647 * Read file list from server
2649 * RETURNS
2650 * Handle to file list on success
2651 * NULL on failure
2654 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2655 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext)
2657 DWORD dwSize = 0;
2658 LPFILEPROPERTIESW lpafp = NULL;
2659 LPWININETFINDNEXTW lpwfn = NULL;
2660 HINTERNET handle = 0;
2662 TRACE("(%p,%d,%s,%p,%ld)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
2664 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
2666 if(lpFindFileData)
2667 FTP_ConvertFileProp(lpafp, lpFindFileData);
2669 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTW));
2670 if (lpwfn)
2672 handle = WININET_AllocHandle( &lpwfn->hdr );
2673 if( handle )
2675 lpwfn->hdr.htype = WH_HFINDNEXT;
2676 lpwfn->hdr.lpwhparent = (LPWININETHANDLEHEADER)lpwfs;
2677 lpwfn->hdr.dwContext = dwContext;
2678 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2679 lpwfn->size = dwSize;
2680 lpwfn->lpafp = lpafp;
2682 else
2683 HeapFree( GetProcessHeap(), 0, lpwfn );
2687 TRACE("Matched %ld files\n", dwSize);
2688 return handle;
2692 /***********************************************************************
2693 * FTP_ConvertFileProp (internal)
2695 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
2697 * RETURNS
2698 * TRUE on success
2699 * FALSE on failure
2702 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
2704 BOOL bSuccess = FALSE;
2706 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
2708 if (lpafp)
2710 /* Convert 'Unix' time to Windows time */
2711 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
2712 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
2714 /* Not all fields are filled in */
2715 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2716 lpFindFileData->nFileSizeLow = lpafp->nSize;
2718 if (lpafp->bIsDirectory)
2719 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2721 if (lpafp->lpszName)
2722 strncpyW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2724 bSuccess = TRUE;
2727 return bSuccess;
2730 /***********************************************************************
2731 * FTP_ParseNextFile (internal)
2733 * Parse the next line in file listing
2735 * RETURNS
2736 * TRUE on success
2737 * FALSE on failure
2739 BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
2741 static const char szSpace[] = " \t";
2742 DWORD nBufLen;
2743 char *pszLine;
2744 char *pszToken;
2745 char *pszTmp;
2746 BOOL found = FALSE;
2747 int i;
2749 lpfp->lpszName = NULL;
2750 do {
2751 if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
2752 return FALSE;
2754 pszToken = strtok(pszLine, szSpace);
2755 /* ls format
2756 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2758 * For instance:
2759 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2761 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
2762 if(!FTP_ParsePermission(pszToken, lpfp))
2763 lpfp->bIsDirectory = FALSE;
2764 for(i=0; i<=3; i++) {
2765 if(!(pszToken = strtok(NULL, szSpace)))
2766 break;
2768 if(!pszToken) continue;
2769 if(lpfp->bIsDirectory) {
2770 TRACE("Is directory\n");
2771 lpfp->nSize = 0;
2773 else {
2774 TRACE("Size: %s\n", pszToken);
2775 lpfp->nSize = atol(pszToken);
2778 lpfp->tmLastModified.tm_sec = 0;
2779 lpfp->tmLastModified.tm_min = 0;
2780 lpfp->tmLastModified.tm_hour = 0;
2781 lpfp->tmLastModified.tm_mday = 0;
2782 lpfp->tmLastModified.tm_mon = 0;
2783 lpfp->tmLastModified.tm_year = 0;
2785 /* Determine month */
2786 pszToken = strtok(NULL, szSpace);
2787 if(!pszToken) continue;
2788 if(strlen(pszToken) >= 3) {
2789 pszToken[3] = 0;
2790 if((pszTmp = StrStrIA(szMonths, pszToken)))
2791 lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
2793 /* Determine day */
2794 pszToken = strtok(NULL, szSpace);
2795 if(!pszToken) continue;
2796 lpfp->tmLastModified.tm_mday = atoi(pszToken);
2797 /* Determine time or year */
2798 pszToken = strtok(NULL, szSpace);
2799 if(!pszToken) continue;
2800 if((pszTmp = strchr(pszToken, ':'))) {
2801 struct tm* apTM;
2802 time_t aTime;
2803 *pszTmp = 0;
2804 pszTmp++;
2805 lpfp->tmLastModified.tm_min = atoi(pszTmp);
2806 lpfp->tmLastModified.tm_hour = atoi(pszToken);
2807 time(&aTime);
2808 apTM = localtime(&aTime);
2809 lpfp->tmLastModified.tm_year = apTM->tm_year;
2811 else {
2812 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
2813 lpfp->tmLastModified.tm_hour = 12;
2815 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
2816 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
2817 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
2818 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
2820 pszToken = strtok(NULL, szSpace);
2821 if(!pszToken) continue;
2822 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
2823 TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
2825 /* NT way of parsing ... :
2827 07-13-03 08:55PM <DIR> sakpatch
2828 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
2830 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
2831 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
2833 sscanf(pszToken, "%d-%d-%d",
2834 &lpfp->tmLastModified.tm_mon,
2835 &lpfp->tmLastModified.tm_mday,
2836 &lpfp->tmLastModified.tm_year);
2838 /* Hacky and bad Y2K protection :-) */
2839 if (lpfp->tmLastModified.tm_year < 70)
2840 lpfp->tmLastModified.tm_year += 100;
2842 pszToken = strtok(NULL, szSpace);
2843 if(!pszToken) continue;
2844 sscanf(pszToken, "%d:%d",
2845 &lpfp->tmLastModified.tm_hour,
2846 &lpfp->tmLastModified.tm_min);
2847 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
2848 lpfp->tmLastModified.tm_hour += 12;
2850 lpfp->tmLastModified.tm_sec = 0;
2852 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
2853 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
2854 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
2855 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
2857 pszToken = strtok(NULL, szSpace);
2858 if(!pszToken) continue;
2859 if(!strcasecmp(pszToken, "<DIR>")) {
2860 lpfp->bIsDirectory = TRUE;
2861 lpfp->nSize = 0;
2862 TRACE("Is directory\n");
2864 else {
2865 lpfp->bIsDirectory = FALSE;
2866 lpfp->nSize = atol(pszToken);
2867 TRACE("Size: %ld\n", lpfp->nSize);
2870 pszToken = strtok(NULL, szSpace);
2871 if(!pszToken) continue;
2872 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
2873 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
2875 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
2876 else if(pszToken[0] == '+') {
2877 FIXME("EPLF Format not implemented\n");
2880 if(lpfp->lpszName) {
2881 if((lpszSearchFile == NULL) ||
2882 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
2883 found = TRUE;
2884 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
2886 else {
2887 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
2888 lpfp->lpszName = NULL;
2891 } while(!found);
2892 return TRUE;
2895 /***********************************************************************
2896 * FTP_ParseDirectory (internal)
2898 * Parse string of directory information
2900 * RETURNS
2901 * TRUE on success
2902 * FALSE on failure
2904 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2905 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
2907 BOOL bSuccess = TRUE;
2908 INT sizeFilePropArray = 500;/*20; */
2909 INT indexFilePropArray = -1;
2911 TRACE("\n");
2913 /* Allocate intial file properties array */
2914 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
2915 if (!*lpafp)
2916 return FALSE;
2918 do {
2919 if (indexFilePropArray+1 >= sizeFilePropArray)
2921 LPFILEPROPERTIESW tmpafp;
2923 sizeFilePropArray *= 2;
2924 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
2925 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
2926 if (NULL == tmpafp)
2928 bSuccess = FALSE;
2929 break;
2932 *lpafp = tmpafp;
2934 indexFilePropArray++;
2935 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
2937 if (bSuccess && indexFilePropArray)
2939 if (indexFilePropArray < sizeFilePropArray - 1)
2941 LPFILEPROPERTIESW tmpafp;
2943 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
2944 sizeof(FILEPROPERTIESW)*indexFilePropArray);
2945 if (NULL == tmpafp)
2946 *lpafp = tmpafp;
2948 *dwfp = indexFilePropArray;
2950 else
2952 HeapFree(GetProcessHeap(), 0, *lpafp);
2953 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2954 bSuccess = FALSE;
2957 return bSuccess;
2961 /***********************************************************************
2962 * FTP_ParsePermission (internal)
2964 * Parse permission string of directory information
2966 * RETURNS
2967 * TRUE on success
2968 * FALSE on failure
2971 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
2973 BOOL bSuccess = TRUE;
2974 unsigned short nPermission = 0;
2975 INT nPos = 1;
2976 INT nLast = 9;
2978 TRACE("\n");
2979 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
2981 bSuccess = FALSE;
2982 return bSuccess;
2985 lpfp->bIsDirectory = (*lpszPermission == 'd');
2988 switch (nPos)
2990 case 1:
2991 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
2992 break;
2993 case 2:
2994 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
2995 break;
2996 case 3:
2997 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
2998 break;
2999 case 4:
3000 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3001 break;
3002 case 5:
3003 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3004 break;
3005 case 6:
3006 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3007 break;
3008 case 7:
3009 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3010 break;
3011 case 8:
3012 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3013 break;
3014 case 9:
3015 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3016 break;
3018 nPos++;
3019 }while (nPos <= nLast);
3021 lpfp->permissions = nPermission;
3022 return bSuccess;
3026 /***********************************************************************
3027 * FTP_SetResponseError (internal)
3029 * Set the appropriate error code for a given response from the server
3031 * RETURNS
3034 DWORD FTP_SetResponseError(DWORD dwResponse)
3036 DWORD dwCode = 0;
3038 switch(dwResponse)
3040 case 421: /* Service not available - Server may be shutting down. */
3041 dwCode = ERROR_INTERNET_TIMEOUT;
3042 break;
3044 case 425: /* Cannot open data connection. */
3045 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3046 break;
3048 case 426: /* Connection closed, transer aborted. */
3049 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3050 break;
3052 case 500: /* Syntax error. Command unrecognized. */
3053 case 501: /* Syntax error. Error in parameters or arguments. */
3054 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
3055 break;
3057 case 530: /* Not logged in. Login incorrect. */
3058 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3059 break;
3061 case 550: /* File action not taken. File not found or no access. */
3062 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
3063 break;
3065 case 450: /* File action not taken. File may be busy. */
3066 case 451: /* Action aborted. Server error. */
3067 case 452: /* Action not taken. Insufficient storage space on server. */
3068 case 502: /* Command not implemented. */
3069 case 503: /* Bad sequence of command. */
3070 case 504: /* Command not implemented for that parameter. */
3071 case 532: /* Need account for storing files */
3072 case 551: /* Requested action aborted. Page type unknown */
3073 case 552: /* Action aborted. Exceeded storage allocation */
3074 case 553: /* Action not taken. File name not allowed. */
3076 default:
3077 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
3078 break;
3081 INTERNET_SetLastError(dwCode);
3082 return dwCode;