HTTP_DealWithProxy: Only add http:// to proxy string when needed.
[wine/multimedia.git] / dlls / wininet / ftp.c
blobfc0b7c747c8ca19080fea976a65d8f658e62fbbb
1 /*
2 * WININET - Ftp implementation
4 * Copyright 1999 Corel Corporation
6 * Ulrich Czekalla
7 * Noureddine Jemmali
9 * Copyright 2000 Andreas Mohr
10 * Copyright 2002 Jaco Greeff
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "config.h"
28 #include "wine/port.h"
30 #include <errno.h>
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #ifdef HAVE_SYS_SOCKET_H
37 # include <sys/socket.h>
38 #endif
39 #ifdef HAVE_UNISTD_H
40 # include <unistd.h>
41 #endif
42 #include <time.h>
44 #include "windef.h"
45 #include "winbase.h"
46 #include "wingdi.h"
47 #include "winuser.h"
48 #include "wininet.h"
49 #include "winnls.h"
50 #include "winerror.h"
51 #include "winreg.h"
52 #include "winternl.h"
54 #include "wine/debug.h"
55 #include "internet.h"
57 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
59 #define NOACCOUNT "noaccount"
60 #define DATA_PACKET_SIZE 0x2000
61 #define szCRLF "\r\n"
62 #define MAX_BACKLOG 5
64 typedef enum {
65 /* FTP commands with arguments. */
66 FTP_CMD_ACCT,
67 FTP_CMD_CWD,
68 FTP_CMD_DELE,
69 FTP_CMD_MKD,
70 FTP_CMD_PASS,
71 FTP_CMD_PORT,
72 FTP_CMD_RETR,
73 FTP_CMD_RMD,
74 FTP_CMD_RNFR,
75 FTP_CMD_RNTO,
76 FTP_CMD_STOR,
77 FTP_CMD_TYPE,
78 FTP_CMD_USER,
79 FTP_CMD_SIZE,
81 /* FTP commands without arguments. */
82 FTP_CMD_ABOR,
83 FTP_CMD_LIST,
84 FTP_CMD_NLST,
85 FTP_CMD_PASV,
86 FTP_CMD_PWD,
87 FTP_CMD_QUIT,
88 } FTP_COMMAND;
90 static const CHAR *szFtpCommands[] = {
91 "ACCT",
92 "CWD",
93 "DELE",
94 "MKD",
95 "PASS",
96 "PORT",
97 "RETR",
98 "RMD",
99 "RNFR",
100 "RNTO",
101 "STOR",
102 "TYPE",
103 "USER",
104 "SIZE",
105 "ABOR",
106 "LIST",
107 "NLST",
108 "PASV",
109 "PWD",
110 "QUIT",
113 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
115 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
116 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
117 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
118 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket);
119 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile);
120 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
121 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
122 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
123 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile);
124 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs);
125 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs);
126 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs);
127 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs);
128 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType);
129 BOOL FTP_GetFileSize(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD *dwSize);
130 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs);
131 BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs);
132 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs);
133 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp);
134 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp);
135 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
136 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext);
137 DWORD FTP_SetResponseError(DWORD dwResponse);
139 inline static LPSTR FTP_strdup( LPCSTR str )
141 LPSTR ret = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
142 if (ret) strcpy( ret, str );
143 return ret;
146 /***********************************************************************
147 * FtpPutFileA (WININET.@)
149 * Uploads a file to the FTP server
151 * RETURNS
152 * TRUE on success
153 * FALSE on failure
156 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
157 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
159 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
160 LPWININETAPPINFOA hIC = NULL;
162 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
164 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
165 return FALSE;
168 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
169 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
171 WORKREQUEST workRequest;
172 struct WORKREQ_FTPPUTFILEA *req = &workRequest.u.FtpPutFileA;
174 workRequest.asyncall = FTPPUTFILEA;
175 workRequest.handle = hConnect;
176 req->lpszLocalFile = FTP_strdup(lpszLocalFile);
177 req->lpszNewRemoteFile = FTP_strdup(lpszNewRemoteFile);
178 req->dwFlags = dwFlags;
179 req->dwContext = dwContext;
181 return INTERNET_AsyncCall(&workRequest);
183 else
185 return FTP_FtpPutFileA(hConnect, lpszLocalFile,
186 lpszNewRemoteFile, dwFlags, dwContext);
190 /***********************************************************************
191 * FTP_FtpPutFileA (Internal)
193 * Uploads a file to the FTP server
195 * RETURNS
196 * TRUE on success
197 * FALSE on failure
200 BOOL WINAPI FTP_FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
201 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
203 HANDLE hFile = NULL;
204 BOOL bSuccess = FALSE;
205 LPWININETAPPINFOA hIC = NULL;
206 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
207 INT nResCode;
209 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", lpszLocalFile, lpszNewRemoteFile);
210 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
212 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
213 return FALSE;
216 /* Clear any error information */
217 INTERNET_SetLastError(0);
219 /* Open file to be uploaded */
220 if (INVALID_HANDLE_VALUE ==
221 (hFile = CreateFileA(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
223 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND);
224 goto lend;
227 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
228 if (hIC->lpfnStatusCB)
229 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
231 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
233 INT nDataSocket;
235 /* Get data socket to server */
236 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
238 FTP_SendData(lpwfs, nDataSocket, hFile);
239 close(nDataSocket);
240 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
241 MAX_REPLY_LEN, 0, 0, 0);
242 if (nResCode)
244 if (nResCode == 226)
245 bSuccess = TRUE;
246 else
247 FTP_SetResponseError(nResCode);
252 lend:
253 if (lpwfs->lstnSocket != -1)
254 close(lpwfs->lstnSocket);
256 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
258 INTERNET_ASYNC_RESULT iar;
260 iar.dwResult = (DWORD)bSuccess;
261 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
262 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
263 &iar, sizeof(INTERNET_ASYNC_RESULT));
266 if (hFile)
267 CloseHandle(hFile);
269 return bSuccess;
273 /***********************************************************************
274 * FtpSetCurrentDirectoryA (WININET.@)
276 * Change the working directory on the FTP server
278 * RETURNS
279 * TRUE on success
280 * FALSE on failure
283 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
285 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
286 LPWININETAPPINFOA hIC = NULL;
288 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
290 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
291 return FALSE;
294 TRACE("lpszDirectory(%s)\n", lpszDirectory);
296 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
297 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
299 WORKREQUEST workRequest;
300 struct WORKREQ_FTPSETCURRENTDIRECTORYA *req;
302 workRequest.asyncall = FTPSETCURRENTDIRECTORYA;
303 workRequest.handle = hConnect;
304 req = &workRequest.u.FtpSetCurrentDirectoryA;
305 req->lpszDirectory = FTP_strdup(lpszDirectory);
307 return INTERNET_AsyncCall(&workRequest);
309 else
311 return FTP_FtpSetCurrentDirectoryA(hConnect, lpszDirectory);
316 /***********************************************************************
317 * FtpSetCurrentDirectoryW (WININET.@)
319 * Change the working directory on the FTP server
321 * RETURNS
322 * TRUE on success
323 * FALSE on failure
326 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
328 CHAR *szDir;
329 INT len;
330 BOOL rc;
332 len = WideCharToMultiByte(CP_ACP, 0, lpszDirectory, -1, NULL, 0, NULL, NULL);
333 szDir = HeapAlloc(GetProcessHeap(), 0, len);
334 if(!szDir)
335 return FALSE;
336 WideCharToMultiByte(CP_ACP, 0, lpszDirectory, -1, szDir, len, NULL, NULL);
337 rc = FtpSetCurrentDirectoryA(hConnect, szDir);
338 HeapFree(GetProcessHeap(), 0, szDir);
340 return rc;
344 /***********************************************************************
345 * FTP_FtpSetCurrentDirectoryA (Internal)
347 * Change the working directory on the FTP server
349 * RETURNS
350 * TRUE on success
351 * FALSE on failure
354 BOOL WINAPI FTP_FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
356 INT nResCode;
357 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
358 LPWININETAPPINFOA hIC = NULL;
359 DWORD bSuccess = FALSE;
361 TRACE("lpszDirectory(%s)\n", lpszDirectory);
363 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
365 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
366 return FALSE;
369 /* Clear any error information */
370 INTERNET_SetLastError(0);
372 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
373 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
374 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
375 goto lend;
377 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
378 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
380 if (nResCode)
382 if (nResCode == 250)
383 bSuccess = TRUE;
384 else
385 FTP_SetResponseError(nResCode);
388 lend:
389 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
391 INTERNET_ASYNC_RESULT iar;
393 iar.dwResult = (DWORD)bSuccess;
394 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
395 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
396 &iar, sizeof(INTERNET_ASYNC_RESULT));
398 return bSuccess;
402 /***********************************************************************
403 * FtpCreateDirectoryA (WININET.@)
405 * Create new directory on the FTP server
407 * RETURNS
408 * TRUE on success
409 * FALSE on failure
412 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
414 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
415 LPWININETAPPINFOA hIC = NULL;
417 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
419 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
420 return FALSE;
423 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
424 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
426 WORKREQUEST workRequest;
427 struct WORKREQ_FTPCREATEDIRECTORYA *req;
429 workRequest.asyncall = FTPCREATEDIRECTORYA;
430 workRequest.handle = hConnect;
431 req = &workRequest.u.FtpCreateDirectoryA;
432 req->lpszDirectory = FTP_strdup(lpszDirectory);
434 return INTERNET_AsyncCall(&workRequest);
436 else
438 return FTP_FtpCreateDirectoryA(hConnect, lpszDirectory);
443 /***********************************************************************
444 * FtpCreateDirectoryW (WININET.@)
446 * Create new directory on the FTP server
448 * RETURNS
449 * TRUE on success
450 * FALSE on failure
453 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
455 CHAR *szDir;
456 INT len;
457 BOOL rc;
459 len = WideCharToMultiByte(CP_ACP, 0, lpszDirectory, -1, NULL, 0, NULL, NULL);
460 szDir = HeapAlloc(GetProcessHeap(), 0, len);
461 if (!szDir)
462 return FALSE;
463 WideCharToMultiByte(CP_ACP, 0, lpszDirectory, -1, szDir, len, NULL, NULL);
464 rc = FtpCreateDirectoryA(hConnect, szDir);
465 HeapFree(GetProcessHeap(), 0, szDir);
467 return rc;
471 /***********************************************************************
472 * FTP_FtpCreateDirectoryA (Internal)
474 * Create new directory on the FTP server
476 * RETURNS
477 * TRUE on success
478 * FALSE on failure
481 BOOL WINAPI FTP_FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
483 INT nResCode;
484 BOOL bSuccess = FALSE;
485 LPWININETAPPINFOA hIC = NULL;
486 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
488 TRACE("\n");
489 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
491 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
492 return FALSE;
495 /* Clear any error information */
496 INTERNET_SetLastError(0);
498 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
499 goto lend;
501 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
502 MAX_REPLY_LEN, 0, 0, 0);
503 if (nResCode)
505 if (nResCode == 257)
506 bSuccess = TRUE;
507 else
508 FTP_SetResponseError(nResCode);
511 lend:
512 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
513 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
515 INTERNET_ASYNC_RESULT iar;
517 iar.dwResult = (DWORD)bSuccess;
518 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
519 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
520 &iar, sizeof(INTERNET_ASYNC_RESULT));
523 return bSuccess;
527 /***********************************************************************
528 * FtpFindFirstFileA (WININET.@)
530 * Search the specified directory
532 * RETURNS
533 * HINTERNET on success
534 * NULL on failure
537 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
538 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
540 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
541 LPWININETAPPINFOA hIC = NULL;
543 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
545 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
546 return FALSE;
549 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
550 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
552 WORKREQUEST workRequest;
553 struct WORKREQ_FTPFINDFIRSTFILEA *req;
555 workRequest.asyncall = FTPFINDFIRSTFILEA;
556 workRequest.handle = hConnect;
557 req = &workRequest.u.FtpFindFirstFileA;
558 req->lpszSearchFile = FTP_strdup(lpszSearchFile);
559 req->lpFindFileData = lpFindFileData;
560 req->dwFlags = dwFlags;
561 req->dwContext= dwContext;
563 INTERNET_AsyncCall(&workRequest);
564 return NULL;
566 else
568 return FTP_FtpFindFirstFileA(hConnect, lpszSearchFile, lpFindFileData,
569 dwFlags, dwContext);
574 /***********************************************************************
575 * FtpFindFirstFileA (WININET.@)
577 * Search the specified directory
579 * RETURNS
580 * HINTERNET on success
581 * NULL on failure
584 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
585 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
587 FIXME("STUB\n");
588 return NULL;
592 /***********************************************************************
593 * FTP_FtpFindFirstFileA (Internal)
595 * Search the specified directory
597 * RETURNS
598 * HINTERNET on success
599 * NULL on failure
602 HINTERNET WINAPI FTP_FtpFindFirstFileA(HINTERNET hConnect,
603 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
605 INT nResCode;
606 LPWININETAPPINFOA hIC = NULL;
607 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
608 LPWININETFINDNEXTA hFindNext = NULL;
610 TRACE("\n");
612 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
614 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
615 return FALSE;
618 /* Clear any error information */
619 INTERNET_SetLastError(0);
621 if (!FTP_InitListenSocket(lpwfs))
622 goto lend;
624 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
625 goto lend;
627 if (!FTP_SendPortOrPasv(lpwfs))
628 goto lend;
630 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
631 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, lpszSearchFile,
632 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
633 goto lend;
635 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
636 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
637 if (nResCode)
639 if (nResCode == 125 || nResCode == 150)
641 INT nDataSocket;
643 /* Get data socket to server */
644 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
646 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpFindFileData, dwContext);
648 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
649 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
650 if (nResCode != 226 && nResCode != 250)
651 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
653 close(nDataSocket);
656 else
657 FTP_SetResponseError(nResCode);
660 lend:
661 if (lpwfs->lstnSocket != -1)
662 close(lpwfs->lstnSocket);
664 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
666 INTERNET_ASYNC_RESULT iar;
668 if (hFindNext)
670 iar.dwResult = (DWORD)hFindNext;
671 iar.dwError = ERROR_SUCCESS;
672 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
673 &iar, sizeof(INTERNET_ASYNC_RESULT));
676 iar.dwResult = (DWORD)hFindNext;
677 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
678 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
679 &iar, sizeof(INTERNET_ASYNC_RESULT));
682 return (HINTERNET)hFindNext;
686 /***********************************************************************
687 * FtpGetCurrentDirectoryA (WININET.@)
689 * Retrieves the current directory
691 * RETURNS
692 * TRUE on success
693 * FALSE on failure
696 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
697 LPDWORD lpdwCurrentDirectory)
699 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
700 LPWININETAPPINFOA hIC = NULL;
702 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
704 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
706 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
707 return FALSE;
710 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
711 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
713 WORKREQUEST workRequest;
714 struct WORKREQ_FTPGETCURRENTDIRECTORYA *req;
716 workRequest.asyncall = FTPGETCURRENTDIRECTORYA;
717 workRequest.handle = hFtpSession;
718 req = &workRequest.u.FtpGetCurrentDirectoryA;
719 req->lpszDirectory = lpszCurrentDirectory;
720 req->lpdwDirectory = lpdwCurrentDirectory;
722 return INTERNET_AsyncCall(&workRequest);
724 else
726 return FTP_FtpGetCurrentDirectoryA(hFtpSession, lpszCurrentDirectory,
727 lpdwCurrentDirectory);
732 /***********************************************************************
733 * FtpGetCurrentDirectoryW (WININET.@)
735 * Retrieves the current directory
737 * RETURNS
738 * TRUE on success
739 * FALSE on failure
742 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
743 LPDWORD lpdwCurrentDirectory)
745 FIXME("STUB\n");
746 return FALSE;
750 /***********************************************************************
751 * FTP_FtpGetCurrentDirectoryA (Internal)
753 * Retrieves the current directory
755 * RETURNS
756 * TRUE on success
757 * FALSE on failure
760 BOOL WINAPI FTP_FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
761 LPDWORD lpdwCurrentDirectory)
763 INT nResCode;
764 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
765 LPWININETAPPINFOA hIC = NULL;
766 DWORD bSuccess = FALSE;
768 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
770 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
772 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
773 return FALSE;
776 /* Clear any error information */
777 INTERNET_SetLastError(0);
779 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
781 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
782 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
783 hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext))
784 goto lend;
786 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
787 MAX_REPLY_LEN, hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext);
788 if (nResCode)
790 if (nResCode == 257) /* Extract directory name */
792 INT firstpos, lastpos, len;
793 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
795 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
797 if ('"' == lpszResponseBuffer[lastpos])
799 if (!firstpos)
800 firstpos = lastpos;
801 else
802 break;
806 len = lastpos - firstpos - 1;
807 strncpy(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1],
808 len < *lpdwCurrentDirectory ? len : *lpdwCurrentDirectory);
809 *lpdwCurrentDirectory = len;
810 bSuccess = TRUE;
812 else
813 FTP_SetResponseError(nResCode);
816 lend:
817 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
819 INTERNET_ASYNC_RESULT iar;
821 iar.dwResult = (DWORD)bSuccess;
822 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
823 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
824 &iar, sizeof(INTERNET_ASYNC_RESULT));
827 return (DWORD) bSuccess;
830 /***********************************************************************
831 * FtpOpenFileA (WININET.@)
833 * Open a remote file for writing or reading
835 * RETURNS
836 * HINTERNET handle on success
837 * NULL on failure
840 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
841 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
842 DWORD dwContext)
844 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
845 LPWININETAPPINFOA hIC = NULL;
847 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
849 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
850 return FALSE;
853 if (lpwfs->download_in_progress != NULL) {
854 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
855 return FALSE;
858 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
859 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
861 WORKREQUEST workRequest;
862 struct WORKREQ_FTPOPENFILEA *req;
864 workRequest.asyncall = FTPOPENFILEA;
865 workRequest.handle = hFtpSession;
866 req = &workRequest.u.FtpOpenFileA;
867 req->lpszFilename = FTP_strdup(lpszFileName);
868 req->dwAccess = fdwAccess;
869 req->dwFlags = dwFlags;
870 req->dwContext = dwContext;
872 INTERNET_AsyncCall(&workRequest);
873 return NULL;
875 else
877 return FTP_FtpOpenFileA(hFtpSession, lpszFileName, fdwAccess, dwFlags, dwContext);
882 /***********************************************************************
883 * FtpOpenFileW (WININET.@)
885 * Open a remote file for writing or reading
887 * RETURNS
888 * HINTERNET handle on success
889 * NULL on failure
892 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
893 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
894 DWORD dwContext)
896 FIXME("STUB\n");
897 return NULL;
901 /***********************************************************************
902 * FTP_FtpOpenFileA (Internal)
904 * Open a remote file for writing or reading
906 * RETURNS
907 * HINTERNET handle on success
908 * NULL on failure
911 HINTERNET FTP_FtpOpenFileA(HINTERNET hFtpSession,
912 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
913 DWORD dwContext)
915 INT nDataSocket;
916 BOOL bSuccess = FALSE;
917 LPWININETFILE hFile = NULL;
918 LPWININETAPPINFOA hIC = NULL;
919 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
921 TRACE("\n");
923 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
925 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
926 return FALSE;
929 /* Clear any error information */
930 INTERNET_SetLastError(0);
932 if (GENERIC_READ == fdwAccess)
934 /* Set up socket to retrieve data */
935 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
937 else if (GENERIC_WRITE == fdwAccess)
939 /* Set up socket to send data */
940 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
943 /* Get data socket to server */
944 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
946 hFile = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE));
947 hFile->hdr.htype = WH_HFILE;
948 hFile->hdr.dwFlags = dwFlags;
949 hFile->hdr.dwContext = dwContext;
950 hFile->hdr.lpwhparent = hFtpSession;
951 hFile->nDataSocket = nDataSocket;
952 hFile->session_deleted = FALSE;
954 /* Indicate that a download is currently in progress */
955 lpwfs->download_in_progress = hFile;
958 if (lpwfs->lstnSocket != -1)
959 close(lpwfs->lstnSocket);
961 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
962 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
964 INTERNET_ASYNC_RESULT iar;
966 if (hFile)
968 iar.dwResult = (DWORD)hFile;
969 iar.dwError = ERROR_SUCCESS;
970 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
971 &iar, sizeof(INTERNET_ASYNC_RESULT));
974 iar.dwResult = (DWORD)bSuccess;
975 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
976 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
977 &iar, sizeof(INTERNET_ASYNC_RESULT));
980 return (HINTERNET)hFile;
984 /***********************************************************************
985 * FtpGetFileA (WININET.@)
987 * Retrieve file from the FTP server
989 * RETURNS
990 * TRUE on success
991 * FALSE on failure
994 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
995 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
996 DWORD dwContext)
998 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet;
999 LPWININETAPPINFOA hIC = NULL;
1001 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1003 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1004 return FALSE;
1007 if (lpwfs->download_in_progress != NULL) {
1008 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1009 return FALSE;
1012 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1013 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1015 WORKREQUEST workRequest;
1016 struct WORKREQ_FTPGETFILEA *req;
1018 workRequest.asyncall = FTPGETFILEA;
1019 workRequest.handle = hInternet;
1020 req = &workRequest.u.FtpGetFileA;
1021 req->lpszRemoteFile = FTP_strdup(lpszRemoteFile);
1022 req->lpszNewFile = FTP_strdup(lpszNewFile);
1023 req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1024 req->fFailIfExists = fFailIfExists;
1025 req->dwFlags = dwInternetFlags;
1026 req->dwContext = dwContext;
1028 return INTERNET_AsyncCall(&workRequest);
1030 else
1032 return FTP_FtpGetFileA(hInternet, lpszRemoteFile, lpszNewFile,
1033 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1038 /***********************************************************************
1039 * FtpGetFileW (WININET.@)
1041 * Retrieve file from the FTP server
1043 * RETURNS
1044 * TRUE on success
1045 * FALSE on failure
1048 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1049 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1050 DWORD dwContext)
1052 FIXME("STUB\n");
1053 return FALSE;
1057 /***********************************************************************
1058 * FTP_FtpGetFileA (Internal)
1060 * Retrieve file from the FTP server
1062 * RETURNS
1063 * TRUE on success
1064 * FALSE on failure
1067 BOOL WINAPI FTP_FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1068 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1069 DWORD dwContext)
1071 DWORD nBytes;
1072 BOOL bSuccess = FALSE;
1073 HANDLE hFile;
1074 LPWININETAPPINFOA hIC = NULL;
1075 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet;
1077 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", lpszRemoteFile, lpszNewFile);
1078 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1080 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1081 return FALSE;
1084 /* Clear any error information */
1085 INTERNET_SetLastError(0);
1087 /* Ensure we can write to lpszNewfile by opening it */
1088 hFile = CreateFileA(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1089 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1090 if (INVALID_HANDLE_VALUE == hFile)
1091 goto lend;
1093 /* Set up socket to retrieve data */
1094 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
1096 if (nBytes > 0)
1098 INT nDataSocket;
1100 /* Get data socket to server */
1101 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1103 INT nResCode;
1105 /* Receive data */
1106 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
1107 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1108 MAX_REPLY_LEN, 0, 0, 0);
1109 if (nResCode)
1111 if (nResCode == 226)
1112 bSuccess = TRUE;
1113 else
1114 FTP_SetResponseError(nResCode);
1116 close(nDataSocket);
1120 lend:
1121 if (lpwfs->lstnSocket != -1)
1122 close(lpwfs->lstnSocket);
1124 if (hFile)
1125 CloseHandle(hFile);
1127 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1128 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1130 INTERNET_ASYNC_RESULT iar;
1132 iar.dwResult = (DWORD)bSuccess;
1133 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1134 hIC->lpfnStatusCB(hInternet, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1135 &iar, sizeof(INTERNET_ASYNC_RESULT));
1138 return bSuccess;
1142 /***********************************************************************
1143 * FtpDeleteFileA (WININET.@)
1145 * Delete a file on the ftp server
1147 * RETURNS
1148 * TRUE on success
1149 * FALSE on failure
1152 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1154 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1155 LPWININETAPPINFOA hIC = NULL;
1157 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1159 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1160 return FALSE;
1163 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1164 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1166 WORKREQUEST workRequest;
1167 struct WORKREQ_FTPDELETEFILEA *req;
1169 workRequest.asyncall = FTPDELETEFILEA;
1170 workRequest.handle = hFtpSession;
1171 req = &workRequest.u.FtpDeleteFileA;
1172 req->lpszFilename = FTP_strdup(lpszFileName);
1174 return INTERNET_AsyncCall(&workRequest);
1176 else
1178 return FTP_FtpDeleteFileA(hFtpSession, lpszFileName);
1183 /***********************************************************************
1184 * FTP_FtpDeleteFileA (Internal)
1186 * Delete a file on the ftp server
1188 * RETURNS
1189 * TRUE on success
1190 * FALSE on failure
1193 BOOL FTP_FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1195 INT nResCode;
1196 BOOL bSuccess = FALSE;
1197 LPWININETAPPINFOA hIC = NULL;
1198 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1200 TRACE("0x%08lx\n", (ULONG) hFtpSession);
1201 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1203 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1204 return FALSE;
1207 /* Clear any error information */
1208 INTERNET_SetLastError(0);
1210 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1211 goto lend;
1213 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1214 MAX_REPLY_LEN, 0, 0, 0);
1215 if (nResCode)
1217 if (nResCode == 250)
1218 bSuccess = TRUE;
1219 else
1220 FTP_SetResponseError(nResCode);
1222 lend:
1223 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1224 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1226 INTERNET_ASYNC_RESULT iar;
1228 iar.dwResult = (DWORD)bSuccess;
1229 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1230 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1231 &iar, sizeof(INTERNET_ASYNC_RESULT));
1234 return bSuccess;
1238 /***********************************************************************
1239 * FtpRemoveDirectoryA (WININET.@)
1241 * Remove a directory on the ftp server
1243 * RETURNS
1244 * TRUE on success
1245 * FALSE on failure
1248 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1250 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1251 LPWININETAPPINFOA hIC = NULL;
1253 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1255 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1256 return FALSE;
1259 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1260 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1262 WORKREQUEST workRequest;
1263 struct WORKREQ_FTPREMOVEDIRECTORYA *req;
1265 workRequest.asyncall = FTPREMOVEDIRECTORYA;
1266 workRequest.handle = hFtpSession;
1267 req = &workRequest.u.FtpRemoveDirectoryA;
1268 req->lpszDirectory = FTP_strdup(lpszDirectory);
1270 return INTERNET_AsyncCall(&workRequest);
1272 else
1274 return FTP_FtpRemoveDirectoryA(hFtpSession, lpszDirectory);
1279 /***********************************************************************
1280 * FTP_FtpRemoveDirectoryA (Internal)
1282 * Remove a directory on the ftp server
1284 * RETURNS
1285 * TRUE on success
1286 * FALSE on failure
1289 BOOL FTP_FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1291 INT nResCode;
1292 BOOL bSuccess = FALSE;
1293 LPWININETAPPINFOA hIC = NULL;
1294 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1296 TRACE("\n");
1297 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1299 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1300 return FALSE;
1303 /* Clear any error information */
1304 INTERNET_SetLastError(0);
1306 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1307 goto lend;
1309 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1310 MAX_REPLY_LEN, 0, 0, 0);
1311 if (nResCode)
1313 if (nResCode == 250)
1314 bSuccess = TRUE;
1315 else
1316 FTP_SetResponseError(nResCode);
1319 lend:
1320 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1321 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1323 INTERNET_ASYNC_RESULT iar;
1325 iar.dwResult = (DWORD)bSuccess;
1326 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1327 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1328 &iar, sizeof(INTERNET_ASYNC_RESULT));
1331 return bSuccess;
1335 /***********************************************************************
1336 * FtpRenameFileA (WININET.@)
1338 * Rename a file on the ftp server
1340 * RETURNS
1341 * TRUE on success
1342 * FALSE on failure
1345 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1347 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1348 LPWININETAPPINFOA hIC = NULL;
1350 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1352 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1353 return FALSE;
1356 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1357 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1359 WORKREQUEST workRequest;
1360 struct WORKREQ_FTPRENAMEFILEA *req;
1362 workRequest.asyncall = FTPRENAMEFILEA;
1363 workRequest.handle = hFtpSession;
1364 req = &workRequest.u.FtpRenameFileA;
1365 req->lpszSrcFile = FTP_strdup(lpszSrc);
1366 req->lpszDestFile = FTP_strdup(lpszDest);
1368 return INTERNET_AsyncCall(&workRequest);
1370 else
1372 return FTP_FtpRenameFileA(hFtpSession, lpszSrc, lpszDest);
1376 /***********************************************************************
1377 * FTP_FtpRenameFileA (Internal)
1379 * Rename a file on the ftp server
1381 * RETURNS
1382 * TRUE on success
1383 * FALSE on failure
1386 BOOL FTP_FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1388 INT nResCode;
1389 BOOL bSuccess = FALSE;
1390 LPWININETAPPINFOA hIC = NULL;
1391 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1393 TRACE("\n");
1394 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1396 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1397 return FALSE;
1400 /* Clear any error information */
1401 INTERNET_SetLastError(0);
1403 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1404 goto lend;
1406 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1407 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1408 if (nResCode == 350)
1410 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1411 goto lend;
1413 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1414 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1417 if (nResCode == 250)
1418 bSuccess = TRUE;
1419 else
1420 FTP_SetResponseError(nResCode);
1422 lend:
1423 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1424 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1426 INTERNET_ASYNC_RESULT iar;
1428 iar.dwResult = (DWORD)bSuccess;
1429 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1430 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1431 &iar, sizeof(INTERNET_ASYNC_RESULT));
1434 return bSuccess;
1438 /***********************************************************************
1439 * FTP_Connect (internal)
1441 * Connect to a ftp server
1443 * RETURNS
1444 * HINTERNET a session handle on success
1445 * NULL on failure
1449 HINTERNET FTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
1450 INTERNET_PORT nServerPort, LPCSTR lpszUserName,
1451 LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
1453 struct sockaddr_in socketAddr;
1454 struct hostent *phe = NULL;
1455 INT nsocket = -1, sock_namelen;
1456 LPWININETAPPINFOA hIC = NULL;
1457 BOOL bSuccess = FALSE;
1458 LPWININETFTPSESSIONA lpwfs = NULL;
1460 TRACE("0x%08lx Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1461 (ULONG) hInternet, lpszServerName,
1462 nServerPort, lpszUserName, lpszPassword);
1464 if (((LPWININETHANDLEHEADER)hInternet)->htype != WH_HINIT)
1465 goto lerror;
1467 hIC = (LPWININETAPPINFOA) hInternet;
1469 if (NULL == lpszUserName && NULL != lpszPassword)
1471 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_USER_NAME);
1472 goto lerror;
1475 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1476 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1478 if (hIC->lpfnStatusCB)
1479 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1480 (LPSTR) lpszServerName, strlen(lpszServerName));
1482 if (!GetAddress(lpszServerName, nServerPort, &phe, &socketAddr))
1484 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1485 goto lerror;
1488 if (hIC->lpfnStatusCB)
1489 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1490 (LPSTR) lpszServerName, strlen(lpszServerName));
1492 nsocket = socket(AF_INET,SOCK_STREAM,0);
1493 if (nsocket == -1)
1495 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1496 goto lerror;
1499 if (hIC->lpfnStatusCB)
1500 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1501 &socketAddr, sizeof(struct sockaddr_in));
1503 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1505 ERR("Unable to connect (%s)\n", strerror(errno));
1506 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1508 else
1510 TRACE("Connected to server\n");
1511 if (hIC->lpfnStatusCB)
1512 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1513 &socketAddr, sizeof(struct sockaddr_in));
1515 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONA));
1516 if (NULL == lpwfs)
1518 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1519 goto lerror;
1522 lpwfs->hdr.htype = WH_HFTPSESSION;
1523 lpwfs->hdr.dwFlags = dwFlags;
1524 lpwfs->hdr.dwContext = dwContext;
1525 lpwfs->hdr.lpwhparent = (LPWININETHANDLEHEADER)hInternet;
1526 lpwfs->sndSocket = nsocket;
1527 lpwfs->download_in_progress = NULL;
1528 sock_namelen = sizeof(lpwfs->socketAddress);
1529 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1530 lpwfs->phostent = phe;
1532 if (NULL == lpszUserName)
1534 lpwfs->lpszUserName = FTP_strdup("anonymous");
1535 lpwfs->lpszPassword = FTP_strdup("user@server");
1537 else
1539 lpwfs->lpszUserName = FTP_strdup(lpszUserName);
1540 lpwfs->lpszPassword = FTP_strdup(lpszPassword);
1543 if (FTP_ConnectToHost(lpwfs))
1545 if (hIC->lpfnStatusCB)
1547 INTERNET_ASYNC_RESULT iar;
1549 iar.dwResult = (DWORD)lpwfs;
1550 iar.dwError = ERROR_SUCCESS;
1552 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_HANDLE_CREATED,
1553 &iar, sizeof(INTERNET_ASYNC_RESULT));
1555 TRACE("Successfully logged into server\n");
1556 bSuccess = TRUE;
1560 lerror:
1561 if (!bSuccess && nsocket == -1)
1562 close(nsocket);
1564 if (!bSuccess && lpwfs)
1566 HeapFree(GetProcessHeap(), 0, lpwfs);
1567 lpwfs = NULL;
1570 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1572 INTERNET_ASYNC_RESULT iar;
1574 iar.dwResult = (DWORD)lpwfs;
1575 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1576 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1577 &iar, sizeof(INTERNET_ASYNC_RESULT));
1580 return (HINTERNET) lpwfs;
1584 /***********************************************************************
1585 * FTP_ConnectToHost (internal)
1587 * Connect to a ftp server
1589 * RETURNS
1590 * TRUE on success
1591 * NULL on failure
1594 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs)
1596 INT nResCode;
1597 BOOL bSuccess = FALSE;
1599 TRACE("\n");
1600 FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1602 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1603 goto lend;
1605 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1606 MAX_REPLY_LEN, 0, 0, 0);
1607 if (nResCode)
1609 /* Login successful... */
1610 if (nResCode == 230)
1611 bSuccess = TRUE;
1612 /* User name okay, need password... */
1613 else if (nResCode == 331)
1614 bSuccess = FTP_SendPassword(lpwfs);
1615 /* Need account for login... */
1616 else if (nResCode == 332)
1617 bSuccess = FTP_SendAccount(lpwfs);
1618 else
1619 FTP_SetResponseError(nResCode);
1622 TRACE("Returning %d\n", bSuccess);
1623 lend:
1624 return bSuccess;
1628 /***********************************************************************
1629 * FTP_SendCommand (internal)
1631 * Send command to server
1633 * RETURNS
1634 * TRUE on success
1635 * NULL on failure
1638 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1639 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1641 DWORD len;
1642 CHAR *buf;
1643 DWORD nBytesSent = 0;
1644 DWORD nRC = 0;
1645 BOOL bParamHasLen;
1647 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1649 if (lpfnStatusCB)
1650 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1652 bParamHasLen = lpszParam && strlen(lpszParam) > 0;
1653 len = (bParamHasLen ? strlen(lpszParam) : -1) + strlen(szFtpCommands[ftpCmd]) +
1654 strlen(szCRLF)+ 1;
1655 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1657 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1658 return FALSE;
1660 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], bParamHasLen ? " " : "",
1661 bParamHasLen ? lpszParam : "", szCRLF);
1663 TRACE("Sending (%s) len(%ld)\n", buf, len);
1664 while((nBytesSent < len) && (nRC != -1))
1666 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1667 nBytesSent += nRC;
1670 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
1672 if (lpfnStatusCB)
1673 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_REQUEST_SENT,
1674 &nBytesSent, sizeof(DWORD));
1676 TRACE("Sent %ld bytes\n", nBytesSent);
1677 return (nRC != -1);
1681 /***********************************************************************
1682 * FTP_ReceiveResponse (internal)
1684 * Receive response from server
1686 * RETURNS
1687 * Reply code on success
1688 * 0 on failure
1692 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
1693 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1695 DWORD nRecv;
1696 INT rc = 0;
1697 char firstprefix[5];
1698 BOOL multiline = FALSE;
1701 TRACE("socket(%d) \n", nSocket);
1703 if (lpfnStatusCB)
1704 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1706 while(1)
1708 nRecv = dwResponse;
1709 if (!INTERNET_GetNextLine(nSocket, lpszResponse, &nRecv))
1710 goto lerror;
1712 if (nRecv >= 3)
1714 if(!multiline)
1716 if(lpszResponse[3] != '-')
1717 break;
1718 else
1719 { /* Start of multiline repsonse. Loop until we get "nnn " */
1720 multiline = TRUE;
1721 memcpy(firstprefix, lpszResponse, 3);
1722 firstprefix[3] = ' ';
1723 firstprefix[4] = '\0';
1726 else
1728 if(!memcmp(firstprefix, lpszResponse, 4))
1729 break;
1734 if (nRecv >= 3)
1736 rc = atoi(lpszResponse);
1738 if (lpfnStatusCB)
1739 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
1740 &nRecv, sizeof(DWORD));
1743 lerror:
1744 TRACE("return %d\n", rc);
1745 return rc;
1749 /***********************************************************************
1750 * FTP_SendPassword (internal)
1752 * Send password to ftp server
1754 * RETURNS
1755 * TRUE on success
1756 * NULL on failure
1759 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs)
1761 INT nResCode;
1762 BOOL bSuccess = FALSE;
1764 TRACE("\n");
1765 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
1766 goto lend;
1768 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1769 MAX_REPLY_LEN, 0, 0, 0);
1770 if (nResCode)
1772 TRACE("Received reply code %d\n", nResCode);
1773 /* Login successful... */
1774 if (nResCode == 230)
1775 bSuccess = TRUE;
1776 /* Command not implemented, superfluous at the server site... */
1777 /* Need account for login... */
1778 else if (nResCode == 332)
1779 bSuccess = FTP_SendAccount(lpwfs);
1780 else
1781 FTP_SetResponseError(nResCode);
1784 lend:
1785 TRACE("Returning %d\n", bSuccess);
1786 return bSuccess;
1790 /***********************************************************************
1791 * FTP_SendAccount (internal)
1795 * RETURNS
1796 * TRUE on success
1797 * FALSE on failure
1800 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs)
1802 INT nResCode;
1803 BOOL bSuccess = FALSE;
1805 TRACE("\n");
1806 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, NOACCOUNT, 0, 0, 0))
1807 goto lend;
1809 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1810 MAX_REPLY_LEN, 0, 0, 0);
1811 if (nResCode)
1812 bSuccess = TRUE;
1813 else
1814 FTP_SetResponseError(nResCode);
1816 lend:
1817 return bSuccess;
1821 /***********************************************************************
1822 * FTP_SendStore (internal)
1824 * Send request to upload file to ftp server
1826 * RETURNS
1827 * TRUE on success
1828 * FALSE on failure
1831 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
1833 INT nResCode;
1834 BOOL bSuccess = FALSE;
1836 TRACE("\n");
1837 if (!FTP_InitListenSocket(lpwfs))
1838 goto lend;
1840 if (!FTP_SendType(lpwfs, dwType))
1841 goto lend;
1843 if (!FTP_SendPortOrPasv(lpwfs))
1844 goto lend;
1846 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
1847 goto lend;
1848 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1849 MAX_REPLY_LEN, 0, 0, 0);
1850 if (nResCode)
1852 if (nResCode == 150)
1853 bSuccess = TRUE;
1854 else
1855 FTP_SetResponseError(nResCode);
1858 lend:
1859 if (!bSuccess && lpwfs->lstnSocket != -1)
1861 close(lpwfs->lstnSocket);
1862 lpwfs->lstnSocket = -1;
1865 return bSuccess;
1869 /***********************************************************************
1870 * FTP_InitListenSocket (internal)
1872 * Create a socket to listen for server response
1874 * RETURNS
1875 * TRUE on success
1876 * FALSE on failure
1879 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs)
1881 BOOL bSuccess = FALSE;
1882 size_t namelen = sizeof(struct sockaddr_in);
1884 TRACE("\n");
1886 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
1887 if (lpwfs->lstnSocket == -1)
1889 TRACE("Unable to create listening socket\n");
1890 goto lend;
1893 /* We obtain our ip addr from the name of the command channel socket */
1894 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
1896 /* and get the system to assign us a port */
1897 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
1899 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
1901 TRACE("Unable to bind socket\n");
1902 goto lend;
1905 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
1907 TRACE("listen failed\n");
1908 goto lend;
1911 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
1912 bSuccess = TRUE;
1914 lend:
1915 if (!bSuccess && lpwfs->lstnSocket == -1)
1917 close(lpwfs->lstnSocket);
1918 lpwfs->lstnSocket = -1;
1921 return bSuccess;
1925 /***********************************************************************
1926 * FTP_SendType (internal)
1928 * Tell server type of data being transferred
1930 * RETURNS
1931 * TRUE on success
1932 * FALSE on failure
1934 * W98SE doesn't cache the type that's currently set
1935 * (i.e. it sends it always),
1936 * so we probably don't want to do that either.
1938 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType)
1940 INT nResCode;
1941 CHAR type[2] = { "I" };
1942 BOOL bSuccess = FALSE;
1944 TRACE("\n");
1945 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
1946 *type = 'A';
1948 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
1949 goto lend;
1951 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1952 MAX_REPLY_LEN, 0, 0, 0)/100;
1953 if (nResCode)
1955 if (nResCode == 2)
1956 bSuccess = TRUE;
1957 else
1958 FTP_SetResponseError(nResCode);
1961 lend:
1962 return bSuccess;
1965 /***********************************************************************
1966 * FTP_GetFileSize (internal)
1968 * Retrieves from the server the size of the given file
1970 * RETURNS
1971 * TRUE on success
1972 * FALSE on failure
1975 BOOL FTP_GetFileSize(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD *dwSize)
1977 INT nResCode;
1978 BOOL bSuccess = FALSE;
1980 TRACE("\n");
1982 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
1983 goto lend;
1985 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1986 MAX_REPLY_LEN, 0, 0, 0);
1987 if (nResCode)
1989 if (nResCode == 213) {
1990 /* Now parses the output to get the actual file size */
1991 int i;
1992 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
1994 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
1995 if (lpszResponseBuffer[i] == '\0') return FALSE;
1996 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
1998 bSuccess = TRUE;
1999 } else {
2000 FTP_SetResponseError(nResCode);
2004 lend:
2005 return bSuccess;
2009 /***********************************************************************
2010 * FTP_SendPort (internal)
2012 * Tell server which port to use
2014 * RETURNS
2015 * TRUE on success
2016 * FALSE on failure
2019 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs)
2021 INT nResCode;
2022 CHAR szIPAddress[64];
2023 BOOL bSuccess = FALSE;
2024 TRACE("\n");
2026 sprintf(szIPAddress, "%d,%d,%d,%d,%d,%d",
2027 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2028 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2029 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2030 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2031 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2032 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2034 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2035 goto lend;
2037 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2038 MAX_REPLY_LEN,0, 0, 0);
2039 if (nResCode)
2041 if (nResCode == 200)
2042 bSuccess = TRUE;
2043 else
2044 FTP_SetResponseError(nResCode);
2047 lend:
2048 return bSuccess;
2052 /***********************************************************************
2053 * FTP_DoPassive (internal)
2055 * Tell server that we want to do passive transfers
2056 * and connect data socket
2058 * RETURNS
2059 * TRUE on success
2060 * FALSE on failure
2063 BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs)
2065 INT nResCode;
2066 BOOL bSuccess = FALSE;
2068 TRACE("\n");
2069 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2070 goto lend;
2072 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2073 MAX_REPLY_LEN,0, 0, 0);
2074 if (nResCode)
2076 if (nResCode == 227)
2078 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2079 LPSTR p;
2080 int f[6];
2081 int i;
2082 char *pAddr, *pPort;
2083 INT nsocket = -1;
2084 struct sockaddr_in dataSocketAddress;
2086 p = lpszResponseBuffer+4; /* skip status code */
2088 /* do a very strict check; we can improve that later. */
2090 if (strncmp(p, "Entering Passive Mode", 21))
2092 ERR("unknown response '%.*s', aborting\n", 21, p);
2093 goto lend;
2095 p += 21; /* skip string */
2096 if ((*p++ != ' ') || (*p++ != '('))
2098 ERR("unknown response format, aborting\n");
2099 goto lend;
2102 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2103 &f[4], &f[5]) != 6)
2105 ERR("unknown response address format '%s', aborting\n", p);
2106 goto lend;
2108 for (i=0; i < 6; i++)
2109 f[i] = f[i] & 0xff;
2111 dataSocketAddress = lpwfs->socketAddress;
2112 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2113 pPort = (char *)&(dataSocketAddress.sin_port);
2114 pAddr[0] = f[0];
2115 pAddr[1] = f[1];
2116 pAddr[2] = f[2];
2117 pAddr[3] = f[3];
2118 pPort[0] = f[4];
2119 pPort[1] = f[5];
2121 nsocket = socket(AF_INET,SOCK_STREAM,0);
2122 if (nsocket == -1)
2123 goto lend;
2125 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2127 ERR("can't connect passive FTP data port.\n");
2128 goto lend;
2130 lpwfs->pasvSocket = nsocket;
2131 bSuccess = TRUE;
2133 else
2134 FTP_SetResponseError(nResCode);
2137 lend:
2138 return bSuccess;
2142 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs)
2144 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2146 if (!FTP_DoPassive(lpwfs))
2147 return FALSE;
2149 else
2151 if (!FTP_SendPort(lpwfs))
2152 return FALSE;
2154 return TRUE;
2158 /***********************************************************************
2159 * FTP_GetDataSocket (internal)
2161 * Either accepts an incoming data socket connection from the server
2162 * or just returns the already opened socket after a PASV command
2163 * in case of passive FTP.
2166 * RETURNS
2167 * TRUE on success
2168 * FALSE on failure
2171 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket)
2173 struct sockaddr_in saddr;
2174 size_t addrlen = sizeof(struct sockaddr);
2176 TRACE("\n");
2177 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2179 *nDataSocket = lpwfs->pasvSocket;
2181 else
2183 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2184 close(lpwfs->lstnSocket);
2185 lpwfs->lstnSocket = -1;
2187 return *nDataSocket != -1;
2191 /***********************************************************************
2192 * FTP_SendData (internal)
2194 * Send data to the server
2196 * RETURNS
2197 * TRUE on success
2198 * FALSE on failure
2201 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile)
2203 BY_HANDLE_FILE_INFORMATION fi;
2204 DWORD nBytesRead = 0;
2205 DWORD nBytesSent = 0;
2206 DWORD nTotalSent = 0;
2207 DWORD nBytesToSend, nLen, nRC = 1;
2208 time_t s_long_time, e_long_time;
2209 LONG nSeconds;
2210 CHAR *lpszBuffer;
2212 TRACE("\n");
2213 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2214 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2216 /* Get the size of the file. */
2217 GetFileInformationByHandle(hFile, &fi);
2218 time(&s_long_time);
2222 nBytesToSend = nBytesRead - nBytesSent;
2224 if (nBytesToSend <= 0)
2226 /* Read data from file. */
2227 nBytesSent = 0;
2228 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2229 ERR("Failed reading from file\n");
2231 if (nBytesRead > 0)
2232 nBytesToSend = nBytesRead;
2233 else
2234 break;
2237 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2238 DATA_PACKET_SIZE : nBytesToSend;
2239 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2241 if (nRC != -1)
2243 nBytesSent += nRC;
2244 nTotalSent += nRC;
2247 /* Do some computation to display the status. */
2248 time(&e_long_time);
2249 nSeconds = e_long_time - s_long_time;
2250 if( nSeconds / 60 > 0 )
2252 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
2253 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2254 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2256 else
2258 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
2259 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2260 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2262 } while (nRC != -1);
2264 TRACE("file transfer complete!\n");
2266 if(lpszBuffer != NULL)
2267 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2269 return nTotalSent;
2273 /***********************************************************************
2274 * FTP_SendRetrieve (internal)
2276 * Send request to retrieve a file
2278 * RETURNS
2279 * Number of bytes to be received on success
2280 * 0 on failure
2283 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
2285 INT nResCode;
2286 DWORD nResult = 0;
2288 TRACE("\n");
2289 if (!FTP_InitListenSocket(lpwfs))
2290 goto lend;
2292 if (!FTP_SendType(lpwfs, dwType))
2293 goto lend;
2295 if (!FTP_SendPortOrPasv(lpwfs))
2296 goto lend;
2298 if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2299 goto lend;
2301 TRACE("Waiting to receive %ld bytes\n", nResult);
2303 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2304 goto lend;
2306 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2307 MAX_REPLY_LEN, 0, 0, 0);
2308 if ((nResCode != 125) && (nResCode != 150)) {
2309 /* That means that we got an error getting the file. */
2310 nResult = 0;
2313 lend:
2314 if (0 == nResult && lpwfs->lstnSocket != -1)
2316 close(lpwfs->lstnSocket);
2317 lpwfs->lstnSocket = -1;
2320 return nResult;
2324 /***********************************************************************
2325 * FTP_RetrieveData (internal)
2327 * Retrieve data from server
2329 * RETURNS
2330 * TRUE on success
2331 * FALSE on failure
2334 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2336 DWORD nBytesWritten;
2337 DWORD nBytesReceived = 0;
2338 INT nRC = 0;
2339 CHAR *lpszBuffer;
2341 TRACE("\n");
2343 if (INVALID_HANDLE_VALUE == hFile)
2344 return FALSE;
2346 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2347 if (NULL == lpszBuffer)
2349 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2350 return FALSE;
2353 while (nBytesReceived < nBytes && nRC != -1)
2355 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2356 if (nRC != -1)
2358 /* other side closed socket. */
2359 if (nRC == 0)
2360 goto recv_end;
2361 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2362 nBytesReceived += nRC;
2365 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
2366 nBytesReceived * 100 / nBytes);
2369 TRACE("Data transfer complete\n");
2370 if (NULL != lpszBuffer)
2371 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2373 recv_end:
2374 return (nRC != -1);
2378 /***********************************************************************
2379 * FTP_CloseSessionHandle (internal)
2381 * Deallocate session handle
2383 * RETURNS
2384 * TRUE on success
2385 * FALSE on failure
2388 BOOL FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs)
2390 TRACE("\n");
2392 if (lpwfs->download_in_progress != NULL)
2393 lpwfs->download_in_progress->session_deleted = TRUE;
2395 if (lpwfs->sndSocket != -1)
2396 close(lpwfs->sndSocket);
2398 if (lpwfs->lstnSocket != -1)
2399 close(lpwfs->lstnSocket);
2401 if (lpwfs->lpszPassword)
2402 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2404 if (lpwfs->lpszUserName)
2405 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2407 HeapFree(GetProcessHeap(), 0, lpwfs);
2409 return TRUE;
2413 /***********************************************************************
2414 * FTP_CloseFindNextHandle (internal)
2416 * Deallocate session handle
2418 * RETURNS
2419 * TRUE on success
2420 * FALSE on failure
2423 BOOL FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn)
2425 INT i;
2427 TRACE("\n");
2429 for (i = 0; i < lpwfn->size; i++)
2431 if (NULL != lpwfn->lpafp[i].lpszName)
2432 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2435 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2436 HeapFree(GetProcessHeap(), 0, lpwfn);
2438 return TRUE;
2441 /***********************************************************************
2442 * FTP_CloseFileTransferHandle (internal)
2444 * Closes the file transfer handle. This also 'cleans' the data queue of
2445 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2447 * RETURNS
2448 * TRUE on success
2449 * FALSE on failure
2452 BOOL FTP_CloseFileTransferHandle(LPWININETFILE lpwh)
2454 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) lpwh->hdr.lpwhparent;
2455 INT nResCode;
2457 TRACE("\n");
2459 if (!lpwh->session_deleted)
2460 lpwfs->download_in_progress = NULL;
2462 /* This just serves to flush the control socket of any spurrious lines written
2463 to it (like '226 Transfer complete.').
2465 Wonder what to do if the server sends us an error code though...
2467 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2468 MAX_REPLY_LEN, 0, 0, 0);
2470 if (lpwh->nDataSocket != -1)
2471 close(lpwh->nDataSocket);
2473 HeapFree(GetProcessHeap(), 0, lpwh);
2475 return TRUE;
2478 /***********************************************************************
2479 * FTP_ReceiveFileList (internal)
2481 * Read file list from server
2483 * RETURNS
2484 * Handle to file list on success
2485 * NULL on failure
2488 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
2489 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext)
2491 DWORD dwSize = 0;
2492 LPFILEPROPERTIESA lpafp = NULL;
2493 LPWININETFINDNEXTA lpwfn = NULL;
2495 TRACE("\n");
2497 if (FTP_ParseDirectory(lpwfs, nSocket, &lpafp, &dwSize))
2499 FTP_ConvertFileProp(lpafp, lpFindFileData);
2501 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTA));
2502 if (NULL != lpwfn)
2504 lpwfn->hdr.htype = WH_HFINDNEXT;
2505 lpwfn->hdr.lpwhparent = (LPWININETHANDLEHEADER)lpwfs;
2506 lpwfn->hdr.dwContext = dwContext;
2507 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2508 lpwfn->size = dwSize;
2509 lpwfn->lpafp = lpafp;
2513 TRACE("Matched %ld files\n", dwSize);
2514 return (HINTERNET)lpwfn;
2518 /***********************************************************************
2519 * FTP_ConvertFileProp (internal)
2521 * Converts FILEPROPERTIESA struct to WIN32_FIND_DATAA
2523 * RETURNS
2524 * TRUE on success
2525 * FALSE on failure
2528 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESA lpafp, LPWIN32_FIND_DATAA lpFindFileData)
2530 BOOL bSuccess = FALSE;
2532 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2534 if (lpafp)
2536 /* Convert 'Unix' time to Windows time */
2537 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
2538 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
2540 /* Not all fields are filled in */
2541 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2542 lpFindFileData->nFileSizeLow = lpafp->nSize;
2544 if (lpafp->bIsDirectory)
2545 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2547 if (lpafp->lpszName)
2548 strncpy(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2550 bSuccess = TRUE;
2553 return bSuccess;
2557 /***********************************************************************
2558 * FTP_ParseDirectory (internal)
2560 * Parse string of directory information
2562 * RETURNS
2563 * TRUE on success
2564 * FALSE on failure
2566 * FIXME: - This function needs serious clea-up
2567 * - We should consider both UNIX and NT list formats
2569 #define MAX_MONTH_LEN 10
2570 #define MIN_LEN_DIR_ENTRY 15
2572 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp)
2575 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2577 * For instance:
2578 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2580 CHAR* pszMinutes;
2581 CHAR* pszHour;
2582 time_t aTime;
2583 struct tm* apTM;
2584 CHAR pszMonth[MAX_MONTH_LEN];
2585 CHAR* pszMatch;
2586 BOOL bSuccess = TRUE;
2587 DWORD nBufLen = MAX_REPLY_LEN;
2588 LPFILEPROPERTIESA curFileProp = NULL;
2589 CHAR* pszLine = NULL;
2590 CHAR* pszToken = NULL;
2591 INT nTokenToSkip = 3;
2592 INT nCount = 0;
2593 INT nSeconds = 0;
2594 INT nMinutes = 0;
2595 INT nHour = 0;
2596 INT nDay = 0;
2597 INT nMonth = 0;
2598 INT nYear = 0;
2599 INT sizeFilePropArray = 20;
2600 INT indexFilePropArray = 0;
2602 TRACE("\n");
2604 /* Allocate intial file properties array */
2605 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESA)*(sizeFilePropArray));
2606 if (NULL == lpafp)
2608 bSuccess = FALSE;
2609 goto lend;
2612 while ((pszLine = INTERNET_GetNextLine(nSocket, INTERNET_GetResponseBuffer(), &nBufLen)) != NULL)
2614 if (sizeFilePropArray <= indexFilePropArray)
2616 LPFILEPROPERTIESA tmpafp;
2618 sizeFilePropArray *= 2;
2619 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
2620 sizeof(FILEPROPERTIESA)*sizeFilePropArray);
2621 if (NULL == tmpafp)
2623 bSuccess = FALSE;
2624 goto lend;
2627 *lpafp = tmpafp;
2630 curFileProp = &((*lpafp)[indexFilePropArray]);
2632 /* First Parse the permissions. */
2633 pszToken = strtok(pszLine, " \t" );
2635 /* HACK! If this is not a file listing skip the line */
2636 if (!pszToken || nBufLen <= MIN_LEN_DIR_ENTRY)
2638 nBufLen = MAX_REPLY_LEN;
2639 continue;
2641 if (10 == strlen(pszToken)) {
2642 /* Unix way of parsing ... */
2643 FTP_ParsePermission(pszToken, curFileProp);
2645 nTokenToSkip = 3;
2646 nCount = 0;
2647 do {
2648 pszToken = strtok( NULL, " \t" );
2649 nCount++;
2650 } while( nCount <= nTokenToSkip );
2652 /* Store the size of the file in the param list. */
2653 TRACE("nSize-> %s\n", pszToken);
2654 if (pszToken != NULL)
2655 curFileProp->nSize = atol(pszToken);
2657 /* Parse last modified time. */
2658 nSeconds = 0;
2659 nMinutes = 0;
2660 nHour = 0;
2661 nDay = 0;
2662 nMonth = 0;
2663 nYear = 0;
2665 pszToken = strtok( NULL, " \t" );
2666 strncpy(pszMonth, pszToken, MAX_MONTH_LEN);
2667 CharUpperA(pszMonth);
2668 pszMatch = strstr(szMonths, pszMonth);
2669 if( pszMatch != NULL )
2670 nMonth = (pszMatch - szMonths) / 3;
2672 pszToken = strtok(NULL, " \t");
2673 TRACE("nDay -> %s\n", pszToken);
2674 if (pszToken != NULL)
2675 nDay = atoi(pszToken);
2677 pszToken = strtok(NULL, " \t");
2678 pszMinutes = strchr(pszToken, ':');
2679 if( pszMinutes != NULL ) {
2680 pszMinutes++;
2681 nMinutes = atoi(pszMinutes);
2682 pszHour = pszMinutes - 3;
2683 if (pszHour != NULL)
2684 nHour = atoi(pszHour);
2685 time(&aTime);
2686 apTM = localtime( &aTime );
2687 nYear = apTM->tm_year;
2688 } else {
2689 nYear = atoi(pszToken);
2690 nYear -= 1900;
2691 nHour = 12;
2694 curFileProp->tmLastModified.tm_sec = nSeconds;
2695 curFileProp->tmLastModified.tm_min = nMinutes;
2696 curFileProp->tmLastModified.tm_hour = nHour;
2697 curFileProp->tmLastModified.tm_mday = nDay;
2698 curFileProp->tmLastModified.tm_mon = nMonth;
2699 curFileProp->tmLastModified.tm_year = nYear;
2701 pszToken = strtok(NULL, " \t");
2702 if(pszToken != NULL) {
2703 curFileProp->lpszName = FTP_strdup(pszToken);
2704 TRACE(": %s\n", curFileProp->lpszName);
2707 nBufLen = MAX_REPLY_LEN;
2708 indexFilePropArray++;
2709 } else if (8 == strlen(pszToken)) {
2710 /* NT way of parsing ... :
2712 07-13-03 08:55PM <DIR> sakpatch
2713 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
2716 curFileProp->permissions = 0xFFFF; /* No idea, put full permission :-) */
2718 sscanf(pszToken, "%d-%d-%d",
2719 &curFileProp->tmLastModified.tm_mon,
2720 &curFileProp->tmLastModified.tm_mday,
2721 &curFileProp->tmLastModified.tm_year);
2723 /* Hacky and bad Y2K protection :-) */
2724 if (curFileProp->tmLastModified.tm_year < 70)
2725 curFileProp->tmLastModified.tm_year += 100;
2727 pszToken = strtok(NULL, " \t");
2728 if (pszToken == NULL) {
2729 nBufLen = MAX_REPLY_LEN;
2730 continue;
2732 sscanf(pszToken, "%d:%d",
2733 &curFileProp->tmLastModified.tm_hour,
2734 &curFileProp->tmLastModified.tm_min);
2735 if ((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
2736 curFileProp->tmLastModified.tm_hour += 12;
2738 curFileProp->tmLastModified.tm_sec = 0;
2740 TRACE("Mod time: %2d:%2d:%2d %2d/%2d/%2d\n",
2741 curFileProp->tmLastModified.tm_hour, curFileProp->tmLastModified.tm_min, curFileProp->tmLastModified.tm_sec,
2742 (curFileProp->tmLastModified.tm_year >= 100) ? curFileProp->tmLastModified.tm_year - 100 : curFileProp->tmLastModified.tm_year,
2743 curFileProp->tmLastModified.tm_mon, curFileProp->tmLastModified.tm_mday);
2745 pszToken = strtok(NULL, " \t");
2746 if (pszToken == NULL) {
2747 nBufLen = MAX_REPLY_LEN;
2748 continue;
2750 if (!strcasecmp(pszToken, "<DIR>")) {
2751 curFileProp->bIsDirectory = TRUE;
2752 TRACE("Is directory\n");
2753 } else {
2754 curFileProp->bIsDirectory = FALSE;
2755 curFileProp->nSize = atol(pszToken);
2756 TRACE("nSize: %ld\n", curFileProp->nSize);
2759 pszToken = strtok(NULL, " \t");
2760 if (pszToken == NULL) {
2761 nBufLen = MAX_REPLY_LEN;
2762 continue;
2764 curFileProp->lpszName = FTP_strdup(pszToken);
2765 TRACE("Name: %s\n", curFileProp->lpszName);
2767 nBufLen = MAX_REPLY_LEN;
2768 indexFilePropArray++;
2769 } else {
2770 nBufLen = MAX_REPLY_LEN;
2774 if (bSuccess && indexFilePropArray)
2776 if (indexFilePropArray < sizeFilePropArray - 1)
2778 LPFILEPROPERTIESA tmpafp;
2780 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
2781 sizeof(FILEPROPERTIESA)*indexFilePropArray);
2782 if (NULL == tmpafp)
2783 *lpafp = tmpafp;
2785 *dwfp = indexFilePropArray;
2787 else
2789 HeapFree(GetProcessHeap(), 0, *lpafp);
2790 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2791 bSuccess = FALSE;
2794 lend:
2795 return bSuccess;
2799 /***********************************************************************
2800 * FTP_ParsePermission (internal)
2802 * Parse permission string of directory information
2804 * RETURNS
2805 * TRUE on success
2806 * FALSE on failure
2809 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp)
2811 BOOL bSuccess = TRUE;
2812 unsigned short nPermission = 0;
2813 INT nPos = 1;
2814 INT nLast = 9;
2816 TRACE("\n");
2817 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
2819 bSuccess = FALSE;
2820 return bSuccess;
2823 lpfp->bIsDirectory = (*lpszPermission == 'd');
2826 switch (nPos)
2828 case 1:
2829 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
2830 break;
2831 case 2:
2832 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
2833 break;
2834 case 3:
2835 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
2836 break;
2837 case 4:
2838 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
2839 break;
2840 case 5:
2841 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
2842 break;
2843 case 6:
2844 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
2845 break;
2846 case 7:
2847 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
2848 break;
2849 case 8:
2850 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
2851 break;
2852 case 9:
2853 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
2854 break;
2856 nPos++;
2857 }while (nPos <= nLast);
2859 lpfp->permissions = nPermission;
2860 return bSuccess;
2864 /***********************************************************************
2865 * FTP_SetResponseError (internal)
2867 * Set the appropriate error code for a given response from the server
2869 * RETURNS
2872 DWORD FTP_SetResponseError(DWORD dwResponse)
2874 DWORD dwCode = 0;
2876 switch(dwResponse)
2878 case 421: /* Service not available - Server may be shutting down. */
2879 dwCode = ERROR_INTERNET_TIMEOUT;
2880 break;
2882 case 425: /* Cannot open data connection. */
2883 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
2884 break;
2886 case 426: /* Connection closed, transer aborted. */
2887 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
2888 break;
2890 case 500: /* Syntax error. Command unrecognized. */
2891 case 501: /* Syntax error. Error in parameters or arguments. */
2892 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
2893 break;
2895 case 530: /* Not logged in. Login incorrect. */
2896 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
2897 break;
2899 case 550: /* File action not taken. File not found or no access. */
2900 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
2901 break;
2903 case 450: /* File action not taken. File may be busy. */
2904 case 451: /* Action aborted. Server error. */
2905 case 452: /* Action not taken. Insufficient storage space on server. */
2906 case 502: /* Command not implemented. */
2907 case 503: /* Bad sequence of command. */
2908 case 504: /* Command not implemented for that parameter. */
2909 case 532: /* Need account for storing files */
2910 case 551: /* Requested action aborted. Page type unknown */
2911 case 552: /* Action aborted. Exceeded storage allocation */
2912 case 553: /* Action not taken. File name not allowed. */
2914 default:
2915 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
2916 break;
2919 INTERNET_SetLastError(dwCode);
2920 return dwCode;