2 * WININET - Ftp implementation
4 * Copyright 1999 Corel Corporation
9 * Copyright 2000 Andreas Mohr
21 #include <sys/types.h>
22 #ifdef HAVE_SYS_SOCKET_H
23 # include <sys/socket.h>
27 #ifdef HAVE_NETINET_IN_SYSTM_H
28 # include <netinet/in_systm.h>
30 #ifdef HAVE_NETINET_IN_H
31 # include <netinet/in.h>
33 #ifdef HAVE_NETINET_IP_H
34 # include <netinet/ip.h>
45 #include "debugtools.h"
48 DEFAULT_DEBUG_CHANNEL(wininet);
50 #define NOACCOUNT "noaccount"
51 #define DATA_PACKET_SIZE 0x2000
56 /* FTP commands with arguments. */
71 /* FTP commands without arguments. */
80 static const CHAR *szFtpCommands[] = {
102 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
104 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
105 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
106 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
107 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket);
108 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile);
109 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
110 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
111 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
112 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile);
113 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs);
114 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs);
115 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs);
116 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs);
117 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType);
118 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs);
119 BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs);
120 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs);
121 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp);
122 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp);
123 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
124 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext);
125 DWORD FTP_SetResponseError(DWORD dwResponse);
127 inline static LPSTR FTP_strdup( LPCSTR str )
129 LPSTR ret = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
130 if (ret) strcpy( ret, str );
134 /***********************************************************************
135 * FtpPutFileA (WININET.43)
137 * Uploads a file to the FTP server
144 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
145 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
147 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
148 LPWININETAPPINFOA hIC = NULL;
150 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
152 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
156 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
157 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
159 WORKREQUEST workRequest;
161 workRequest.asyncall = FTPPUTFILEA;
162 workRequest.HFTPSESSION = (DWORD)hConnect;
163 workRequest.LPSZLOCALFILE = (DWORD)FTP_strdup(lpszLocalFile);
164 workRequest.LPSZNEWREMOTEFILE = (DWORD)FTP_strdup(lpszNewRemoteFile);
165 workRequest.DWFLAGS = dwFlags;
166 workRequest.DWCONTEXT = dwContext;
168 return INTERNET_AsyncCall(&workRequest);
172 return FTP_FtpPutFileA(hConnect, lpszLocalFile,
173 lpszNewRemoteFile, dwFlags, dwContext);
177 /***********************************************************************
178 * FTP_FtpPutFileA (Internal)
180 * Uploads a file to the FTP server
187 BOOL WINAPI FTP_FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
188 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
190 HANDLE hFile = (HANDLE)NULL;
191 BOOL bSuccess = FALSE;
192 LPWININETAPPINFOA hIC = NULL;
193 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
196 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", lpszLocalFile, lpszNewRemoteFile);
197 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
199 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
203 /* Clear any error information */
204 INTERNET_SetLastError(0);
206 /* Open file to be uploaded */
207 if (INVALID_HANDLE_VALUE ==
208 (hFile = CreateFileA(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
210 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND);
214 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
215 if (hIC->lpfnStatusCB)
216 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
218 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
222 /* Get data socket to server */
223 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
225 FTP_SendData(lpwfs, nDataSocket, hFile);
227 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
228 MAX_REPLY_LEN, 0, 0, 0);
234 FTP_SetResponseError(nResCode);
240 if (lpwfs->lstnSocket != INVALID_SOCKET)
241 close(lpwfs->lstnSocket);
243 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
245 INTERNET_ASYNC_RESULT iar;
247 iar.dwResult = (DWORD)bSuccess;
248 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
249 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
250 &iar, sizeof(INTERNET_ASYNC_RESULT));
260 /***********************************************************************
261 * FtpSetCurrentDirectoryA (WININET.49)
263 * Change the working directory on the FTP server
270 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
272 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
273 LPWININETAPPINFOA hIC = NULL;
275 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
277 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
281 TRACE("lpszDirectory(%s)\n", lpszDirectory);
283 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
284 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
286 WORKREQUEST workRequest;
288 workRequest.asyncall = FTPSETCURRENTDIRECTORYA;
289 workRequest.HFTPSESSION = (DWORD)hConnect;
290 workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
292 return INTERNET_AsyncCall(&workRequest);
296 return FTP_FtpSetCurrentDirectoryA(hConnect, lpszDirectory);
301 /***********************************************************************
302 * FTP_FtpSetCurrentDirectoryA (Internal)
304 * Change the working directory on the FTP server
311 BOOL WINAPI FTP_FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
314 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
315 LPWININETAPPINFOA hIC = NULL;
316 DWORD bSuccess = FALSE;
318 TRACE("lpszDirectory(%s)\n", lpszDirectory);
320 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
322 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
326 /* Clear any error information */
327 INTERNET_SetLastError(0);
329 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
330 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
331 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
334 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
335 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
342 FTP_SetResponseError(nResCode);
346 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
348 INTERNET_ASYNC_RESULT iar;
350 iar.dwResult = (DWORD)bSuccess;
351 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
352 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
353 &iar, sizeof(INTERNET_ASYNC_RESULT));
359 /***********************************************************************
360 * FtpCreateDirectoryA (WININET.31)
362 * Create new directory on the FTP server
369 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
371 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
372 LPWININETAPPINFOA hIC = NULL;
374 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
376 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
380 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
381 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
383 WORKREQUEST workRequest;
385 workRequest.asyncall = FTPCREATEDIRECTORYA;
386 workRequest.HFTPSESSION = (DWORD)hConnect;
387 workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
389 return INTERNET_AsyncCall(&workRequest);
393 return FTP_FtpCreateDirectoryA(hConnect, lpszDirectory);
398 /***********************************************************************
399 * FTP_FtpCreateDirectoryA (Internal)
401 * Create new directory on the FTP server
408 BOOL WINAPI FTP_FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
411 BOOL bSuccess = FALSE;
412 LPWININETAPPINFOA hIC = NULL;
413 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
416 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
418 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
422 /* Clear any error information */
423 INTERNET_SetLastError(0);
425 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
428 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
429 MAX_REPLY_LEN, 0, 0, 0);
435 FTP_SetResponseError(nResCode);
439 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
440 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
442 INTERNET_ASYNC_RESULT iar;
444 iar.dwResult = (DWORD)bSuccess;
445 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
446 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
447 &iar, sizeof(INTERNET_ASYNC_RESULT));
454 /***********************************************************************
455 * FtpFindFirstFileA (WININET.35)
457 * Search the specified directory
460 * HINTERNET on success
464 INTERNETAPI HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
465 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
467 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
468 LPWININETAPPINFOA hIC = NULL;
470 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
472 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
476 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
477 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
479 WORKREQUEST workRequest;
481 workRequest.asyncall = FTPFINDFIRSTFILEA;
482 workRequest.HFTPSESSION = (DWORD)hConnect;
483 workRequest.LPSZSEARCHFILE = (DWORD)FTP_strdup(lpszSearchFile);
484 workRequest.LPFINDFILEDATA = (DWORD)lpFindFileData;
485 workRequest.DWFLAGS = dwFlags;
486 workRequest.DWCONTEXT= dwContext;
488 INTERNET_AsyncCall(&workRequest);
493 return FTP_FtpFindFirstFileA(hConnect, lpszSearchFile, lpFindFileData,
499 /***********************************************************************
500 * FTP_FtpFindFirstFileA (Internal)
502 * Search the specified directory
505 * HINTERNET on success
509 INTERNETAPI HINTERNET WINAPI FTP_FtpFindFirstFileA(HINTERNET hConnect,
510 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
513 LPWININETAPPINFOA hIC = NULL;
514 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
515 LPWININETFINDNEXTA hFindNext = NULL;
519 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
521 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
525 /* Clear any error information */
526 INTERNET_SetLastError(0);
528 if (!FTP_InitListenSocket(lpwfs))
531 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
534 if (!FTP_SendPortOrPasv(lpwfs))
537 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
538 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, lpszSearchFile,
539 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
542 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
543 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
546 if (nResCode == 125 || nResCode == 150)
550 /* Get data socket to server */
551 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
553 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpFindFileData, dwContext);
555 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
556 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
557 if (nResCode != 226 && nResCode != 250)
558 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
564 FTP_SetResponseError(nResCode);
568 if (lpwfs->lstnSocket != INVALID_SOCKET)
569 close(lpwfs->lstnSocket);
571 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
573 INTERNET_ASYNC_RESULT iar;
577 iar.dwResult = (DWORD)hFindNext;
578 iar.dwError = ERROR_SUCCESS;
579 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
580 &iar, sizeof(INTERNET_ASYNC_RESULT));
583 iar.dwResult = (DWORD)hFindNext;
584 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
585 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
586 &iar, sizeof(INTERNET_ASYNC_RESULT));
589 return (HINTERNET)hFindNext;
593 /***********************************************************************
594 * FtpGetCurrentDirectoryA (WININET.37)
596 * Retrieves the current directory
603 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
604 LPDWORD lpdwCurrentDirectory)
606 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
607 LPWININETAPPINFOA hIC = NULL;
609 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
611 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
613 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
617 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
618 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
620 WORKREQUEST workRequest;
622 workRequest.asyncall = FTPGETCURRENTDIRECTORYA;
623 workRequest.HFTPSESSION = (DWORD)hFtpSession;
624 workRequest.LPSZDIRECTORY = (DWORD)lpszCurrentDirectory;
625 workRequest.LPDWDIRECTORY = (DWORD)lpdwCurrentDirectory;
627 return INTERNET_AsyncCall(&workRequest);
631 return FTP_FtpGetCurrentDirectoryA(hFtpSession, lpszCurrentDirectory,
632 lpdwCurrentDirectory);
637 /***********************************************************************
638 * FTP_FtpGetCurrentDirectoryA (Internal)
640 * Retrieves the current directory
647 BOOL WINAPI FTP_FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
648 LPDWORD lpdwCurrentDirectory)
651 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
652 LPWININETAPPINFOA hIC = NULL;
653 DWORD bSuccess = FALSE;
655 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
657 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
659 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
663 /* Clear any error information */
664 INTERNET_SetLastError(0);
666 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
668 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
669 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
670 hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext))
673 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
674 MAX_REPLY_LEN, hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext);
677 if (nResCode == 257) /* Extract directory name */
679 INT firstpos, lastpos, len;
680 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
682 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
684 if ('"' == lpszResponseBuffer[lastpos])
693 len = lastpos - firstpos - 1;
694 strncpy(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1],
695 len < *lpdwCurrentDirectory ? len : *lpdwCurrentDirectory);
696 *lpdwCurrentDirectory = len;
700 FTP_SetResponseError(nResCode);
704 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
706 INTERNET_ASYNC_RESULT iar;
708 iar.dwResult = (DWORD)bSuccess;
709 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
710 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
711 &iar, sizeof(INTERNET_ASYNC_RESULT));
714 return (DWORD) bSuccess;
717 /***********************************************************************
718 * FtpOpenFileA (WININET.41)
720 * Open a remote file for writing or reading
723 * HINTERNET handle on success
727 INTERNETAPI HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
728 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
731 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
732 LPWININETAPPINFOA hIC = NULL;
734 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
736 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
740 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
741 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
743 WORKREQUEST workRequest;
745 workRequest.asyncall = FTPOPENFILEA;
746 workRequest.HFTPSESSION = (DWORD)hFtpSession;
747 workRequest.LPSZFILENAME = (DWORD)FTP_strdup(lpszFileName);
748 workRequest.FDWACCESS = fdwAccess;
749 workRequest.DWFLAGS = dwFlags;
750 workRequest.DWCONTEXT = dwContext;
752 INTERNET_AsyncCall(&workRequest);
757 return FTP_FtpOpenFileA(hFtpSession, lpszFileName, fdwAccess, dwFlags, dwContext);
762 /***********************************************************************
763 * FTP_FtpOpenFileA (Internal)
765 * Open a remote file for writing or reading
768 * HINTERNET handle on success
772 HINTERNET FTP_FtpOpenFileA(HINTERNET hFtpSession,
773 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
777 BOOL bSuccess = FALSE;
778 LPWININETFILE hFile = NULL;
779 LPWININETAPPINFOA hIC = NULL;
780 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
784 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
786 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
790 /* Clear any error information */
791 INTERNET_SetLastError(0);
793 if (GENERIC_READ == fdwAccess)
795 /* Set up socket to retrieve data */
796 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
798 else if (GENERIC_WRITE == fdwAccess)
800 /* Set up socket to send data */
801 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
804 /* Get data socket to server */
805 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
807 hFile = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE));
808 hFile->hdr.htype = WH_HFILE;
809 hFile->hdr.dwFlags = dwFlags;
810 hFile->hdr.dwContext = dwContext;
811 hFile->hdr.lpwhparent = hFtpSession;
812 hFile->nDataSocket = nDataSocket;
815 if (lpwfs->lstnSocket != INVALID_SOCKET)
816 close(lpwfs->lstnSocket);
818 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
819 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
821 INTERNET_ASYNC_RESULT iar;
825 iar.dwResult = (DWORD)hFile;
826 iar.dwError = ERROR_SUCCESS;
827 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
828 &iar, sizeof(INTERNET_ASYNC_RESULT));
831 iar.dwResult = (DWORD)bSuccess;
832 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
833 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
834 &iar, sizeof(INTERNET_ASYNC_RESULT));
837 return (HINTERNET)hFile;
841 /***********************************************************************
842 * FtpGetFileA (WININET.39)
844 * Retrieve file from the FTP server
851 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
852 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
855 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet;
856 LPWININETAPPINFOA hIC = NULL;
858 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
860 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
864 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
865 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
867 WORKREQUEST workRequest;
869 workRequest.asyncall = FTPGETFILEA;
870 workRequest.HFTPSESSION = (DWORD)hInternet;
871 workRequest.LPSZREMOTEFILE = (DWORD)FTP_strdup(lpszRemoteFile);
872 workRequest.LPSZNEWFILE = (DWORD)FTP_strdup(lpszNewFile);
873 workRequest.DWLOCALFLAGSATTRIBUTE = dwLocalFlagsAttribute;
874 workRequest.FFAILIFEXISTS = (DWORD)fFailIfExists;
875 workRequest.DWFLAGS = dwInternetFlags;
876 workRequest.DWCONTEXT = dwContext;
878 return INTERNET_AsyncCall(&workRequest);
882 return FTP_FtpGetFileA(hInternet, lpszRemoteFile, lpszNewFile,
883 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
888 /***********************************************************************
889 * FTP_FtpGetFileA (Internal)
891 * Retrieve file from the FTP server
898 BOOL WINAPI FTP_FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
899 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
903 BOOL bSuccess = FALSE;
905 LPWININETAPPINFOA hIC = NULL;
906 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet;
908 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", lpszRemoteFile, lpszNewFile);
909 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
911 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
915 /* Clear any error information */
916 INTERNET_SetLastError(0);
918 /* Ensure we can write to lpszNewfile by opening it */
919 hFile = CreateFileA(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
920 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
921 if (INVALID_HANDLE_VALUE == hFile)
924 /* Set up socket to retrieve data */
925 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
931 /* Get data socket to server */
932 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
937 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
938 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
939 MAX_REPLY_LEN, 0, 0, 0);
945 FTP_SetResponseError(nResCode);
952 if (lpwfs->lstnSocket != INVALID_SOCKET)
953 close(lpwfs->lstnSocket);
958 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
959 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
961 INTERNET_ASYNC_RESULT iar;
963 iar.dwResult = (DWORD)bSuccess;
964 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
965 hIC->lpfnStatusCB(hInternet, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
966 &iar, sizeof(INTERNET_ASYNC_RESULT));
973 /***********************************************************************
974 * FtpDeleteFileA (WININET.33)
976 * Delete a file on the ftp server
983 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
985 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
986 LPWININETAPPINFOA hIC = NULL;
988 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
990 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
994 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
995 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
997 WORKREQUEST workRequest;
999 workRequest.asyncall = FTPRENAMEFILEA;
1000 workRequest.HFTPSESSION = (DWORD)hFtpSession;
1001 workRequest.LPSZFILENAME = (DWORD)FTP_strdup(lpszFileName);
1003 return INTERNET_AsyncCall(&workRequest);
1007 return FTP_FtpDeleteFileA(hFtpSession, lpszFileName);
1012 /***********************************************************************
1013 * FTP_FtpDeleteFileA (Internal)
1015 * Delete a file on the ftp server
1022 BOOL FTP_FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1025 BOOL bSuccess = FALSE;
1026 LPWININETAPPINFOA hIC = NULL;
1027 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1029 TRACE("0x%08lx\n", (ULONG) hFtpSession);
1030 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1032 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1036 /* Clear any error information */
1037 INTERNET_SetLastError(0);
1039 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1042 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1043 MAX_REPLY_LEN, 0, 0, 0);
1046 if (nResCode == 250)
1049 FTP_SetResponseError(nResCode);
1052 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1053 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1055 INTERNET_ASYNC_RESULT iar;
1057 iar.dwResult = (DWORD)bSuccess;
1058 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1059 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1060 &iar, sizeof(INTERNET_ASYNC_RESULT));
1067 /***********************************************************************
1068 * FtpRemoveDirectoryA (WININET.45)
1070 * Remove a directory on the ftp server
1077 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1079 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1080 LPWININETAPPINFOA hIC = NULL;
1082 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1084 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1088 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1089 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1091 WORKREQUEST workRequest;
1093 workRequest.asyncall = FTPREMOVEDIRECTORYA;
1094 workRequest.HFTPSESSION = (DWORD)hFtpSession;
1095 workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
1097 return INTERNET_AsyncCall(&workRequest);
1101 return FTP_FtpRemoveDirectoryA(hFtpSession, lpszDirectory);
1106 /***********************************************************************
1107 * FTP_FtpRemoveDirectoryA (Internal)
1109 * Remove a directory on the ftp server
1116 BOOL FTP_FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1119 BOOL bSuccess = FALSE;
1120 LPWININETAPPINFOA hIC = NULL;
1121 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1124 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1126 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1130 /* Clear any error information */
1131 INTERNET_SetLastError(0);
1133 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1136 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1137 MAX_REPLY_LEN, 0, 0, 0);
1140 if (nResCode == 250)
1143 FTP_SetResponseError(nResCode);
1147 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1148 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1150 INTERNET_ASYNC_RESULT iar;
1152 iar.dwResult = (DWORD)bSuccess;
1153 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1154 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1155 &iar, sizeof(INTERNET_ASYNC_RESULT));
1162 /***********************************************************************
1163 * FtpRenameFileA (WININET.47)
1165 * Rename a file on the ftp server
1172 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1174 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1175 LPWININETAPPINFOA hIC = NULL;
1177 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1179 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1183 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1184 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1186 WORKREQUEST workRequest;
1188 workRequest.asyncall = FTPRENAMEFILEA;
1189 workRequest.HFTPSESSION = (DWORD)hFtpSession;
1190 workRequest.LPSZSRCFILE = (DWORD)FTP_strdup(lpszSrc);
1191 workRequest.LPSZDESTFILE = (DWORD)FTP_strdup(lpszDest);
1193 return INTERNET_AsyncCall(&workRequest);
1197 return FTP_FtpRenameFileA(hFtpSession, lpszSrc, lpszDest);
1201 /***********************************************************************
1202 * FTP_FtpRenameFileA (Internal)
1204 * Rename a file on the ftp server
1211 BOOL FTP_FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1214 BOOL bSuccess = FALSE;
1215 LPWININETAPPINFOA hIC = NULL;
1216 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1219 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1221 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1225 /* Clear any error information */
1226 INTERNET_SetLastError(0);
1228 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1231 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1232 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1233 if (nResCode == 350)
1235 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1238 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1239 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1242 if (nResCode == 250)
1245 FTP_SetResponseError(nResCode);
1248 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1249 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1251 INTERNET_ASYNC_RESULT iar;
1253 iar.dwResult = (DWORD)bSuccess;
1254 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1255 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1256 &iar, sizeof(INTERNET_ASYNC_RESULT));
1263 /***********************************************************************
1264 * FTP_Connect (internal)
1266 * Connect to a ftp server
1269 * HINTERNET a session handle on success
1274 HINTERNET FTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
1275 INTERNET_PORT nServerPort, LPCSTR lpszUserName,
1276 LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
1278 struct sockaddr_in socketAddr;
1279 struct hostent *phe = NULL;
1280 INT nsocket = INVALID_SOCKET, sock_namelen;
1281 LPWININETAPPINFOA hIC = NULL;
1282 BOOL bSuccess = FALSE;
1283 LPWININETFTPSESSIONA lpwfs = NULL;
1285 TRACE("0x%08lx Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1286 (ULONG) hInternet, lpszServerName,
1287 nServerPort, lpszUserName, lpszPassword);
1289 if (((LPWININETHANDLEHEADER)hInternet)->htype != WH_HINIT)
1292 hIC = (LPWININETAPPINFOA) hInternet;
1294 if (NULL == lpszUserName && NULL != lpszPassword)
1296 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_USER_NAME);
1300 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1301 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1303 if (hIC->lpfnStatusCB)
1304 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1305 (LPSTR) lpszServerName, strlen(lpszServerName));
1307 if (!GetAddress(lpszServerName, nServerPort, &phe, &socketAddr))
1309 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1313 if (hIC->lpfnStatusCB)
1314 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1315 (LPSTR) lpszServerName, strlen(lpszServerName));
1317 if (INVALID_SOCKET == (nsocket = socket(AF_INET,SOCK_STREAM,0)))
1319 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1323 if (hIC->lpfnStatusCB)
1324 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1325 &socketAddr, sizeof(struct sockaddr_in));
1327 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1329 ERR("Unable to connect (%s)\n", strerror(errno));
1330 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1334 TRACE("Connected to server\n");
1335 if (hIC->lpfnStatusCB)
1336 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1337 &socketAddr, sizeof(struct sockaddr_in));
1339 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONA));
1342 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1346 lpwfs->hdr.htype = WH_HFTPSESSION;
1347 lpwfs->hdr.dwFlags = dwFlags;
1348 lpwfs->hdr.dwContext = dwContext;
1349 lpwfs->hdr.lpwhparent = (LPWININETHANDLEHEADER)hInternet;
1350 lpwfs->sndSocket = nsocket;
1351 sock_namelen = sizeof(lpwfs->socketAddress);
1352 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1353 lpwfs->phostent = phe;
1355 if (NULL == lpszUserName)
1357 lpwfs->lpszUserName = FTP_strdup("anonymous");
1358 lpwfs->lpszPassword = FTP_strdup("user@server");
1362 lpwfs->lpszUserName = FTP_strdup(lpszUserName);
1363 lpwfs->lpszPassword = FTP_strdup(lpszPassword);
1366 if (FTP_ConnectToHost(lpwfs))
1368 if (hIC->lpfnStatusCB)
1370 INTERNET_ASYNC_RESULT iar;
1372 iar.dwResult = (DWORD)lpwfs;
1373 iar.dwError = ERROR_SUCCESS;
1375 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_HANDLE_CREATED,
1376 &iar, sizeof(INTERNET_ASYNC_RESULT));
1378 TRACE("Successfully logged into server\n");
1384 if (!bSuccess && INVALID_SOCKET != nsocket)
1387 if (!bSuccess && lpwfs)
1389 HeapFree(GetProcessHeap(), 0, lpwfs);
1393 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1395 INTERNET_ASYNC_RESULT iar;
1397 iar.dwResult = (DWORD)lpwfs;
1398 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1399 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1400 &iar, sizeof(INTERNET_ASYNC_RESULT));
1403 return (HINTERNET) lpwfs;
1407 /***********************************************************************
1408 * FTP_ConnectToHost (internal)
1410 * Connect to a ftp server
1417 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs)
1420 BOOL bSuccess = FALSE;
1423 FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1425 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1428 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1429 MAX_REPLY_LEN, 0, 0, 0);
1432 /* Login successful... */
1433 if (nResCode == 230)
1435 /* User name okay, need password... */
1436 else if (nResCode == 331)
1437 bSuccess = FTP_SendPassword(lpwfs);
1438 /* Need account for login... */
1439 else if (nResCode == 332)
1440 bSuccess = FTP_SendAccount(lpwfs);
1442 FTP_SetResponseError(nResCode);
1445 TRACE("Returning %d\n", bSuccess);
1451 /***********************************************************************
1452 * FTP_SendCommand (internal)
1454 * Send command to server
1461 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1462 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1466 DWORD nBytesSent = 0;
1470 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1473 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1475 bParamHasLen = lpszParam && strlen(lpszParam) > 0;
1476 len = (bParamHasLen ? strlen(lpszParam) : -1) + strlen(szFtpCommands[ftpCmd]) +
1478 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1480 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1483 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], bParamHasLen ? " " : "",
1484 bParamHasLen ? lpszParam : "", szCRLF);
1486 TRACE("Sending (%s) len(%ld)\n", buf, len);
1487 while((nBytesSent < len) && (nRC != SOCKET_ERROR))
1489 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1493 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
1496 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_REQUEST_SENT,
1497 &nBytesSent, sizeof(DWORD));
1499 TRACE("Sent %ld bytes\n", nBytesSent);
1500 return (nRC != SOCKET_ERROR);
1504 /***********************************************************************
1505 * FTP_ReceiveResponse (internal)
1507 * Receive response from server
1510 * Reply code on success
1515 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
1516 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1520 char firstprefix[5];
1521 BOOL multiline = FALSE;
1524 TRACE("socket(%d) \n", nSocket);
1527 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1532 if (!INTERNET_GetNextLine(nSocket, lpszResponse, &nRecv))
1539 if(lpszResponse[3] != '-')
1542 { /* Start of multiline repsonse. Loop until we get "nnn " */
1544 memcpy(firstprefix, lpszResponse, 3);
1545 firstprefix[3] = ' ';
1546 firstprefix[4] = '\0';
1551 if(!memcmp(firstprefix, lpszResponse, 4))
1559 lpszResponse[nRecv] = '\0';
1560 rc = atoi(lpszResponse);
1563 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
1564 &nRecv, sizeof(DWORD));
1568 TRACE("return %d\n", rc);
1573 /***********************************************************************
1574 * FTP_SendPassword (internal)
1576 * Send password to ftp server
1583 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs)
1586 BOOL bSuccess = FALSE;
1589 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
1592 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1593 MAX_REPLY_LEN, 0, 0, 0);
1596 TRACE("Received reply code %d\n", nResCode);
1597 /* Login successful... */
1598 if (nResCode == 230)
1600 /* Command not implemented, superfluous at the server site... */
1601 /* Need account for login... */
1602 else if (nResCode == 332)
1603 bSuccess = FTP_SendAccount(lpwfs);
1605 FTP_SetResponseError(nResCode);
1609 TRACE("Returning %d\n", bSuccess);
1614 /***********************************************************************
1615 * FTP_SendAccount (internal)
1624 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs)
1627 BOOL bSuccess = FALSE;
1630 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, NOACCOUNT, 0, 0, 0))
1633 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1634 MAX_REPLY_LEN, 0, 0, 0);
1638 FTP_SetResponseError(nResCode);
1645 /***********************************************************************
1646 * FTP_SendStore (internal)
1648 * Send request to upload file to ftp server
1655 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
1658 BOOL bSuccess = FALSE;
1661 if (!FTP_InitListenSocket(lpwfs))
1664 if (!FTP_SendType(lpwfs, dwType))
1667 if (!FTP_SendPortOrPasv(lpwfs))
1670 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
1672 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1673 MAX_REPLY_LEN, 0, 0, 0);
1676 if (nResCode == 150)
1679 FTP_SetResponseError(nResCode);
1683 if (!bSuccess && INVALID_SOCKET != lpwfs->lstnSocket)
1685 close(lpwfs->lstnSocket);
1686 lpwfs->lstnSocket = INVALID_SOCKET;
1693 /***********************************************************************
1694 * FTP_InitListenSocket (internal)
1696 * Create a socket to listen for server response
1703 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs)
1705 BOOL bSuccess = FALSE;
1706 size_t namelen = sizeof(struct sockaddr_in);
1710 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
1711 if (INVALID_SOCKET == lpwfs->lstnSocket)
1713 TRACE("Unable to create listening socket\n");
1717 /* We obtain our ip addr from the name of the command channel socket */
1718 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
1720 /* and get the system to assign us a port */
1721 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
1723 if (SOCKET_ERROR == bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)))
1725 TRACE("Unable to bind socket\n");
1729 if (SOCKET_ERROR == listen(lpwfs->lstnSocket, MAX_BACKLOG))
1731 TRACE("listen failed\n");
1735 if (SOCKET_ERROR != getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen))
1739 if (!bSuccess && INVALID_SOCKET == lpwfs->lstnSocket)
1741 close(lpwfs->lstnSocket);
1742 lpwfs->lstnSocket = INVALID_SOCKET;
1749 /***********************************************************************
1750 * FTP_SendType (internal)
1752 * Tell server type of data being transfered
1758 * W98SE doesn't cache the type that's currently set
1759 * (i.e. it sends it always),
1760 * so we probably don't want to do that either.
1762 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType)
1765 CHAR type[2] = { "I\0" };
1766 BOOL bSuccess = FALSE;
1769 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
1772 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
1775 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1776 MAX_REPLY_LEN, 0, 0, 0)/100;
1782 FTP_SetResponseError(nResCode);
1790 /***********************************************************************
1791 * FTP_SendPort (internal)
1793 * Tell server which port to use
1800 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs)
1803 CHAR szIPAddress[64];
1804 BOOL bSuccess = FALSE;
1807 sprintf(szIPAddress, "%d,%d,%d,%d,%d,%d",
1808 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
1809 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
1810 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
1811 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
1812 lpwfs->lstnSocketAddress.sin_port & 0xFF,
1813 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
1815 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
1818 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1819 MAX_REPLY_LEN,0, 0, 0);
1822 if (nResCode == 200)
1825 FTP_SetResponseError(nResCode);
1833 /***********************************************************************
1834 * FTP_DoPassive (internal)
1836 * Tell server that we want to do passive transfers
1837 * and connect data socket
1844 BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs)
1847 BOOL bSuccess = FALSE;
1850 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
1853 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1854 MAX_REPLY_LEN,0, 0, 0);
1857 if (nResCode == 227)
1859 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
1863 char *pAddr, *pPort;
1864 INT nsocket = INVALID_SOCKET;
1865 struct sockaddr_in dataSocketAddress;
1867 p = lpszResponseBuffer+4; /* skip status code */
1869 /* do a very strict check; we can improve that later. */
1871 if (strncmp(p, "Entering Passive Mode", 21))
1873 ERR("unknown response '%.*s', aborting\n", 21, p);
1876 p += 21; /* skip string */
1877 if ((*p++ != ' ') || (*p++ != '('))
1879 ERR("unknown response format, aborting\n");
1883 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
1886 ERR("unknown response address format '%s', aborting\n", p);
1889 for (i=0; i < 6; i++)
1892 dataSocketAddress = lpwfs->socketAddress;
1893 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
1894 pPort = (char *)&(dataSocketAddress.sin_port);
1902 if (INVALID_SOCKET == (nsocket = socket(AF_INET,SOCK_STREAM,0)))
1905 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
1907 ERR("can't connect passive FTP data port.\n");
1910 lpwfs->pasvSocket = nsocket;
1914 FTP_SetResponseError(nResCode);
1922 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs)
1924 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
1926 if (!FTP_DoPassive(lpwfs))
1931 if (!FTP_SendPort(lpwfs))
1938 /***********************************************************************
1939 * FTP_GetDataSocket (internal)
1941 * Either accepts an incoming data socket connection from the server
1942 * or just returns the already opened socket after a PASV command
1943 * in case of passive FTP.
1951 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket)
1953 struct sockaddr_in saddr;
1954 size_t addrlen = sizeof(struct sockaddr);
1957 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
1959 *nDataSocket = lpwfs->pasvSocket;
1963 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
1964 close(lpwfs->lstnSocket);
1965 lpwfs->lstnSocket = INVALID_SOCKET;
1967 return *nDataSocket != INVALID_SOCKET;
1971 /***********************************************************************
1972 * FTP_SendData (internal)
1974 * Send data to the server
1981 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile)
1983 BY_HANDLE_FILE_INFORMATION fi;
1984 DWORD nBytesRead = 0;
1985 DWORD nBytesSent = 0;
1986 DWORD nTotalSent = 0;
1987 DWORD nBytesToSend, nLen, nRC = 1;
1988 time_t s_long_time, e_long_time;
1993 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
1994 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
1996 /* Get the size of the file. */
1997 GetFileInformationByHandle(hFile, &fi);
2002 nBytesToSend = nBytesRead - nBytesSent;
2004 if (nBytesToSend <= 0)
2006 /* Read data from file. */
2008 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2009 ERR("Failed reading from file\n");
2012 nBytesToSend = nBytesRead;
2017 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2018 DATA_PACKET_SIZE : nBytesToSend;
2019 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2021 if (nRC != SOCKET_ERROR)
2027 /* Do some computation to display the status. */
2029 nSeconds = e_long_time - s_long_time;
2030 if( nSeconds / 60 > 0 )
2032 TRACE( "%ld bytes of %d bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
2033 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2034 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2038 TRACE( "%ld bytes of %d bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
2039 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2040 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2042 } while (nRC != SOCKET_ERROR);
2044 TRACE("file transfer complete!\n");
2046 if(lpszBuffer != NULL)
2047 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2053 /***********************************************************************
2054 * FTP_SendRetrieve (internal)
2056 * Send request to retrieve a file
2059 * Number of bytes to be received on success
2063 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
2069 if (!FTP_InitListenSocket(lpwfs))
2072 if (!FTP_SendType(lpwfs, dwType))
2075 if (!FTP_SendPortOrPasv(lpwfs))
2078 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2081 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2082 MAX_REPLY_LEN, 0, 0, 0);
2085 if (nResCode == 125 || nResCode == 150)
2087 /* Parse size of data to be retrieved */
2088 INT i, sizepos = -1;
2089 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2090 for (i = strlen(lpszResponseBuffer) - 1; i >= 0; i--)
2092 if ('(' == lpszResponseBuffer[i])
2101 nResult = atol(&lpszResponseBuffer[sizepos+1]);
2102 TRACE("Waiting to receive %ld bytes\n", nResult);
2108 if (0 == nResult && INVALID_SOCKET != lpwfs->lstnSocket)
2110 close(lpwfs->lstnSocket);
2111 lpwfs->lstnSocket = INVALID_SOCKET;
2118 /***********************************************************************
2119 * FTP_RetrieveData (internal)
2121 * Retrieve data from server
2128 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2130 DWORD nBytesWritten;
2131 DWORD nBytesReceived = 0;
2137 if (INVALID_HANDLE_VALUE == hFile)
2140 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2141 if (NULL == lpszBuffer)
2143 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2147 while (nBytesReceived < nBytes && nRC != SOCKET_ERROR)
2149 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2150 if (nRC != SOCKET_ERROR)
2152 /* other side closed socket. */
2155 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2156 nBytesReceived += nRC;
2159 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
2160 nBytesReceived * 100 / nBytes);
2163 TRACE("Data transfer complete\n");
2164 if (NULL != lpszBuffer)
2165 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2168 return (nRC != SOCKET_ERROR);
2172 /***********************************************************************
2173 * FTP_CloseSessionHandle (internal)
2175 * Deallocate session handle
2182 BOOL FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs)
2184 if (INVALID_SOCKET != lpwfs->sndSocket)
2185 close(lpwfs->sndSocket);
2187 if (INVALID_SOCKET != lpwfs->lstnSocket)
2188 close(lpwfs->lstnSocket);
2190 if (lpwfs->lpszPassword)
2191 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2193 if (lpwfs->lpszUserName)
2194 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2196 HeapFree(GetProcessHeap(), 0, lpwfs);
2202 /***********************************************************************
2203 * FTP_CloseSessionHandle (internal)
2205 * Deallocate session handle
2212 BOOL FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn)
2218 for (i = 0; i < lpwfn->size; i++)
2220 if (NULL != lpwfn->lpafp[i].lpszName)
2221 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2224 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2225 HeapFree(GetProcessHeap(), 0, lpwfn);
2231 /***********************************************************************
2232 * FTP_ReceiveFileList (internal)
2234 * Read file list from server
2237 * Handle to file list on success
2241 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
2242 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext)
2245 LPFILEPROPERTIESA lpafp = NULL;
2246 LPWININETFINDNEXTA lpwfn = NULL;
2250 if (FTP_ParseDirectory(lpwfs, nSocket, &lpafp, &dwSize))
2252 FTP_ConvertFileProp(lpafp, lpFindFileData);
2254 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTA));
2257 lpwfn->hdr.htype = WH_HFINDNEXT;
2258 lpwfn->hdr.lpwhparent = (LPWININETHANDLEHEADER)lpwfs;
2259 lpwfn->hdr.dwContext = dwContext;
2260 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2261 lpwfn->size = dwSize;
2262 lpwfn->lpafp = lpafp;
2266 TRACE("Matched %ld files\n", dwSize);
2267 return (HINTERNET)lpwfn;
2271 /***********************************************************************
2272 * FTP_ConvertFileProp (internal)
2274 * Converts FILEPROPERTIESA struct to WIN32_FIND_DATAA
2281 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESA lpafp, LPWIN32_FIND_DATAA lpFindFileData)
2283 BOOL bSuccess = FALSE;
2285 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2289 DWORD access = mktime(&lpafp->tmLastModified);
2291 /* Not all fields are filled in */
2292 lpFindFileData->ftLastAccessTime.dwHighDateTime = HIWORD(access);
2293 lpFindFileData->ftLastAccessTime.dwLowDateTime = LOWORD(access);
2294 lpFindFileData->nFileSizeHigh = HIWORD(lpafp->nSize);
2295 lpFindFileData->nFileSizeLow = LOWORD(lpafp->nSize);
2297 if (lpafp->bIsDirectory)
2298 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2300 if (lpafp->lpszName)
2301 strncpy(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2310 /***********************************************************************
2311 * FTP_ParseDirectory (internal)
2313 * Parse string of directory information
2319 * FIXME: - This function needs serious clea-up
2320 * - We should consider both UNIX and NT list formats
2322 #define MAX_MONTH_LEN 10
2323 #define MIN_LEN_DIR_ENTRY 15
2325 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp)
2328 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2331 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2337 CHAR pszMonth[MAX_MONTH_LEN];
2339 BOOL bSuccess = TRUE;
2340 DWORD nBufLen = MAX_REPLY_LEN;
2341 LPFILEPROPERTIESA curFileProp = NULL;
2342 CHAR* pszLine = NULL;
2343 CHAR* pszToken = NULL;
2344 INT nTokenToSkip = 3;
2352 INT sizeFilePropArray = 20;
2353 INT indexFilePropArray = 0;
2357 /* Allocate intial file properties array */
2358 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESA)*(sizeFilePropArray));
2365 while ((pszLine = INTERNET_GetNextLine(nSocket, INTERNET_GetResponseBuffer(), &nBufLen)) != NULL)
2367 if (sizeFilePropArray <= indexFilePropArray)
2369 LPFILEPROPERTIESA tmpafp;
2371 sizeFilePropArray *= 2;
2372 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
2373 sizeof(FILEPROPERTIESA)*sizeFilePropArray);
2383 curFileProp = &((*lpafp)[indexFilePropArray]);
2385 /* First Parse the permissions. */
2386 pszToken = strtok(pszLine, " \t" );
2388 /* HACK! If this is not a file listing skip the line */
2389 if (!pszToken || 10 != strlen(pszToken) || nBufLen <= MIN_LEN_DIR_ENTRY)
2391 nBufLen = MAX_REPLY_LEN;
2395 FTP_ParsePermission(pszToken, curFileProp);
2401 pszToken = strtok( NULL, " \t" );
2403 } while( nCount <= nTokenToSkip );
2405 /* Store the size of the file in the param list. */
2406 TRACE("nSize-> %s\n", pszToken);
2407 if (pszToken != NULL)
2408 curFileProp->nSize = atol(pszToken);
2410 /* Parse last modified time. */
2418 pszToken = strtok( NULL, " \t" );
2419 strncpy(pszMonth, pszToken, MAX_MONTH_LEN);
2420 CharUpperA(pszMonth);
2421 pszMatch = strstr(szMonths, pszMonth);
2422 if( pszMatch != NULL )
2423 nMonth = (pszMatch - szMonths) / 3;
2425 pszToken = strtok(NULL, " \t");
2426 TRACE("nDay -> %s\n", pszToken);
2427 if (pszToken != NULL)
2428 nDay = atoi(pszToken);
2430 pszToken = strtok(NULL, " \t");
2431 pszMinutes = strchr(pszToken, ':');
2432 if( pszMinutes != NULL )
2435 nMinutes = atoi(pszMinutes);
2436 pszHour = pszMinutes - 3;
2437 if (pszHour != NULL)
2438 nHour = atoi(pszHour);
2440 apTM = localtime( &aTime );
2441 nYear = apTM->tm_year;
2445 nYear = atoi(pszToken);
2450 curFileProp->tmLastModified.tm_sec = nSeconds;
2451 curFileProp->tmLastModified.tm_min = nMinutes;
2452 curFileProp->tmLastModified.tm_hour = nHour;
2453 curFileProp->tmLastModified.tm_mday = nDay;
2454 curFileProp->tmLastModified.tm_mon = nMonth;
2455 curFileProp->tmLastModified.tm_year = nYear;
2457 pszToken = strtok(NULL, " \t");
2458 if(pszToken != NULL)
2460 curFileProp->lpszName = FTP_strdup(pszToken);
2461 TRACE(": %s\n", curFileProp->lpszName);
2464 nBufLen = MAX_REPLY_LEN;
2465 indexFilePropArray++;
2468 if (bSuccess && indexFilePropArray)
2470 if (indexFilePropArray < sizeFilePropArray - 1)
2472 LPFILEPROPERTIESA tmpafp;
2474 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
2475 sizeof(FILEPROPERTIESA)*indexFilePropArray);
2479 *dwfp = indexFilePropArray;
2483 HeapFree(GetProcessHeap(), 0, *lpafp);
2484 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2493 /***********************************************************************
2494 * FTP_ParsePermission (internal)
2496 * Parse permission string of directory information
2503 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp)
2505 BOOL bSuccess = TRUE;
2506 unsigned short nPermission = 0;
2511 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
2517 lpfp->bIsDirectory = (*lpszPermission == 'd');
2523 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
2526 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
2529 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
2532 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
2535 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
2538 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
2541 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
2544 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
2547 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
2551 }while (nPos <= nLast);
2553 lpfp->permissions = nPermission;
2558 /***********************************************************************
2559 * FTP_SetResponseError (internal)
2561 * Set the appropriate error code for a given response from the server
2566 DWORD FTP_SetResponseError(DWORD dwResponse)
2572 case 421: /* Service not available - Server may be shutting down. */
2573 dwCode = ERROR_INTERNET_TIMEOUT;
2576 case 425: /* Cannot open data connection. */
2577 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
2580 case 426: /* Connection closed, transer aborted. */
2581 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
2584 case 500: /* Syntax error. Command unrecognized. */
2585 case 501: /* Syntax error. Error in parameters or arguments. */
2586 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
2589 case 530: /* Not logged in. Login incorrect. */
2590 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
2593 case 550: /* File action not taken. File not found or no access. */
2594 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
2597 case 450: /* File action not taken. File may be busy. */
2598 case 451: /* Action aborted. Server error. */
2599 case 452: /* Action not taken. Insufficient storage space on server. */
2600 case 502: /* Command not implemented. */
2601 case 503: /* Bad sequence of command. */
2602 case 504: /* Command not implemented for that parameter. */
2603 case 532: /* Need account for storing files */
2604 case 551: /* Requested action aborted. Page type unknown */
2605 case 552: /* Action aborted. Exceeded storage allocation */
2606 case 553: /* Action not taken. File name not allowed. */
2609 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
2613 INTERNET_SetLastError(dwCode);