Fixed header dependencies to be fully compatible with the Windows
[wine/multimedia.git] / dlls / wininet / ftp.c
blob2986fc56813d8e2881a422eaea397565f7a82359
1 /*
2 * WININET - Ftp implementation
4 * Copyright 1999 Corel Corporation
6 * Ulrich Czekalla
7 * Noureddine Jemmali
9 * Copyright 2000 Andreas Mohr
10 * Copyright 2002 Jaco Greeff
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "config.h"
28 #include "wine/port.h"
30 #include <errno.h>
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #ifdef HAVE_SYS_SOCKET_H
37 # include <sys/socket.h>
38 #endif
39 #ifdef HAVE_UNISTD_H
40 # include <unistd.h>
41 #endif
42 #include <time.h>
44 #include "windef.h"
45 #include "winbase.h"
46 #include "wingdi.h"
47 #include "winuser.h"
48 #include "wininet.h"
49 #include "winnls.h"
50 #include "winerror.h"
51 #include "winreg.h"
52 #include "winternl.h"
54 #include "wine/debug.h"
55 #include "internet.h"
57 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
59 #define NOACCOUNT "noaccount"
60 #define DATA_PACKET_SIZE 0x2000
61 #define szCRLF "\r\n"
62 #define MAX_BACKLOG 5
64 typedef enum {
65 /* FTP commands with arguments. */
66 FTP_CMD_ACCT,
67 FTP_CMD_CWD,
68 FTP_CMD_DELE,
69 FTP_CMD_MKD,
70 FTP_CMD_PASS,
71 FTP_CMD_PORT,
72 FTP_CMD_RETR,
73 FTP_CMD_RMD,
74 FTP_CMD_RNFR,
75 FTP_CMD_RNTO,
76 FTP_CMD_STOR,
77 FTP_CMD_TYPE,
78 FTP_CMD_USER,
79 FTP_CMD_SIZE,
81 /* FTP commands without arguments. */
82 FTP_CMD_ABOR,
83 FTP_CMD_LIST,
84 FTP_CMD_NLST,
85 FTP_CMD_PASV,
86 FTP_CMD_PWD,
87 FTP_CMD_QUIT,
88 } FTP_COMMAND;
90 static const CHAR *szFtpCommands[] = {
91 "ACCT",
92 "CWD",
93 "DELE",
94 "MKD",
95 "PASS",
96 "PORT",
97 "RETR",
98 "RMD",
99 "RNFR",
100 "RNTO",
101 "STOR",
102 "TYPE",
103 "USER",
104 "SIZE",
105 "ABOR",
106 "LIST",
107 "NLST",
108 "PASV",
109 "PWD",
110 "QUIT",
113 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
115 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
116 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
117 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
118 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket);
119 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile);
120 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
121 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
122 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
123 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile);
124 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs);
125 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs);
126 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs);
127 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs);
128 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType);
129 BOOL FTP_GetFileSize(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD *dwSize);
130 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs);
131 BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs);
132 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs);
133 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp);
134 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp);
135 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
136 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext);
137 DWORD FTP_SetResponseError(DWORD dwResponse);
139 inline static LPSTR FTP_strdup( LPCSTR str )
141 LPSTR ret = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
142 if (ret) strcpy( ret, str );
143 return ret;
146 /***********************************************************************
147 * FtpPutFileA (WININET.@)
149 * Uploads a file to the FTP server
151 * RETURNS
152 * TRUE on success
153 * FALSE on failure
156 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
157 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
159 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
160 LPWININETAPPINFOA hIC = NULL;
162 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
164 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
165 return FALSE;
168 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
169 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
171 WORKREQUEST workRequest;
173 workRequest.asyncall = FTPPUTFILEA;
174 workRequest.HFTPSESSION = (DWORD)hConnect;
175 workRequest.LPSZLOCALFILE = (DWORD)FTP_strdup(lpszLocalFile);
176 workRequest.LPSZNEWREMOTEFILE = (DWORD)FTP_strdup(lpszNewRemoteFile);
177 workRequest.DWFLAGS = dwFlags;
178 workRequest.DWCONTEXT = dwContext;
180 return INTERNET_AsyncCall(&workRequest);
182 else
184 return FTP_FtpPutFileA(hConnect, lpszLocalFile,
185 lpszNewRemoteFile, dwFlags, dwContext);
189 /***********************************************************************
190 * FTP_FtpPutFileA (Internal)
192 * Uploads a file to the FTP server
194 * RETURNS
195 * TRUE on success
196 * FALSE on failure
199 BOOL WINAPI FTP_FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
200 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
202 HANDLE hFile = NULL;
203 BOOL bSuccess = FALSE;
204 LPWININETAPPINFOA hIC = NULL;
205 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
206 INT nResCode;
208 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", lpszLocalFile, lpszNewRemoteFile);
209 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
211 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
212 return FALSE;
215 /* Clear any error information */
216 INTERNET_SetLastError(0);
218 /* Open file to be uploaded */
219 if (INVALID_HANDLE_VALUE ==
220 (hFile = CreateFileA(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
222 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND);
223 goto lend;
226 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
227 if (hIC->lpfnStatusCB)
228 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
230 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
232 INT nDataSocket;
234 /* Get data socket to server */
235 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
237 FTP_SendData(lpwfs, nDataSocket, hFile);
238 close(nDataSocket);
239 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
240 MAX_REPLY_LEN, 0, 0, 0);
241 if (nResCode)
243 if (nResCode == 226)
244 bSuccess = TRUE;
245 else
246 FTP_SetResponseError(nResCode);
251 lend:
252 if (lpwfs->lstnSocket != -1)
253 close(lpwfs->lstnSocket);
255 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
257 INTERNET_ASYNC_RESULT iar;
259 iar.dwResult = (DWORD)bSuccess;
260 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
261 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
262 &iar, sizeof(INTERNET_ASYNC_RESULT));
265 if (hFile)
266 CloseHandle(hFile);
268 return bSuccess;
272 /***********************************************************************
273 * FtpSetCurrentDirectoryA (WININET.@)
275 * Change the working directory on the FTP server
277 * RETURNS
278 * TRUE on success
279 * FALSE on failure
282 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
284 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
285 LPWININETAPPINFOA hIC = NULL;
287 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
289 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
290 return FALSE;
293 TRACE("lpszDirectory(%s)\n", lpszDirectory);
295 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
296 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
298 WORKREQUEST workRequest;
300 workRequest.asyncall = FTPSETCURRENTDIRECTORYA;
301 workRequest.HFTPSESSION = (DWORD)hConnect;
302 workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
304 return INTERNET_AsyncCall(&workRequest);
306 else
308 return FTP_FtpSetCurrentDirectoryA(hConnect, lpszDirectory);
313 /***********************************************************************
314 * FtpSetCurrentDirectoryW (WININET.@)
316 * Change the working directory on the FTP server
318 * RETURNS
319 * TRUE on success
320 * FALSE on failure
323 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
325 CHAR *szDir;
326 INT len;
327 BOOL rc;
329 len = lstrlenW(lpszDirectory)+1;
330 if (!(szDir = (CHAR *)malloc(len*sizeof(CHAR))))
331 return FALSE;
332 WideCharToMultiByte(CP_ACP, -1, lpszDirectory, -1, szDir, len, NULL, NULL);
333 rc = FtpSetCurrentDirectoryA(hConnect, szDir);
334 free(szDir);
336 return rc;
340 /***********************************************************************
341 * FTP_FtpSetCurrentDirectoryA (Internal)
343 * Change the working directory on the FTP server
345 * RETURNS
346 * TRUE on success
347 * FALSE on failure
350 BOOL WINAPI FTP_FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
352 INT nResCode;
353 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
354 LPWININETAPPINFOA hIC = NULL;
355 DWORD bSuccess = FALSE;
357 TRACE("lpszDirectory(%s)\n", lpszDirectory);
359 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
361 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
362 return FALSE;
365 /* Clear any error information */
366 INTERNET_SetLastError(0);
368 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
369 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
370 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
371 goto lend;
373 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
374 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
376 if (nResCode)
378 if (nResCode == 250)
379 bSuccess = TRUE;
380 else
381 FTP_SetResponseError(nResCode);
384 lend:
385 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
387 INTERNET_ASYNC_RESULT iar;
389 iar.dwResult = (DWORD)bSuccess;
390 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
391 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
392 &iar, sizeof(INTERNET_ASYNC_RESULT));
394 return bSuccess;
398 /***********************************************************************
399 * FtpCreateDirectoryA (WININET.@)
401 * Create new directory on the FTP server
403 * RETURNS
404 * TRUE on success
405 * FALSE on failure
408 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
410 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
411 LPWININETAPPINFOA hIC = NULL;
413 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
415 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
416 return FALSE;
419 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
420 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
422 WORKREQUEST workRequest;
424 workRequest.asyncall = FTPCREATEDIRECTORYA;
425 workRequest.HFTPSESSION = (DWORD)hConnect;
426 workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
428 return INTERNET_AsyncCall(&workRequest);
430 else
432 return FTP_FtpCreateDirectoryA(hConnect, lpszDirectory);
437 /***********************************************************************
438 * FtpCreateDirectoryW (WININET.@)
440 * Create new directory on the FTP server
442 * RETURNS
443 * TRUE on success
444 * FALSE on failure
447 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
449 CHAR *szDir;
450 INT len;
451 BOOL rc;
453 len = lstrlenW(lpszDirectory)+1;
454 if (!(szDir = (CHAR *)malloc(len*sizeof(CHAR))))
455 return FALSE;
456 WideCharToMultiByte(CP_ACP, -1, lpszDirectory, -1, szDir, len, NULL, NULL);
457 rc = FtpCreateDirectoryA(hConnect, szDir);
458 free(szDir);
460 return rc;
464 /***********************************************************************
465 * FTP_FtpCreateDirectoryA (Internal)
467 * Create new directory on the FTP server
469 * RETURNS
470 * TRUE on success
471 * FALSE on failure
474 BOOL WINAPI FTP_FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
476 INT nResCode;
477 BOOL bSuccess = FALSE;
478 LPWININETAPPINFOA hIC = NULL;
479 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
481 TRACE("\n");
482 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
484 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
485 return FALSE;
488 /* Clear any error information */
489 INTERNET_SetLastError(0);
491 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
492 goto lend;
494 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
495 MAX_REPLY_LEN, 0, 0, 0);
496 if (nResCode)
498 if (nResCode == 257)
499 bSuccess = TRUE;
500 else
501 FTP_SetResponseError(nResCode);
504 lend:
505 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
506 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
508 INTERNET_ASYNC_RESULT iar;
510 iar.dwResult = (DWORD)bSuccess;
511 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
512 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
513 &iar, sizeof(INTERNET_ASYNC_RESULT));
516 return bSuccess;
520 /***********************************************************************
521 * FtpFindFirstFileA (WININET.@)
523 * Search the specified directory
525 * RETURNS
526 * HINTERNET on success
527 * NULL on failure
530 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
531 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
533 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
534 LPWININETAPPINFOA hIC = NULL;
536 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
538 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
539 return FALSE;
542 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
543 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
545 WORKREQUEST workRequest;
547 workRequest.asyncall = FTPFINDFIRSTFILEA;
548 workRequest.HFTPSESSION = (DWORD)hConnect;
549 workRequest.LPSZSEARCHFILE = (DWORD)FTP_strdup(lpszSearchFile);
550 workRequest.LPFINDFILEDATA = (DWORD)lpFindFileData;
551 workRequest.DWFLAGS = dwFlags;
552 workRequest.DWCONTEXT= dwContext;
554 INTERNET_AsyncCall(&workRequest);
555 return NULL;
557 else
559 return FTP_FtpFindFirstFileA(hConnect, lpszSearchFile, lpFindFileData,
560 dwFlags, dwContext);
565 /***********************************************************************
566 * FtpFindFirstFileA (WININET.@)
568 * Search the specified directory
570 * RETURNS
571 * HINTERNET on success
572 * NULL on failure
575 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
576 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
578 FIXME("STUB\n");
579 return NULL;
583 /***********************************************************************
584 * FTP_FtpFindFirstFileA (Internal)
586 * Search the specified directory
588 * RETURNS
589 * HINTERNET on success
590 * NULL on failure
593 HINTERNET WINAPI FTP_FtpFindFirstFileA(HINTERNET hConnect,
594 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
596 INT nResCode;
597 LPWININETAPPINFOA hIC = NULL;
598 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
599 LPWININETFINDNEXTA hFindNext = NULL;
601 TRACE("\n");
603 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
605 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
606 return FALSE;
609 /* Clear any error information */
610 INTERNET_SetLastError(0);
612 if (!FTP_InitListenSocket(lpwfs))
613 goto lend;
615 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
616 goto lend;
618 if (!FTP_SendPortOrPasv(lpwfs))
619 goto lend;
621 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
622 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, lpszSearchFile,
623 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
624 goto lend;
626 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
627 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
628 if (nResCode)
630 if (nResCode == 125 || nResCode == 150)
632 INT nDataSocket;
634 /* Get data socket to server */
635 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
637 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpFindFileData, dwContext);
639 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
640 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
641 if (nResCode != 226 && nResCode != 250)
642 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
644 close(nDataSocket);
647 else
648 FTP_SetResponseError(nResCode);
651 lend:
652 if (lpwfs->lstnSocket != -1)
653 close(lpwfs->lstnSocket);
655 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
657 INTERNET_ASYNC_RESULT iar;
659 if (hFindNext)
661 iar.dwResult = (DWORD)hFindNext;
662 iar.dwError = ERROR_SUCCESS;
663 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
664 &iar, sizeof(INTERNET_ASYNC_RESULT));
667 iar.dwResult = (DWORD)hFindNext;
668 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
669 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
670 &iar, sizeof(INTERNET_ASYNC_RESULT));
673 return (HINTERNET)hFindNext;
677 /***********************************************************************
678 * FtpGetCurrentDirectoryA (WININET.@)
680 * Retrieves the current directory
682 * RETURNS
683 * TRUE on success
684 * FALSE on failure
687 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
688 LPDWORD lpdwCurrentDirectory)
690 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
691 LPWININETAPPINFOA hIC = NULL;
693 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
695 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
697 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
698 return FALSE;
701 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
702 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
704 WORKREQUEST workRequest;
706 workRequest.asyncall = FTPGETCURRENTDIRECTORYA;
707 workRequest.HFTPSESSION = (DWORD)hFtpSession;
708 workRequest.LPSZDIRECTORY = (DWORD)lpszCurrentDirectory;
709 workRequest.LPDWDIRECTORY = (DWORD)lpdwCurrentDirectory;
711 return INTERNET_AsyncCall(&workRequest);
713 else
715 return FTP_FtpGetCurrentDirectoryA(hFtpSession, lpszCurrentDirectory,
716 lpdwCurrentDirectory);
721 /***********************************************************************
722 * FtpGetCurrentDirectoryW (WININET.@)
724 * Retrieves the current directory
726 * RETURNS
727 * TRUE on success
728 * FALSE on failure
731 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
732 LPDWORD lpdwCurrentDirectory)
734 FIXME("STUB\n");
735 return FALSE;
739 /***********************************************************************
740 * FTP_FtpGetCurrentDirectoryA (Internal)
742 * Retrieves the current directory
744 * RETURNS
745 * TRUE on success
746 * FALSE on failure
749 BOOL WINAPI FTP_FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
750 LPDWORD lpdwCurrentDirectory)
752 INT nResCode;
753 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
754 LPWININETAPPINFOA hIC = NULL;
755 DWORD bSuccess = FALSE;
757 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
759 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
761 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
762 return FALSE;
765 /* Clear any error information */
766 INTERNET_SetLastError(0);
768 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
770 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
771 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
772 hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext))
773 goto lend;
775 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
776 MAX_REPLY_LEN, hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext);
777 if (nResCode)
779 if (nResCode == 257) /* Extract directory name */
781 INT firstpos, lastpos, len;
782 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
784 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
786 if ('"' == lpszResponseBuffer[lastpos])
788 if (!firstpos)
789 firstpos = lastpos;
790 else
791 break;
795 len = lastpos - firstpos - 1;
796 strncpy(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1],
797 len < *lpdwCurrentDirectory ? len : *lpdwCurrentDirectory);
798 *lpdwCurrentDirectory = len;
799 bSuccess = TRUE;
801 else
802 FTP_SetResponseError(nResCode);
805 lend:
806 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
808 INTERNET_ASYNC_RESULT iar;
810 iar.dwResult = (DWORD)bSuccess;
811 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
812 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
813 &iar, sizeof(INTERNET_ASYNC_RESULT));
816 return (DWORD) bSuccess;
819 /***********************************************************************
820 * FtpOpenFileA (WININET.@)
822 * Open a remote file for writing or reading
824 * RETURNS
825 * HINTERNET handle on success
826 * NULL on failure
829 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
830 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
831 DWORD dwContext)
833 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
834 LPWININETAPPINFOA hIC = NULL;
836 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
838 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
839 return FALSE;
842 if (lpwfs->download_in_progress != NULL) {
843 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
844 return FALSE;
847 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
848 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
850 WORKREQUEST workRequest;
852 workRequest.asyncall = FTPOPENFILEA;
853 workRequest.HFTPSESSION = (DWORD)hFtpSession;
854 workRequest.LPSZFILENAME = (DWORD)FTP_strdup(lpszFileName);
855 workRequest.FDWACCESS = fdwAccess;
856 workRequest.DWFLAGS = dwFlags;
857 workRequest.DWCONTEXT = dwContext;
859 INTERNET_AsyncCall(&workRequest);
860 return NULL;
862 else
864 return FTP_FtpOpenFileA(hFtpSession, lpszFileName, fdwAccess, dwFlags, dwContext);
869 /***********************************************************************
870 * FtpOpenFileW (WININET.@)
872 * Open a remote file for writing or reading
874 * RETURNS
875 * HINTERNET handle on success
876 * NULL on failure
879 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
880 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
881 DWORD dwContext)
883 FIXME("STUB\n");
884 return NULL;
888 /***********************************************************************
889 * FTP_FtpOpenFileA (Internal)
891 * Open a remote file for writing or reading
893 * RETURNS
894 * HINTERNET handle on success
895 * NULL on failure
898 HINTERNET FTP_FtpOpenFileA(HINTERNET hFtpSession,
899 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
900 DWORD dwContext)
902 INT nDataSocket;
903 BOOL bSuccess = FALSE;
904 LPWININETFILE hFile = NULL;
905 LPWININETAPPINFOA hIC = NULL;
906 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
908 TRACE("\n");
910 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
912 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
913 return FALSE;
916 /* Clear any error information */
917 INTERNET_SetLastError(0);
919 if (GENERIC_READ == fdwAccess)
921 /* Set up socket to retrieve data */
922 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
924 else if (GENERIC_WRITE == fdwAccess)
926 /* Set up socket to send data */
927 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
930 /* Get data socket to server */
931 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
933 hFile = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE));
934 hFile->hdr.htype = WH_HFILE;
935 hFile->hdr.dwFlags = dwFlags;
936 hFile->hdr.dwContext = dwContext;
937 hFile->hdr.lpwhparent = hFtpSession;
938 hFile->nDataSocket = nDataSocket;
939 hFile->session_deleted = FALSE;
941 /* Indicate that a download is currently in progress */
942 lpwfs->download_in_progress = hFile;
945 if (lpwfs->lstnSocket != -1)
946 close(lpwfs->lstnSocket);
948 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
949 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
951 INTERNET_ASYNC_RESULT iar;
953 if (hFile)
955 iar.dwResult = (DWORD)hFile;
956 iar.dwError = ERROR_SUCCESS;
957 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
958 &iar, sizeof(INTERNET_ASYNC_RESULT));
961 iar.dwResult = (DWORD)bSuccess;
962 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
963 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
964 &iar, sizeof(INTERNET_ASYNC_RESULT));
967 return (HINTERNET)hFile;
971 /***********************************************************************
972 * FtpGetFileA (WININET.@)
974 * Retrieve file from the FTP server
976 * RETURNS
977 * TRUE on success
978 * FALSE on failure
981 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
982 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
983 DWORD dwContext)
985 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet;
986 LPWININETAPPINFOA hIC = NULL;
988 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
990 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
991 return FALSE;
994 if (lpwfs->download_in_progress != NULL) {
995 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
996 return FALSE;
999 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1000 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1002 WORKREQUEST workRequest;
1004 workRequest.asyncall = FTPGETFILEA;
1005 workRequest.HFTPSESSION = (DWORD)hInternet;
1006 workRequest.LPSZREMOTEFILE = (DWORD)FTP_strdup(lpszRemoteFile);
1007 workRequest.LPSZNEWFILE = (DWORD)FTP_strdup(lpszNewFile);
1008 workRequest.DWLOCALFLAGSATTRIBUTE = dwLocalFlagsAttribute;
1009 workRequest.FFAILIFEXISTS = (DWORD)fFailIfExists;
1010 workRequest.DWFLAGS = dwInternetFlags;
1011 workRequest.DWCONTEXT = dwContext;
1013 return INTERNET_AsyncCall(&workRequest);
1015 else
1017 return FTP_FtpGetFileA(hInternet, lpszRemoteFile, lpszNewFile,
1018 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1023 /***********************************************************************
1024 * FtpGetFileW (WININET.@)
1026 * Retrieve file from the FTP server
1028 * RETURNS
1029 * TRUE on success
1030 * FALSE on failure
1033 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1034 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1035 DWORD dwContext)
1037 FIXME("STUB\n");
1038 return FALSE;
1042 /***********************************************************************
1043 * FTP_FtpGetFileA (Internal)
1045 * Retrieve file from the FTP server
1047 * RETURNS
1048 * TRUE on success
1049 * FALSE on failure
1052 BOOL WINAPI FTP_FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1053 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1054 DWORD dwContext)
1056 DWORD nBytes;
1057 BOOL bSuccess = FALSE;
1058 HANDLE hFile;
1059 LPWININETAPPINFOA hIC = NULL;
1060 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet;
1062 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", lpszRemoteFile, lpszNewFile);
1063 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1065 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1066 return FALSE;
1069 /* Clear any error information */
1070 INTERNET_SetLastError(0);
1072 /* Ensure we can write to lpszNewfile by opening it */
1073 hFile = CreateFileA(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1074 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1075 if (INVALID_HANDLE_VALUE == hFile)
1076 goto lend;
1078 /* Set up socket to retrieve data */
1079 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
1081 if (nBytes > 0)
1083 INT nDataSocket;
1085 /* Get data socket to server */
1086 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1088 INT nResCode;
1090 /* Receive data */
1091 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
1092 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1093 MAX_REPLY_LEN, 0, 0, 0);
1094 if (nResCode)
1096 if (nResCode == 226)
1097 bSuccess = TRUE;
1098 else
1099 FTP_SetResponseError(nResCode);
1101 close(nDataSocket);
1105 lend:
1106 if (lpwfs->lstnSocket != -1)
1107 close(lpwfs->lstnSocket);
1109 if (hFile)
1110 CloseHandle(hFile);
1112 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1113 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1115 INTERNET_ASYNC_RESULT iar;
1117 iar.dwResult = (DWORD)bSuccess;
1118 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1119 hIC->lpfnStatusCB(hInternet, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1120 &iar, sizeof(INTERNET_ASYNC_RESULT));
1123 return bSuccess;
1127 /***********************************************************************
1128 * FtpDeleteFileA (WININET.@)
1130 * Delete a file on the ftp server
1132 * RETURNS
1133 * TRUE on success
1134 * FALSE on failure
1137 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1139 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1140 LPWININETAPPINFOA hIC = NULL;
1142 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1144 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1145 return FALSE;
1148 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1149 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1151 WORKREQUEST workRequest;
1153 workRequest.asyncall = FTPRENAMEFILEA;
1154 workRequest.HFTPSESSION = (DWORD)hFtpSession;
1155 workRequest.LPSZFILENAME = (DWORD)FTP_strdup(lpszFileName);
1157 return INTERNET_AsyncCall(&workRequest);
1159 else
1161 return FTP_FtpDeleteFileA(hFtpSession, lpszFileName);
1166 /***********************************************************************
1167 * FTP_FtpDeleteFileA (Internal)
1169 * Delete a file on the ftp server
1171 * RETURNS
1172 * TRUE on success
1173 * FALSE on failure
1176 BOOL FTP_FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1178 INT nResCode;
1179 BOOL bSuccess = FALSE;
1180 LPWININETAPPINFOA hIC = NULL;
1181 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1183 TRACE("0x%08lx\n", (ULONG) hFtpSession);
1184 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1186 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1187 return FALSE;
1190 /* Clear any error information */
1191 INTERNET_SetLastError(0);
1193 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1194 goto lend;
1196 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1197 MAX_REPLY_LEN, 0, 0, 0);
1198 if (nResCode)
1200 if (nResCode == 250)
1201 bSuccess = TRUE;
1202 else
1203 FTP_SetResponseError(nResCode);
1205 lend:
1206 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1207 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1209 INTERNET_ASYNC_RESULT iar;
1211 iar.dwResult = (DWORD)bSuccess;
1212 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1213 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1214 &iar, sizeof(INTERNET_ASYNC_RESULT));
1217 return bSuccess;
1221 /***********************************************************************
1222 * FtpRemoveDirectoryA (WININET.@)
1224 * Remove a directory on the ftp server
1226 * RETURNS
1227 * TRUE on success
1228 * FALSE on failure
1231 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1233 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1234 LPWININETAPPINFOA hIC = NULL;
1236 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1238 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1239 return FALSE;
1242 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1243 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1245 WORKREQUEST workRequest;
1247 workRequest.asyncall = FTPREMOVEDIRECTORYA;
1248 workRequest.HFTPSESSION = (DWORD)hFtpSession;
1249 workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
1251 return INTERNET_AsyncCall(&workRequest);
1253 else
1255 return FTP_FtpRemoveDirectoryA(hFtpSession, lpszDirectory);
1260 /***********************************************************************
1261 * FTP_FtpRemoveDirectoryA (Internal)
1263 * Remove a directory on the ftp server
1265 * RETURNS
1266 * TRUE on success
1267 * FALSE on failure
1270 BOOL FTP_FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1272 INT nResCode;
1273 BOOL bSuccess = FALSE;
1274 LPWININETAPPINFOA hIC = NULL;
1275 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1277 TRACE("\n");
1278 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1280 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1281 return FALSE;
1284 /* Clear any error information */
1285 INTERNET_SetLastError(0);
1287 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1288 goto lend;
1290 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1291 MAX_REPLY_LEN, 0, 0, 0);
1292 if (nResCode)
1294 if (nResCode == 250)
1295 bSuccess = TRUE;
1296 else
1297 FTP_SetResponseError(nResCode);
1300 lend:
1301 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1302 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1304 INTERNET_ASYNC_RESULT iar;
1306 iar.dwResult = (DWORD)bSuccess;
1307 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1308 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1309 &iar, sizeof(INTERNET_ASYNC_RESULT));
1312 return bSuccess;
1316 /***********************************************************************
1317 * FtpRenameFileA (WININET.@)
1319 * Rename a file on the ftp server
1321 * RETURNS
1322 * TRUE on success
1323 * FALSE on failure
1326 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1328 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1329 LPWININETAPPINFOA hIC = NULL;
1331 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1333 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1334 return FALSE;
1337 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1338 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1340 WORKREQUEST workRequest;
1342 workRequest.asyncall = FTPRENAMEFILEA;
1343 workRequest.HFTPSESSION = (DWORD)hFtpSession;
1344 workRequest.LPSZSRCFILE = (DWORD)FTP_strdup(lpszSrc);
1345 workRequest.LPSZDESTFILE = (DWORD)FTP_strdup(lpszDest);
1347 return INTERNET_AsyncCall(&workRequest);
1349 else
1351 return FTP_FtpRenameFileA(hFtpSession, lpszSrc, lpszDest);
1355 /***********************************************************************
1356 * FTP_FtpRenameFileA (Internal)
1358 * Rename a file on the ftp server
1360 * RETURNS
1361 * TRUE on success
1362 * FALSE on failure
1365 BOOL FTP_FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1367 INT nResCode;
1368 BOOL bSuccess = FALSE;
1369 LPWININETAPPINFOA hIC = NULL;
1370 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1372 TRACE("\n");
1373 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1375 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1376 return FALSE;
1379 /* Clear any error information */
1380 INTERNET_SetLastError(0);
1382 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1383 goto lend;
1385 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1386 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1387 if (nResCode == 350)
1389 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1390 goto lend;
1392 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1393 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1396 if (nResCode == 250)
1397 bSuccess = TRUE;
1398 else
1399 FTP_SetResponseError(nResCode);
1401 lend:
1402 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1403 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1405 INTERNET_ASYNC_RESULT iar;
1407 iar.dwResult = (DWORD)bSuccess;
1408 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1409 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1410 &iar, sizeof(INTERNET_ASYNC_RESULT));
1413 return bSuccess;
1417 /***********************************************************************
1418 * FTP_Connect (internal)
1420 * Connect to a ftp server
1422 * RETURNS
1423 * HINTERNET a session handle on success
1424 * NULL on failure
1428 HINTERNET FTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
1429 INTERNET_PORT nServerPort, LPCSTR lpszUserName,
1430 LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
1432 struct sockaddr_in socketAddr;
1433 struct hostent *phe = NULL;
1434 INT nsocket = -1, sock_namelen;
1435 LPWININETAPPINFOA hIC = NULL;
1436 BOOL bSuccess = FALSE;
1437 LPWININETFTPSESSIONA lpwfs = NULL;
1439 TRACE("0x%08lx Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1440 (ULONG) hInternet, lpszServerName,
1441 nServerPort, lpszUserName, lpszPassword);
1443 if (((LPWININETHANDLEHEADER)hInternet)->htype != WH_HINIT)
1444 goto lerror;
1446 hIC = (LPWININETAPPINFOA) hInternet;
1448 if (NULL == lpszUserName && NULL != lpszPassword)
1450 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_USER_NAME);
1451 goto lerror;
1454 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1455 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1457 if (hIC->lpfnStatusCB)
1458 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1459 (LPSTR) lpszServerName, strlen(lpszServerName));
1461 if (!GetAddress(lpszServerName, nServerPort, &phe, &socketAddr))
1463 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1464 goto lerror;
1467 if (hIC->lpfnStatusCB)
1468 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1469 (LPSTR) lpszServerName, strlen(lpszServerName));
1471 nsocket = socket(AF_INET,SOCK_STREAM,0);
1472 if (nsocket == -1)
1474 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1475 goto lerror;
1478 if (hIC->lpfnStatusCB)
1479 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1480 &socketAddr, sizeof(struct sockaddr_in));
1482 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1484 ERR("Unable to connect (%s)\n", strerror(errno));
1485 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1487 else
1489 TRACE("Connected to server\n");
1490 if (hIC->lpfnStatusCB)
1491 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1492 &socketAddr, sizeof(struct sockaddr_in));
1494 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONA));
1495 if (NULL == lpwfs)
1497 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1498 goto lerror;
1501 lpwfs->hdr.htype = WH_HFTPSESSION;
1502 lpwfs->hdr.dwFlags = dwFlags;
1503 lpwfs->hdr.dwContext = dwContext;
1504 lpwfs->hdr.lpwhparent = (LPWININETHANDLEHEADER)hInternet;
1505 lpwfs->sndSocket = nsocket;
1506 lpwfs->download_in_progress = NULL;
1507 sock_namelen = sizeof(lpwfs->socketAddress);
1508 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1509 lpwfs->phostent = phe;
1511 if (NULL == lpszUserName)
1513 lpwfs->lpszUserName = FTP_strdup("anonymous");
1514 lpwfs->lpszPassword = FTP_strdup("user@server");
1516 else
1518 lpwfs->lpszUserName = FTP_strdup(lpszUserName);
1519 lpwfs->lpszPassword = FTP_strdup(lpszPassword);
1522 if (FTP_ConnectToHost(lpwfs))
1524 if (hIC->lpfnStatusCB)
1526 INTERNET_ASYNC_RESULT iar;
1528 iar.dwResult = (DWORD)lpwfs;
1529 iar.dwError = ERROR_SUCCESS;
1531 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_HANDLE_CREATED,
1532 &iar, sizeof(INTERNET_ASYNC_RESULT));
1534 TRACE("Successfully logged into server\n");
1535 bSuccess = TRUE;
1539 lerror:
1540 if (!bSuccess && nsocket == -1)
1541 close(nsocket);
1543 if (!bSuccess && lpwfs)
1545 HeapFree(GetProcessHeap(), 0, lpwfs);
1546 lpwfs = NULL;
1549 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1551 INTERNET_ASYNC_RESULT iar;
1553 iar.dwResult = (DWORD)lpwfs;
1554 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1555 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1556 &iar, sizeof(INTERNET_ASYNC_RESULT));
1559 return (HINTERNET) lpwfs;
1563 /***********************************************************************
1564 * FTP_ConnectToHost (internal)
1566 * Connect to a ftp server
1568 * RETURNS
1569 * TRUE on success
1570 * NULL on failure
1573 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs)
1575 INT nResCode;
1576 BOOL bSuccess = FALSE;
1578 TRACE("\n");
1579 FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1581 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1582 goto lend;
1584 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1585 MAX_REPLY_LEN, 0, 0, 0);
1586 if (nResCode)
1588 /* Login successful... */
1589 if (nResCode == 230)
1590 bSuccess = TRUE;
1591 /* User name okay, need password... */
1592 else if (nResCode == 331)
1593 bSuccess = FTP_SendPassword(lpwfs);
1594 /* Need account for login... */
1595 else if (nResCode == 332)
1596 bSuccess = FTP_SendAccount(lpwfs);
1597 else
1598 FTP_SetResponseError(nResCode);
1601 TRACE("Returning %d\n", bSuccess);
1602 lend:
1603 return bSuccess;
1607 /***********************************************************************
1608 * FTP_SendCommand (internal)
1610 * Send command to server
1612 * RETURNS
1613 * TRUE on success
1614 * NULL on failure
1617 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1618 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1620 DWORD len;
1621 CHAR *buf;
1622 DWORD nBytesSent = 0;
1623 DWORD nRC = 0;
1624 BOOL bParamHasLen;
1626 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1628 if (lpfnStatusCB)
1629 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1631 bParamHasLen = lpszParam && strlen(lpszParam) > 0;
1632 len = (bParamHasLen ? strlen(lpszParam) : -1) + strlen(szFtpCommands[ftpCmd]) +
1633 strlen(szCRLF)+ 1;
1634 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1636 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1637 return FALSE;
1639 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], bParamHasLen ? " " : "",
1640 bParamHasLen ? lpszParam : "", szCRLF);
1642 TRACE("Sending (%s) len(%ld)\n", buf, len);
1643 while((nBytesSent < len) && (nRC != -1))
1645 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1646 nBytesSent += nRC;
1649 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
1651 if (lpfnStatusCB)
1652 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_REQUEST_SENT,
1653 &nBytesSent, sizeof(DWORD));
1655 TRACE("Sent %ld bytes\n", nBytesSent);
1656 return (nRC != -1);
1660 /***********************************************************************
1661 * FTP_ReceiveResponse (internal)
1663 * Receive response from server
1665 * RETURNS
1666 * Reply code on success
1667 * 0 on failure
1671 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
1672 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1674 DWORD nRecv;
1675 INT rc = 0;
1676 char firstprefix[5];
1677 BOOL multiline = FALSE;
1680 TRACE("socket(%d) \n", nSocket);
1682 if (lpfnStatusCB)
1683 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1685 while(1)
1687 nRecv = dwResponse;
1688 if (!INTERNET_GetNextLine(nSocket, lpszResponse, &nRecv))
1689 goto lerror;
1691 if (nRecv >= 3)
1693 if(!multiline)
1695 if(lpszResponse[3] != '-')
1696 break;
1697 else
1698 { /* Start of multiline repsonse. Loop until we get "nnn " */
1699 multiline = TRUE;
1700 memcpy(firstprefix, lpszResponse, 3);
1701 firstprefix[3] = ' ';
1702 firstprefix[4] = '\0';
1705 else
1707 if(!memcmp(firstprefix, lpszResponse, 4))
1708 break;
1713 if (nRecv >= 3)
1715 rc = atoi(lpszResponse);
1717 if (lpfnStatusCB)
1718 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
1719 &nRecv, sizeof(DWORD));
1722 lerror:
1723 TRACE("return %d\n", rc);
1724 return rc;
1728 /***********************************************************************
1729 * FTP_SendPassword (internal)
1731 * Send password to ftp server
1733 * RETURNS
1734 * TRUE on success
1735 * NULL on failure
1738 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs)
1740 INT nResCode;
1741 BOOL bSuccess = FALSE;
1743 TRACE("\n");
1744 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
1745 goto lend;
1747 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1748 MAX_REPLY_LEN, 0, 0, 0);
1749 if (nResCode)
1751 TRACE("Received reply code %d\n", nResCode);
1752 /* Login successful... */
1753 if (nResCode == 230)
1754 bSuccess = TRUE;
1755 /* Command not implemented, superfluous at the server site... */
1756 /* Need account for login... */
1757 else if (nResCode == 332)
1758 bSuccess = FTP_SendAccount(lpwfs);
1759 else
1760 FTP_SetResponseError(nResCode);
1763 lend:
1764 TRACE("Returning %d\n", bSuccess);
1765 return bSuccess;
1769 /***********************************************************************
1770 * FTP_SendAccount (internal)
1774 * RETURNS
1775 * TRUE on success
1776 * FALSE on failure
1779 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs)
1781 INT nResCode;
1782 BOOL bSuccess = FALSE;
1784 TRACE("\n");
1785 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, NOACCOUNT, 0, 0, 0))
1786 goto lend;
1788 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1789 MAX_REPLY_LEN, 0, 0, 0);
1790 if (nResCode)
1791 bSuccess = TRUE;
1792 else
1793 FTP_SetResponseError(nResCode);
1795 lend:
1796 return bSuccess;
1800 /***********************************************************************
1801 * FTP_SendStore (internal)
1803 * Send request to upload file to ftp server
1805 * RETURNS
1806 * TRUE on success
1807 * FALSE on failure
1810 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
1812 INT nResCode;
1813 BOOL bSuccess = FALSE;
1815 TRACE("\n");
1816 if (!FTP_InitListenSocket(lpwfs))
1817 goto lend;
1819 if (!FTP_SendType(lpwfs, dwType))
1820 goto lend;
1822 if (!FTP_SendPortOrPasv(lpwfs))
1823 goto lend;
1825 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
1826 goto lend;
1827 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1828 MAX_REPLY_LEN, 0, 0, 0);
1829 if (nResCode)
1831 if (nResCode == 150)
1832 bSuccess = TRUE;
1833 else
1834 FTP_SetResponseError(nResCode);
1837 lend:
1838 if (!bSuccess && lpwfs->lstnSocket != -1)
1840 close(lpwfs->lstnSocket);
1841 lpwfs->lstnSocket = -1;
1844 return bSuccess;
1848 /***********************************************************************
1849 * FTP_InitListenSocket (internal)
1851 * Create a socket to listen for server response
1853 * RETURNS
1854 * TRUE on success
1855 * FALSE on failure
1858 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs)
1860 BOOL bSuccess = FALSE;
1861 size_t namelen = sizeof(struct sockaddr_in);
1863 TRACE("\n");
1865 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
1866 if (lpwfs->lstnSocket == -1)
1868 TRACE("Unable to create listening socket\n");
1869 goto lend;
1872 /* We obtain our ip addr from the name of the command channel socket */
1873 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
1875 /* and get the system to assign us a port */
1876 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
1878 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
1880 TRACE("Unable to bind socket\n");
1881 goto lend;
1884 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
1886 TRACE("listen failed\n");
1887 goto lend;
1890 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
1891 bSuccess = TRUE;
1893 lend:
1894 if (!bSuccess && lpwfs->lstnSocket == -1)
1896 close(lpwfs->lstnSocket);
1897 lpwfs->lstnSocket = -1;
1900 return bSuccess;
1904 /***********************************************************************
1905 * FTP_SendType (internal)
1907 * Tell server type of data being transferred
1909 * RETURNS
1910 * TRUE on success
1911 * FALSE on failure
1913 * W98SE doesn't cache the type that's currently set
1914 * (i.e. it sends it always),
1915 * so we probably don't want to do that either.
1917 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType)
1919 INT nResCode;
1920 CHAR type[2] = { "I" };
1921 BOOL bSuccess = FALSE;
1923 TRACE("\n");
1924 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
1925 *type = 'A';
1927 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
1928 goto lend;
1930 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1931 MAX_REPLY_LEN, 0, 0, 0)/100;
1932 if (nResCode)
1934 if (nResCode == 2)
1935 bSuccess = TRUE;
1936 else
1937 FTP_SetResponseError(nResCode);
1940 lend:
1941 return bSuccess;
1944 /***********************************************************************
1945 * FTP_GetFileSize (internal)
1947 * Retrieves from the server the size of the given file
1949 * RETURNS
1950 * TRUE on success
1951 * FALSE on failure
1954 BOOL FTP_GetFileSize(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD *dwSize)
1956 INT nResCode;
1957 BOOL bSuccess = FALSE;
1959 TRACE("\n");
1961 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
1962 goto lend;
1964 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1965 MAX_REPLY_LEN, 0, 0, 0);
1966 if (nResCode)
1968 if (nResCode == 213) {
1969 /* Now parses the output to get the actual file size */
1970 int i;
1971 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
1973 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
1974 if (lpszResponseBuffer[i] == '\0') return FALSE;
1975 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
1977 bSuccess = TRUE;
1978 } else {
1979 FTP_SetResponseError(nResCode);
1983 lend:
1984 return bSuccess;
1988 /***********************************************************************
1989 * FTP_SendPort (internal)
1991 * Tell server which port to use
1993 * RETURNS
1994 * TRUE on success
1995 * FALSE on failure
1998 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs)
2000 INT nResCode;
2001 CHAR szIPAddress[64];
2002 BOOL bSuccess = FALSE;
2003 TRACE("\n");
2005 sprintf(szIPAddress, "%d,%d,%d,%d,%d,%d",
2006 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2007 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2008 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2009 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2010 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2011 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2013 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2014 goto lend;
2016 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2017 MAX_REPLY_LEN,0, 0, 0);
2018 if (nResCode)
2020 if (nResCode == 200)
2021 bSuccess = TRUE;
2022 else
2023 FTP_SetResponseError(nResCode);
2026 lend:
2027 return bSuccess;
2031 /***********************************************************************
2032 * FTP_DoPassive (internal)
2034 * Tell server that we want to do passive transfers
2035 * and connect data socket
2037 * RETURNS
2038 * TRUE on success
2039 * FALSE on failure
2042 BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs)
2044 INT nResCode;
2045 BOOL bSuccess = FALSE;
2047 TRACE("\n");
2048 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2049 goto lend;
2051 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2052 MAX_REPLY_LEN,0, 0, 0);
2053 if (nResCode)
2055 if (nResCode == 227)
2057 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2058 LPSTR p;
2059 int f[6];
2060 int i;
2061 char *pAddr, *pPort;
2062 INT nsocket = -1;
2063 struct sockaddr_in dataSocketAddress;
2065 p = lpszResponseBuffer+4; /* skip status code */
2067 /* do a very strict check; we can improve that later. */
2069 if (strncmp(p, "Entering Passive Mode", 21))
2071 ERR("unknown response '%.*s', aborting\n", 21, p);
2072 goto lend;
2074 p += 21; /* skip string */
2075 if ((*p++ != ' ') || (*p++ != '('))
2077 ERR("unknown response format, aborting\n");
2078 goto lend;
2081 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2082 &f[4], &f[5]) != 6)
2084 ERR("unknown response address format '%s', aborting\n", p);
2085 goto lend;
2087 for (i=0; i < 6; i++)
2088 f[i] = f[i] & 0xff;
2090 dataSocketAddress = lpwfs->socketAddress;
2091 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2092 pPort = (char *)&(dataSocketAddress.sin_port);
2093 pAddr[0] = f[0];
2094 pAddr[1] = f[1];
2095 pAddr[2] = f[2];
2096 pAddr[3] = f[3];
2097 pPort[0] = f[4];
2098 pPort[1] = f[5];
2100 nsocket = socket(AF_INET,SOCK_STREAM,0);
2101 if (nsocket == -1)
2102 goto lend;
2104 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2106 ERR("can't connect passive FTP data port.\n");
2107 goto lend;
2109 lpwfs->pasvSocket = nsocket;
2110 bSuccess = TRUE;
2112 else
2113 FTP_SetResponseError(nResCode);
2116 lend:
2117 return bSuccess;
2121 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs)
2123 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2125 if (!FTP_DoPassive(lpwfs))
2126 return FALSE;
2128 else
2130 if (!FTP_SendPort(lpwfs))
2131 return FALSE;
2133 return TRUE;
2137 /***********************************************************************
2138 * FTP_GetDataSocket (internal)
2140 * Either accepts an incoming data socket connection from the server
2141 * or just returns the already opened socket after a PASV command
2142 * in case of passive FTP.
2145 * RETURNS
2146 * TRUE on success
2147 * FALSE on failure
2150 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket)
2152 struct sockaddr_in saddr;
2153 size_t addrlen = sizeof(struct sockaddr);
2155 TRACE("\n");
2156 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2158 *nDataSocket = lpwfs->pasvSocket;
2160 else
2162 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2163 close(lpwfs->lstnSocket);
2164 lpwfs->lstnSocket = -1;
2166 return *nDataSocket != -1;
2170 /***********************************************************************
2171 * FTP_SendData (internal)
2173 * Send data to the server
2175 * RETURNS
2176 * TRUE on success
2177 * FALSE on failure
2180 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile)
2182 BY_HANDLE_FILE_INFORMATION fi;
2183 DWORD nBytesRead = 0;
2184 DWORD nBytesSent = 0;
2185 DWORD nTotalSent = 0;
2186 DWORD nBytesToSend, nLen, nRC = 1;
2187 time_t s_long_time, e_long_time;
2188 LONG nSeconds;
2189 CHAR *lpszBuffer;
2191 TRACE("\n");
2192 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2193 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2195 /* Get the size of the file. */
2196 GetFileInformationByHandle(hFile, &fi);
2197 time(&s_long_time);
2201 nBytesToSend = nBytesRead - nBytesSent;
2203 if (nBytesToSend <= 0)
2205 /* Read data from file. */
2206 nBytesSent = 0;
2207 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2208 ERR("Failed reading from file\n");
2210 if (nBytesRead > 0)
2211 nBytesToSend = nBytesRead;
2212 else
2213 break;
2216 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2217 DATA_PACKET_SIZE : nBytesToSend;
2218 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2220 if (nRC != -1)
2222 nBytesSent += nRC;
2223 nTotalSent += nRC;
2226 /* Do some computation to display the status. */
2227 time(&e_long_time);
2228 nSeconds = e_long_time - s_long_time;
2229 if( nSeconds / 60 > 0 )
2231 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
2232 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2233 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2235 else
2237 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
2238 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2239 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2241 } while (nRC != -1);
2243 TRACE("file transfer complete!\n");
2245 if(lpszBuffer != NULL)
2246 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2248 return nTotalSent;
2252 /***********************************************************************
2253 * FTP_SendRetrieve (internal)
2255 * Send request to retrieve a file
2257 * RETURNS
2258 * Number of bytes to be received on success
2259 * 0 on failure
2262 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
2264 INT nResCode;
2265 DWORD nResult = 0;
2267 TRACE("\n");
2268 if (!FTP_InitListenSocket(lpwfs))
2269 goto lend;
2271 if (!FTP_SendType(lpwfs, dwType))
2272 goto lend;
2274 if (!FTP_SendPortOrPasv(lpwfs))
2275 goto lend;
2277 if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2278 goto lend;
2280 TRACE("Waiting to receive %ld bytes\n", nResult);
2282 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2283 goto lend;
2285 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2286 MAX_REPLY_LEN, 0, 0, 0);
2287 if ((nResCode != 125) && (nResCode != 150)) {
2288 /* That means that we got an error getting the file. */
2289 nResult = 0;
2292 lend:
2293 if (0 == nResult && lpwfs->lstnSocket != -1)
2295 close(lpwfs->lstnSocket);
2296 lpwfs->lstnSocket = -1;
2299 return nResult;
2303 /***********************************************************************
2304 * FTP_RetrieveData (internal)
2306 * Retrieve data from server
2308 * RETURNS
2309 * TRUE on success
2310 * FALSE on failure
2313 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2315 DWORD nBytesWritten;
2316 DWORD nBytesReceived = 0;
2317 INT nRC = 0;
2318 CHAR *lpszBuffer;
2320 TRACE("\n");
2322 if (INVALID_HANDLE_VALUE == hFile)
2323 return FALSE;
2325 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2326 if (NULL == lpszBuffer)
2328 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2329 return FALSE;
2332 while (nBytesReceived < nBytes && nRC != -1)
2334 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2335 if (nRC != -1)
2337 /* other side closed socket. */
2338 if (nRC == 0)
2339 goto recv_end;
2340 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2341 nBytesReceived += nRC;
2344 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
2345 nBytesReceived * 100 / nBytes);
2348 TRACE("Data transfer complete\n");
2349 if (NULL != lpszBuffer)
2350 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2352 recv_end:
2353 return (nRC != -1);
2357 /***********************************************************************
2358 * FTP_CloseSessionHandle (internal)
2360 * Deallocate session handle
2362 * RETURNS
2363 * TRUE on success
2364 * FALSE on failure
2367 BOOL FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs)
2369 TRACE("\n");
2371 if (lpwfs->download_in_progress != NULL)
2372 lpwfs->download_in_progress->session_deleted = TRUE;
2374 if (lpwfs->sndSocket != -1)
2375 close(lpwfs->sndSocket);
2377 if (lpwfs->lstnSocket != -1)
2378 close(lpwfs->lstnSocket);
2380 if (lpwfs->lpszPassword)
2381 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2383 if (lpwfs->lpszUserName)
2384 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2386 HeapFree(GetProcessHeap(), 0, lpwfs);
2388 return TRUE;
2392 /***********************************************************************
2393 * FTP_CloseFindNextHandle (internal)
2395 * Deallocate session handle
2397 * RETURNS
2398 * TRUE on success
2399 * FALSE on failure
2402 BOOL FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn)
2404 INT i;
2406 TRACE("\n");
2408 for (i = 0; i < lpwfn->size; i++)
2410 if (NULL != lpwfn->lpafp[i].lpszName)
2411 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2414 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2415 HeapFree(GetProcessHeap(), 0, lpwfn);
2417 return TRUE;
2420 /***********************************************************************
2421 * FTP_CloseFileTransferHandle (internal)
2423 * Closes the file transfer handle. This also 'cleans' the data queue of
2424 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2426 * RETURNS
2427 * TRUE on success
2428 * FALSE on failure
2431 BOOL FTP_CloseFileTransferHandle(LPWININETFILE lpwh)
2433 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) lpwh->hdr.lpwhparent;
2434 INT nResCode;
2436 TRACE("\n");
2438 if (!lpwh->session_deleted)
2439 lpwfs->download_in_progress = NULL;
2441 /* This just serves to flush the control socket of any spurrious lines written
2442 to it (like '226 Transfer complete.').
2444 Wonder what to do if the server sends us an error code though...
2446 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2447 MAX_REPLY_LEN, 0, 0, 0);
2449 if (lpwh->nDataSocket != -1)
2450 close(lpwh->nDataSocket);
2452 HeapFree(GetProcessHeap(), 0, lpwh);
2454 return TRUE;
2457 /***********************************************************************
2458 * FTP_ReceiveFileList (internal)
2460 * Read file list from server
2462 * RETURNS
2463 * Handle to file list on success
2464 * NULL on failure
2467 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
2468 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext)
2470 DWORD dwSize = 0;
2471 LPFILEPROPERTIESA lpafp = NULL;
2472 LPWININETFINDNEXTA lpwfn = NULL;
2474 TRACE("\n");
2476 if (FTP_ParseDirectory(lpwfs, nSocket, &lpafp, &dwSize))
2478 FTP_ConvertFileProp(lpafp, lpFindFileData);
2480 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTA));
2481 if (NULL != lpwfn)
2483 lpwfn->hdr.htype = WH_HFINDNEXT;
2484 lpwfn->hdr.lpwhparent = (LPWININETHANDLEHEADER)lpwfs;
2485 lpwfn->hdr.dwContext = dwContext;
2486 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2487 lpwfn->size = dwSize;
2488 lpwfn->lpafp = lpafp;
2492 TRACE("Matched %ld files\n", dwSize);
2493 return (HINTERNET)lpwfn;
2497 /***********************************************************************
2498 * FTP_ConvertFileProp (internal)
2500 * Converts FILEPROPERTIESA struct to WIN32_FIND_DATAA
2502 * RETURNS
2503 * TRUE on success
2504 * FALSE on failure
2507 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESA lpafp, LPWIN32_FIND_DATAA lpFindFileData)
2509 BOOL bSuccess = FALSE;
2511 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2513 if (lpafp)
2515 /* Convert 'Unix' time to Windows time */
2516 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
2517 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
2519 /* Not all fields are filled in */
2520 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2521 lpFindFileData->nFileSizeLow = lpafp->nSize;
2523 if (lpafp->bIsDirectory)
2524 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2526 if (lpafp->lpszName)
2527 strncpy(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2529 bSuccess = TRUE;
2532 return bSuccess;
2536 /***********************************************************************
2537 * FTP_ParseDirectory (internal)
2539 * Parse string of directory information
2541 * RETURNS
2542 * TRUE on success
2543 * FALSE on failure
2545 * FIXME: - This function needs serious clea-up
2546 * - We should consider both UNIX and NT list formats
2548 #define MAX_MONTH_LEN 10
2549 #define MIN_LEN_DIR_ENTRY 15
2551 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp)
2554 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2556 * For instance:
2557 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2559 CHAR* pszMinutes;
2560 CHAR* pszHour;
2561 time_t aTime;
2562 struct tm* apTM;
2563 CHAR pszMonth[MAX_MONTH_LEN];
2564 CHAR* pszMatch;
2565 BOOL bSuccess = TRUE;
2566 DWORD nBufLen = MAX_REPLY_LEN;
2567 LPFILEPROPERTIESA curFileProp = NULL;
2568 CHAR* pszLine = NULL;
2569 CHAR* pszToken = NULL;
2570 INT nTokenToSkip = 3;
2571 INT nCount = 0;
2572 INT nSeconds = 0;
2573 INT nMinutes = 0;
2574 INT nHour = 0;
2575 INT nDay = 0;
2576 INT nMonth = 0;
2577 INT nYear = 0;
2578 INT sizeFilePropArray = 20;
2579 INT indexFilePropArray = 0;
2581 TRACE("\n");
2583 /* Allocate intial file properties array */
2584 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESA)*(sizeFilePropArray));
2585 if (NULL == lpafp)
2587 bSuccess = FALSE;
2588 goto lend;
2591 while ((pszLine = INTERNET_GetNextLine(nSocket, INTERNET_GetResponseBuffer(), &nBufLen)) != NULL)
2593 if (sizeFilePropArray <= indexFilePropArray)
2595 LPFILEPROPERTIESA tmpafp;
2597 sizeFilePropArray *= 2;
2598 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
2599 sizeof(FILEPROPERTIESA)*sizeFilePropArray);
2600 if (NULL == tmpafp)
2602 bSuccess = FALSE;
2603 goto lend;
2606 *lpafp = tmpafp;
2609 curFileProp = &((*lpafp)[indexFilePropArray]);
2611 /* First Parse the permissions. */
2612 pszToken = strtok(pszLine, " \t" );
2614 /* HACK! If this is not a file listing skip the line */
2615 if (!pszToken || nBufLen <= MIN_LEN_DIR_ENTRY)
2617 nBufLen = MAX_REPLY_LEN;
2618 continue;
2620 if (10 == strlen(pszToken)) {
2621 /* Unix way of parsing ... */
2622 FTP_ParsePermission(pszToken, curFileProp);
2624 nTokenToSkip = 3;
2625 nCount = 0;
2626 do {
2627 pszToken = strtok( NULL, " \t" );
2628 nCount++;
2629 } while( nCount <= nTokenToSkip );
2631 /* Store the size of the file in the param list. */
2632 TRACE("nSize-> %s\n", pszToken);
2633 if (pszToken != NULL)
2634 curFileProp->nSize = atol(pszToken);
2636 /* Parse last modified time. */
2637 nSeconds = 0;
2638 nMinutes = 0;
2639 nHour = 0;
2640 nDay = 0;
2641 nMonth = 0;
2642 nYear = 0;
2644 pszToken = strtok( NULL, " \t" );
2645 strncpy(pszMonth, pszToken, MAX_MONTH_LEN);
2646 CharUpperA(pszMonth);
2647 pszMatch = strstr(szMonths, pszMonth);
2648 if( pszMatch != NULL )
2649 nMonth = (pszMatch - szMonths) / 3;
2651 pszToken = strtok(NULL, " \t");
2652 TRACE("nDay -> %s\n", pszToken);
2653 if (pszToken != NULL)
2654 nDay = atoi(pszToken);
2656 pszToken = strtok(NULL, " \t");
2657 pszMinutes = strchr(pszToken, ':');
2658 if( pszMinutes != NULL ) {
2659 pszMinutes++;
2660 nMinutes = atoi(pszMinutes);
2661 pszHour = pszMinutes - 3;
2662 if (pszHour != NULL)
2663 nHour = atoi(pszHour);
2664 time(&aTime);
2665 apTM = localtime( &aTime );
2666 nYear = apTM->tm_year;
2667 } else {
2668 nYear = atoi(pszToken);
2669 nYear -= 1900;
2670 nHour = 12;
2673 curFileProp->tmLastModified.tm_sec = nSeconds;
2674 curFileProp->tmLastModified.tm_min = nMinutes;
2675 curFileProp->tmLastModified.tm_hour = nHour;
2676 curFileProp->tmLastModified.tm_mday = nDay;
2677 curFileProp->tmLastModified.tm_mon = nMonth;
2678 curFileProp->tmLastModified.tm_year = nYear;
2680 pszToken = strtok(NULL, " \t");
2681 if(pszToken != NULL) {
2682 curFileProp->lpszName = FTP_strdup(pszToken);
2683 TRACE(": %s\n", curFileProp->lpszName);
2686 nBufLen = MAX_REPLY_LEN;
2687 indexFilePropArray++;
2688 } else if (8 == strlen(pszToken)) {
2689 /* NT way of parsing ... :
2691 07-13-03 08:55PM <DIR> sakpatch
2692 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
2695 curFileProp->permissions = 0xFFFF; /* No idea, put full permission :-) */
2697 sscanf(pszToken, "%d-%d-%d",
2698 &curFileProp->tmLastModified.tm_mon,
2699 &curFileProp->tmLastModified.tm_mday,
2700 &curFileProp->tmLastModified.tm_year);
2702 /* Hacky and bad Y2K protection :-) */
2703 if (curFileProp->tmLastModified.tm_year < 70)
2704 curFileProp->tmLastModified.tm_year += 100;
2706 pszToken = strtok(NULL, " \t");
2707 if (pszToken == NULL) {
2708 nBufLen = MAX_REPLY_LEN;
2709 continue;
2711 sscanf(pszToken, "%d:%d",
2712 &curFileProp->tmLastModified.tm_hour,
2713 &curFileProp->tmLastModified.tm_min);
2714 if ((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
2715 curFileProp->tmLastModified.tm_hour += 12;
2717 curFileProp->tmLastModified.tm_sec = 0;
2719 TRACE("Mod time: %2d:%2d:%2d %2d/%2d/%2d\n",
2720 curFileProp->tmLastModified.tm_hour, curFileProp->tmLastModified.tm_min, curFileProp->tmLastModified.tm_sec,
2721 (curFileProp->tmLastModified.tm_year >= 100) ? curFileProp->tmLastModified.tm_year - 100 : curFileProp->tmLastModified.tm_year,
2722 curFileProp->tmLastModified.tm_mon, curFileProp->tmLastModified.tm_mday);
2724 pszToken = strtok(NULL, " \t");
2725 if (pszToken == NULL) {
2726 nBufLen = MAX_REPLY_LEN;
2727 continue;
2729 if (!strcasecmp(pszToken, "<DIR>")) {
2730 curFileProp->bIsDirectory = TRUE;
2731 TRACE("Is directory\n");
2732 } else {
2733 curFileProp->bIsDirectory = FALSE;
2734 curFileProp->nSize = atol(pszToken);
2735 TRACE("nSize: %ld\n", curFileProp->nSize);
2738 pszToken = strtok(NULL, " \t");
2739 if (pszToken == NULL) {
2740 nBufLen = MAX_REPLY_LEN;
2741 continue;
2743 curFileProp->lpszName = FTP_strdup(pszToken);
2744 TRACE("Name: %s\n", curFileProp->lpszName);
2746 nBufLen = MAX_REPLY_LEN;
2747 indexFilePropArray++;
2748 } else {
2749 nBufLen = MAX_REPLY_LEN;
2753 if (bSuccess && indexFilePropArray)
2755 if (indexFilePropArray < sizeFilePropArray - 1)
2757 LPFILEPROPERTIESA tmpafp;
2759 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
2760 sizeof(FILEPROPERTIESA)*indexFilePropArray);
2761 if (NULL == tmpafp)
2762 *lpafp = tmpafp;
2764 *dwfp = indexFilePropArray;
2766 else
2768 HeapFree(GetProcessHeap(), 0, *lpafp);
2769 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2770 bSuccess = FALSE;
2773 lend:
2774 return bSuccess;
2778 /***********************************************************************
2779 * FTP_ParsePermission (internal)
2781 * Parse permission string of directory information
2783 * RETURNS
2784 * TRUE on success
2785 * FALSE on failure
2788 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp)
2790 BOOL bSuccess = TRUE;
2791 unsigned short nPermission = 0;
2792 INT nPos = 1;
2793 INT nLast = 9;
2795 TRACE("\n");
2796 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
2798 bSuccess = FALSE;
2799 return bSuccess;
2802 lpfp->bIsDirectory = (*lpszPermission == 'd');
2805 switch (nPos)
2807 case 1:
2808 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
2809 break;
2810 case 2:
2811 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
2812 break;
2813 case 3:
2814 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
2815 break;
2816 case 4:
2817 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
2818 break;
2819 case 5:
2820 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
2821 break;
2822 case 6:
2823 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
2824 break;
2825 case 7:
2826 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
2827 break;
2828 case 8:
2829 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
2830 break;
2831 case 9:
2832 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
2833 break;
2835 nPos++;
2836 }while (nPos <= nLast);
2838 lpfp->permissions = nPermission;
2839 return bSuccess;
2843 /***********************************************************************
2844 * FTP_SetResponseError (internal)
2846 * Set the appropriate error code for a given response from the server
2848 * RETURNS
2851 DWORD FTP_SetResponseError(DWORD dwResponse)
2853 DWORD dwCode = 0;
2855 switch(dwResponse)
2857 case 421: /* Service not available - Server may be shutting down. */
2858 dwCode = ERROR_INTERNET_TIMEOUT;
2859 break;
2861 case 425: /* Cannot open data connection. */
2862 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
2863 break;
2865 case 426: /* Connection closed, transer aborted. */
2866 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
2867 break;
2869 case 500: /* Syntax error. Command unrecognized. */
2870 case 501: /* Syntax error. Error in parameters or arguments. */
2871 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
2872 break;
2874 case 530: /* Not logged in. Login incorrect. */
2875 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
2876 break;
2878 case 550: /* File action not taken. File not found or no access. */
2879 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
2880 break;
2882 case 450: /* File action not taken. File may be busy. */
2883 case 451: /* Action aborted. Server error. */
2884 case 452: /* Action not taken. Insufficient storage space on server. */
2885 case 502: /* Command not implemented. */
2886 case 503: /* Bad sequence of command. */
2887 case 504: /* Command not implemented for that parameter. */
2888 case 532: /* Need account for storing files */
2889 case 551: /* Requested action aborted. Page type unknown */
2890 case 552: /* Action aborted. Exceeded storage allocation */
2891 case 553: /* Action not taken. File name not allowed. */
2893 default:
2894 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
2895 break;
2898 INTERNET_SetLastError(dwCode);
2899 return dwCode;