Minor fixes.
[wine/testsucceed.git] / dlls / wininet / ftp.c
blob8a241b728e8395bc9a1ca2ef43e0628c42699baa
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)
1491 struct sockaddr_in socketAddr;
1492 struct hostent *phe = NULL;
1493 INT nsocket = -1, sock_namelen;
1494 LPWININETAPPINFOW hIC = NULL;
1495 BOOL bSuccess = FALSE;
1496 LPWININETFTPSESSIONA lpwfs = NULL;
1497 HINTERNET handle = NULL;
1499 TRACE("0x%08lx Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1500 (ULONG) hInternet, debugstr_w(lpszServerName),
1501 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
1503 hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
1504 if ( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) )
1505 goto lerror;
1507 if (NULL == lpszUserName && NULL != lpszPassword)
1509 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_USER_NAME);
1510 goto lerror;
1513 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1514 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1516 if (hIC->lpfnStatusCB)
1517 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1518 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1520 if (!GetAddress(lpszServerName, nServerPort, &phe, &socketAddr))
1522 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1523 goto lerror;
1526 if (hIC->lpfnStatusCB)
1527 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1528 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1530 nsocket = socket(AF_INET,SOCK_STREAM,0);
1531 if (nsocket == -1)
1533 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1534 goto lerror;
1537 if (hIC->lpfnStatusCB)
1538 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1539 &socketAddr, sizeof(struct sockaddr_in));
1541 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1543 ERR("Unable to connect (%s)\n", strerror(errno));
1544 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1546 else
1548 TRACE("Connected to server\n");
1549 if (hIC->lpfnStatusCB)
1550 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1551 &socketAddr, sizeof(struct sockaddr_in));
1553 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONA));
1554 if (NULL == lpwfs)
1556 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1557 goto lerror;
1560 handle = WININET_AllocHandle( &lpwfs->hdr );
1561 if( !handle )
1563 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1564 goto lerror;
1567 lpwfs->hdr.htype = WH_HFTPSESSION;
1568 lpwfs->hdr.dwFlags = dwFlags;
1569 lpwfs->hdr.dwContext = dwContext;
1570 lpwfs->hdr.lpwhparent = (LPWININETHANDLEHEADER)hInternet;
1571 lpwfs->sndSocket = nsocket;
1572 lpwfs->download_in_progress = NULL;
1573 sock_namelen = sizeof(lpwfs->socketAddress);
1574 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1575 lpwfs->phostent = phe;
1577 if (NULL == lpszUserName)
1579 lpwfs->lpszUserName = FTP_strdup("anonymous");
1580 lpwfs->lpszPassword = FTP_strdup("user@server");
1582 else
1584 lpwfs->lpszUserName = FTP_strdup_WtoA(lpszUserName);
1585 lpwfs->lpszPassword = FTP_strdup_WtoA(lpszPassword);
1588 if (FTP_ConnectToHost(lpwfs))
1590 if (hIC->lpfnStatusCB)
1592 INTERNET_ASYNC_RESULT iar;
1594 iar.dwResult = (DWORD)handle;
1595 iar.dwError = ERROR_SUCCESS;
1597 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_HANDLE_CREATED,
1598 &iar, sizeof(INTERNET_ASYNC_RESULT));
1600 TRACE("Successfully logged into server\n");
1601 bSuccess = TRUE;
1605 lerror:
1606 if (!bSuccess && nsocket == -1)
1607 close(nsocket);
1609 if (!bSuccess && lpwfs)
1611 HeapFree(GetProcessHeap(), 0, lpwfs);
1612 WININET_FreeHandle( handle );
1613 lpwfs = NULL;
1616 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1618 INTERNET_ASYNC_RESULT iar;
1620 iar.dwResult = (DWORD)lpwfs;
1621 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1622 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1623 &iar, sizeof(INTERNET_ASYNC_RESULT));
1626 return handle;
1630 /***********************************************************************
1631 * FTP_ConnectToHost (internal)
1633 * Connect to a ftp server
1635 * RETURNS
1636 * TRUE on success
1637 * NULL on failure
1640 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs)
1642 INT nResCode;
1643 BOOL bSuccess = FALSE;
1645 TRACE("\n");
1646 FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1648 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1649 goto lend;
1651 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1652 MAX_REPLY_LEN, 0, 0, 0);
1653 if (nResCode)
1655 /* Login successful... */
1656 if (nResCode == 230)
1657 bSuccess = TRUE;
1658 /* User name okay, need password... */
1659 else if (nResCode == 331)
1660 bSuccess = FTP_SendPassword(lpwfs);
1661 /* Need account for login... */
1662 else if (nResCode == 332)
1663 bSuccess = FTP_SendAccount(lpwfs);
1664 else
1665 FTP_SetResponseError(nResCode);
1668 TRACE("Returning %d\n", bSuccess);
1669 lend:
1670 return bSuccess;
1674 /***********************************************************************
1675 * FTP_SendCommand (internal)
1677 * Send command to server
1679 * RETURNS
1680 * TRUE on success
1681 * NULL on failure
1684 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1685 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1687 DWORD len;
1688 CHAR *buf;
1689 DWORD nBytesSent = 0;
1690 DWORD nRC = 0;
1691 BOOL bParamHasLen;
1693 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1695 if (lpfnStatusCB)
1696 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1698 bParamHasLen = lpszParam && strlen(lpszParam) > 0;
1699 len = (bParamHasLen ? strlen(lpszParam) : -1) + strlen(szFtpCommands[ftpCmd]) +
1700 strlen(szCRLF)+ 1;
1701 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1703 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1704 return FALSE;
1706 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], bParamHasLen ? " " : "",
1707 bParamHasLen ? lpszParam : "", szCRLF);
1709 TRACE("Sending (%s) len(%ld)\n", buf, len);
1710 while((nBytesSent < len) && (nRC != -1))
1712 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1713 nBytesSent += nRC;
1716 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
1718 if (lpfnStatusCB)
1719 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_REQUEST_SENT,
1720 &nBytesSent, sizeof(DWORD));
1722 TRACE("Sent %ld bytes\n", nBytesSent);
1723 return (nRC != -1);
1727 /***********************************************************************
1728 * FTP_ReceiveResponse (internal)
1730 * Receive response from server
1732 * RETURNS
1733 * Reply code on success
1734 * 0 on failure
1738 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
1739 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1741 DWORD nRecv;
1742 INT rc = 0;
1743 char firstprefix[5];
1744 BOOL multiline = FALSE;
1747 TRACE("socket(%d) \n", nSocket);
1749 if (lpfnStatusCB)
1750 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1752 while(1)
1754 nRecv = dwResponse;
1755 if (!INTERNET_GetNextLine(nSocket, lpszResponse, &nRecv))
1756 goto lerror;
1758 if (nRecv >= 3)
1760 if(!multiline)
1762 if(lpszResponse[3] != '-')
1763 break;
1764 else
1765 { /* Start of multiline repsonse. Loop until we get "nnn " */
1766 multiline = TRUE;
1767 memcpy(firstprefix, lpszResponse, 3);
1768 firstprefix[3] = ' ';
1769 firstprefix[4] = '\0';
1772 else
1774 if(!memcmp(firstprefix, lpszResponse, 4))
1775 break;
1780 if (nRecv >= 3)
1782 rc = atoi(lpszResponse);
1784 if (lpfnStatusCB)
1785 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
1786 &nRecv, sizeof(DWORD));
1789 lerror:
1790 TRACE("return %d\n", rc);
1791 return rc;
1795 /***********************************************************************
1796 * FTP_SendPassword (internal)
1798 * Send password to ftp server
1800 * RETURNS
1801 * TRUE on success
1802 * NULL on failure
1805 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs)
1807 INT nResCode;
1808 BOOL bSuccess = FALSE;
1810 TRACE("\n");
1811 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
1812 goto lend;
1814 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1815 MAX_REPLY_LEN, 0, 0, 0);
1816 if (nResCode)
1818 TRACE("Received reply code %d\n", nResCode);
1819 /* Login successful... */
1820 if (nResCode == 230)
1821 bSuccess = TRUE;
1822 /* Command not implemented, superfluous at the server site... */
1823 /* Need account for login... */
1824 else if (nResCode == 332)
1825 bSuccess = FTP_SendAccount(lpwfs);
1826 else
1827 FTP_SetResponseError(nResCode);
1830 lend:
1831 TRACE("Returning %d\n", bSuccess);
1832 return bSuccess;
1836 /***********************************************************************
1837 * FTP_SendAccount (internal)
1841 * RETURNS
1842 * TRUE on success
1843 * FALSE on failure
1846 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs)
1848 INT nResCode;
1849 BOOL bSuccess = FALSE;
1851 TRACE("\n");
1852 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, NOACCOUNT, 0, 0, 0))
1853 goto lend;
1855 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1856 MAX_REPLY_LEN, 0, 0, 0);
1857 if (nResCode)
1858 bSuccess = TRUE;
1859 else
1860 FTP_SetResponseError(nResCode);
1862 lend:
1863 return bSuccess;
1867 /***********************************************************************
1868 * FTP_SendStore (internal)
1870 * Send request to upload file to ftp server
1872 * RETURNS
1873 * TRUE on success
1874 * FALSE on failure
1877 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
1879 INT nResCode;
1880 BOOL bSuccess = FALSE;
1882 TRACE("\n");
1883 if (!FTP_InitListenSocket(lpwfs))
1884 goto lend;
1886 if (!FTP_SendType(lpwfs, dwType))
1887 goto lend;
1889 if (!FTP_SendPortOrPasv(lpwfs))
1890 goto lend;
1892 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
1893 goto lend;
1894 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1895 MAX_REPLY_LEN, 0, 0, 0);
1896 if (nResCode)
1898 if (nResCode == 150)
1899 bSuccess = TRUE;
1900 else
1901 FTP_SetResponseError(nResCode);
1904 lend:
1905 if (!bSuccess && lpwfs->lstnSocket != -1)
1907 close(lpwfs->lstnSocket);
1908 lpwfs->lstnSocket = -1;
1911 return bSuccess;
1915 /***********************************************************************
1916 * FTP_InitListenSocket (internal)
1918 * Create a socket to listen for server response
1920 * RETURNS
1921 * TRUE on success
1922 * FALSE on failure
1925 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs)
1927 BOOL bSuccess = FALSE;
1928 size_t namelen = sizeof(struct sockaddr_in);
1930 TRACE("\n");
1932 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
1933 if (lpwfs->lstnSocket == -1)
1935 TRACE("Unable to create listening socket\n");
1936 goto lend;
1939 /* We obtain our ip addr from the name of the command channel socket */
1940 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
1942 /* and get the system to assign us a port */
1943 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
1945 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
1947 TRACE("Unable to bind socket\n");
1948 goto lend;
1951 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
1953 TRACE("listen failed\n");
1954 goto lend;
1957 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
1958 bSuccess = TRUE;
1960 lend:
1961 if (!bSuccess && lpwfs->lstnSocket == -1)
1963 close(lpwfs->lstnSocket);
1964 lpwfs->lstnSocket = -1;
1967 return bSuccess;
1971 /***********************************************************************
1972 * FTP_SendType (internal)
1974 * Tell server type of data being transferred
1976 * RETURNS
1977 * TRUE on success
1978 * FALSE on failure
1980 * W98SE doesn't cache the type that's currently set
1981 * (i.e. it sends it always),
1982 * so we probably don't want to do that either.
1984 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType)
1986 INT nResCode;
1987 CHAR type[2] = { "I" };
1988 BOOL bSuccess = FALSE;
1990 TRACE("\n");
1991 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
1992 *type = 'A';
1994 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
1995 goto lend;
1997 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1998 MAX_REPLY_LEN, 0, 0, 0)/100;
1999 if (nResCode)
2001 if (nResCode == 2)
2002 bSuccess = TRUE;
2003 else
2004 FTP_SetResponseError(nResCode);
2007 lend:
2008 return bSuccess;
2011 /***********************************************************************
2012 * FTP_GetFileSize (internal)
2014 * Retrieves from the server the size of the given file
2016 * RETURNS
2017 * TRUE on success
2018 * FALSE on failure
2021 BOOL FTP_GetFileSize(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD *dwSize)
2023 INT nResCode;
2024 BOOL bSuccess = FALSE;
2026 TRACE("\n");
2028 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2029 goto lend;
2031 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2032 MAX_REPLY_LEN, 0, 0, 0);
2033 if (nResCode)
2035 if (nResCode == 213) {
2036 /* Now parses the output to get the actual file size */
2037 int i;
2038 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2040 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2041 if (lpszResponseBuffer[i] == '\0') return FALSE;
2042 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2044 bSuccess = TRUE;
2045 } else {
2046 FTP_SetResponseError(nResCode);
2050 lend:
2051 return bSuccess;
2055 /***********************************************************************
2056 * FTP_SendPort (internal)
2058 * Tell server which port to use
2060 * RETURNS
2061 * TRUE on success
2062 * FALSE on failure
2065 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs)
2067 INT nResCode;
2068 CHAR szIPAddress[64];
2069 BOOL bSuccess = FALSE;
2070 TRACE("\n");
2072 sprintf(szIPAddress, "%d,%d,%d,%d,%d,%d",
2073 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2074 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2075 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2076 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2077 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2078 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2080 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2081 goto lend;
2083 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2084 MAX_REPLY_LEN,0, 0, 0);
2085 if (nResCode)
2087 if (nResCode == 200)
2088 bSuccess = TRUE;
2089 else
2090 FTP_SetResponseError(nResCode);
2093 lend:
2094 return bSuccess;
2098 /***********************************************************************
2099 * FTP_DoPassive (internal)
2101 * Tell server that we want to do passive transfers
2102 * and connect data socket
2104 * RETURNS
2105 * TRUE on success
2106 * FALSE on failure
2109 BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs)
2111 INT nResCode;
2112 BOOL bSuccess = FALSE;
2114 TRACE("\n");
2115 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2116 goto lend;
2118 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2119 MAX_REPLY_LEN,0, 0, 0);
2120 if (nResCode)
2122 if (nResCode == 227)
2124 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2125 LPSTR p;
2126 int f[6];
2127 int i;
2128 char *pAddr, *pPort;
2129 INT nsocket = -1;
2130 struct sockaddr_in dataSocketAddress;
2132 p = lpszResponseBuffer+4; /* skip status code */
2134 /* do a very strict check; we can improve that later. */
2136 if (strncmp(p, "Entering Passive Mode", 21))
2138 ERR("unknown response '%.*s', aborting\n", 21, p);
2139 goto lend;
2141 p += 21; /* skip string */
2142 if ((*p++ != ' ') || (*p++ != '('))
2144 ERR("unknown response format, aborting\n");
2145 goto lend;
2148 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2149 &f[4], &f[5]) != 6)
2151 ERR("unknown response address format '%s', aborting\n", p);
2152 goto lend;
2154 for (i=0; i < 6; i++)
2155 f[i] = f[i] & 0xff;
2157 dataSocketAddress = lpwfs->socketAddress;
2158 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2159 pPort = (char *)&(dataSocketAddress.sin_port);
2160 pAddr[0] = f[0];
2161 pAddr[1] = f[1];
2162 pAddr[2] = f[2];
2163 pAddr[3] = f[3];
2164 pPort[0] = f[4];
2165 pPort[1] = f[5];
2167 nsocket = socket(AF_INET,SOCK_STREAM,0);
2168 if (nsocket == -1)
2169 goto lend;
2171 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2173 ERR("can't connect passive FTP data port.\n");
2174 goto lend;
2176 lpwfs->pasvSocket = nsocket;
2177 bSuccess = TRUE;
2179 else
2180 FTP_SetResponseError(nResCode);
2183 lend:
2184 return bSuccess;
2188 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs)
2190 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2192 if (!FTP_DoPassive(lpwfs))
2193 return FALSE;
2195 else
2197 if (!FTP_SendPort(lpwfs))
2198 return FALSE;
2200 return TRUE;
2204 /***********************************************************************
2205 * FTP_GetDataSocket (internal)
2207 * Either accepts an incoming data socket connection from the server
2208 * or just returns the already opened socket after a PASV command
2209 * in case of passive FTP.
2212 * RETURNS
2213 * TRUE on success
2214 * FALSE on failure
2217 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket)
2219 struct sockaddr_in saddr;
2220 size_t addrlen = sizeof(struct sockaddr);
2222 TRACE("\n");
2223 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2225 *nDataSocket = lpwfs->pasvSocket;
2227 else
2229 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2230 close(lpwfs->lstnSocket);
2231 lpwfs->lstnSocket = -1;
2233 return *nDataSocket != -1;
2237 /***********************************************************************
2238 * FTP_SendData (internal)
2240 * Send data to the server
2242 * RETURNS
2243 * TRUE on success
2244 * FALSE on failure
2247 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile)
2249 BY_HANDLE_FILE_INFORMATION fi;
2250 DWORD nBytesRead = 0;
2251 DWORD nBytesSent = 0;
2252 DWORD nTotalSent = 0;
2253 DWORD nBytesToSend, nLen, nRC = 1;
2254 time_t s_long_time, e_long_time;
2255 LONG nSeconds;
2256 CHAR *lpszBuffer;
2258 TRACE("\n");
2259 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2260 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2262 /* Get the size of the file. */
2263 GetFileInformationByHandle(hFile, &fi);
2264 time(&s_long_time);
2268 nBytesToSend = nBytesRead - nBytesSent;
2270 if (nBytesToSend <= 0)
2272 /* Read data from file. */
2273 nBytesSent = 0;
2274 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2275 ERR("Failed reading from file\n");
2277 if (nBytesRead > 0)
2278 nBytesToSend = nBytesRead;
2279 else
2280 break;
2283 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2284 DATA_PACKET_SIZE : nBytesToSend;
2285 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2287 if (nRC != -1)
2289 nBytesSent += nRC;
2290 nTotalSent += nRC;
2293 /* Do some computation to display the status. */
2294 time(&e_long_time);
2295 nSeconds = e_long_time - s_long_time;
2296 if( nSeconds / 60 > 0 )
2298 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
2299 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2300 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2302 else
2304 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
2305 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2306 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2308 } while (nRC != -1);
2310 TRACE("file transfer complete!\n");
2312 if(lpszBuffer != NULL)
2313 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2315 return nTotalSent;
2319 /***********************************************************************
2320 * FTP_SendRetrieve (internal)
2322 * Send request to retrieve a file
2324 * RETURNS
2325 * Number of bytes to be received on success
2326 * 0 on failure
2329 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
2331 INT nResCode;
2332 DWORD nResult = 0;
2334 TRACE("\n");
2335 if (!FTP_InitListenSocket(lpwfs))
2336 goto lend;
2338 if (!FTP_SendType(lpwfs, dwType))
2339 goto lend;
2341 if (!FTP_SendPortOrPasv(lpwfs))
2342 goto lend;
2344 if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2345 goto lend;
2347 TRACE("Waiting to receive %ld bytes\n", nResult);
2349 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2350 goto lend;
2352 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2353 MAX_REPLY_LEN, 0, 0, 0);
2354 if ((nResCode != 125) && (nResCode != 150)) {
2355 /* That means that we got an error getting the file. */
2356 nResult = 0;
2359 lend:
2360 if (0 == nResult && lpwfs->lstnSocket != -1)
2362 close(lpwfs->lstnSocket);
2363 lpwfs->lstnSocket = -1;
2366 return nResult;
2370 /***********************************************************************
2371 * FTP_RetrieveData (internal)
2373 * Retrieve data from server
2375 * RETURNS
2376 * TRUE on success
2377 * FALSE on failure
2380 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2382 DWORD nBytesWritten;
2383 DWORD nBytesReceived = 0;
2384 INT nRC = 0;
2385 CHAR *lpszBuffer;
2387 TRACE("\n");
2389 if (INVALID_HANDLE_VALUE == hFile)
2390 return FALSE;
2392 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2393 if (NULL == lpszBuffer)
2395 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2396 return FALSE;
2399 while (nBytesReceived < nBytes && nRC != -1)
2401 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2402 if (nRC != -1)
2404 /* other side closed socket. */
2405 if (nRC == 0)
2406 goto recv_end;
2407 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2408 nBytesReceived += nRC;
2411 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
2412 nBytesReceived * 100 / nBytes);
2415 TRACE("Data transfer complete\n");
2416 if (NULL != lpszBuffer)
2417 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2419 recv_end:
2420 return (nRC != -1);
2424 /***********************************************************************
2425 * FTP_CloseSessionHandle (internal)
2427 * Deallocate session handle
2429 * RETURNS
2430 * TRUE on success
2431 * FALSE on failure
2434 BOOL FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs)
2436 TRACE("\n");
2438 if (lpwfs->download_in_progress != NULL)
2439 lpwfs->download_in_progress->session_deleted = TRUE;
2441 if (lpwfs->sndSocket != -1)
2442 close(lpwfs->sndSocket);
2444 if (lpwfs->lstnSocket != -1)
2445 close(lpwfs->lstnSocket);
2447 if (lpwfs->lpszPassword)
2448 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2450 if (lpwfs->lpszUserName)
2451 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2453 HeapFree(GetProcessHeap(), 0, lpwfs);
2455 return TRUE;
2459 /***********************************************************************
2460 * FTP_CloseFindNextHandle (internal)
2462 * Deallocate session handle
2464 * RETURNS
2465 * TRUE on success
2466 * FALSE on failure
2469 BOOL FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn)
2471 INT i;
2473 TRACE("\n");
2475 for (i = 0; i < lpwfn->size; i++)
2477 if (NULL != lpwfn->lpafp[i].lpszName)
2478 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2481 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2482 HeapFree(GetProcessHeap(), 0, lpwfn);
2484 return TRUE;
2487 /***********************************************************************
2488 * FTP_CloseFileTransferHandle (internal)
2490 * Closes the file transfer handle. This also 'cleans' the data queue of
2491 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2493 * RETURNS
2494 * TRUE on success
2495 * FALSE on failure
2498 BOOL FTP_CloseFileTransferHandle(LPWININETFILE lpwh)
2500 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) lpwh->hdr.lpwhparent;
2501 INT nResCode;
2503 TRACE("\n");
2505 if (!lpwh->session_deleted)
2506 lpwfs->download_in_progress = NULL;
2508 /* This just serves to flush the control socket of any spurrious lines written
2509 to it (like '226 Transfer complete.').
2511 Wonder what to do if the server sends us an error code though...
2513 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2514 MAX_REPLY_LEN, 0, 0, 0);
2516 if (lpwh->nDataSocket != -1)
2517 close(lpwh->nDataSocket);
2519 HeapFree(GetProcessHeap(), 0, lpwh);
2521 return TRUE;
2524 /***********************************************************************
2525 * FTP_ReceiveFileList (internal)
2527 * Read file list from server
2529 * RETURNS
2530 * Handle to file list on success
2531 * NULL on failure
2534 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
2535 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext)
2537 DWORD dwSize = 0;
2538 LPFILEPROPERTIESA lpafp = NULL;
2539 LPWININETFINDNEXTA lpwfn = NULL;
2540 HINTERNET handle = 0;
2542 TRACE("\n");
2544 if (FTP_ParseDirectory(lpwfs, nSocket, &lpafp, &dwSize))
2546 FTP_ConvertFileProp(lpafp, lpFindFileData);
2548 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTA));
2549 if (lpwfn)
2551 handle = WININET_AllocHandle( &lpwfn->hdr );
2552 if( handle )
2554 lpwfn->hdr.htype = WH_HFINDNEXT;
2555 lpwfn->hdr.lpwhparent = (LPWININETHANDLEHEADER)lpwfs;
2556 lpwfn->hdr.dwContext = dwContext;
2557 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2558 lpwfn->size = dwSize;
2559 lpwfn->lpafp = lpafp;
2561 else
2562 HeapFree( GetProcessHeap(), 0, lpwfn );
2566 TRACE("Matched %ld files\n", dwSize);
2567 return handle;
2571 /***********************************************************************
2572 * FTP_ConvertFileProp (internal)
2574 * Converts FILEPROPERTIESA struct to WIN32_FIND_DATAA
2576 * RETURNS
2577 * TRUE on success
2578 * FALSE on failure
2581 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESA lpafp, LPWIN32_FIND_DATAA lpFindFileData)
2583 BOOL bSuccess = FALSE;
2585 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2587 if (lpafp)
2589 /* Convert 'Unix' time to Windows time */
2590 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
2591 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
2593 /* Not all fields are filled in */
2594 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2595 lpFindFileData->nFileSizeLow = lpafp->nSize;
2597 if (lpafp->bIsDirectory)
2598 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2600 if (lpafp->lpszName)
2601 strncpy(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2603 bSuccess = TRUE;
2606 return bSuccess;
2610 /***********************************************************************
2611 * FTP_ParseDirectory (internal)
2613 * Parse string of directory information
2615 * RETURNS
2616 * TRUE on success
2617 * FALSE on failure
2619 * FIXME: - This function needs serious clea-up
2620 * - We should consider both UNIX and NT list formats
2622 #define MAX_MONTH_LEN 10
2623 #define MIN_LEN_DIR_ENTRY 15
2625 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp)
2628 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2630 * For instance:
2631 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2633 CHAR* pszMinutes;
2634 CHAR* pszHour;
2635 time_t aTime;
2636 struct tm* apTM;
2637 CHAR pszMonth[MAX_MONTH_LEN];
2638 CHAR* pszMatch;
2639 BOOL bSuccess = TRUE;
2640 DWORD nBufLen = MAX_REPLY_LEN;
2641 LPFILEPROPERTIESA curFileProp = NULL;
2642 CHAR* pszLine = NULL;
2643 CHAR* pszToken = NULL;
2644 INT nTokenToSkip = 3;
2645 INT nCount = 0;
2646 INT nSeconds = 0;
2647 INT nMinutes = 0;
2648 INT nHour = 0;
2649 INT nDay = 0;
2650 INT nMonth = 0;
2651 INT nYear = 0;
2652 INT sizeFilePropArray = 20;
2653 INT indexFilePropArray = 0;
2655 TRACE("\n");
2657 /* Allocate intial file properties array */
2658 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESA)*(sizeFilePropArray));
2659 if (NULL == lpafp)
2661 bSuccess = FALSE;
2662 goto lend;
2665 while ((pszLine = INTERNET_GetNextLine(nSocket, INTERNET_GetResponseBuffer(), &nBufLen)) != NULL)
2667 if (sizeFilePropArray <= indexFilePropArray)
2669 LPFILEPROPERTIESA tmpafp;
2671 sizeFilePropArray *= 2;
2672 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
2673 sizeof(FILEPROPERTIESA)*sizeFilePropArray);
2674 if (NULL == tmpafp)
2676 bSuccess = FALSE;
2677 goto lend;
2680 *lpafp = tmpafp;
2683 curFileProp = &((*lpafp)[indexFilePropArray]);
2685 /* First Parse the permissions. */
2686 pszToken = strtok(pszLine, " \t" );
2688 /* HACK! If this is not a file listing skip the line */
2689 if (!pszToken || nBufLen <= MIN_LEN_DIR_ENTRY)
2691 nBufLen = MAX_REPLY_LEN;
2692 continue;
2694 if (10 == strlen(pszToken)) {
2695 /* Unix way of parsing ... */
2696 FTP_ParsePermission(pszToken, curFileProp);
2698 nTokenToSkip = 3;
2699 nCount = 0;
2700 do {
2701 pszToken = strtok( NULL, " \t" );
2702 nCount++;
2703 } while( nCount <= nTokenToSkip );
2705 /* Store the size of the file in the param list. */
2706 TRACE("nSize-> %s\n", pszToken);
2707 if (pszToken != NULL)
2708 curFileProp->nSize = atol(pszToken);
2710 /* Parse last modified time. */
2711 nSeconds = 0;
2712 nMinutes = 0;
2713 nHour = 0;
2714 nDay = 0;
2715 nMonth = 0;
2716 nYear = 0;
2718 pszToken = strtok( NULL, " \t" );
2719 strncpy(pszMonth, pszToken, MAX_MONTH_LEN);
2720 CharUpperA(pszMonth);
2721 pszMatch = strstr(szMonths, pszMonth);
2722 if( pszMatch != NULL )
2723 nMonth = (pszMatch - szMonths) / 3;
2725 pszToken = strtok(NULL, " \t");
2726 TRACE("nDay -> %s\n", pszToken);
2727 if (pszToken != NULL)
2728 nDay = atoi(pszToken);
2730 pszToken = strtok(NULL, " \t");
2731 pszMinutes = strchr(pszToken, ':');
2732 if( pszMinutes != NULL ) {
2733 pszMinutes++;
2734 nMinutes = atoi(pszMinutes);
2735 pszHour = pszMinutes - 3;
2736 if (pszHour != NULL)
2737 nHour = atoi(pszHour);
2738 time(&aTime);
2739 apTM = localtime( &aTime );
2740 nYear = apTM->tm_year;
2741 } else {
2742 nYear = atoi(pszToken);
2743 nYear -= 1900;
2744 nHour = 12;
2747 curFileProp->tmLastModified.tm_sec = nSeconds;
2748 curFileProp->tmLastModified.tm_min = nMinutes;
2749 curFileProp->tmLastModified.tm_hour = nHour;
2750 curFileProp->tmLastModified.tm_mday = nDay;
2751 curFileProp->tmLastModified.tm_mon = nMonth;
2752 curFileProp->tmLastModified.tm_year = nYear;
2754 pszToken = strtok(NULL, " \t");
2755 if(pszToken != NULL) {
2756 curFileProp->lpszName = FTP_strdup(pszToken);
2757 TRACE(": %s\n", curFileProp->lpszName);
2760 nBufLen = MAX_REPLY_LEN;
2761 indexFilePropArray++;
2762 } else if (8 == strlen(pszToken)) {
2763 /* NT way of parsing ... :
2765 07-13-03 08:55PM <DIR> sakpatch
2766 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
2769 curFileProp->permissions = 0xFFFF; /* No idea, put full permission :-) */
2771 sscanf(pszToken, "%d-%d-%d",
2772 &curFileProp->tmLastModified.tm_mon,
2773 &curFileProp->tmLastModified.tm_mday,
2774 &curFileProp->tmLastModified.tm_year);
2776 /* Hacky and bad Y2K protection :-) */
2777 if (curFileProp->tmLastModified.tm_year < 70)
2778 curFileProp->tmLastModified.tm_year += 100;
2780 pszToken = strtok(NULL, " \t");
2781 if (pszToken == NULL) {
2782 nBufLen = MAX_REPLY_LEN;
2783 continue;
2785 sscanf(pszToken, "%d:%d",
2786 &curFileProp->tmLastModified.tm_hour,
2787 &curFileProp->tmLastModified.tm_min);
2788 if ((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
2789 curFileProp->tmLastModified.tm_hour += 12;
2791 curFileProp->tmLastModified.tm_sec = 0;
2793 TRACE("Mod time: %2d:%2d:%2d %2d/%2d/%2d\n",
2794 curFileProp->tmLastModified.tm_hour, curFileProp->tmLastModified.tm_min, curFileProp->tmLastModified.tm_sec,
2795 (curFileProp->tmLastModified.tm_year >= 100) ? curFileProp->tmLastModified.tm_year - 100 : curFileProp->tmLastModified.tm_year,
2796 curFileProp->tmLastModified.tm_mon, curFileProp->tmLastModified.tm_mday);
2798 pszToken = strtok(NULL, " \t");
2799 if (pszToken == NULL) {
2800 nBufLen = MAX_REPLY_LEN;
2801 continue;
2803 if (!strcasecmp(pszToken, "<DIR>")) {
2804 curFileProp->bIsDirectory = TRUE;
2805 TRACE("Is directory\n");
2806 } else {
2807 curFileProp->bIsDirectory = FALSE;
2808 curFileProp->nSize = atol(pszToken);
2809 TRACE("nSize: %ld\n", curFileProp->nSize);
2812 pszToken = strtok(NULL, " \t");
2813 if (pszToken == NULL) {
2814 nBufLen = MAX_REPLY_LEN;
2815 continue;
2817 curFileProp->lpszName = FTP_strdup(pszToken);
2818 TRACE("Name: %s\n", curFileProp->lpszName);
2820 nBufLen = MAX_REPLY_LEN;
2821 indexFilePropArray++;
2822 } else {
2823 nBufLen = MAX_REPLY_LEN;
2827 if (bSuccess && indexFilePropArray)
2829 if (indexFilePropArray < sizeFilePropArray - 1)
2831 LPFILEPROPERTIESA tmpafp;
2833 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
2834 sizeof(FILEPROPERTIESA)*indexFilePropArray);
2835 if (NULL == tmpafp)
2836 *lpafp = tmpafp;
2838 *dwfp = indexFilePropArray;
2840 else
2842 HeapFree(GetProcessHeap(), 0, *lpafp);
2843 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2844 bSuccess = FALSE;
2847 lend:
2848 return bSuccess;
2852 /***********************************************************************
2853 * FTP_ParsePermission (internal)
2855 * Parse permission string of directory information
2857 * RETURNS
2858 * TRUE on success
2859 * FALSE on failure
2862 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp)
2864 BOOL bSuccess = TRUE;
2865 unsigned short nPermission = 0;
2866 INT nPos = 1;
2867 INT nLast = 9;
2869 TRACE("\n");
2870 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
2872 bSuccess = FALSE;
2873 return bSuccess;
2876 lpfp->bIsDirectory = (*lpszPermission == 'd');
2879 switch (nPos)
2881 case 1:
2882 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
2883 break;
2884 case 2:
2885 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
2886 break;
2887 case 3:
2888 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
2889 break;
2890 case 4:
2891 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
2892 break;
2893 case 5:
2894 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
2895 break;
2896 case 6:
2897 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
2898 break;
2899 case 7:
2900 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
2901 break;
2902 case 8:
2903 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
2904 break;
2905 case 9:
2906 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
2907 break;
2909 nPos++;
2910 }while (nPos <= nLast);
2912 lpfp->permissions = nPermission;
2913 return bSuccess;
2917 /***********************************************************************
2918 * FTP_SetResponseError (internal)
2920 * Set the appropriate error code for a given response from the server
2922 * RETURNS
2925 DWORD FTP_SetResponseError(DWORD dwResponse)
2927 DWORD dwCode = 0;
2929 switch(dwResponse)
2931 case 421: /* Service not available - Server may be shutting down. */
2932 dwCode = ERROR_INTERNET_TIMEOUT;
2933 break;
2935 case 425: /* Cannot open data connection. */
2936 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
2937 break;
2939 case 426: /* Connection closed, transer aborted. */
2940 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
2941 break;
2943 case 500: /* Syntax error. Command unrecognized. */
2944 case 501: /* Syntax error. Error in parameters or arguments. */
2945 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
2946 break;
2948 case 530: /* Not logged in. Login incorrect. */
2949 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
2950 break;
2952 case 550: /* File action not taken. File not found or no access. */
2953 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
2954 break;
2956 case 450: /* File action not taken. File may be busy. */
2957 case 451: /* Action aborted. Server error. */
2958 case 452: /* Action not taken. Insufficient storage space on server. */
2959 case 502: /* Command not implemented. */
2960 case 503: /* Bad sequence of command. */
2961 case 504: /* Command not implemented for that parameter. */
2962 case 532: /* Need account for storing files */
2963 case 551: /* Requested action aborted. Page type unknown */
2964 case 552: /* Action aborted. Exceeded storage allocation */
2965 case 553: /* Action not taken. File name not allowed. */
2967 default:
2968 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
2969 break;
2972 INTERNET_SetLastError(dwCode);
2973 return dwCode;