2 * WININET - Ftp implementation
4 * Copyright 1999 Corel Corporation
9 * Copyright 2000 Andreas Mohr
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "wine/port.h"
33 #include <sys/types.h>
34 #ifdef HAVE_SYS_SOCKET_H
35 # include <sys/socket.h>
48 #include "wine/debug.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
53 #define NOACCOUNT "noaccount"
54 #define DATA_PACKET_SIZE 0x2000
59 /* FTP commands with arguments. */
74 /* FTP commands without arguments. */
83 static const CHAR *szFtpCommands[] = {
105 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
107 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
108 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
109 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
110 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket);
111 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile);
112 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
113 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
114 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
115 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile);
116 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs);
117 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs);
118 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs);
119 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs);
120 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType);
121 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs);
122 BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs);
123 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs);
124 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp);
125 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp);
126 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
127 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext);
128 DWORD FTP_SetResponseError(DWORD dwResponse);
130 inline static LPSTR FTP_strdup( LPCSTR str )
132 LPSTR ret = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
133 if (ret) strcpy( ret, str );
137 /***********************************************************************
138 * FtpPutFileA (WININET.@)
140 * Uploads a file to the FTP server
147 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
148 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
150 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
151 LPWININETAPPINFOA hIC = NULL;
153 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
155 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
159 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
160 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
162 WORKREQUEST workRequest;
164 workRequest.asyncall = FTPPUTFILEA;
165 workRequest.HFTPSESSION = (DWORD)hConnect;
166 workRequest.LPSZLOCALFILE = (DWORD)FTP_strdup(lpszLocalFile);
167 workRequest.LPSZNEWREMOTEFILE = (DWORD)FTP_strdup(lpszNewRemoteFile);
168 workRequest.DWFLAGS = dwFlags;
169 workRequest.DWCONTEXT = dwContext;
171 return INTERNET_AsyncCall(&workRequest);
175 return FTP_FtpPutFileA(hConnect, lpszLocalFile,
176 lpszNewRemoteFile, dwFlags, dwContext);
180 /***********************************************************************
181 * FTP_FtpPutFileA (Internal)
183 * Uploads a file to the FTP server
190 BOOL WINAPI FTP_FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
191 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
193 HANDLE hFile = (HANDLE)NULL;
194 BOOL bSuccess = FALSE;
195 LPWININETAPPINFOA hIC = NULL;
196 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
199 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", lpszLocalFile, lpszNewRemoteFile);
200 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
202 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
206 /* Clear any error information */
207 INTERNET_SetLastError(0);
209 /* Open file to be uploaded */
210 if (INVALID_HANDLE_VALUE ==
211 (hFile = CreateFileA(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
213 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND);
217 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
218 if (hIC->lpfnStatusCB)
219 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
221 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
225 /* Get data socket to server */
226 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
228 FTP_SendData(lpwfs, nDataSocket, hFile);
230 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
231 MAX_REPLY_LEN, 0, 0, 0);
237 FTP_SetResponseError(nResCode);
243 if (lpwfs->lstnSocket != -1)
244 close(lpwfs->lstnSocket);
246 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
248 INTERNET_ASYNC_RESULT iar;
250 iar.dwResult = (DWORD)bSuccess;
251 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
252 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
253 &iar, sizeof(INTERNET_ASYNC_RESULT));
263 /***********************************************************************
264 * FtpSetCurrentDirectoryA (WININET.@)
266 * Change the working directory on the FTP server
273 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
275 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
276 LPWININETAPPINFOA hIC = NULL;
278 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
280 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
284 TRACE("lpszDirectory(%s)\n", lpszDirectory);
286 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
287 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
289 WORKREQUEST workRequest;
291 workRequest.asyncall = FTPSETCURRENTDIRECTORYA;
292 workRequest.HFTPSESSION = (DWORD)hConnect;
293 workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
295 return INTERNET_AsyncCall(&workRequest);
299 return FTP_FtpSetCurrentDirectoryA(hConnect, lpszDirectory);
304 /***********************************************************************
305 * FTP_FtpSetCurrentDirectoryA (Internal)
307 * Change the working directory on the FTP server
314 BOOL WINAPI FTP_FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
317 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
318 LPWININETAPPINFOA hIC = NULL;
319 DWORD bSuccess = FALSE;
321 TRACE("lpszDirectory(%s)\n", lpszDirectory);
323 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
325 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
329 /* Clear any error information */
330 INTERNET_SetLastError(0);
332 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
333 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
334 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
337 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
338 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
345 FTP_SetResponseError(nResCode);
349 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
351 INTERNET_ASYNC_RESULT iar;
353 iar.dwResult = (DWORD)bSuccess;
354 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
355 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
356 &iar, sizeof(INTERNET_ASYNC_RESULT));
362 /***********************************************************************
363 * FtpCreateDirectoryA (WININET.@)
365 * Create new directory on the FTP server
372 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
374 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
375 LPWININETAPPINFOA hIC = NULL;
377 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
379 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
383 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
384 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
386 WORKREQUEST workRequest;
388 workRequest.asyncall = FTPCREATEDIRECTORYA;
389 workRequest.HFTPSESSION = (DWORD)hConnect;
390 workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
392 return INTERNET_AsyncCall(&workRequest);
396 return FTP_FtpCreateDirectoryA(hConnect, lpszDirectory);
401 /***********************************************************************
402 * FTP_FtpCreateDirectoryA (Internal)
404 * Create new directory on the FTP server
411 BOOL WINAPI FTP_FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
414 BOOL bSuccess = FALSE;
415 LPWININETAPPINFOA hIC = NULL;
416 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
419 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
421 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
425 /* Clear any error information */
426 INTERNET_SetLastError(0);
428 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
431 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
432 MAX_REPLY_LEN, 0, 0, 0);
438 FTP_SetResponseError(nResCode);
442 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
443 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
445 INTERNET_ASYNC_RESULT iar;
447 iar.dwResult = (DWORD)bSuccess;
448 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
449 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
450 &iar, sizeof(INTERNET_ASYNC_RESULT));
457 /***********************************************************************
458 * FtpFindFirstFileA (WININET.@)
460 * Search the specified directory
463 * HINTERNET on success
467 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
468 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
470 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
471 LPWININETAPPINFOA hIC = NULL;
473 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
475 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
479 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
480 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
482 WORKREQUEST workRequest;
484 workRequest.asyncall = FTPFINDFIRSTFILEA;
485 workRequest.HFTPSESSION = (DWORD)hConnect;
486 workRequest.LPSZSEARCHFILE = (DWORD)FTP_strdup(lpszSearchFile);
487 workRequest.LPFINDFILEDATA = (DWORD)lpFindFileData;
488 workRequest.DWFLAGS = dwFlags;
489 workRequest.DWCONTEXT= dwContext;
491 INTERNET_AsyncCall(&workRequest);
496 return FTP_FtpFindFirstFileA(hConnect, lpszSearchFile, lpFindFileData,
502 /***********************************************************************
503 * FTP_FtpFindFirstFileA (Internal)
505 * Search the specified directory
508 * HINTERNET on success
512 HINTERNET WINAPI FTP_FtpFindFirstFileA(HINTERNET hConnect,
513 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
516 LPWININETAPPINFOA hIC = NULL;
517 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
518 LPWININETFINDNEXTA hFindNext = NULL;
522 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
524 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
528 /* Clear any error information */
529 INTERNET_SetLastError(0);
531 if (!FTP_InitListenSocket(lpwfs))
534 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
537 if (!FTP_SendPortOrPasv(lpwfs))
540 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
541 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, lpszSearchFile,
542 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
545 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
546 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
549 if (nResCode == 125 || nResCode == 150)
553 /* Get data socket to server */
554 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
556 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpFindFileData, dwContext);
558 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
559 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
560 if (nResCode != 226 && nResCode != 250)
561 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
567 FTP_SetResponseError(nResCode);
571 if (lpwfs->lstnSocket != -1)
572 close(lpwfs->lstnSocket);
574 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
576 INTERNET_ASYNC_RESULT iar;
580 iar.dwResult = (DWORD)hFindNext;
581 iar.dwError = ERROR_SUCCESS;
582 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
583 &iar, sizeof(INTERNET_ASYNC_RESULT));
586 iar.dwResult = (DWORD)hFindNext;
587 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
588 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
589 &iar, sizeof(INTERNET_ASYNC_RESULT));
592 return (HINTERNET)hFindNext;
596 /***********************************************************************
597 * FtpGetCurrentDirectoryA (WININET.@)
599 * Retrieves the current directory
606 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
607 LPDWORD lpdwCurrentDirectory)
609 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
610 LPWININETAPPINFOA hIC = NULL;
612 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
614 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
616 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
620 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
621 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
623 WORKREQUEST workRequest;
625 workRequest.asyncall = FTPGETCURRENTDIRECTORYA;
626 workRequest.HFTPSESSION = (DWORD)hFtpSession;
627 workRequest.LPSZDIRECTORY = (DWORD)lpszCurrentDirectory;
628 workRequest.LPDWDIRECTORY = (DWORD)lpdwCurrentDirectory;
630 return INTERNET_AsyncCall(&workRequest);
634 return FTP_FtpGetCurrentDirectoryA(hFtpSession, lpszCurrentDirectory,
635 lpdwCurrentDirectory);
640 /***********************************************************************
641 * FTP_FtpGetCurrentDirectoryA (Internal)
643 * Retrieves the current directory
650 BOOL WINAPI FTP_FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
651 LPDWORD lpdwCurrentDirectory)
654 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
655 LPWININETAPPINFOA hIC = NULL;
656 DWORD bSuccess = FALSE;
658 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
660 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
662 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
666 /* Clear any error information */
667 INTERNET_SetLastError(0);
669 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
671 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
672 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
673 hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext))
676 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
677 MAX_REPLY_LEN, hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext);
680 if (nResCode == 257) /* Extract directory name */
682 INT firstpos, lastpos, len;
683 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
685 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
687 if ('"' == lpszResponseBuffer[lastpos])
696 len = lastpos - firstpos - 1;
697 strncpy(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1],
698 len < *lpdwCurrentDirectory ? len : *lpdwCurrentDirectory);
699 *lpdwCurrentDirectory = len;
703 FTP_SetResponseError(nResCode);
707 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
709 INTERNET_ASYNC_RESULT iar;
711 iar.dwResult = (DWORD)bSuccess;
712 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
713 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
714 &iar, sizeof(INTERNET_ASYNC_RESULT));
717 return (DWORD) bSuccess;
720 /***********************************************************************
721 * FtpOpenFileA (WININET.@)
723 * Open a remote file for writing or reading
726 * HINTERNET handle on success
730 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
731 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
734 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
735 LPWININETAPPINFOA hIC = NULL;
737 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
739 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
743 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
744 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
746 WORKREQUEST workRequest;
748 workRequest.asyncall = FTPOPENFILEA;
749 workRequest.HFTPSESSION = (DWORD)hFtpSession;
750 workRequest.LPSZFILENAME = (DWORD)FTP_strdup(lpszFileName);
751 workRequest.FDWACCESS = fdwAccess;
752 workRequest.DWFLAGS = dwFlags;
753 workRequest.DWCONTEXT = dwContext;
755 INTERNET_AsyncCall(&workRequest);
760 return FTP_FtpOpenFileA(hFtpSession, lpszFileName, fdwAccess, dwFlags, dwContext);
765 /***********************************************************************
766 * FTP_FtpOpenFileA (Internal)
768 * Open a remote file for writing or reading
771 * HINTERNET handle on success
775 HINTERNET FTP_FtpOpenFileA(HINTERNET hFtpSession,
776 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
780 BOOL bSuccess = FALSE;
781 LPWININETFILE hFile = NULL;
782 LPWININETAPPINFOA hIC = NULL;
783 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
787 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
789 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
793 /* Clear any error information */
794 INTERNET_SetLastError(0);
796 if (GENERIC_READ == fdwAccess)
798 /* Set up socket to retrieve data */
799 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
801 else if (GENERIC_WRITE == fdwAccess)
803 /* Set up socket to send data */
804 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
807 /* Get data socket to server */
808 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
810 hFile = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE));
811 hFile->hdr.htype = WH_HFILE;
812 hFile->hdr.dwFlags = dwFlags;
813 hFile->hdr.dwContext = dwContext;
814 hFile->hdr.lpwhparent = hFtpSession;
815 hFile->nDataSocket = nDataSocket;
818 if (lpwfs->lstnSocket != -1)
819 close(lpwfs->lstnSocket);
821 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
822 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
824 INTERNET_ASYNC_RESULT iar;
828 iar.dwResult = (DWORD)hFile;
829 iar.dwError = ERROR_SUCCESS;
830 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
831 &iar, sizeof(INTERNET_ASYNC_RESULT));
834 iar.dwResult = (DWORD)bSuccess;
835 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
836 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
837 &iar, sizeof(INTERNET_ASYNC_RESULT));
840 return (HINTERNET)hFile;
844 /***********************************************************************
845 * FtpGetFileA (WININET.@)
847 * Retrieve file from the FTP server
854 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
855 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
858 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet;
859 LPWININETAPPINFOA hIC = NULL;
861 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
863 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
867 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
868 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
870 WORKREQUEST workRequest;
872 workRequest.asyncall = FTPGETFILEA;
873 workRequest.HFTPSESSION = (DWORD)hInternet;
874 workRequest.LPSZREMOTEFILE = (DWORD)FTP_strdup(lpszRemoteFile);
875 workRequest.LPSZNEWFILE = (DWORD)FTP_strdup(lpszNewFile);
876 workRequest.DWLOCALFLAGSATTRIBUTE = dwLocalFlagsAttribute;
877 workRequest.FFAILIFEXISTS = (DWORD)fFailIfExists;
878 workRequest.DWFLAGS = dwInternetFlags;
879 workRequest.DWCONTEXT = dwContext;
881 return INTERNET_AsyncCall(&workRequest);
885 return FTP_FtpGetFileA(hInternet, lpszRemoteFile, lpszNewFile,
886 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
891 /***********************************************************************
892 * FTP_FtpGetFileA (Internal)
894 * Retrieve file from the FTP server
901 BOOL WINAPI FTP_FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
902 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
906 BOOL bSuccess = FALSE;
908 LPWININETAPPINFOA hIC = NULL;
909 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet;
911 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", lpszRemoteFile, lpszNewFile);
912 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
914 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
918 /* Clear any error information */
919 INTERNET_SetLastError(0);
921 /* Ensure we can write to lpszNewfile by opening it */
922 hFile = CreateFileA(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
923 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
924 if (INVALID_HANDLE_VALUE == hFile)
927 /* Set up socket to retrieve data */
928 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
934 /* Get data socket to server */
935 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
940 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
941 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
942 MAX_REPLY_LEN, 0, 0, 0);
948 FTP_SetResponseError(nResCode);
955 if (lpwfs->lstnSocket != -1)
956 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 iar.dwResult = (DWORD)bSuccess;
967 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
968 hIC->lpfnStatusCB(hInternet, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
969 &iar, sizeof(INTERNET_ASYNC_RESULT));
976 /***********************************************************************
977 * FtpDeleteFileA (WININET.@)
979 * Delete a file on the ftp server
986 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
988 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
989 LPWININETAPPINFOA hIC = NULL;
991 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
993 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
997 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
998 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1000 WORKREQUEST workRequest;
1002 workRequest.asyncall = FTPRENAMEFILEA;
1003 workRequest.HFTPSESSION = (DWORD)hFtpSession;
1004 workRequest.LPSZFILENAME = (DWORD)FTP_strdup(lpszFileName);
1006 return INTERNET_AsyncCall(&workRequest);
1010 return FTP_FtpDeleteFileA(hFtpSession, lpszFileName);
1015 /***********************************************************************
1016 * FTP_FtpDeleteFileA (Internal)
1018 * Delete a file on the ftp server
1025 BOOL FTP_FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1028 BOOL bSuccess = FALSE;
1029 LPWININETAPPINFOA hIC = NULL;
1030 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1032 TRACE("0x%08lx\n", (ULONG) hFtpSession);
1033 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1035 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1039 /* Clear any error information */
1040 INTERNET_SetLastError(0);
1042 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1045 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1046 MAX_REPLY_LEN, 0, 0, 0);
1049 if (nResCode == 250)
1052 FTP_SetResponseError(nResCode);
1055 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1056 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1058 INTERNET_ASYNC_RESULT iar;
1060 iar.dwResult = (DWORD)bSuccess;
1061 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1062 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1063 &iar, sizeof(INTERNET_ASYNC_RESULT));
1070 /***********************************************************************
1071 * FtpRemoveDirectoryA (WININET.@)
1073 * Remove a directory on the ftp server
1080 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1082 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1083 LPWININETAPPINFOA hIC = NULL;
1085 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1087 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1091 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1092 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1094 WORKREQUEST workRequest;
1096 workRequest.asyncall = FTPREMOVEDIRECTORYA;
1097 workRequest.HFTPSESSION = (DWORD)hFtpSession;
1098 workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
1100 return INTERNET_AsyncCall(&workRequest);
1104 return FTP_FtpRemoveDirectoryA(hFtpSession, lpszDirectory);
1109 /***********************************************************************
1110 * FTP_FtpRemoveDirectoryA (Internal)
1112 * Remove a directory on the ftp server
1119 BOOL FTP_FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1122 BOOL bSuccess = FALSE;
1123 LPWININETAPPINFOA hIC = NULL;
1124 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1127 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1129 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1133 /* Clear any error information */
1134 INTERNET_SetLastError(0);
1136 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1139 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1140 MAX_REPLY_LEN, 0, 0, 0);
1143 if (nResCode == 250)
1146 FTP_SetResponseError(nResCode);
1150 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1151 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1153 INTERNET_ASYNC_RESULT iar;
1155 iar.dwResult = (DWORD)bSuccess;
1156 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1157 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1158 &iar, sizeof(INTERNET_ASYNC_RESULT));
1165 /***********************************************************************
1166 * FtpRenameFileA (WININET.@)
1168 * Rename a file on the ftp server
1175 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1177 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1178 LPWININETAPPINFOA hIC = NULL;
1180 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1182 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1186 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1187 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1189 WORKREQUEST workRequest;
1191 workRequest.asyncall = FTPRENAMEFILEA;
1192 workRequest.HFTPSESSION = (DWORD)hFtpSession;
1193 workRequest.LPSZSRCFILE = (DWORD)FTP_strdup(lpszSrc);
1194 workRequest.LPSZDESTFILE = (DWORD)FTP_strdup(lpszDest);
1196 return INTERNET_AsyncCall(&workRequest);
1200 return FTP_FtpRenameFileA(hFtpSession, lpszSrc, lpszDest);
1204 /***********************************************************************
1205 * FTP_FtpRenameFileA (Internal)
1207 * Rename a file on the ftp server
1214 BOOL FTP_FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1217 BOOL bSuccess = FALSE;
1218 LPWININETAPPINFOA hIC = NULL;
1219 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1222 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1224 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1228 /* Clear any error information */
1229 INTERNET_SetLastError(0);
1231 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1234 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1235 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1236 if (nResCode == 350)
1238 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1241 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1242 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1245 if (nResCode == 250)
1248 FTP_SetResponseError(nResCode);
1251 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1252 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1254 INTERNET_ASYNC_RESULT iar;
1256 iar.dwResult = (DWORD)bSuccess;
1257 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1258 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1259 &iar, sizeof(INTERNET_ASYNC_RESULT));
1266 /***********************************************************************
1267 * FTP_Connect (internal)
1269 * Connect to a ftp server
1272 * HINTERNET a session handle on success
1277 HINTERNET FTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
1278 INTERNET_PORT nServerPort, LPCSTR lpszUserName,
1279 LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
1281 struct sockaddr_in socketAddr;
1282 struct hostent *phe = NULL;
1283 INT nsocket = -1, sock_namelen;
1284 LPWININETAPPINFOA hIC = NULL;
1285 BOOL bSuccess = FALSE;
1286 LPWININETFTPSESSIONA lpwfs = NULL;
1288 TRACE("0x%08lx Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1289 (ULONG) hInternet, lpszServerName,
1290 nServerPort, lpszUserName, lpszPassword);
1292 if (((LPWININETHANDLEHEADER)hInternet)->htype != WH_HINIT)
1295 hIC = (LPWININETAPPINFOA) hInternet;
1297 if (NULL == lpszUserName && NULL != lpszPassword)
1299 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_USER_NAME);
1303 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1304 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1306 if (hIC->lpfnStatusCB)
1307 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1308 (LPSTR) lpszServerName, strlen(lpszServerName));
1310 if (!GetAddress(lpszServerName, nServerPort, &phe, &socketAddr))
1312 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1316 if (hIC->lpfnStatusCB)
1317 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1318 (LPSTR) lpszServerName, strlen(lpszServerName));
1320 nsocket = socket(AF_INET,SOCK_STREAM,0);
1323 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1327 if (hIC->lpfnStatusCB)
1328 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1329 &socketAddr, sizeof(struct sockaddr_in));
1331 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1333 ERR("Unable to connect (%s)\n", strerror(errno));
1334 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1338 TRACE("Connected to server\n");
1339 if (hIC->lpfnStatusCB)
1340 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1341 &socketAddr, sizeof(struct sockaddr_in));
1343 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONA));
1346 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1350 lpwfs->hdr.htype = WH_HFTPSESSION;
1351 lpwfs->hdr.dwFlags = dwFlags;
1352 lpwfs->hdr.dwContext = dwContext;
1353 lpwfs->hdr.lpwhparent = (LPWININETHANDLEHEADER)hInternet;
1354 lpwfs->sndSocket = nsocket;
1355 sock_namelen = sizeof(lpwfs->socketAddress);
1356 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1357 lpwfs->phostent = phe;
1359 if (NULL == lpszUserName)
1361 lpwfs->lpszUserName = FTP_strdup("anonymous");
1362 lpwfs->lpszPassword = FTP_strdup("user@server");
1366 lpwfs->lpszUserName = FTP_strdup(lpszUserName);
1367 lpwfs->lpszPassword = FTP_strdup(lpszPassword);
1370 if (FTP_ConnectToHost(lpwfs))
1372 if (hIC->lpfnStatusCB)
1374 INTERNET_ASYNC_RESULT iar;
1376 iar.dwResult = (DWORD)lpwfs;
1377 iar.dwError = ERROR_SUCCESS;
1379 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_HANDLE_CREATED,
1380 &iar, sizeof(INTERNET_ASYNC_RESULT));
1382 TRACE("Successfully logged into server\n");
1388 if (!bSuccess && nsocket == -1)
1391 if (!bSuccess && lpwfs)
1393 HeapFree(GetProcessHeap(), 0, lpwfs);
1397 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1399 INTERNET_ASYNC_RESULT iar;
1401 iar.dwResult = (DWORD)lpwfs;
1402 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1403 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1404 &iar, sizeof(INTERNET_ASYNC_RESULT));
1407 return (HINTERNET) lpwfs;
1411 /***********************************************************************
1412 * FTP_ConnectToHost (internal)
1414 * Connect to a ftp server
1421 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs)
1424 BOOL bSuccess = FALSE;
1427 FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1429 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1432 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1433 MAX_REPLY_LEN, 0, 0, 0);
1436 /* Login successful... */
1437 if (nResCode == 230)
1439 /* User name okay, need password... */
1440 else if (nResCode == 331)
1441 bSuccess = FTP_SendPassword(lpwfs);
1442 /* Need account for login... */
1443 else if (nResCode == 332)
1444 bSuccess = FTP_SendAccount(lpwfs);
1446 FTP_SetResponseError(nResCode);
1449 TRACE("Returning %d\n", bSuccess);
1455 /***********************************************************************
1456 * FTP_SendCommand (internal)
1458 * Send command to server
1465 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1466 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1470 DWORD nBytesSent = 0;
1474 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1477 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1479 bParamHasLen = lpszParam && strlen(lpszParam) > 0;
1480 len = (bParamHasLen ? strlen(lpszParam) : -1) + strlen(szFtpCommands[ftpCmd]) +
1482 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1484 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1487 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], bParamHasLen ? " " : "",
1488 bParamHasLen ? lpszParam : "", szCRLF);
1490 TRACE("Sending (%s) len(%ld)\n", buf, len);
1491 while((nBytesSent < len) && (nRC != -1))
1493 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1497 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
1500 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_REQUEST_SENT,
1501 &nBytesSent, sizeof(DWORD));
1503 TRACE("Sent %ld bytes\n", nBytesSent);
1508 /***********************************************************************
1509 * FTP_ReceiveResponse (internal)
1511 * Receive response from server
1514 * Reply code on success
1519 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
1520 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1524 char firstprefix[5];
1525 BOOL multiline = FALSE;
1528 TRACE("socket(%d) \n", nSocket);
1531 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1536 if (!INTERNET_GetNextLine(nSocket, lpszResponse, &nRecv))
1543 if(lpszResponse[3] != '-')
1546 { /* Start of multiline repsonse. Loop until we get "nnn " */
1548 memcpy(firstprefix, lpszResponse, 3);
1549 firstprefix[3] = ' ';
1550 firstprefix[4] = '\0';
1555 if(!memcmp(firstprefix, lpszResponse, 4))
1563 lpszResponse[nRecv] = '\0';
1564 rc = atoi(lpszResponse);
1567 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
1568 &nRecv, sizeof(DWORD));
1572 TRACE("return %d\n", rc);
1577 /***********************************************************************
1578 * FTP_SendPassword (internal)
1580 * Send password to ftp server
1587 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs)
1590 BOOL bSuccess = FALSE;
1593 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
1596 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1597 MAX_REPLY_LEN, 0, 0, 0);
1600 TRACE("Received reply code %d\n", nResCode);
1601 /* Login successful... */
1602 if (nResCode == 230)
1604 /* Command not implemented, superfluous at the server site... */
1605 /* Need account for login... */
1606 else if (nResCode == 332)
1607 bSuccess = FTP_SendAccount(lpwfs);
1609 FTP_SetResponseError(nResCode);
1613 TRACE("Returning %d\n", bSuccess);
1618 /***********************************************************************
1619 * FTP_SendAccount (internal)
1628 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs)
1631 BOOL bSuccess = FALSE;
1634 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, NOACCOUNT, 0, 0, 0))
1637 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1638 MAX_REPLY_LEN, 0, 0, 0);
1642 FTP_SetResponseError(nResCode);
1649 /***********************************************************************
1650 * FTP_SendStore (internal)
1652 * Send request to upload file to ftp server
1659 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
1662 BOOL bSuccess = FALSE;
1665 if (!FTP_InitListenSocket(lpwfs))
1668 if (!FTP_SendType(lpwfs, dwType))
1671 if (!FTP_SendPortOrPasv(lpwfs))
1674 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
1676 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1677 MAX_REPLY_LEN, 0, 0, 0);
1680 if (nResCode == 150)
1683 FTP_SetResponseError(nResCode);
1687 if (!bSuccess && lpwfs->lstnSocket != -1)
1689 close(lpwfs->lstnSocket);
1690 lpwfs->lstnSocket = -1;
1697 /***********************************************************************
1698 * FTP_InitListenSocket (internal)
1700 * Create a socket to listen for server response
1707 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs)
1709 BOOL bSuccess = FALSE;
1710 size_t namelen = sizeof(struct sockaddr_in);
1714 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
1715 if (lpwfs->lstnSocket == -1)
1717 TRACE("Unable to create listening socket\n");
1721 /* We obtain our ip addr from the name of the command channel socket */
1722 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
1724 /* and get the system to assign us a port */
1725 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
1727 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
1729 TRACE("Unable to bind socket\n");
1733 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
1735 TRACE("listen failed\n");
1739 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
1743 if (!bSuccess && lpwfs->lstnSocket == -1)
1745 close(lpwfs->lstnSocket);
1746 lpwfs->lstnSocket = -1;
1753 /***********************************************************************
1754 * FTP_SendType (internal)
1756 * Tell server type of data being transferred
1762 * W98SE doesn't cache the type that's currently set
1763 * (i.e. it sends it always),
1764 * so we probably don't want to do that either.
1766 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType)
1769 CHAR type[2] = { "I\0" };
1770 BOOL bSuccess = FALSE;
1773 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
1776 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
1779 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1780 MAX_REPLY_LEN, 0, 0, 0)/100;
1786 FTP_SetResponseError(nResCode);
1794 /***********************************************************************
1795 * FTP_SendPort (internal)
1797 * Tell server which port to use
1804 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs)
1807 CHAR szIPAddress[64];
1808 BOOL bSuccess = FALSE;
1811 sprintf(szIPAddress, "%d,%d,%d,%d,%d,%d",
1812 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
1813 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
1814 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
1815 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
1816 lpwfs->lstnSocketAddress.sin_port & 0xFF,
1817 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
1819 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
1822 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1823 MAX_REPLY_LEN,0, 0, 0);
1826 if (nResCode == 200)
1829 FTP_SetResponseError(nResCode);
1837 /***********************************************************************
1838 * FTP_DoPassive (internal)
1840 * Tell server that we want to do passive transfers
1841 * and connect data socket
1848 BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs)
1851 BOOL bSuccess = FALSE;
1854 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
1857 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1858 MAX_REPLY_LEN,0, 0, 0);
1861 if (nResCode == 227)
1863 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
1867 char *pAddr, *pPort;
1869 struct sockaddr_in dataSocketAddress;
1871 p = lpszResponseBuffer+4; /* skip status code */
1873 /* do a very strict check; we can improve that later. */
1875 if (strncmp(p, "Entering Passive Mode", 21))
1877 ERR("unknown response '%.*s', aborting\n", 21, p);
1880 p += 21; /* skip string */
1881 if ((*p++ != ' ') || (*p++ != '('))
1883 ERR("unknown response format, aborting\n");
1887 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
1890 ERR("unknown response address format '%s', aborting\n", p);
1893 for (i=0; i < 6; i++)
1896 dataSocketAddress = lpwfs->socketAddress;
1897 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
1898 pPort = (char *)&(dataSocketAddress.sin_port);
1906 nsocket = socket(AF_INET,SOCK_STREAM,0);
1910 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
1912 ERR("can't connect passive FTP data port.\n");
1915 lpwfs->pasvSocket = nsocket;
1919 FTP_SetResponseError(nResCode);
1927 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs)
1929 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
1931 if (!FTP_DoPassive(lpwfs))
1936 if (!FTP_SendPort(lpwfs))
1943 /***********************************************************************
1944 * FTP_GetDataSocket (internal)
1946 * Either accepts an incoming data socket connection from the server
1947 * or just returns the already opened socket after a PASV command
1948 * in case of passive FTP.
1956 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket)
1958 struct sockaddr_in saddr;
1959 size_t addrlen = sizeof(struct sockaddr);
1962 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
1964 *nDataSocket = lpwfs->pasvSocket;
1968 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
1969 close(lpwfs->lstnSocket);
1970 lpwfs->lstnSocket = -1;
1972 return *nDataSocket != -1;
1976 /***********************************************************************
1977 * FTP_SendData (internal)
1979 * Send data to the server
1986 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile)
1988 BY_HANDLE_FILE_INFORMATION fi;
1989 DWORD nBytesRead = 0;
1990 DWORD nBytesSent = 0;
1991 DWORD nTotalSent = 0;
1992 DWORD nBytesToSend, nLen, nRC = 1;
1993 time_t s_long_time, e_long_time;
1998 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
1999 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2001 /* Get the size of the file. */
2002 GetFileInformationByHandle(hFile, &fi);
2007 nBytesToSend = nBytesRead - nBytesSent;
2009 if (nBytesToSend <= 0)
2011 /* Read data from file. */
2013 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2014 ERR("Failed reading from file\n");
2017 nBytesToSend = nBytesRead;
2022 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2023 DATA_PACKET_SIZE : nBytesToSend;
2024 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2032 /* Do some computation to display the status. */
2034 nSeconds = e_long_time - s_long_time;
2035 if( nSeconds / 60 > 0 )
2037 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
2038 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2039 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2043 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
2044 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2045 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2047 } while (nRC != -1);
2049 TRACE("file transfer complete!\n");
2051 if(lpszBuffer != NULL)
2052 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2058 /***********************************************************************
2059 * FTP_SendRetrieve (internal)
2061 * Send request to retrieve a file
2064 * Number of bytes to be received on success
2068 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
2074 if (!FTP_InitListenSocket(lpwfs))
2077 if (!FTP_SendType(lpwfs, dwType))
2080 if (!FTP_SendPortOrPasv(lpwfs))
2083 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2086 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2087 MAX_REPLY_LEN, 0, 0, 0);
2090 if (nResCode == 125 || nResCode == 150)
2092 /* Parse size of data to be retrieved */
2093 INT i, sizepos = -1;
2094 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2095 for (i = strlen(lpszResponseBuffer) - 1; i >= 0; i--)
2097 if ('(' == lpszResponseBuffer[i])
2106 nResult = atol(&lpszResponseBuffer[sizepos+1]);
2107 TRACE("Waiting to receive %ld bytes\n", nResult);
2113 if (0 == nResult && lpwfs->lstnSocket != -1)
2115 close(lpwfs->lstnSocket);
2116 lpwfs->lstnSocket = -1;
2123 /***********************************************************************
2124 * FTP_RetrieveData (internal)
2126 * Retrieve data from server
2133 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2135 DWORD nBytesWritten;
2136 DWORD nBytesReceived = 0;
2142 if (INVALID_HANDLE_VALUE == hFile)
2145 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2146 if (NULL == lpszBuffer)
2148 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2152 while (nBytesReceived < nBytes && nRC != -1)
2154 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2157 /* other side closed socket. */
2160 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2161 nBytesReceived += nRC;
2164 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
2165 nBytesReceived * 100 / nBytes);
2168 TRACE("Data transfer complete\n");
2169 if (NULL != lpszBuffer)
2170 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2177 /***********************************************************************
2178 * FTP_CloseSessionHandle (internal)
2180 * Deallocate session handle
2187 BOOL FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs)
2189 if (lpwfs->sndSocket != -1)
2190 close(lpwfs->sndSocket);
2192 if (lpwfs->lstnSocket != -1)
2193 close(lpwfs->lstnSocket);
2195 if (lpwfs->lpszPassword)
2196 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2198 if (lpwfs->lpszUserName)
2199 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2201 HeapFree(GetProcessHeap(), 0, lpwfs);
2207 /***********************************************************************
2208 * FTP_CloseSessionHandle (internal)
2210 * Deallocate session handle
2217 BOOL FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn)
2223 for (i = 0; i < lpwfn->size; i++)
2225 if (NULL != lpwfn->lpafp[i].lpszName)
2226 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2229 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2230 HeapFree(GetProcessHeap(), 0, lpwfn);
2236 /***********************************************************************
2237 * FTP_ReceiveFileList (internal)
2239 * Read file list from server
2242 * Handle to file list on success
2246 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
2247 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext)
2250 LPFILEPROPERTIESA lpafp = NULL;
2251 LPWININETFINDNEXTA lpwfn = NULL;
2255 if (FTP_ParseDirectory(lpwfs, nSocket, &lpafp, &dwSize))
2257 FTP_ConvertFileProp(lpafp, lpFindFileData);
2259 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTA));
2262 lpwfn->hdr.htype = WH_HFINDNEXT;
2263 lpwfn->hdr.lpwhparent = (LPWININETHANDLEHEADER)lpwfs;
2264 lpwfn->hdr.dwContext = dwContext;
2265 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2266 lpwfn->size = dwSize;
2267 lpwfn->lpafp = lpafp;
2271 TRACE("Matched %ld files\n", dwSize);
2272 return (HINTERNET)lpwfn;
2276 /***********************************************************************
2277 * FTP_ConvertFileProp (internal)
2279 * Converts FILEPROPERTIESA struct to WIN32_FIND_DATAA
2286 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESA lpafp, LPWIN32_FIND_DATAA lpFindFileData)
2288 BOOL bSuccess = FALSE;
2290 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2294 DWORD access = mktime(&lpafp->tmLastModified);
2296 /* Not all fields are filled in */
2297 lpFindFileData->ftLastAccessTime.dwHighDateTime = HIWORD(access);
2298 lpFindFileData->ftLastAccessTime.dwLowDateTime = LOWORD(access);
2299 lpFindFileData->nFileSizeHigh = HIWORD(lpafp->nSize);
2300 lpFindFileData->nFileSizeLow = LOWORD(lpafp->nSize);
2302 if (lpafp->bIsDirectory)
2303 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2305 if (lpafp->lpszName)
2306 strncpy(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2315 /***********************************************************************
2316 * FTP_ParseDirectory (internal)
2318 * Parse string of directory information
2324 * FIXME: - This function needs serious clea-up
2325 * - We should consider both UNIX and NT list formats
2327 #define MAX_MONTH_LEN 10
2328 #define MIN_LEN_DIR_ENTRY 15
2330 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp)
2333 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2336 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2342 CHAR pszMonth[MAX_MONTH_LEN];
2344 BOOL bSuccess = TRUE;
2345 DWORD nBufLen = MAX_REPLY_LEN;
2346 LPFILEPROPERTIESA curFileProp = NULL;
2347 CHAR* pszLine = NULL;
2348 CHAR* pszToken = NULL;
2349 INT nTokenToSkip = 3;
2357 INT sizeFilePropArray = 20;
2358 INT indexFilePropArray = 0;
2362 /* Allocate intial file properties array */
2363 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESA)*(sizeFilePropArray));
2370 while ((pszLine = INTERNET_GetNextLine(nSocket, INTERNET_GetResponseBuffer(), &nBufLen)) != NULL)
2372 if (sizeFilePropArray <= indexFilePropArray)
2374 LPFILEPROPERTIESA tmpafp;
2376 sizeFilePropArray *= 2;
2377 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
2378 sizeof(FILEPROPERTIESA)*sizeFilePropArray);
2388 curFileProp = &((*lpafp)[indexFilePropArray]);
2390 /* First Parse the permissions. */
2391 pszToken = strtok(pszLine, " \t" );
2393 /* HACK! If this is not a file listing skip the line */
2394 if (!pszToken || 10 != strlen(pszToken) || nBufLen <= MIN_LEN_DIR_ENTRY)
2396 nBufLen = MAX_REPLY_LEN;
2400 FTP_ParsePermission(pszToken, curFileProp);
2406 pszToken = strtok( NULL, " \t" );
2408 } while( nCount <= nTokenToSkip );
2410 /* Store the size of the file in the param list. */
2411 TRACE("nSize-> %s\n", pszToken);
2412 if (pszToken != NULL)
2413 curFileProp->nSize = atol(pszToken);
2415 /* Parse last modified time. */
2423 pszToken = strtok( NULL, " \t" );
2424 strncpy(pszMonth, pszToken, MAX_MONTH_LEN);
2425 CharUpperA(pszMonth);
2426 pszMatch = strstr(szMonths, pszMonth);
2427 if( pszMatch != NULL )
2428 nMonth = (pszMatch - szMonths) / 3;
2430 pszToken = strtok(NULL, " \t");
2431 TRACE("nDay -> %s\n", pszToken);
2432 if (pszToken != NULL)
2433 nDay = atoi(pszToken);
2435 pszToken = strtok(NULL, " \t");
2436 pszMinutes = strchr(pszToken, ':');
2437 if( pszMinutes != NULL )
2440 nMinutes = atoi(pszMinutes);
2441 pszHour = pszMinutes - 3;
2442 if (pszHour != NULL)
2443 nHour = atoi(pszHour);
2445 apTM = localtime( &aTime );
2446 nYear = apTM->tm_year;
2450 nYear = atoi(pszToken);
2455 curFileProp->tmLastModified.tm_sec = nSeconds;
2456 curFileProp->tmLastModified.tm_min = nMinutes;
2457 curFileProp->tmLastModified.tm_hour = nHour;
2458 curFileProp->tmLastModified.tm_mday = nDay;
2459 curFileProp->tmLastModified.tm_mon = nMonth;
2460 curFileProp->tmLastModified.tm_year = nYear;
2462 pszToken = strtok(NULL, " \t");
2463 if(pszToken != NULL)
2465 curFileProp->lpszName = FTP_strdup(pszToken);
2466 TRACE(": %s\n", curFileProp->lpszName);
2469 nBufLen = MAX_REPLY_LEN;
2470 indexFilePropArray++;
2473 if (bSuccess && indexFilePropArray)
2475 if (indexFilePropArray < sizeFilePropArray - 1)
2477 LPFILEPROPERTIESA tmpafp;
2479 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
2480 sizeof(FILEPROPERTIESA)*indexFilePropArray);
2484 *dwfp = indexFilePropArray;
2488 HeapFree(GetProcessHeap(), 0, *lpafp);
2489 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2498 /***********************************************************************
2499 * FTP_ParsePermission (internal)
2501 * Parse permission string of directory information
2508 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp)
2510 BOOL bSuccess = TRUE;
2511 unsigned short nPermission = 0;
2516 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
2522 lpfp->bIsDirectory = (*lpszPermission == 'd');
2528 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
2531 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
2534 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
2537 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
2540 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
2543 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
2546 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
2549 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
2552 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
2556 }while (nPos <= nLast);
2558 lpfp->permissions = nPermission;
2563 /***********************************************************************
2564 * FTP_SetResponseError (internal)
2566 * Set the appropriate error code for a given response from the server
2571 DWORD FTP_SetResponseError(DWORD dwResponse)
2577 case 421: /* Service not available - Server may be shutting down. */
2578 dwCode = ERROR_INTERNET_TIMEOUT;
2581 case 425: /* Cannot open data connection. */
2582 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
2585 case 426: /* Connection closed, transer aborted. */
2586 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
2589 case 500: /* Syntax error. Command unrecognized. */
2590 case 501: /* Syntax error. Error in parameters or arguments. */
2591 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
2594 case 530: /* Not logged in. Login incorrect. */
2595 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
2598 case 550: /* File action not taken. File not found or no access. */
2599 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
2602 case 450: /* File action not taken. File may be busy. */
2603 case 451: /* Action aborted. Server error. */
2604 case 452: /* Action not taken. Insufficient storage space on server. */
2605 case 502: /* Command not implemented. */
2606 case 503: /* Bad sequence of command. */
2607 case 504: /* Command not implemented for that parameter. */
2608 case 532: /* Need account for storing files */
2609 case 551: /* Requested action aborted. Page type unknown */
2610 case 552: /* Action aborted. Exceeded storage allocation */
2611 case 553: /* Action not taken. File name not allowed. */
2614 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
2618 INTERNET_SetLastError(dwCode);