Prevent memory leak and superfluous status notifications.
[wine/wine-kai.git] / dlls / wininet / ftp.c
blob1cd383a5fc229ff5849e8cd39ef1042d79544ce4
1 /*
2 * WININET - Ftp implementation
4 * Copyright 1999 Corel Corporation
5 * Copyright 2004 Mike McCormack for CodeWeavers
7 * Ulrich Czekalla
8 * Noureddine Jemmali
10 * Copyright 2000 Andreas Mohr
11 * Copyright 2002 Jaco Greeff
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "config.h"
29 #include "wine/port.h"
31 #include <errno.h>
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/types.h>
37 #ifdef HAVE_SYS_SOCKET_H
38 # include <sys/socket.h>
39 #endif
40 #ifdef HAVE_UNISTD_H
41 # include <unistd.h>
42 #endif
43 #include <time.h>
45 #include "windef.h"
46 #include "winbase.h"
47 #include "wingdi.h"
48 #include "winuser.h"
49 #include "wininet.h"
50 #include "winnls.h"
51 #include "winerror.h"
52 #include "winreg.h"
53 #include "winternl.h"
55 #include "wine/debug.h"
56 #include "internet.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
60 #define NOACCOUNT "noaccount"
61 #define DATA_PACKET_SIZE 0x2000
62 #define szCRLF "\r\n"
63 #define MAX_BACKLOG 5
65 typedef enum {
66 /* FTP commands with arguments. */
67 FTP_CMD_ACCT,
68 FTP_CMD_CWD,
69 FTP_CMD_DELE,
70 FTP_CMD_MKD,
71 FTP_CMD_PASS,
72 FTP_CMD_PORT,
73 FTP_CMD_RETR,
74 FTP_CMD_RMD,
75 FTP_CMD_RNFR,
76 FTP_CMD_RNTO,
77 FTP_CMD_STOR,
78 FTP_CMD_TYPE,
79 FTP_CMD_USER,
80 FTP_CMD_SIZE,
82 /* FTP commands without arguments. */
83 FTP_CMD_ABOR,
84 FTP_CMD_LIST,
85 FTP_CMD_NLST,
86 FTP_CMD_PASV,
87 FTP_CMD_PWD,
88 FTP_CMD_QUIT,
89 } FTP_COMMAND;
91 static const CHAR *szFtpCommands[] = {
92 "ACCT",
93 "CWD",
94 "DELE",
95 "MKD",
96 "PASS",
97 "PORT",
98 "RETR",
99 "RMD",
100 "RNFR",
101 "RNTO",
102 "STOR",
103 "TYPE",
104 "USER",
105 "SIZE",
106 "ABOR",
107 "LIST",
108 "NLST",
109 "PASV",
110 "PWD",
111 "QUIT",
114 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
116 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
117 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
118 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
119 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket);
120 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile);
121 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
122 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
123 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
124 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile);
125 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs);
126 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs);
127 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs);
128 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs);
129 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType);
130 BOOL FTP_GetFileSize(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD *dwSize);
131 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs);
132 BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs);
133 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs);
134 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp);
135 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp);
136 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
137 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext);
138 DWORD FTP_SetResponseError(DWORD dwResponse);
140 inline static LPSTR FTP_strdup( LPCSTR str )
142 LPSTR ret = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
143 if (ret) strcpy( ret, str );
144 return ret;
147 inline static LPSTR FTP_strdup_WtoA( LPCWSTR str )
149 int len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
150 LPSTR ret = HeapAlloc( GetProcessHeap(), 0, len );
151 if (ret)
152 WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL);
153 return ret;
156 /***********************************************************************
157 * FtpPutFileA (WININET.@)
159 * Uploads a file to the FTP server
161 * RETURNS
162 * TRUE on success
163 * FALSE on failure
166 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
167 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
169 LPWININETFTPSESSIONA lpwfs;
170 LPWININETAPPINFOW hIC = NULL;
172 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hConnect );
173 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
175 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
176 return FALSE;
179 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
180 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
182 WORKREQUEST workRequest;
183 struct WORKREQ_FTPPUTFILEA *req = &workRequest.u.FtpPutFileA;
185 workRequest.asyncall = FTPPUTFILEA;
186 workRequest.handle = hConnect;
187 req->lpszLocalFile = FTP_strdup(lpszLocalFile);
188 req->lpszNewRemoteFile = FTP_strdup(lpszNewRemoteFile);
189 req->dwFlags = dwFlags;
190 req->dwContext = dwContext;
192 return INTERNET_AsyncCall(&workRequest);
194 else
196 return FTP_FtpPutFileA(hConnect, lpszLocalFile,
197 lpszNewRemoteFile, dwFlags, dwContext);
201 /***********************************************************************
202 * FTP_FtpPutFileA (Internal)
204 * Uploads a file to the FTP server
206 * RETURNS
207 * TRUE on success
208 * FALSE on failure
211 BOOL WINAPI FTP_FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
212 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
214 HANDLE hFile = NULL;
215 BOOL bSuccess = FALSE;
216 LPWININETAPPINFOW hIC = NULL;
217 LPWININETFTPSESSIONA lpwfs;
218 INT nResCode;
220 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", lpszLocalFile, lpszNewRemoteFile);
222 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hConnect );
223 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
225 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
226 return FALSE;
229 /* Clear any error information */
230 INTERNET_SetLastError(0);
232 /* Open file to be uploaded */
233 if (INVALID_HANDLE_VALUE ==
234 (hFile = CreateFileA(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
236 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND);
237 goto lend;
240 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
241 if (hIC->lpfnStatusCB)
242 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
244 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
246 INT nDataSocket;
248 /* Get data socket to server */
249 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
251 FTP_SendData(lpwfs, nDataSocket, hFile);
252 close(nDataSocket);
253 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
254 MAX_REPLY_LEN, 0, 0, 0);
255 if (nResCode)
257 if (nResCode == 226)
258 bSuccess = TRUE;
259 else
260 FTP_SetResponseError(nResCode);
265 lend:
266 if (lpwfs->lstnSocket != -1)
267 close(lpwfs->lstnSocket);
269 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
271 INTERNET_ASYNC_RESULT iar;
273 iar.dwResult = (DWORD)bSuccess;
274 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
275 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
276 &iar, sizeof(INTERNET_ASYNC_RESULT));
279 if (hFile)
280 CloseHandle(hFile);
282 return bSuccess;
286 /***********************************************************************
287 * FtpSetCurrentDirectoryA (WININET.@)
289 * Change the working directory on the FTP server
291 * RETURNS
292 * TRUE on success
293 * FALSE on failure
296 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
298 LPWININETFTPSESSIONA lpwfs;
299 LPWININETAPPINFOW hIC = NULL;
301 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hConnect );
302 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
304 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
305 return FALSE;
308 TRACE("lpszDirectory(%s)\n", lpszDirectory);
310 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
311 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
313 WORKREQUEST workRequest;
314 struct WORKREQ_FTPSETCURRENTDIRECTORYA *req;
316 workRequest.asyncall = FTPSETCURRENTDIRECTORYA;
317 workRequest.handle = hConnect;
318 req = &workRequest.u.FtpSetCurrentDirectoryA;
319 req->lpszDirectory = FTP_strdup(lpszDirectory);
321 return INTERNET_AsyncCall(&workRequest);
323 else
325 return FTP_FtpSetCurrentDirectoryA(hConnect, lpszDirectory);
330 /***********************************************************************
331 * FtpSetCurrentDirectoryW (WININET.@)
333 * Change the working directory on the FTP server
335 * RETURNS
336 * TRUE on success
337 * FALSE on failure
340 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
342 CHAR *szDir;
343 INT len;
344 BOOL rc;
346 len = WideCharToMultiByte(CP_ACP, 0, lpszDirectory, -1, NULL, 0, NULL, NULL);
347 szDir = HeapAlloc(GetProcessHeap(), 0, len);
348 if(!szDir)
349 return FALSE;
350 WideCharToMultiByte(CP_ACP, 0, lpszDirectory, -1, szDir, len, NULL, NULL);
351 rc = FtpSetCurrentDirectoryA(hConnect, szDir);
352 HeapFree(GetProcessHeap(), 0, szDir);
354 return rc;
358 /***********************************************************************
359 * FTP_FtpSetCurrentDirectoryA (Internal)
361 * Change the working directory on the FTP server
363 * RETURNS
364 * TRUE on success
365 * FALSE on failure
368 BOOL WINAPI FTP_FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
370 INT nResCode;
371 LPWININETFTPSESSIONA lpwfs;
372 LPWININETAPPINFOW hIC = NULL;
373 DWORD bSuccess = FALSE;
375 TRACE("lpszDirectory(%s)\n", lpszDirectory);
377 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hConnect );
378 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
380 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
381 return FALSE;
384 /* Clear any error information */
385 INTERNET_SetLastError(0);
387 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
388 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
389 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
390 goto lend;
392 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
393 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
395 if (nResCode)
397 if (nResCode == 250)
398 bSuccess = TRUE;
399 else
400 FTP_SetResponseError(nResCode);
403 lend:
404 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
406 INTERNET_ASYNC_RESULT iar;
408 iar.dwResult = (DWORD)bSuccess;
409 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
410 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
411 &iar, sizeof(INTERNET_ASYNC_RESULT));
413 return bSuccess;
417 /***********************************************************************
418 * FtpCreateDirectoryA (WININET.@)
420 * Create new directory on the FTP server
422 * RETURNS
423 * TRUE on success
424 * FALSE on failure
427 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
429 LPWININETFTPSESSIONA lpwfs;
430 LPWININETAPPINFOW hIC = NULL;
432 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hConnect );
433 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
435 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
436 return FALSE;
439 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
440 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
442 WORKREQUEST workRequest;
443 struct WORKREQ_FTPCREATEDIRECTORYA *req;
445 workRequest.asyncall = FTPCREATEDIRECTORYA;
446 workRequest.handle = hConnect;
447 req = &workRequest.u.FtpCreateDirectoryA;
448 req->lpszDirectory = FTP_strdup(lpszDirectory);
450 return INTERNET_AsyncCall(&workRequest);
452 else
454 return FTP_FtpCreateDirectoryA(hConnect, lpszDirectory);
459 /***********************************************************************
460 * FtpCreateDirectoryW (WININET.@)
462 * Create new directory on the FTP server
464 * RETURNS
465 * TRUE on success
466 * FALSE on failure
469 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
471 CHAR *szDir;
472 INT len;
473 BOOL rc;
475 len = WideCharToMultiByte(CP_ACP, 0, lpszDirectory, -1, NULL, 0, NULL, NULL);
476 szDir = HeapAlloc(GetProcessHeap(), 0, len);
477 if (!szDir)
478 return FALSE;
479 WideCharToMultiByte(CP_ACP, 0, lpszDirectory, -1, szDir, len, NULL, NULL);
480 rc = FtpCreateDirectoryA(hConnect, szDir);
481 HeapFree(GetProcessHeap(), 0, szDir);
483 return rc;
487 /***********************************************************************
488 * FTP_FtpCreateDirectoryA (Internal)
490 * Create new directory on the FTP server
492 * RETURNS
493 * TRUE on success
494 * FALSE on failure
497 BOOL WINAPI FTP_FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
499 INT nResCode;
500 BOOL bSuccess = FALSE;
501 LPWININETAPPINFOW hIC = NULL;
502 LPWININETFTPSESSIONA lpwfs;
504 TRACE("\n");
506 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hConnect );
507 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
509 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
510 return FALSE;
513 /* Clear any error information */
514 INTERNET_SetLastError(0);
516 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
517 goto lend;
519 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
520 MAX_REPLY_LEN, 0, 0, 0);
521 if (nResCode)
523 if (nResCode == 257)
524 bSuccess = TRUE;
525 else
526 FTP_SetResponseError(nResCode);
529 lend:
530 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
531 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
533 INTERNET_ASYNC_RESULT iar;
535 iar.dwResult = (DWORD)bSuccess;
536 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
537 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
538 &iar, sizeof(INTERNET_ASYNC_RESULT));
541 return bSuccess;
545 /***********************************************************************
546 * FtpFindFirstFileA (WININET.@)
548 * Search the specified directory
550 * RETURNS
551 * HINTERNET on success
552 * NULL on failure
555 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
556 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
558 LPWININETFTPSESSIONA lpwfs;
559 LPWININETAPPINFOW hIC = NULL;
561 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hConnect );
562 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
564 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
565 return FALSE;
568 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
569 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
571 WORKREQUEST workRequest;
572 struct WORKREQ_FTPFINDFIRSTFILEA *req;
574 workRequest.asyncall = FTPFINDFIRSTFILEA;
575 workRequest.handle = hConnect;
576 req = &workRequest.u.FtpFindFirstFileA;
577 req->lpszSearchFile = FTP_strdup(lpszSearchFile);
578 req->lpFindFileData = lpFindFileData;
579 req->dwFlags = dwFlags;
580 req->dwContext= dwContext;
582 INTERNET_AsyncCall(&workRequest);
583 return NULL;
585 else
587 return FTP_FtpFindFirstFileA(hConnect, lpszSearchFile, lpFindFileData,
588 dwFlags, dwContext);
593 /***********************************************************************
594 * FtpFindFirstFileA (WININET.@)
596 * Search the specified directory
598 * RETURNS
599 * HINTERNET on success
600 * NULL on failure
603 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
604 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
606 FIXME("STUB\n");
607 return NULL;
611 /***********************************************************************
612 * FTP_FtpFindFirstFileA (Internal)
614 * Search the specified directory
616 * RETURNS
617 * HINTERNET on success
618 * NULL on failure
621 HINTERNET WINAPI FTP_FtpFindFirstFileA(HINTERNET hConnect,
622 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
624 INT nResCode;
625 LPWININETAPPINFOW hIC = NULL;
626 LPWININETFTPSESSIONA lpwfs;
627 HINTERNET hFindNext = NULL;
629 TRACE("\n");
631 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hConnect );
632 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
634 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
635 return FALSE;
638 /* Clear any error information */
639 INTERNET_SetLastError(0);
641 if (!FTP_InitListenSocket(lpwfs))
642 goto lend;
644 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
645 goto lend;
647 if (!FTP_SendPortOrPasv(lpwfs))
648 goto lend;
650 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
651 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, lpszSearchFile,
652 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
653 goto lend;
655 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
656 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
657 if (nResCode)
659 if (nResCode == 125 || nResCode == 150)
661 INT nDataSocket;
663 /* Get data socket to server */
664 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
666 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpFindFileData, dwContext);
668 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
669 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
670 if (nResCode != 226 && nResCode != 250)
671 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
673 close(nDataSocket);
676 else
677 FTP_SetResponseError(nResCode);
680 lend:
681 if (lpwfs->lstnSocket != -1)
682 close(lpwfs->lstnSocket);
684 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
686 INTERNET_ASYNC_RESULT iar;
688 if (hFindNext)
690 iar.dwResult = (DWORD)hFindNext;
691 iar.dwError = ERROR_SUCCESS;
692 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
693 &iar, sizeof(INTERNET_ASYNC_RESULT));
696 iar.dwResult = (DWORD)hFindNext;
697 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
698 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
699 &iar, sizeof(INTERNET_ASYNC_RESULT));
702 return hFindNext;
706 /***********************************************************************
707 * FtpGetCurrentDirectoryA (WININET.@)
709 * Retrieves the current directory
711 * RETURNS
712 * TRUE on success
713 * FALSE on failure
716 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
717 LPDWORD lpdwCurrentDirectory)
719 LPWININETFTPSESSIONA lpwfs;
720 LPWININETAPPINFOW hIC = NULL;
722 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
724 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
725 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
727 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
728 return FALSE;
731 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
732 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
734 WORKREQUEST workRequest;
735 struct WORKREQ_FTPGETCURRENTDIRECTORYA *req;
737 workRequest.asyncall = FTPGETCURRENTDIRECTORYA;
738 workRequest.handle = hFtpSession;
739 req = &workRequest.u.FtpGetCurrentDirectoryA;
740 req->lpszDirectory = lpszCurrentDirectory;
741 req->lpdwDirectory = lpdwCurrentDirectory;
743 return INTERNET_AsyncCall(&workRequest);
745 else
747 return FTP_FtpGetCurrentDirectoryA(hFtpSession, lpszCurrentDirectory,
748 lpdwCurrentDirectory);
753 /***********************************************************************
754 * FtpGetCurrentDirectoryW (WININET.@)
756 * Retrieves the current directory
758 * RETURNS
759 * TRUE on success
760 * FALSE on failure
763 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
764 LPDWORD lpdwCurrentDirectory)
766 FIXME("STUB\n");
767 return FALSE;
771 /***********************************************************************
772 * FTP_FtpGetCurrentDirectoryA (Internal)
774 * Retrieves the current directory
776 * RETURNS
777 * TRUE on success
778 * FALSE on failure
781 BOOL WINAPI FTP_FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
782 LPDWORD lpdwCurrentDirectory)
784 INT nResCode;
785 LPWININETFTPSESSIONA lpwfs;
786 LPWININETAPPINFOW hIC = NULL;
787 DWORD bSuccess = FALSE;
789 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
791 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
792 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
794 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
795 return FALSE;
798 /* Clear any error information */
799 INTERNET_SetLastError(0);
801 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
803 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
804 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
805 hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext))
806 goto lend;
808 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
809 MAX_REPLY_LEN, hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext);
810 if (nResCode)
812 if (nResCode == 257) /* Extract directory name */
814 INT firstpos, lastpos, len;
815 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
817 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
819 if ('"' == lpszResponseBuffer[lastpos])
821 if (!firstpos)
822 firstpos = lastpos;
823 else
824 break;
828 len = lastpos - firstpos - 1;
829 strncpy(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1],
830 len < *lpdwCurrentDirectory ? len : *lpdwCurrentDirectory);
831 *lpdwCurrentDirectory = len;
832 bSuccess = TRUE;
834 else
835 FTP_SetResponseError(nResCode);
838 lend:
839 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
841 INTERNET_ASYNC_RESULT iar;
843 iar.dwResult = (DWORD)bSuccess;
844 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
845 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
846 &iar, sizeof(INTERNET_ASYNC_RESULT));
849 return (DWORD) bSuccess;
852 /***********************************************************************
853 * FtpOpenFileA (WININET.@)
855 * Open a remote file for writing or reading
857 * RETURNS
858 * HINTERNET handle on success
859 * NULL on failure
862 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
863 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
864 DWORD dwContext)
866 LPWININETFTPSESSIONA lpwfs;
867 LPWININETAPPINFOW hIC = NULL;
869 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
870 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
872 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
873 return FALSE;
876 if (lpwfs->download_in_progress != NULL) {
877 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
878 return FALSE;
881 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
882 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
884 WORKREQUEST workRequest;
885 struct WORKREQ_FTPOPENFILEA *req;
887 workRequest.asyncall = FTPOPENFILEA;
888 workRequest.handle = hFtpSession;
889 req = &workRequest.u.FtpOpenFileA;
890 req->lpszFilename = FTP_strdup(lpszFileName);
891 req->dwAccess = fdwAccess;
892 req->dwFlags = dwFlags;
893 req->dwContext = dwContext;
895 INTERNET_AsyncCall(&workRequest);
896 return NULL;
898 else
900 return FTP_FtpOpenFileA(hFtpSession, lpszFileName, fdwAccess, dwFlags, dwContext);
905 /***********************************************************************
906 * FtpOpenFileW (WININET.@)
908 * Open a remote file for writing or reading
910 * RETURNS
911 * HINTERNET handle on success
912 * NULL on failure
915 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
916 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
917 DWORD dwContext)
919 FIXME("STUB\n");
920 return NULL;
924 /***********************************************************************
925 * FTP_FtpOpenFileA (Internal)
927 * Open a remote file for writing or reading
929 * RETURNS
930 * HINTERNET handle on success
931 * NULL on failure
934 HINTERNET FTP_FtpOpenFileA(HINTERNET hFtpSession,
935 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
936 DWORD dwContext)
938 INT nDataSocket;
939 BOOL bSuccess = FALSE;
940 LPWININETFILE lpwh = NULL;
941 LPWININETAPPINFOW hIC = NULL;
942 LPWININETFTPSESSIONA lpwfs;
943 HINTERNET handle = NULL;
945 TRACE("\n");
947 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
948 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
950 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
951 return FALSE;
954 /* Clear any error information */
955 INTERNET_SetLastError(0);
957 if (GENERIC_READ == fdwAccess)
959 /* Set up socket to retrieve data */
960 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
962 else if (GENERIC_WRITE == fdwAccess)
964 /* Set up socket to send data */
965 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
968 /* Get data socket to server */
969 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
971 lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE));
972 handle = WININET_AllocHandle( &lpwh->hdr );
973 lpwh->hdr.htype = WH_HFILE;
974 lpwh->hdr.dwFlags = dwFlags;
975 lpwh->hdr.dwContext = dwContext;
976 lpwh->hdr.lpwhparent = &lpwfs->hdr;
977 lpwh->nDataSocket = nDataSocket;
978 lpwh->session_deleted = FALSE;
980 /* Indicate that a download is currently in progress */
981 lpwfs->download_in_progress = lpwh;
984 if (lpwfs->lstnSocket != -1)
985 close(lpwfs->lstnSocket);
987 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
988 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
990 INTERNET_ASYNC_RESULT iar;
992 if (lpwh)
994 iar.dwResult = (DWORD)handle;
995 iar.dwError = ERROR_SUCCESS;
996 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
997 &iar, sizeof(INTERNET_ASYNC_RESULT));
1000 iar.dwResult = (DWORD)bSuccess;
1001 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1002 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1003 &iar, sizeof(INTERNET_ASYNC_RESULT));
1006 return handle;
1010 /***********************************************************************
1011 * FtpGetFileA (WININET.@)
1013 * Retrieve file from the FTP server
1015 * RETURNS
1016 * TRUE on success
1017 * FALSE on failure
1020 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1021 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1022 DWORD dwContext)
1024 LPWININETFTPSESSIONA lpwfs;
1025 LPWININETAPPINFOW hIC = NULL;
1027 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hInternet );
1028 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1030 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1031 return FALSE;
1034 if (lpwfs->download_in_progress != NULL) {
1035 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1036 return FALSE;
1039 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1040 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1042 WORKREQUEST workRequest;
1043 struct WORKREQ_FTPGETFILEA *req;
1045 workRequest.asyncall = FTPGETFILEA;
1046 workRequest.handle = hInternet;
1047 req = &workRequest.u.FtpGetFileA;
1048 req->lpszRemoteFile = FTP_strdup(lpszRemoteFile);
1049 req->lpszNewFile = FTP_strdup(lpszNewFile);
1050 req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1051 req->fFailIfExists = fFailIfExists;
1052 req->dwFlags = dwInternetFlags;
1053 req->dwContext = dwContext;
1055 return INTERNET_AsyncCall(&workRequest);
1057 else
1059 return FTP_FtpGetFileA(hInternet, lpszRemoteFile, lpszNewFile,
1060 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
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 FIXME("STUB\n");
1080 return FALSE;
1084 /***********************************************************************
1085 * FTP_FtpGetFileA (Internal)
1087 * Retrieve file from the FTP server
1089 * RETURNS
1090 * TRUE on success
1091 * FALSE on failure
1094 BOOL WINAPI FTP_FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1095 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1096 DWORD dwContext)
1098 DWORD nBytes;
1099 BOOL bSuccess = FALSE;
1100 HANDLE hFile;
1101 LPWININETAPPINFOW hIC = NULL;
1102 LPWININETFTPSESSIONA lpwfs;
1104 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", lpszRemoteFile, lpszNewFile);
1106 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hInternet );
1107 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1109 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1110 return FALSE;
1113 /* Clear any error information */
1114 INTERNET_SetLastError(0);
1116 /* Ensure we can write to lpszNewfile by opening it */
1117 hFile = CreateFileA(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1118 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1119 if (INVALID_HANDLE_VALUE == hFile)
1120 goto lend;
1122 /* Set up socket to retrieve data */
1123 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
1125 if (nBytes > 0)
1127 INT nDataSocket;
1129 /* Get data socket to server */
1130 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1132 INT nResCode;
1134 /* Receive data */
1135 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
1136 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1137 MAX_REPLY_LEN, 0, 0, 0);
1138 if (nResCode)
1140 if (nResCode == 226)
1141 bSuccess = TRUE;
1142 else
1143 FTP_SetResponseError(nResCode);
1145 close(nDataSocket);
1149 lend:
1150 if (lpwfs->lstnSocket != -1)
1151 close(lpwfs->lstnSocket);
1153 if (hFile)
1154 CloseHandle(hFile);
1156 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1157 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1159 INTERNET_ASYNC_RESULT iar;
1161 iar.dwResult = (DWORD)bSuccess;
1162 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1163 hIC->lpfnStatusCB(hInternet, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1164 &iar, sizeof(INTERNET_ASYNC_RESULT));
1167 return bSuccess;
1171 /***********************************************************************
1172 * FtpDeleteFileA (WININET.@)
1174 * Delete a file on the ftp server
1176 * RETURNS
1177 * TRUE on success
1178 * FALSE on failure
1181 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1183 LPWININETFTPSESSIONA lpwfs;
1184 LPWININETAPPINFOW hIC = NULL;
1186 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
1187 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1189 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1190 return FALSE;
1193 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1194 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1196 WORKREQUEST workRequest;
1197 struct WORKREQ_FTPDELETEFILEA *req;
1199 workRequest.asyncall = FTPDELETEFILEA;
1200 workRequest.handle = hFtpSession;
1201 req = &workRequest.u.FtpDeleteFileA;
1202 req->lpszFilename = FTP_strdup(lpszFileName);
1204 return INTERNET_AsyncCall(&workRequest);
1206 else
1208 return FTP_FtpDeleteFileA(hFtpSession, lpszFileName);
1213 /***********************************************************************
1214 * FTP_FtpDeleteFileA (Internal)
1216 * Delete a file on the ftp server
1218 * RETURNS
1219 * TRUE on success
1220 * FALSE on failure
1223 BOOL FTP_FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1225 INT nResCode;
1226 BOOL bSuccess = FALSE;
1227 LPWININETAPPINFOW hIC = NULL;
1228 LPWININETFTPSESSIONA lpwfs;
1230 TRACE("0x%08lx\n", (ULONG) hFtpSession);
1232 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
1233 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1235 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1236 return FALSE;
1239 /* Clear any error information */
1240 INTERNET_SetLastError(0);
1242 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1243 goto lend;
1245 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1246 MAX_REPLY_LEN, 0, 0, 0);
1247 if (nResCode)
1249 if (nResCode == 250)
1250 bSuccess = TRUE;
1251 else
1252 FTP_SetResponseError(nResCode);
1254 lend:
1255 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1256 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1258 INTERNET_ASYNC_RESULT iar;
1260 iar.dwResult = (DWORD)bSuccess;
1261 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1262 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1263 &iar, sizeof(INTERNET_ASYNC_RESULT));
1266 return bSuccess;
1270 /***********************************************************************
1271 * FtpRemoveDirectoryA (WININET.@)
1273 * Remove a directory on the ftp server
1275 * RETURNS
1276 * TRUE on success
1277 * FALSE on failure
1280 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1282 LPWININETFTPSESSIONA lpwfs;
1283 LPWININETAPPINFOW hIC = NULL;
1285 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
1286 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1288 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1289 return FALSE;
1292 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1293 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1295 WORKREQUEST workRequest;
1296 struct WORKREQ_FTPREMOVEDIRECTORYA *req;
1298 workRequest.asyncall = FTPREMOVEDIRECTORYA;
1299 workRequest.handle = hFtpSession;
1300 req = &workRequest.u.FtpRemoveDirectoryA;
1301 req->lpszDirectory = FTP_strdup(lpszDirectory);
1303 return INTERNET_AsyncCall(&workRequest);
1305 else
1307 return FTP_FtpRemoveDirectoryA(hFtpSession, lpszDirectory);
1312 /***********************************************************************
1313 * FTP_FtpRemoveDirectoryA (Internal)
1315 * Remove a directory on the ftp server
1317 * RETURNS
1318 * TRUE on success
1319 * FALSE on failure
1322 BOOL FTP_FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1324 INT nResCode;
1325 BOOL bSuccess = FALSE;
1326 LPWININETAPPINFOW hIC = NULL;
1327 LPWININETFTPSESSIONA lpwfs;
1329 TRACE("\n");
1331 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
1332 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1334 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1335 return FALSE;
1338 /* Clear any error information */
1339 INTERNET_SetLastError(0);
1341 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1342 goto lend;
1344 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1345 MAX_REPLY_LEN, 0, 0, 0);
1346 if (nResCode)
1348 if (nResCode == 250)
1349 bSuccess = TRUE;
1350 else
1351 FTP_SetResponseError(nResCode);
1354 lend:
1355 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1356 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1358 INTERNET_ASYNC_RESULT iar;
1360 iar.dwResult = (DWORD)bSuccess;
1361 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1362 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1363 &iar, sizeof(INTERNET_ASYNC_RESULT));
1366 return bSuccess;
1370 /***********************************************************************
1371 * FtpRenameFileA (WININET.@)
1373 * Rename a file on the ftp server
1375 * RETURNS
1376 * TRUE on success
1377 * FALSE on failure
1380 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1382 LPWININETFTPSESSIONA lpwfs;
1383 LPWININETAPPINFOW hIC = NULL;
1385 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
1386 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1388 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1389 return FALSE;
1392 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1393 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1395 WORKREQUEST workRequest;
1396 struct WORKREQ_FTPRENAMEFILEA *req;
1398 workRequest.asyncall = FTPRENAMEFILEA;
1399 workRequest.handle = hFtpSession;
1400 req = &workRequest.u.FtpRenameFileA;
1401 req->lpszSrcFile = FTP_strdup(lpszSrc);
1402 req->lpszDestFile = FTP_strdup(lpszDest);
1404 return INTERNET_AsyncCall(&workRequest);
1406 else
1408 return FTP_FtpRenameFileA(hFtpSession, lpszSrc, lpszDest);
1412 /***********************************************************************
1413 * FTP_FtpRenameFileA (Internal)
1415 * Rename a file on the ftp server
1417 * RETURNS
1418 * TRUE on success
1419 * FALSE on failure
1422 BOOL FTP_FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1424 INT nResCode;
1425 BOOL bSuccess = FALSE;
1426 LPWININETAPPINFOW hIC = NULL;
1427 LPWININETFTPSESSIONA lpwfs;
1429 TRACE("\n");
1431 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
1432 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1434 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1435 return FALSE;
1438 /* Clear any error information */
1439 INTERNET_SetLastError(0);
1441 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1442 goto lend;
1444 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1445 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1446 if (nResCode == 350)
1448 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1449 goto lend;
1451 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1452 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1455 if (nResCode == 250)
1456 bSuccess = TRUE;
1457 else
1458 FTP_SetResponseError(nResCode);
1460 lend:
1461 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1462 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1464 INTERNET_ASYNC_RESULT iar;
1466 iar.dwResult = (DWORD)bSuccess;
1467 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1468 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1469 &iar, sizeof(INTERNET_ASYNC_RESULT));
1472 return bSuccess;
1476 /***********************************************************************
1477 * FTP_Connect (internal)
1479 * Connect to a ftp server
1481 * RETURNS
1482 * HINTERNET a session handle on success
1483 * NULL on failure
1487 HINTERNET FTP_Connect(HINTERNET hInternet, LPCWSTR lpszServerName,
1488 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1489 LPCWSTR lpszPassword, DWORD dwFlags, DWORD dwContext,
1490 DWORD dwInternalFlags)
1492 struct sockaddr_in socketAddr;
1493 struct hostent *phe = NULL;
1494 INT nsocket = -1, sock_namelen;
1495 LPWININETAPPINFOW hIC = NULL;
1496 BOOL bSuccess = FALSE;
1497 LPWININETFTPSESSIONA lpwfs = NULL;
1498 HINTERNET handle = NULL;
1500 TRACE("0x%08lx Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1501 (ULONG) hInternet, debugstr_w(lpszServerName),
1502 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
1504 hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
1505 if ( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) )
1506 goto lerror;
1508 if (NULL == lpszUserName && NULL != lpszPassword)
1510 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_USER_NAME);
1511 goto lerror;
1514 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1515 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1517 if (hIC->lpfnStatusCB)
1518 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1519 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1521 if (!GetAddress(lpszServerName, nServerPort, &phe, &socketAddr))
1523 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1524 goto lerror;
1527 if (hIC->lpfnStatusCB)
1528 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1529 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1531 nsocket = socket(AF_INET,SOCK_STREAM,0);
1532 if (nsocket == -1)
1534 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1535 goto lerror;
1538 if (hIC->lpfnStatusCB)
1539 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1540 &socketAddr, sizeof(struct sockaddr_in));
1542 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1544 ERR("Unable to connect (%s)\n", strerror(errno));
1545 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1547 else
1549 TRACE("Connected to server\n");
1550 if (hIC->lpfnStatusCB)
1551 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1552 &socketAddr, sizeof(struct sockaddr_in));
1554 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONA));
1555 if (NULL == lpwfs)
1557 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1558 goto lerror;
1561 handle = WININET_AllocHandle( &lpwfs->hdr );
1562 if( !handle )
1564 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1565 goto lerror;
1568 lpwfs->hdr.htype = WH_HFTPSESSION;
1569 lpwfs->hdr.dwFlags = dwFlags;
1570 lpwfs->hdr.dwContext = dwContext;
1571 lpwfs->hdr.dwInternalFlags = dwInternalFlags;
1572 lpwfs->hdr.lpwhparent = (LPWININETHANDLEHEADER)hInternet;
1573 lpwfs->sndSocket = nsocket;
1574 lpwfs->download_in_progress = NULL;
1575 sock_namelen = sizeof(lpwfs->socketAddress);
1576 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1577 lpwfs->phostent = phe;
1579 if (NULL == lpszUserName)
1581 lpwfs->lpszUserName = FTP_strdup("anonymous");
1582 lpwfs->lpszPassword = FTP_strdup("user@server");
1584 else
1586 lpwfs->lpszUserName = FTP_strdup_WtoA(lpszUserName);
1587 lpwfs->lpszPassword = FTP_strdup_WtoA(lpszPassword);
1590 if (FTP_ConnectToHost(lpwfs))
1592 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1593 if (hIC->lpfnStatusCB && !(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
1595 INTERNET_ASYNC_RESULT iar;
1597 iar.dwResult = (DWORD)handle;
1598 iar.dwError = ERROR_SUCCESS;
1600 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_HANDLE_CREATED,
1601 &iar, sizeof(INTERNET_ASYNC_RESULT));
1603 TRACE("Successfully logged into server\n");
1604 bSuccess = TRUE;
1608 lerror:
1609 if (!bSuccess && nsocket == -1)
1610 close(nsocket);
1612 if (!bSuccess && lpwfs)
1614 HeapFree(GetProcessHeap(), 0, lpwfs);
1615 WININET_FreeHandle( handle );
1616 lpwfs = NULL;
1619 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1621 INTERNET_ASYNC_RESULT iar;
1623 iar.dwResult = (DWORD)lpwfs;
1624 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1625 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1626 &iar, sizeof(INTERNET_ASYNC_RESULT));
1629 return handle;
1633 /***********************************************************************
1634 * FTP_ConnectToHost (internal)
1636 * Connect to a ftp server
1638 * RETURNS
1639 * TRUE on success
1640 * NULL on failure
1643 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs)
1645 INT nResCode;
1646 BOOL bSuccess = FALSE;
1648 TRACE("\n");
1649 FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1651 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1652 goto lend;
1654 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1655 MAX_REPLY_LEN, 0, 0, 0);
1656 if (nResCode)
1658 /* Login successful... */
1659 if (nResCode == 230)
1660 bSuccess = TRUE;
1661 /* User name okay, need password... */
1662 else if (nResCode == 331)
1663 bSuccess = FTP_SendPassword(lpwfs);
1664 /* Need account for login... */
1665 else if (nResCode == 332)
1666 bSuccess = FTP_SendAccount(lpwfs);
1667 else
1668 FTP_SetResponseError(nResCode);
1671 TRACE("Returning %d\n", bSuccess);
1672 lend:
1673 return bSuccess;
1677 /***********************************************************************
1678 * FTP_SendCommand (internal)
1680 * Send command to server
1682 * RETURNS
1683 * TRUE on success
1684 * NULL on failure
1687 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1688 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1690 DWORD len;
1691 CHAR *buf;
1692 DWORD nBytesSent = 0;
1693 DWORD nRC = 0;
1694 BOOL bParamHasLen;
1696 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1698 if (lpfnStatusCB)
1699 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1701 bParamHasLen = lpszParam && strlen(lpszParam) > 0;
1702 len = (bParamHasLen ? strlen(lpszParam) : -1) + strlen(szFtpCommands[ftpCmd]) +
1703 strlen(szCRLF)+ 1;
1704 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1706 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1707 return FALSE;
1709 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], bParamHasLen ? " " : "",
1710 bParamHasLen ? lpszParam : "", szCRLF);
1712 TRACE("Sending (%s) len(%ld)\n", buf, len);
1713 while((nBytesSent < len) && (nRC != -1))
1715 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1716 nBytesSent += nRC;
1719 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
1721 if (lpfnStatusCB)
1722 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_REQUEST_SENT,
1723 &nBytesSent, sizeof(DWORD));
1725 TRACE("Sent %ld bytes\n", nBytesSent);
1726 return (nRC != -1);
1730 /***********************************************************************
1731 * FTP_ReceiveResponse (internal)
1733 * Receive response from server
1735 * RETURNS
1736 * Reply code on success
1737 * 0 on failure
1741 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
1742 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1744 DWORD nRecv;
1745 INT rc = 0;
1746 char firstprefix[5];
1747 BOOL multiline = FALSE;
1750 TRACE("socket(%d) \n", nSocket);
1752 if (lpfnStatusCB)
1753 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1755 while(1)
1757 nRecv = dwResponse;
1758 if (!INTERNET_GetNextLine(nSocket, lpszResponse, &nRecv))
1759 goto lerror;
1761 if (nRecv >= 3)
1763 if(!multiline)
1765 if(lpszResponse[3] != '-')
1766 break;
1767 else
1768 { /* Start of multiline repsonse. Loop until we get "nnn " */
1769 multiline = TRUE;
1770 memcpy(firstprefix, lpszResponse, 3);
1771 firstprefix[3] = ' ';
1772 firstprefix[4] = '\0';
1775 else
1777 if(!memcmp(firstprefix, lpszResponse, 4))
1778 break;
1783 if (nRecv >= 3)
1785 rc = atoi(lpszResponse);
1787 if (lpfnStatusCB)
1788 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
1789 &nRecv, sizeof(DWORD));
1792 lerror:
1793 TRACE("return %d\n", rc);
1794 return rc;
1798 /***********************************************************************
1799 * FTP_SendPassword (internal)
1801 * Send password to ftp server
1803 * RETURNS
1804 * TRUE on success
1805 * NULL on failure
1808 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs)
1810 INT nResCode;
1811 BOOL bSuccess = FALSE;
1813 TRACE("\n");
1814 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
1815 goto lend;
1817 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1818 MAX_REPLY_LEN, 0, 0, 0);
1819 if (nResCode)
1821 TRACE("Received reply code %d\n", nResCode);
1822 /* Login successful... */
1823 if (nResCode == 230)
1824 bSuccess = TRUE;
1825 /* Command not implemented, superfluous at the server site... */
1826 /* Need account for login... */
1827 else if (nResCode == 332)
1828 bSuccess = FTP_SendAccount(lpwfs);
1829 else
1830 FTP_SetResponseError(nResCode);
1833 lend:
1834 TRACE("Returning %d\n", bSuccess);
1835 return bSuccess;
1839 /***********************************************************************
1840 * FTP_SendAccount (internal)
1844 * RETURNS
1845 * TRUE on success
1846 * FALSE on failure
1849 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs)
1851 INT nResCode;
1852 BOOL bSuccess = FALSE;
1854 TRACE("\n");
1855 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, NOACCOUNT, 0, 0, 0))
1856 goto lend;
1858 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1859 MAX_REPLY_LEN, 0, 0, 0);
1860 if (nResCode)
1861 bSuccess = TRUE;
1862 else
1863 FTP_SetResponseError(nResCode);
1865 lend:
1866 return bSuccess;
1870 /***********************************************************************
1871 * FTP_SendStore (internal)
1873 * Send request to upload file to ftp server
1875 * RETURNS
1876 * TRUE on success
1877 * FALSE on failure
1880 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
1882 INT nResCode;
1883 BOOL bSuccess = FALSE;
1885 TRACE("\n");
1886 if (!FTP_InitListenSocket(lpwfs))
1887 goto lend;
1889 if (!FTP_SendType(lpwfs, dwType))
1890 goto lend;
1892 if (!FTP_SendPortOrPasv(lpwfs))
1893 goto lend;
1895 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
1896 goto lend;
1897 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1898 MAX_REPLY_LEN, 0, 0, 0);
1899 if (nResCode)
1901 if (nResCode == 150)
1902 bSuccess = TRUE;
1903 else
1904 FTP_SetResponseError(nResCode);
1907 lend:
1908 if (!bSuccess && lpwfs->lstnSocket != -1)
1910 close(lpwfs->lstnSocket);
1911 lpwfs->lstnSocket = -1;
1914 return bSuccess;
1918 /***********************************************************************
1919 * FTP_InitListenSocket (internal)
1921 * Create a socket to listen for server response
1923 * RETURNS
1924 * TRUE on success
1925 * FALSE on failure
1928 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs)
1930 BOOL bSuccess = FALSE;
1931 size_t namelen = sizeof(struct sockaddr_in);
1933 TRACE("\n");
1935 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
1936 if (lpwfs->lstnSocket == -1)
1938 TRACE("Unable to create listening socket\n");
1939 goto lend;
1942 /* We obtain our ip addr from the name of the command channel socket */
1943 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
1945 /* and get the system to assign us a port */
1946 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
1948 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
1950 TRACE("Unable to bind socket\n");
1951 goto lend;
1954 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
1956 TRACE("listen failed\n");
1957 goto lend;
1960 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
1961 bSuccess = TRUE;
1963 lend:
1964 if (!bSuccess && lpwfs->lstnSocket == -1)
1966 close(lpwfs->lstnSocket);
1967 lpwfs->lstnSocket = -1;
1970 return bSuccess;
1974 /***********************************************************************
1975 * FTP_SendType (internal)
1977 * Tell server type of data being transferred
1979 * RETURNS
1980 * TRUE on success
1981 * FALSE on failure
1983 * W98SE doesn't cache the type that's currently set
1984 * (i.e. it sends it always),
1985 * so we probably don't want to do that either.
1987 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType)
1989 INT nResCode;
1990 CHAR type[2] = { "I" };
1991 BOOL bSuccess = FALSE;
1993 TRACE("\n");
1994 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
1995 *type = 'A';
1997 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
1998 goto lend;
2000 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2001 MAX_REPLY_LEN, 0, 0, 0)/100;
2002 if (nResCode)
2004 if (nResCode == 2)
2005 bSuccess = TRUE;
2006 else
2007 FTP_SetResponseError(nResCode);
2010 lend:
2011 return bSuccess;
2014 /***********************************************************************
2015 * FTP_GetFileSize (internal)
2017 * Retrieves from the server the size of the given file
2019 * RETURNS
2020 * TRUE on success
2021 * FALSE on failure
2024 BOOL FTP_GetFileSize(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD *dwSize)
2026 INT nResCode;
2027 BOOL bSuccess = FALSE;
2029 TRACE("\n");
2031 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2032 goto lend;
2034 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2035 MAX_REPLY_LEN, 0, 0, 0);
2036 if (nResCode)
2038 if (nResCode == 213) {
2039 /* Now parses the output to get the actual file size */
2040 int i;
2041 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2043 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2044 if (lpszResponseBuffer[i] == '\0') return FALSE;
2045 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2047 bSuccess = TRUE;
2048 } else {
2049 FTP_SetResponseError(nResCode);
2053 lend:
2054 return bSuccess;
2058 /***********************************************************************
2059 * FTP_SendPort (internal)
2061 * Tell server which port to use
2063 * RETURNS
2064 * TRUE on success
2065 * FALSE on failure
2068 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs)
2070 INT nResCode;
2071 CHAR szIPAddress[64];
2072 BOOL bSuccess = FALSE;
2073 TRACE("\n");
2075 sprintf(szIPAddress, "%d,%d,%d,%d,%d,%d",
2076 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2077 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2078 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2079 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2080 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2081 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2083 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2084 goto lend;
2086 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2087 MAX_REPLY_LEN,0, 0, 0);
2088 if (nResCode)
2090 if (nResCode == 200)
2091 bSuccess = TRUE;
2092 else
2093 FTP_SetResponseError(nResCode);
2096 lend:
2097 return bSuccess;
2101 /***********************************************************************
2102 * FTP_DoPassive (internal)
2104 * Tell server that we want to do passive transfers
2105 * and connect data socket
2107 * RETURNS
2108 * TRUE on success
2109 * FALSE on failure
2112 BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs)
2114 INT nResCode;
2115 BOOL bSuccess = FALSE;
2117 TRACE("\n");
2118 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2119 goto lend;
2121 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2122 MAX_REPLY_LEN,0, 0, 0);
2123 if (nResCode)
2125 if (nResCode == 227)
2127 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2128 LPSTR p;
2129 int f[6];
2130 int i;
2131 char *pAddr, *pPort;
2132 INT nsocket = -1;
2133 struct sockaddr_in dataSocketAddress;
2135 p = lpszResponseBuffer+4; /* skip status code */
2137 /* do a very strict check; we can improve that later. */
2139 if (strncmp(p, "Entering Passive Mode", 21))
2141 ERR("unknown response '%.*s', aborting\n", 21, p);
2142 goto lend;
2144 p += 21; /* skip string */
2145 if ((*p++ != ' ') || (*p++ != '('))
2147 ERR("unknown response format, aborting\n");
2148 goto lend;
2151 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2152 &f[4], &f[5]) != 6)
2154 ERR("unknown response address format '%s', aborting\n", p);
2155 goto lend;
2157 for (i=0; i < 6; i++)
2158 f[i] = f[i] & 0xff;
2160 dataSocketAddress = lpwfs->socketAddress;
2161 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2162 pPort = (char *)&(dataSocketAddress.sin_port);
2163 pAddr[0] = f[0];
2164 pAddr[1] = f[1];
2165 pAddr[2] = f[2];
2166 pAddr[3] = f[3];
2167 pPort[0] = f[4];
2168 pPort[1] = f[5];
2170 nsocket = socket(AF_INET,SOCK_STREAM,0);
2171 if (nsocket == -1)
2172 goto lend;
2174 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2176 ERR("can't connect passive FTP data port.\n");
2177 goto lend;
2179 lpwfs->pasvSocket = nsocket;
2180 bSuccess = TRUE;
2182 else
2183 FTP_SetResponseError(nResCode);
2186 lend:
2187 return bSuccess;
2191 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs)
2193 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2195 if (!FTP_DoPassive(lpwfs))
2196 return FALSE;
2198 else
2200 if (!FTP_SendPort(lpwfs))
2201 return FALSE;
2203 return TRUE;
2207 /***********************************************************************
2208 * FTP_GetDataSocket (internal)
2210 * Either accepts an incoming data socket connection from the server
2211 * or just returns the already opened socket after a PASV command
2212 * in case of passive FTP.
2215 * RETURNS
2216 * TRUE on success
2217 * FALSE on failure
2220 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket)
2222 struct sockaddr_in saddr;
2223 size_t addrlen = sizeof(struct sockaddr);
2225 TRACE("\n");
2226 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2228 *nDataSocket = lpwfs->pasvSocket;
2230 else
2232 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2233 close(lpwfs->lstnSocket);
2234 lpwfs->lstnSocket = -1;
2236 return *nDataSocket != -1;
2240 /***********************************************************************
2241 * FTP_SendData (internal)
2243 * Send data to the server
2245 * RETURNS
2246 * TRUE on success
2247 * FALSE on failure
2250 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile)
2252 BY_HANDLE_FILE_INFORMATION fi;
2253 DWORD nBytesRead = 0;
2254 DWORD nBytesSent = 0;
2255 DWORD nTotalSent = 0;
2256 DWORD nBytesToSend, nLen, nRC = 1;
2257 time_t s_long_time, e_long_time;
2258 LONG nSeconds;
2259 CHAR *lpszBuffer;
2261 TRACE("\n");
2262 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2263 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2265 /* Get the size of the file. */
2266 GetFileInformationByHandle(hFile, &fi);
2267 time(&s_long_time);
2271 nBytesToSend = nBytesRead - nBytesSent;
2273 if (nBytesToSend <= 0)
2275 /* Read data from file. */
2276 nBytesSent = 0;
2277 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2278 ERR("Failed reading from file\n");
2280 if (nBytesRead > 0)
2281 nBytesToSend = nBytesRead;
2282 else
2283 break;
2286 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2287 DATA_PACKET_SIZE : nBytesToSend;
2288 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2290 if (nRC != -1)
2292 nBytesSent += nRC;
2293 nTotalSent += nRC;
2296 /* Do some computation to display the status. */
2297 time(&e_long_time);
2298 nSeconds = e_long_time - s_long_time;
2299 if( nSeconds / 60 > 0 )
2301 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
2302 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2303 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2305 else
2307 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
2308 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2309 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2311 } while (nRC != -1);
2313 TRACE("file transfer complete!\n");
2315 if(lpszBuffer != NULL)
2316 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2318 return nTotalSent;
2322 /***********************************************************************
2323 * FTP_SendRetrieve (internal)
2325 * Send request to retrieve a file
2327 * RETURNS
2328 * Number of bytes to be received on success
2329 * 0 on failure
2332 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
2334 INT nResCode;
2335 DWORD nResult = 0;
2337 TRACE("\n");
2338 if (!FTP_InitListenSocket(lpwfs))
2339 goto lend;
2341 if (!FTP_SendType(lpwfs, dwType))
2342 goto lend;
2344 if (!FTP_SendPortOrPasv(lpwfs))
2345 goto lend;
2347 if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2348 goto lend;
2350 TRACE("Waiting to receive %ld bytes\n", nResult);
2352 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2353 goto lend;
2355 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2356 MAX_REPLY_LEN, 0, 0, 0);
2357 if ((nResCode != 125) && (nResCode != 150)) {
2358 /* That means that we got an error getting the file. */
2359 nResult = 0;
2362 lend:
2363 if (0 == nResult && lpwfs->lstnSocket != -1)
2365 close(lpwfs->lstnSocket);
2366 lpwfs->lstnSocket = -1;
2369 return nResult;
2373 /***********************************************************************
2374 * FTP_RetrieveData (internal)
2376 * Retrieve data from server
2378 * RETURNS
2379 * TRUE on success
2380 * FALSE on failure
2383 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2385 DWORD nBytesWritten;
2386 DWORD nBytesReceived = 0;
2387 INT nRC = 0;
2388 CHAR *lpszBuffer;
2390 TRACE("\n");
2392 if (INVALID_HANDLE_VALUE == hFile)
2393 return FALSE;
2395 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2396 if (NULL == lpszBuffer)
2398 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2399 return FALSE;
2402 while (nBytesReceived < nBytes && nRC != -1)
2404 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2405 if (nRC != -1)
2407 /* other side closed socket. */
2408 if (nRC == 0)
2409 goto recv_end;
2410 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2411 nBytesReceived += nRC;
2414 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
2415 nBytesReceived * 100 / nBytes);
2418 TRACE("Data transfer complete\n");
2419 if (NULL != lpszBuffer)
2420 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2422 recv_end:
2423 return (nRC != -1);
2427 /***********************************************************************
2428 * FTP_CloseSessionHandle (internal)
2430 * Deallocate session handle
2432 * RETURNS
2433 * TRUE on success
2434 * FALSE on failure
2437 BOOL FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs)
2439 TRACE("\n");
2441 if (lpwfs->download_in_progress != NULL)
2442 lpwfs->download_in_progress->session_deleted = TRUE;
2444 if (lpwfs->sndSocket != -1)
2445 close(lpwfs->sndSocket);
2447 if (lpwfs->lstnSocket != -1)
2448 close(lpwfs->lstnSocket);
2450 if (lpwfs->lpszPassword)
2451 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2453 if (lpwfs->lpszUserName)
2454 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2456 HeapFree(GetProcessHeap(), 0, lpwfs);
2458 return TRUE;
2462 /***********************************************************************
2463 * FTP_CloseFindNextHandle (internal)
2465 * Deallocate session handle
2467 * RETURNS
2468 * TRUE on success
2469 * FALSE on failure
2472 BOOL FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn)
2474 INT i;
2476 TRACE("\n");
2478 for (i = 0; i < lpwfn->size; i++)
2480 if (NULL != lpwfn->lpafp[i].lpszName)
2481 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2484 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2485 HeapFree(GetProcessHeap(), 0, lpwfn);
2487 return TRUE;
2490 /***********************************************************************
2491 * FTP_CloseFileTransferHandle (internal)
2493 * Closes the file transfer handle. This also 'cleans' the data queue of
2494 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2496 * RETURNS
2497 * TRUE on success
2498 * FALSE on failure
2501 BOOL FTP_CloseFileTransferHandle(LPWININETFILE lpwh)
2503 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) lpwh->hdr.lpwhparent;
2504 INT nResCode;
2505 HINTERNET handle;
2507 TRACE("\n");
2509 if (!lpwh->session_deleted)
2510 lpwfs->download_in_progress = NULL;
2512 /* This just serves to flush the control socket of any spurrious lines written
2513 to it (like '226 Transfer complete.').
2515 Wonder what to do if the server sends us an error code though...
2517 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2518 MAX_REPLY_LEN, 0, 0, 0);
2520 if (lpwh->nDataSocket != -1)
2521 close(lpwh->nDataSocket);
2523 HeapFree(GetProcessHeap(), 0, lpwh);
2525 /* If this handle was opened with InternetOpenUrl, we need to close the parent to prevent
2526 a memory leek
2528 if(lpwfs->hdr.dwInternalFlags & INET_OPENURL)
2530 handle = WININET_FindHandle( &lpwfs->hdr );
2531 InternetCloseHandle(handle);
2533 return TRUE;
2536 /***********************************************************************
2537 * FTP_ReceiveFileList (internal)
2539 * Read file list from server
2541 * RETURNS
2542 * Handle to file list on success
2543 * NULL on failure
2546 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
2547 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext)
2549 DWORD dwSize = 0;
2550 LPFILEPROPERTIESA lpafp = NULL;
2551 LPWININETFINDNEXTA lpwfn = NULL;
2552 HINTERNET handle = 0;
2554 TRACE("\n");
2556 if (FTP_ParseDirectory(lpwfs, nSocket, &lpafp, &dwSize))
2558 FTP_ConvertFileProp(lpafp, lpFindFileData);
2560 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTA));
2561 if (lpwfn)
2563 handle = WININET_AllocHandle( &lpwfn->hdr );
2564 if( handle )
2566 lpwfn->hdr.htype = WH_HFINDNEXT;
2567 lpwfn->hdr.lpwhparent = (LPWININETHANDLEHEADER)lpwfs;
2568 lpwfn->hdr.dwContext = dwContext;
2569 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2570 lpwfn->size = dwSize;
2571 lpwfn->lpafp = lpafp;
2573 else
2574 HeapFree( GetProcessHeap(), 0, lpwfn );
2578 TRACE("Matched %ld files\n", dwSize);
2579 return handle;
2583 /***********************************************************************
2584 * FTP_ConvertFileProp (internal)
2586 * Converts FILEPROPERTIESA struct to WIN32_FIND_DATAA
2588 * RETURNS
2589 * TRUE on success
2590 * FALSE on failure
2593 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESA lpafp, LPWIN32_FIND_DATAA lpFindFileData)
2595 BOOL bSuccess = FALSE;
2597 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2599 if (lpafp)
2601 /* Convert 'Unix' time to Windows time */
2602 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
2603 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
2605 /* Not all fields are filled in */
2606 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2607 lpFindFileData->nFileSizeLow = lpafp->nSize;
2609 if (lpafp->bIsDirectory)
2610 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2612 if (lpafp->lpszName)
2613 strncpy(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2615 bSuccess = TRUE;
2618 return bSuccess;
2622 /***********************************************************************
2623 * FTP_ParseDirectory (internal)
2625 * Parse string of directory information
2627 * RETURNS
2628 * TRUE on success
2629 * FALSE on failure
2631 * FIXME: - This function needs serious clea-up
2632 * - We should consider both UNIX and NT list formats
2634 #define MAX_MONTH_LEN 10
2635 #define MIN_LEN_DIR_ENTRY 15
2637 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp)
2640 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2642 * For instance:
2643 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2645 CHAR* pszMinutes;
2646 CHAR* pszHour;
2647 time_t aTime;
2648 struct tm* apTM;
2649 CHAR pszMonth[MAX_MONTH_LEN];
2650 CHAR* pszMatch;
2651 BOOL bSuccess = TRUE;
2652 DWORD nBufLen = MAX_REPLY_LEN;
2653 LPFILEPROPERTIESA curFileProp = NULL;
2654 CHAR* pszLine = NULL;
2655 CHAR* pszToken = NULL;
2656 INT nTokenToSkip = 3;
2657 INT nCount = 0;
2658 INT nSeconds = 0;
2659 INT nMinutes = 0;
2660 INT nHour = 0;
2661 INT nDay = 0;
2662 INT nMonth = 0;
2663 INT nYear = 0;
2664 INT sizeFilePropArray = 20;
2665 INT indexFilePropArray = 0;
2667 TRACE("\n");
2669 /* Allocate intial file properties array */
2670 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESA)*(sizeFilePropArray));
2671 if (NULL == lpafp)
2673 bSuccess = FALSE;
2674 goto lend;
2677 while ((pszLine = INTERNET_GetNextLine(nSocket, INTERNET_GetResponseBuffer(), &nBufLen)) != NULL)
2679 if (sizeFilePropArray <= indexFilePropArray)
2681 LPFILEPROPERTIESA tmpafp;
2683 sizeFilePropArray *= 2;
2684 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
2685 sizeof(FILEPROPERTIESA)*sizeFilePropArray);
2686 if (NULL == tmpafp)
2688 bSuccess = FALSE;
2689 goto lend;
2692 *lpafp = tmpafp;
2695 curFileProp = &((*lpafp)[indexFilePropArray]);
2697 /* First Parse the permissions. */
2698 pszToken = strtok(pszLine, " \t" );
2700 /* HACK! If this is not a file listing skip the line */
2701 if (!pszToken || nBufLen <= MIN_LEN_DIR_ENTRY)
2703 nBufLen = MAX_REPLY_LEN;
2704 continue;
2706 if (10 == strlen(pszToken)) {
2707 /* Unix way of parsing ... */
2708 FTP_ParsePermission(pszToken, curFileProp);
2710 nTokenToSkip = 3;
2711 nCount = 0;
2712 do {
2713 pszToken = strtok( NULL, " \t" );
2714 nCount++;
2715 } while( nCount <= nTokenToSkip );
2717 /* Store the size of the file in the param list. */
2718 TRACE("nSize-> %s\n", pszToken);
2719 if (pszToken != NULL)
2720 curFileProp->nSize = atol(pszToken);
2722 /* Parse last modified time. */
2723 nSeconds = 0;
2724 nMinutes = 0;
2725 nHour = 0;
2726 nDay = 0;
2727 nMonth = 0;
2728 nYear = 0;
2730 pszToken = strtok( NULL, " \t" );
2731 strncpy(pszMonth, pszToken, MAX_MONTH_LEN);
2732 CharUpperA(pszMonth);
2733 pszMatch = strstr(szMonths, pszMonth);
2734 if( pszMatch != NULL )
2735 nMonth = (pszMatch - szMonths) / 3;
2737 pszToken = strtok(NULL, " \t");
2738 TRACE("nDay -> %s\n", pszToken);
2739 if (pszToken != NULL)
2740 nDay = atoi(pszToken);
2742 pszToken = strtok(NULL, " \t");
2743 pszMinutes = strchr(pszToken, ':');
2744 if( pszMinutes != NULL ) {
2745 pszMinutes++;
2746 nMinutes = atoi(pszMinutes);
2747 pszHour = pszMinutes - 3;
2748 if (pszHour != NULL)
2749 nHour = atoi(pszHour);
2750 time(&aTime);
2751 apTM = localtime( &aTime );
2752 nYear = apTM->tm_year;
2753 } else {
2754 nYear = atoi(pszToken);
2755 nYear -= 1900;
2756 nHour = 12;
2759 curFileProp->tmLastModified.tm_sec = nSeconds;
2760 curFileProp->tmLastModified.tm_min = nMinutes;
2761 curFileProp->tmLastModified.tm_hour = nHour;
2762 curFileProp->tmLastModified.tm_mday = nDay;
2763 curFileProp->tmLastModified.tm_mon = nMonth;
2764 curFileProp->tmLastModified.tm_year = nYear;
2766 pszToken = strtok(NULL, " \t");
2767 if(pszToken != NULL) {
2768 curFileProp->lpszName = FTP_strdup(pszToken);
2769 TRACE(": %s\n", curFileProp->lpszName);
2772 nBufLen = MAX_REPLY_LEN;
2773 indexFilePropArray++;
2774 } else if (8 == strlen(pszToken)) {
2775 /* NT way of parsing ... :
2777 07-13-03 08:55PM <DIR> sakpatch
2778 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
2781 curFileProp->permissions = 0xFFFF; /* No idea, put full permission :-) */
2783 sscanf(pszToken, "%d-%d-%d",
2784 &curFileProp->tmLastModified.tm_mon,
2785 &curFileProp->tmLastModified.tm_mday,
2786 &curFileProp->tmLastModified.tm_year);
2788 /* Hacky and bad Y2K protection :-) */
2789 if (curFileProp->tmLastModified.tm_year < 70)
2790 curFileProp->tmLastModified.tm_year += 100;
2792 pszToken = strtok(NULL, " \t");
2793 if (pszToken == NULL) {
2794 nBufLen = MAX_REPLY_LEN;
2795 continue;
2797 sscanf(pszToken, "%d:%d",
2798 &curFileProp->tmLastModified.tm_hour,
2799 &curFileProp->tmLastModified.tm_min);
2800 if ((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
2801 curFileProp->tmLastModified.tm_hour += 12;
2803 curFileProp->tmLastModified.tm_sec = 0;
2805 TRACE("Mod time: %2d:%2d:%2d %2d/%2d/%2d\n",
2806 curFileProp->tmLastModified.tm_hour, curFileProp->tmLastModified.tm_min, curFileProp->tmLastModified.tm_sec,
2807 (curFileProp->tmLastModified.tm_year >= 100) ? curFileProp->tmLastModified.tm_year - 100 : curFileProp->tmLastModified.tm_year,
2808 curFileProp->tmLastModified.tm_mon, curFileProp->tmLastModified.tm_mday);
2810 pszToken = strtok(NULL, " \t");
2811 if (pszToken == NULL) {
2812 nBufLen = MAX_REPLY_LEN;
2813 continue;
2815 if (!strcasecmp(pszToken, "<DIR>")) {
2816 curFileProp->bIsDirectory = TRUE;
2817 TRACE("Is directory\n");
2818 } else {
2819 curFileProp->bIsDirectory = FALSE;
2820 curFileProp->nSize = atol(pszToken);
2821 TRACE("nSize: %ld\n", curFileProp->nSize);
2824 pszToken = strtok(NULL, " \t");
2825 if (pszToken == NULL) {
2826 nBufLen = MAX_REPLY_LEN;
2827 continue;
2829 curFileProp->lpszName = FTP_strdup(pszToken);
2830 TRACE("Name: %s\n", curFileProp->lpszName);
2832 nBufLen = MAX_REPLY_LEN;
2833 indexFilePropArray++;
2834 } else {
2835 nBufLen = MAX_REPLY_LEN;
2839 if (bSuccess && indexFilePropArray)
2841 if (indexFilePropArray < sizeFilePropArray - 1)
2843 LPFILEPROPERTIESA tmpafp;
2845 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
2846 sizeof(FILEPROPERTIESA)*indexFilePropArray);
2847 if (NULL == tmpafp)
2848 *lpafp = tmpafp;
2850 *dwfp = indexFilePropArray;
2852 else
2854 HeapFree(GetProcessHeap(), 0, *lpafp);
2855 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2856 bSuccess = FALSE;
2859 lend:
2860 return bSuccess;
2864 /***********************************************************************
2865 * FTP_ParsePermission (internal)
2867 * Parse permission string of directory information
2869 * RETURNS
2870 * TRUE on success
2871 * FALSE on failure
2874 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp)
2876 BOOL bSuccess = TRUE;
2877 unsigned short nPermission = 0;
2878 INT nPos = 1;
2879 INT nLast = 9;
2881 TRACE("\n");
2882 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
2884 bSuccess = FALSE;
2885 return bSuccess;
2888 lpfp->bIsDirectory = (*lpszPermission == 'd');
2891 switch (nPos)
2893 case 1:
2894 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
2895 break;
2896 case 2:
2897 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
2898 break;
2899 case 3:
2900 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
2901 break;
2902 case 4:
2903 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
2904 break;
2905 case 5:
2906 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
2907 break;
2908 case 6:
2909 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
2910 break;
2911 case 7:
2912 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
2913 break;
2914 case 8:
2915 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
2916 break;
2917 case 9:
2918 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
2919 break;
2921 nPos++;
2922 }while (nPos <= nLast);
2924 lpfp->permissions = nPermission;
2925 return bSuccess;
2929 /***********************************************************************
2930 * FTP_SetResponseError (internal)
2932 * Set the appropriate error code for a given response from the server
2934 * RETURNS
2937 DWORD FTP_SetResponseError(DWORD dwResponse)
2939 DWORD dwCode = 0;
2941 switch(dwResponse)
2943 case 421: /* Service not available - Server may be shutting down. */
2944 dwCode = ERROR_INTERNET_TIMEOUT;
2945 break;
2947 case 425: /* Cannot open data connection. */
2948 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
2949 break;
2951 case 426: /* Connection closed, transer aborted. */
2952 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
2953 break;
2955 case 500: /* Syntax error. Command unrecognized. */
2956 case 501: /* Syntax error. Error in parameters or arguments. */
2957 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
2958 break;
2960 case 530: /* Not logged in. Login incorrect. */
2961 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
2962 break;
2964 case 550: /* File action not taken. File not found or no access. */
2965 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
2966 break;
2968 case 450: /* File action not taken. File may be busy. */
2969 case 451: /* Action aborted. Server error. */
2970 case 452: /* Action not taken. Insufficient storage space on server. */
2971 case 502: /* Command not implemented. */
2972 case 503: /* Bad sequence of command. */
2973 case 504: /* Command not implemented for that parameter. */
2974 case 532: /* Need account for storing files */
2975 case 551: /* Requested action aborted. Page type unknown */
2976 case 552: /* Action aborted. Exceeded storage allocation */
2977 case 553: /* Action not taken. File name not allowed. */
2979 default:
2980 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
2981 break;
2984 INTERNET_SetLastError(dwCode);
2985 return dwCode;