Added support for implementing VxDs as separate dlls and loading them
[wine.git] / dlls / wininet / ftp.c
blob53265b73db3db3db556a0fee0ce426b9879243c1
1 /*
2 * WININET - Ftp implementation
4 * Copyright 1999 Corel Corporation
5 * Copyright 2004 Mike McCormack for CodeWeavers
7 * Ulrich Czekalla
8 * Noureddine Jemmali
10 * Copyright 2000 Andreas Mohr
11 * Copyright 2002 Jaco Greeff
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "config.h"
29 #include "wine/port.h"
31 #include <errno.h>
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/types.h>
37 #ifdef HAVE_SYS_SOCKET_H
38 # include <sys/socket.h>
39 #endif
40 #ifdef HAVE_UNISTD_H
41 # include <unistd.h>
42 #endif
43 #include <time.h>
45 #include "windef.h"
46 #include "winbase.h"
47 #include "wingdi.h"
48 #include "winuser.h"
49 #include "wininet.h"
50 #include "winnls.h"
51 #include "winerror.h"
52 #include "winreg.h"
53 #include "winternl.h"
55 #include "wine/debug.h"
56 #include "internet.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
60 #define NOACCOUNT "noaccount"
61 #define DATA_PACKET_SIZE 0x2000
62 #define szCRLF "\r\n"
63 #define MAX_BACKLOG 5
65 typedef enum {
66 /* FTP commands with arguments. */
67 FTP_CMD_ACCT,
68 FTP_CMD_CWD,
69 FTP_CMD_DELE,
70 FTP_CMD_MKD,
71 FTP_CMD_PASS,
72 FTP_CMD_PORT,
73 FTP_CMD_RETR,
74 FTP_CMD_RMD,
75 FTP_CMD_RNFR,
76 FTP_CMD_RNTO,
77 FTP_CMD_STOR,
78 FTP_CMD_TYPE,
79 FTP_CMD_USER,
80 FTP_CMD_SIZE,
82 /* FTP commands without arguments. */
83 FTP_CMD_ABOR,
84 FTP_CMD_LIST,
85 FTP_CMD_NLST,
86 FTP_CMD_PASV,
87 FTP_CMD_PWD,
88 FTP_CMD_QUIT,
89 } FTP_COMMAND;
91 static const CHAR *szFtpCommands[] = {
92 "ACCT",
93 "CWD",
94 "DELE",
95 "MKD",
96 "PASS",
97 "PORT",
98 "RETR",
99 "RMD",
100 "RNFR",
101 "RNTO",
102 "STOR",
103 "TYPE",
104 "USER",
105 "SIZE",
106 "ABOR",
107 "LIST",
108 "NLST",
109 "PASV",
110 "PWD",
111 "QUIT",
114 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
116 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
117 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
118 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
119 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket);
120 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile);
121 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
122 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
123 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
124 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile);
125 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs);
126 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs);
127 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs);
128 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs);
129 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType);
130 BOOL FTP_GetFileSize(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD *dwSize);
131 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs);
132 BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs);
133 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs);
134 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp);
135 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp);
136 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
137 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext);
138 DWORD FTP_SetResponseError(DWORD dwResponse);
140 inline static LPSTR FTP_strdup( LPCSTR str )
142 LPSTR ret = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
143 if (ret) strcpy( ret, str );
144 return ret;
147 /***********************************************************************
148 * FtpPutFileA (WININET.@)
150 * Uploads a file to the FTP server
152 * RETURNS
153 * TRUE on success
154 * FALSE on failure
157 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
158 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
160 LPWININETFTPSESSIONA lpwfs;
161 LPWININETAPPINFOA hIC = NULL;
163 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hConnect );
164 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
166 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
167 return FALSE;
170 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
171 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
173 WORKREQUEST workRequest;
174 struct WORKREQ_FTPPUTFILEA *req = &workRequest.u.FtpPutFileA;
176 workRequest.asyncall = FTPPUTFILEA;
177 workRequest.handle = hConnect;
178 req->lpszLocalFile = FTP_strdup(lpszLocalFile);
179 req->lpszNewRemoteFile = FTP_strdup(lpszNewRemoteFile);
180 req->dwFlags = dwFlags;
181 req->dwContext = dwContext;
183 return INTERNET_AsyncCall(&workRequest);
185 else
187 return FTP_FtpPutFileA(hConnect, lpszLocalFile,
188 lpszNewRemoteFile, dwFlags, dwContext);
192 /***********************************************************************
193 * FTP_FtpPutFileA (Internal)
195 * Uploads a file to the FTP server
197 * RETURNS
198 * TRUE on success
199 * FALSE on failure
202 BOOL WINAPI FTP_FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
203 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
205 HANDLE hFile = NULL;
206 BOOL bSuccess = FALSE;
207 LPWININETAPPINFOA hIC = NULL;
208 LPWININETFTPSESSIONA lpwfs;
209 INT nResCode;
211 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", lpszLocalFile, lpszNewRemoteFile);
213 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hConnect );
214 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
216 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
217 return FALSE;
220 /* Clear any error information */
221 INTERNET_SetLastError(0);
223 /* Open file to be uploaded */
224 if (INVALID_HANDLE_VALUE ==
225 (hFile = CreateFileA(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
227 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND);
228 goto lend;
231 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
232 if (hIC->lpfnStatusCB)
233 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
235 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
237 INT nDataSocket;
239 /* Get data socket to server */
240 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
242 FTP_SendData(lpwfs, nDataSocket, hFile);
243 close(nDataSocket);
244 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
245 MAX_REPLY_LEN, 0, 0, 0);
246 if (nResCode)
248 if (nResCode == 226)
249 bSuccess = TRUE;
250 else
251 FTP_SetResponseError(nResCode);
256 lend:
257 if (lpwfs->lstnSocket != -1)
258 close(lpwfs->lstnSocket);
260 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
262 INTERNET_ASYNC_RESULT iar;
264 iar.dwResult = (DWORD)bSuccess;
265 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
266 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
267 &iar, sizeof(INTERNET_ASYNC_RESULT));
270 if (hFile)
271 CloseHandle(hFile);
273 return bSuccess;
277 /***********************************************************************
278 * FtpSetCurrentDirectoryA (WININET.@)
280 * Change the working directory on the FTP server
282 * RETURNS
283 * TRUE on success
284 * FALSE on failure
287 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
289 LPWININETFTPSESSIONA lpwfs;
290 LPWININETAPPINFOA hIC = NULL;
292 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hConnect );
293 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
295 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
296 return FALSE;
299 TRACE("lpszDirectory(%s)\n", lpszDirectory);
301 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
302 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
304 WORKREQUEST workRequest;
305 struct WORKREQ_FTPSETCURRENTDIRECTORYA *req;
307 workRequest.asyncall = FTPSETCURRENTDIRECTORYA;
308 workRequest.handle = hConnect;
309 req = &workRequest.u.FtpSetCurrentDirectoryA;
310 req->lpszDirectory = FTP_strdup(lpszDirectory);
312 return INTERNET_AsyncCall(&workRequest);
314 else
316 return FTP_FtpSetCurrentDirectoryA(hConnect, lpszDirectory);
321 /***********************************************************************
322 * FtpSetCurrentDirectoryW (WININET.@)
324 * Change the working directory on the FTP server
326 * RETURNS
327 * TRUE on success
328 * FALSE on failure
331 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
333 CHAR *szDir;
334 INT len;
335 BOOL rc;
337 len = WideCharToMultiByte(CP_ACP, 0, lpszDirectory, -1, NULL, 0, NULL, NULL);
338 szDir = HeapAlloc(GetProcessHeap(), 0, len);
339 if(!szDir)
340 return FALSE;
341 WideCharToMultiByte(CP_ACP, 0, lpszDirectory, -1, szDir, len, NULL, NULL);
342 rc = FtpSetCurrentDirectoryA(hConnect, szDir);
343 HeapFree(GetProcessHeap(), 0, szDir);
345 return rc;
349 /***********************************************************************
350 * FTP_FtpSetCurrentDirectoryA (Internal)
352 * Change the working directory on the FTP server
354 * RETURNS
355 * TRUE on success
356 * FALSE on failure
359 BOOL WINAPI FTP_FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
361 INT nResCode;
362 LPWININETFTPSESSIONA lpwfs;
363 LPWININETAPPINFOA hIC = NULL;
364 DWORD bSuccess = FALSE;
366 TRACE("lpszDirectory(%s)\n", lpszDirectory);
368 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hConnect );
369 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
371 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
372 return FALSE;
375 /* Clear any error information */
376 INTERNET_SetLastError(0);
378 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
379 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
380 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
381 goto lend;
383 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
384 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
386 if (nResCode)
388 if (nResCode == 250)
389 bSuccess = TRUE;
390 else
391 FTP_SetResponseError(nResCode);
394 lend:
395 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
397 INTERNET_ASYNC_RESULT iar;
399 iar.dwResult = (DWORD)bSuccess;
400 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
401 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
402 &iar, sizeof(INTERNET_ASYNC_RESULT));
404 return bSuccess;
408 /***********************************************************************
409 * FtpCreateDirectoryA (WININET.@)
411 * Create new directory on the FTP server
413 * RETURNS
414 * TRUE on success
415 * FALSE on failure
418 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
420 LPWININETFTPSESSIONA lpwfs;
421 LPWININETAPPINFOA hIC = NULL;
423 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hConnect );
424 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
426 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
427 return FALSE;
430 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
431 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
433 WORKREQUEST workRequest;
434 struct WORKREQ_FTPCREATEDIRECTORYA *req;
436 workRequest.asyncall = FTPCREATEDIRECTORYA;
437 workRequest.handle = hConnect;
438 req = &workRequest.u.FtpCreateDirectoryA;
439 req->lpszDirectory = FTP_strdup(lpszDirectory);
441 return INTERNET_AsyncCall(&workRequest);
443 else
445 return FTP_FtpCreateDirectoryA(hConnect, lpszDirectory);
450 /***********************************************************************
451 * FtpCreateDirectoryW (WININET.@)
453 * Create new directory on the FTP server
455 * RETURNS
456 * TRUE on success
457 * FALSE on failure
460 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
462 CHAR *szDir;
463 INT len;
464 BOOL rc;
466 len = WideCharToMultiByte(CP_ACP, 0, lpszDirectory, -1, NULL, 0, NULL, NULL);
467 szDir = HeapAlloc(GetProcessHeap(), 0, len);
468 if (!szDir)
469 return FALSE;
470 WideCharToMultiByte(CP_ACP, 0, lpszDirectory, -1, szDir, len, NULL, NULL);
471 rc = FtpCreateDirectoryA(hConnect, szDir);
472 HeapFree(GetProcessHeap(), 0, szDir);
474 return rc;
478 /***********************************************************************
479 * FTP_FtpCreateDirectoryA (Internal)
481 * Create new directory on the FTP server
483 * RETURNS
484 * TRUE on success
485 * FALSE on failure
488 BOOL WINAPI FTP_FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
490 INT nResCode;
491 BOOL bSuccess = FALSE;
492 LPWININETAPPINFOA hIC = NULL;
493 LPWININETFTPSESSIONA lpwfs;
495 TRACE("\n");
497 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hConnect );
498 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
500 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
501 return FALSE;
504 /* Clear any error information */
505 INTERNET_SetLastError(0);
507 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
508 goto lend;
510 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
511 MAX_REPLY_LEN, 0, 0, 0);
512 if (nResCode)
514 if (nResCode == 257)
515 bSuccess = TRUE;
516 else
517 FTP_SetResponseError(nResCode);
520 lend:
521 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
522 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
524 INTERNET_ASYNC_RESULT iar;
526 iar.dwResult = (DWORD)bSuccess;
527 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
528 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
529 &iar, sizeof(INTERNET_ASYNC_RESULT));
532 return bSuccess;
536 /***********************************************************************
537 * FtpFindFirstFileA (WININET.@)
539 * Search the specified directory
541 * RETURNS
542 * HINTERNET on success
543 * NULL on failure
546 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
547 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
549 LPWININETFTPSESSIONA lpwfs;
550 LPWININETAPPINFOA hIC = NULL;
552 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hConnect );
553 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
555 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
556 return FALSE;
559 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
560 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
562 WORKREQUEST workRequest;
563 struct WORKREQ_FTPFINDFIRSTFILEA *req;
565 workRequest.asyncall = FTPFINDFIRSTFILEA;
566 workRequest.handle = hConnect;
567 req = &workRequest.u.FtpFindFirstFileA;
568 req->lpszSearchFile = FTP_strdup(lpszSearchFile);
569 req->lpFindFileData = lpFindFileData;
570 req->dwFlags = dwFlags;
571 req->dwContext= dwContext;
573 INTERNET_AsyncCall(&workRequest);
574 return NULL;
576 else
578 return FTP_FtpFindFirstFileA(hConnect, lpszSearchFile, lpFindFileData,
579 dwFlags, dwContext);
584 /***********************************************************************
585 * FtpFindFirstFileA (WININET.@)
587 * Search the specified directory
589 * RETURNS
590 * HINTERNET on success
591 * NULL on failure
594 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
595 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
597 FIXME("STUB\n");
598 return NULL;
602 /***********************************************************************
603 * FTP_FtpFindFirstFileA (Internal)
605 * Search the specified directory
607 * RETURNS
608 * HINTERNET on success
609 * NULL on failure
612 HINTERNET WINAPI FTP_FtpFindFirstFileA(HINTERNET hConnect,
613 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
615 INT nResCode;
616 LPWININETAPPINFOA hIC = NULL;
617 LPWININETFTPSESSIONA lpwfs;
618 HINTERNET hFindNext = NULL;
620 TRACE("\n");
622 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hConnect );
623 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
625 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
626 return FALSE;
629 /* Clear any error information */
630 INTERNET_SetLastError(0);
632 if (!FTP_InitListenSocket(lpwfs))
633 goto lend;
635 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
636 goto lend;
638 if (!FTP_SendPortOrPasv(lpwfs))
639 goto lend;
641 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
642 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, lpszSearchFile,
643 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
644 goto lend;
646 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
647 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
648 if (nResCode)
650 if (nResCode == 125 || nResCode == 150)
652 INT nDataSocket;
654 /* Get data socket to server */
655 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
657 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpFindFileData, dwContext);
659 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
660 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
661 if (nResCode != 226 && nResCode != 250)
662 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
664 close(nDataSocket);
667 else
668 FTP_SetResponseError(nResCode);
671 lend:
672 if (lpwfs->lstnSocket != -1)
673 close(lpwfs->lstnSocket);
675 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
677 INTERNET_ASYNC_RESULT iar;
679 if (hFindNext)
681 iar.dwResult = (DWORD)hFindNext;
682 iar.dwError = ERROR_SUCCESS;
683 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
684 &iar, sizeof(INTERNET_ASYNC_RESULT));
687 iar.dwResult = (DWORD)hFindNext;
688 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
689 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
690 &iar, sizeof(INTERNET_ASYNC_RESULT));
693 return hFindNext;
697 /***********************************************************************
698 * FtpGetCurrentDirectoryA (WININET.@)
700 * Retrieves the current directory
702 * RETURNS
703 * TRUE on success
704 * FALSE on failure
707 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
708 LPDWORD lpdwCurrentDirectory)
710 LPWININETFTPSESSIONA lpwfs;
711 LPWININETAPPINFOA hIC = NULL;
713 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
715 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
716 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
718 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
719 return FALSE;
722 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
723 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
725 WORKREQUEST workRequest;
726 struct WORKREQ_FTPGETCURRENTDIRECTORYA *req;
728 workRequest.asyncall = FTPGETCURRENTDIRECTORYA;
729 workRequest.handle = hFtpSession;
730 req = &workRequest.u.FtpGetCurrentDirectoryA;
731 req->lpszDirectory = lpszCurrentDirectory;
732 req->lpdwDirectory = lpdwCurrentDirectory;
734 return INTERNET_AsyncCall(&workRequest);
736 else
738 return FTP_FtpGetCurrentDirectoryA(hFtpSession, lpszCurrentDirectory,
739 lpdwCurrentDirectory);
744 /***********************************************************************
745 * FtpGetCurrentDirectoryW (WININET.@)
747 * Retrieves the current directory
749 * RETURNS
750 * TRUE on success
751 * FALSE on failure
754 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
755 LPDWORD lpdwCurrentDirectory)
757 FIXME("STUB\n");
758 return FALSE;
762 /***********************************************************************
763 * FTP_FtpGetCurrentDirectoryA (Internal)
765 * Retrieves the current directory
767 * RETURNS
768 * TRUE on success
769 * FALSE on failure
772 BOOL WINAPI FTP_FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
773 LPDWORD lpdwCurrentDirectory)
775 INT nResCode;
776 LPWININETFTPSESSIONA lpwfs;
777 LPWININETAPPINFOA hIC = NULL;
778 DWORD bSuccess = FALSE;
780 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
782 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
783 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
785 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
786 return FALSE;
789 /* Clear any error information */
790 INTERNET_SetLastError(0);
792 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
794 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
795 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
796 hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext))
797 goto lend;
799 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
800 MAX_REPLY_LEN, hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext);
801 if (nResCode)
803 if (nResCode == 257) /* Extract directory name */
805 INT firstpos, lastpos, len;
806 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
808 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
810 if ('"' == lpszResponseBuffer[lastpos])
812 if (!firstpos)
813 firstpos = lastpos;
814 else
815 break;
819 len = lastpos - firstpos - 1;
820 strncpy(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1],
821 len < *lpdwCurrentDirectory ? len : *lpdwCurrentDirectory);
822 *lpdwCurrentDirectory = len;
823 bSuccess = TRUE;
825 else
826 FTP_SetResponseError(nResCode);
829 lend:
830 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
832 INTERNET_ASYNC_RESULT iar;
834 iar.dwResult = (DWORD)bSuccess;
835 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
836 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
837 &iar, sizeof(INTERNET_ASYNC_RESULT));
840 return (DWORD) bSuccess;
843 /***********************************************************************
844 * FtpOpenFileA (WININET.@)
846 * Open a remote file for writing or reading
848 * RETURNS
849 * HINTERNET handle on success
850 * NULL on failure
853 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
854 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
855 DWORD dwContext)
857 LPWININETFTPSESSIONA lpwfs;
858 LPWININETAPPINFOA hIC = NULL;
860 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
861 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
863 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
864 return FALSE;
867 if (lpwfs->download_in_progress != NULL) {
868 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
869 return FALSE;
872 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
873 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
875 WORKREQUEST workRequest;
876 struct WORKREQ_FTPOPENFILEA *req;
878 workRequest.asyncall = FTPOPENFILEA;
879 workRequest.handle = hFtpSession;
880 req = &workRequest.u.FtpOpenFileA;
881 req->lpszFilename = FTP_strdup(lpszFileName);
882 req->dwAccess = fdwAccess;
883 req->dwFlags = dwFlags;
884 req->dwContext = dwContext;
886 INTERNET_AsyncCall(&workRequest);
887 return NULL;
889 else
891 return FTP_FtpOpenFileA(hFtpSession, lpszFileName, fdwAccess, dwFlags, dwContext);
896 /***********************************************************************
897 * FtpOpenFileW (WININET.@)
899 * Open a remote file for writing or reading
901 * RETURNS
902 * HINTERNET handle on success
903 * NULL on failure
906 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
907 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
908 DWORD dwContext)
910 FIXME("STUB\n");
911 return NULL;
915 /***********************************************************************
916 * FTP_FtpOpenFileA (Internal)
918 * Open a remote file for writing or reading
920 * RETURNS
921 * HINTERNET handle on success
922 * NULL on failure
925 HINTERNET FTP_FtpOpenFileA(HINTERNET hFtpSession,
926 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
927 DWORD dwContext)
929 INT nDataSocket;
930 BOOL bSuccess = FALSE;
931 LPWININETFILE lpwh = NULL;
932 LPWININETAPPINFOA hIC = NULL;
933 LPWININETFTPSESSIONA lpwfs;
934 HINTERNET handle = NULL;
936 TRACE("\n");
938 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
939 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
941 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
942 return FALSE;
945 /* Clear any error information */
946 INTERNET_SetLastError(0);
948 if (GENERIC_READ == fdwAccess)
950 /* Set up socket to retrieve data */
951 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
953 else if (GENERIC_WRITE == fdwAccess)
955 /* Set up socket to send data */
956 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
959 /* Get data socket to server */
960 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
962 lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE));
963 handle = WININET_AllocHandle( &lpwh->hdr );
964 lpwh->hdr.htype = WH_HFILE;
965 lpwh->hdr.dwFlags = dwFlags;
966 lpwh->hdr.dwContext = dwContext;
967 lpwh->hdr.lpwhparent = &lpwfs->hdr;
968 lpwh->nDataSocket = nDataSocket;
969 lpwh->session_deleted = FALSE;
971 /* Indicate that a download is currently in progress */
972 lpwfs->download_in_progress = lpwh;
975 if (lpwfs->lstnSocket != -1)
976 close(lpwfs->lstnSocket);
978 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
979 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
981 INTERNET_ASYNC_RESULT iar;
983 if (lpwh)
985 iar.dwResult = (DWORD)handle;
986 iar.dwError = ERROR_SUCCESS;
987 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
988 &iar, sizeof(INTERNET_ASYNC_RESULT));
991 iar.dwResult = (DWORD)bSuccess;
992 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
993 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
994 &iar, sizeof(INTERNET_ASYNC_RESULT));
997 return handle;
1001 /***********************************************************************
1002 * FtpGetFileA (WININET.@)
1004 * Retrieve file from the FTP server
1006 * RETURNS
1007 * TRUE on success
1008 * FALSE on failure
1011 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1012 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1013 DWORD dwContext)
1015 LPWININETFTPSESSIONA lpwfs;
1016 LPWININETAPPINFOA hIC = NULL;
1018 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hInternet );
1019 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1021 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1022 return FALSE;
1025 if (lpwfs->download_in_progress != NULL) {
1026 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1027 return FALSE;
1030 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1031 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1033 WORKREQUEST workRequest;
1034 struct WORKREQ_FTPGETFILEA *req;
1036 workRequest.asyncall = FTPGETFILEA;
1037 workRequest.handle = hInternet;
1038 req = &workRequest.u.FtpGetFileA;
1039 req->lpszRemoteFile = FTP_strdup(lpszRemoteFile);
1040 req->lpszNewFile = FTP_strdup(lpszNewFile);
1041 req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1042 req->fFailIfExists = fFailIfExists;
1043 req->dwFlags = dwInternetFlags;
1044 req->dwContext = dwContext;
1046 return INTERNET_AsyncCall(&workRequest);
1048 else
1050 return FTP_FtpGetFileA(hInternet, lpszRemoteFile, lpszNewFile,
1051 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1056 /***********************************************************************
1057 * FtpGetFileW (WININET.@)
1059 * Retrieve file from the FTP server
1061 * RETURNS
1062 * TRUE on success
1063 * FALSE on failure
1066 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1067 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1068 DWORD dwContext)
1070 FIXME("STUB\n");
1071 return FALSE;
1075 /***********************************************************************
1076 * FTP_FtpGetFileA (Internal)
1078 * Retrieve file from the FTP server
1080 * RETURNS
1081 * TRUE on success
1082 * FALSE on failure
1085 BOOL WINAPI FTP_FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1086 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1087 DWORD dwContext)
1089 DWORD nBytes;
1090 BOOL bSuccess = FALSE;
1091 HANDLE hFile;
1092 LPWININETAPPINFOA hIC = NULL;
1093 LPWININETFTPSESSIONA lpwfs;
1095 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", lpszRemoteFile, lpszNewFile);
1097 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hInternet );
1098 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1100 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1101 return FALSE;
1104 /* Clear any error information */
1105 INTERNET_SetLastError(0);
1107 /* Ensure we can write to lpszNewfile by opening it */
1108 hFile = CreateFileA(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1109 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1110 if (INVALID_HANDLE_VALUE == hFile)
1111 goto lend;
1113 /* Set up socket to retrieve data */
1114 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
1116 if (nBytes > 0)
1118 INT nDataSocket;
1120 /* Get data socket to server */
1121 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1123 INT nResCode;
1125 /* Receive data */
1126 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
1127 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1128 MAX_REPLY_LEN, 0, 0, 0);
1129 if (nResCode)
1131 if (nResCode == 226)
1132 bSuccess = TRUE;
1133 else
1134 FTP_SetResponseError(nResCode);
1136 close(nDataSocket);
1140 lend:
1141 if (lpwfs->lstnSocket != -1)
1142 close(lpwfs->lstnSocket);
1144 if (hFile)
1145 CloseHandle(hFile);
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(hInternet, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1155 &iar, sizeof(INTERNET_ASYNC_RESULT));
1158 return bSuccess;
1162 /***********************************************************************
1163 * FtpDeleteFileA (WININET.@)
1165 * Delete a file on the ftp server
1167 * RETURNS
1168 * TRUE on success
1169 * FALSE on failure
1172 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1174 LPWININETFTPSESSIONA lpwfs;
1175 LPWININETAPPINFOA hIC = NULL;
1177 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
1178 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1180 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1181 return FALSE;
1184 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1185 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1187 WORKREQUEST workRequest;
1188 struct WORKREQ_FTPDELETEFILEA *req;
1190 workRequest.asyncall = FTPDELETEFILEA;
1191 workRequest.handle = hFtpSession;
1192 req = &workRequest.u.FtpDeleteFileA;
1193 req->lpszFilename = FTP_strdup(lpszFileName);
1195 return INTERNET_AsyncCall(&workRequest);
1197 else
1199 return FTP_FtpDeleteFileA(hFtpSession, lpszFileName);
1204 /***********************************************************************
1205 * FTP_FtpDeleteFileA (Internal)
1207 * Delete a file on the ftp server
1209 * RETURNS
1210 * TRUE on success
1211 * FALSE on failure
1214 BOOL FTP_FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1216 INT nResCode;
1217 BOOL bSuccess = FALSE;
1218 LPWININETAPPINFOA hIC = NULL;
1219 LPWININETFTPSESSIONA lpwfs;
1221 TRACE("0x%08lx\n", (ULONG) hFtpSession);
1223 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
1224 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1226 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1227 return FALSE;
1230 /* Clear any error information */
1231 INTERNET_SetLastError(0);
1233 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1234 goto lend;
1236 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1237 MAX_REPLY_LEN, 0, 0, 0);
1238 if (nResCode)
1240 if (nResCode == 250)
1241 bSuccess = TRUE;
1242 else
1243 FTP_SetResponseError(nResCode);
1245 lend:
1246 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1247 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1249 INTERNET_ASYNC_RESULT iar;
1251 iar.dwResult = (DWORD)bSuccess;
1252 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1253 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1254 &iar, sizeof(INTERNET_ASYNC_RESULT));
1257 return bSuccess;
1261 /***********************************************************************
1262 * FtpRemoveDirectoryA (WININET.@)
1264 * Remove a directory on the ftp server
1266 * RETURNS
1267 * TRUE on success
1268 * FALSE on failure
1271 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1273 LPWININETFTPSESSIONA lpwfs;
1274 LPWININETAPPINFOA hIC = NULL;
1276 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
1277 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1279 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1280 return FALSE;
1283 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1284 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1286 WORKREQUEST workRequest;
1287 struct WORKREQ_FTPREMOVEDIRECTORYA *req;
1289 workRequest.asyncall = FTPREMOVEDIRECTORYA;
1290 workRequest.handle = hFtpSession;
1291 req = &workRequest.u.FtpRemoveDirectoryA;
1292 req->lpszDirectory = FTP_strdup(lpszDirectory);
1294 return INTERNET_AsyncCall(&workRequest);
1296 else
1298 return FTP_FtpRemoveDirectoryA(hFtpSession, lpszDirectory);
1303 /***********************************************************************
1304 * FTP_FtpRemoveDirectoryA (Internal)
1306 * Remove a directory on the ftp server
1308 * RETURNS
1309 * TRUE on success
1310 * FALSE on failure
1313 BOOL FTP_FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1315 INT nResCode;
1316 BOOL bSuccess = FALSE;
1317 LPWININETAPPINFOA hIC = NULL;
1318 LPWININETFTPSESSIONA lpwfs;
1320 TRACE("\n");
1322 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
1323 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1325 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1326 return FALSE;
1329 /* Clear any error information */
1330 INTERNET_SetLastError(0);
1332 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1333 goto lend;
1335 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1336 MAX_REPLY_LEN, 0, 0, 0);
1337 if (nResCode)
1339 if (nResCode == 250)
1340 bSuccess = TRUE;
1341 else
1342 FTP_SetResponseError(nResCode);
1345 lend:
1346 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1347 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1349 INTERNET_ASYNC_RESULT iar;
1351 iar.dwResult = (DWORD)bSuccess;
1352 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1353 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1354 &iar, sizeof(INTERNET_ASYNC_RESULT));
1357 return bSuccess;
1361 /***********************************************************************
1362 * FtpRenameFileA (WININET.@)
1364 * Rename a file on the ftp server
1366 * RETURNS
1367 * TRUE on success
1368 * FALSE on failure
1371 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1373 LPWININETFTPSESSIONA lpwfs;
1374 LPWININETAPPINFOA hIC = NULL;
1376 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
1377 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1379 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1380 return FALSE;
1383 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1384 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1386 WORKREQUEST workRequest;
1387 struct WORKREQ_FTPRENAMEFILEA *req;
1389 workRequest.asyncall = FTPRENAMEFILEA;
1390 workRequest.handle = hFtpSession;
1391 req = &workRequest.u.FtpRenameFileA;
1392 req->lpszSrcFile = FTP_strdup(lpszSrc);
1393 req->lpszDestFile = FTP_strdup(lpszDest);
1395 return INTERNET_AsyncCall(&workRequest);
1397 else
1399 return FTP_FtpRenameFileA(hFtpSession, lpszSrc, lpszDest);
1403 /***********************************************************************
1404 * FTP_FtpRenameFileA (Internal)
1406 * Rename a file on the ftp server
1408 * RETURNS
1409 * TRUE on success
1410 * FALSE on failure
1413 BOOL FTP_FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1415 INT nResCode;
1416 BOOL bSuccess = FALSE;
1417 LPWININETAPPINFOA hIC = NULL;
1418 LPWININETFTPSESSIONA lpwfs;
1420 TRACE("\n");
1422 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
1423 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1425 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1426 return FALSE;
1429 /* Clear any error information */
1430 INTERNET_SetLastError(0);
1432 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1433 goto lend;
1435 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1436 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1437 if (nResCode == 350)
1439 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1440 goto lend;
1442 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1443 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1446 if (nResCode == 250)
1447 bSuccess = TRUE;
1448 else
1449 FTP_SetResponseError(nResCode);
1451 lend:
1452 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1453 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1455 INTERNET_ASYNC_RESULT iar;
1457 iar.dwResult = (DWORD)bSuccess;
1458 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1459 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1460 &iar, sizeof(INTERNET_ASYNC_RESULT));
1463 return bSuccess;
1467 /***********************************************************************
1468 * FTP_Connect (internal)
1470 * Connect to a ftp server
1472 * RETURNS
1473 * HINTERNET a session handle on success
1474 * NULL on failure
1478 HINTERNET FTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
1479 INTERNET_PORT nServerPort, LPCSTR lpszUserName,
1480 LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
1482 struct sockaddr_in socketAddr;
1483 struct hostent *phe = NULL;
1484 INT nsocket = -1, sock_namelen;
1485 LPWININETAPPINFOA hIC = NULL;
1486 BOOL bSuccess = FALSE;
1487 LPWININETFTPSESSIONA lpwfs = NULL;
1488 HINTERNET handle = NULL;
1490 TRACE("0x%08lx Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1491 (ULONG) hInternet, lpszServerName,
1492 nServerPort, lpszUserName, lpszPassword);
1494 hIC = (LPWININETAPPINFOA) WININET_GetObject( hInternet );
1495 if ( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) )
1496 goto lerror;
1498 if (NULL == lpszUserName && NULL != lpszPassword)
1500 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_USER_NAME);
1501 goto lerror;
1504 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1505 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1507 if (hIC->lpfnStatusCB)
1508 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1509 (LPSTR) lpszServerName, strlen(lpszServerName));
1511 if (!GetAddress(lpszServerName, nServerPort, &phe, &socketAddr))
1513 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1514 goto lerror;
1517 if (hIC->lpfnStatusCB)
1518 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1519 (LPSTR) lpszServerName, strlen(lpszServerName));
1521 nsocket = socket(AF_INET,SOCK_STREAM,0);
1522 if (nsocket == -1)
1524 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1525 goto lerror;
1528 if (hIC->lpfnStatusCB)
1529 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1530 &socketAddr, sizeof(struct sockaddr_in));
1532 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1534 ERR("Unable to connect (%s)\n", strerror(errno));
1535 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1537 else
1539 TRACE("Connected to server\n");
1540 if (hIC->lpfnStatusCB)
1541 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1542 &socketAddr, sizeof(struct sockaddr_in));
1544 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONA));
1545 if (NULL == lpwfs)
1547 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1548 goto lerror;
1551 handle = WININET_AllocHandle( &lpwfs->hdr );
1552 if( !handle )
1554 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1555 goto lerror;
1558 lpwfs->hdr.htype = WH_HFTPSESSION;
1559 lpwfs->hdr.dwFlags = dwFlags;
1560 lpwfs->hdr.dwContext = dwContext;
1561 lpwfs->hdr.lpwhparent = &hIC->hdr;
1562 lpwfs->sndSocket = nsocket;
1563 lpwfs->download_in_progress = NULL;
1564 sock_namelen = sizeof(lpwfs->socketAddress);
1565 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1566 lpwfs->phostent = phe;
1568 if (NULL == lpszUserName)
1570 lpwfs->lpszUserName = FTP_strdup("anonymous");
1571 lpwfs->lpszPassword = FTP_strdup("user@server");
1573 else
1575 lpwfs->lpszUserName = FTP_strdup(lpszUserName);
1576 lpwfs->lpszPassword = FTP_strdup(lpszPassword);
1579 if (FTP_ConnectToHost(lpwfs))
1581 if (hIC->lpfnStatusCB)
1583 INTERNET_ASYNC_RESULT iar;
1585 iar.dwResult = (DWORD)handle;
1586 iar.dwError = ERROR_SUCCESS;
1588 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_HANDLE_CREATED,
1589 &iar, sizeof(INTERNET_ASYNC_RESULT));
1591 TRACE("Successfully logged into server\n");
1592 bSuccess = TRUE;
1596 lerror:
1597 if (!bSuccess && nsocket == -1)
1598 close(nsocket);
1600 if (!bSuccess && lpwfs)
1602 HeapFree(GetProcessHeap(), 0, lpwfs);
1603 WININET_FreeHandle( handle );
1604 lpwfs = NULL;
1607 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1609 INTERNET_ASYNC_RESULT iar;
1611 iar.dwResult = (DWORD)lpwfs;
1612 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1613 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1614 &iar, sizeof(INTERNET_ASYNC_RESULT));
1617 return handle;
1621 /***********************************************************************
1622 * FTP_ConnectToHost (internal)
1624 * Connect to a ftp server
1626 * RETURNS
1627 * TRUE on success
1628 * NULL on failure
1631 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs)
1633 INT nResCode;
1634 BOOL bSuccess = FALSE;
1636 TRACE("\n");
1637 FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1639 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1640 goto lend;
1642 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1643 MAX_REPLY_LEN, 0, 0, 0);
1644 if (nResCode)
1646 /* Login successful... */
1647 if (nResCode == 230)
1648 bSuccess = TRUE;
1649 /* User name okay, need password... */
1650 else if (nResCode == 331)
1651 bSuccess = FTP_SendPassword(lpwfs);
1652 /* Need account for login... */
1653 else if (nResCode == 332)
1654 bSuccess = FTP_SendAccount(lpwfs);
1655 else
1656 FTP_SetResponseError(nResCode);
1659 TRACE("Returning %d\n", bSuccess);
1660 lend:
1661 return bSuccess;
1665 /***********************************************************************
1666 * FTP_SendCommand (internal)
1668 * Send command to server
1670 * RETURNS
1671 * TRUE on success
1672 * NULL on failure
1675 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1676 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1678 DWORD len;
1679 CHAR *buf;
1680 DWORD nBytesSent = 0;
1681 DWORD nRC = 0;
1682 BOOL bParamHasLen;
1684 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1686 if (lpfnStatusCB)
1687 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1689 bParamHasLen = lpszParam && strlen(lpszParam) > 0;
1690 len = (bParamHasLen ? strlen(lpszParam) : -1) + strlen(szFtpCommands[ftpCmd]) +
1691 strlen(szCRLF)+ 1;
1692 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1694 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1695 return FALSE;
1697 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], bParamHasLen ? " " : "",
1698 bParamHasLen ? lpszParam : "", szCRLF);
1700 TRACE("Sending (%s) len(%ld)\n", buf, len);
1701 while((nBytesSent < len) && (nRC != -1))
1703 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1704 nBytesSent += nRC;
1707 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
1709 if (lpfnStatusCB)
1710 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_REQUEST_SENT,
1711 &nBytesSent, sizeof(DWORD));
1713 TRACE("Sent %ld bytes\n", nBytesSent);
1714 return (nRC != -1);
1718 /***********************************************************************
1719 * FTP_ReceiveResponse (internal)
1721 * Receive response from server
1723 * RETURNS
1724 * Reply code on success
1725 * 0 on failure
1729 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
1730 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1732 DWORD nRecv;
1733 INT rc = 0;
1734 char firstprefix[5];
1735 BOOL multiline = FALSE;
1738 TRACE("socket(%d) \n", nSocket);
1740 if (lpfnStatusCB)
1741 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1743 while(1)
1745 nRecv = dwResponse;
1746 if (!INTERNET_GetNextLine(nSocket, lpszResponse, &nRecv))
1747 goto lerror;
1749 if (nRecv >= 3)
1751 if(!multiline)
1753 if(lpszResponse[3] != '-')
1754 break;
1755 else
1756 { /* Start of multiline repsonse. Loop until we get "nnn " */
1757 multiline = TRUE;
1758 memcpy(firstprefix, lpszResponse, 3);
1759 firstprefix[3] = ' ';
1760 firstprefix[4] = '\0';
1763 else
1765 if(!memcmp(firstprefix, lpszResponse, 4))
1766 break;
1771 if (nRecv >= 3)
1773 rc = atoi(lpszResponse);
1775 if (lpfnStatusCB)
1776 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
1777 &nRecv, sizeof(DWORD));
1780 lerror:
1781 TRACE("return %d\n", rc);
1782 return rc;
1786 /***********************************************************************
1787 * FTP_SendPassword (internal)
1789 * Send password to ftp server
1791 * RETURNS
1792 * TRUE on success
1793 * NULL on failure
1796 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs)
1798 INT nResCode;
1799 BOOL bSuccess = FALSE;
1801 TRACE("\n");
1802 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
1803 goto lend;
1805 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1806 MAX_REPLY_LEN, 0, 0, 0);
1807 if (nResCode)
1809 TRACE("Received reply code %d\n", nResCode);
1810 /* Login successful... */
1811 if (nResCode == 230)
1812 bSuccess = TRUE;
1813 /* Command not implemented, superfluous at the server site... */
1814 /* Need account for login... */
1815 else if (nResCode == 332)
1816 bSuccess = FTP_SendAccount(lpwfs);
1817 else
1818 FTP_SetResponseError(nResCode);
1821 lend:
1822 TRACE("Returning %d\n", bSuccess);
1823 return bSuccess;
1827 /***********************************************************************
1828 * FTP_SendAccount (internal)
1832 * RETURNS
1833 * TRUE on success
1834 * FALSE on failure
1837 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs)
1839 INT nResCode;
1840 BOOL bSuccess = FALSE;
1842 TRACE("\n");
1843 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, NOACCOUNT, 0, 0, 0))
1844 goto lend;
1846 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1847 MAX_REPLY_LEN, 0, 0, 0);
1848 if (nResCode)
1849 bSuccess = TRUE;
1850 else
1851 FTP_SetResponseError(nResCode);
1853 lend:
1854 return bSuccess;
1858 /***********************************************************************
1859 * FTP_SendStore (internal)
1861 * Send request to upload file to ftp server
1863 * RETURNS
1864 * TRUE on success
1865 * FALSE on failure
1868 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
1870 INT nResCode;
1871 BOOL bSuccess = FALSE;
1873 TRACE("\n");
1874 if (!FTP_InitListenSocket(lpwfs))
1875 goto lend;
1877 if (!FTP_SendType(lpwfs, dwType))
1878 goto lend;
1880 if (!FTP_SendPortOrPasv(lpwfs))
1881 goto lend;
1883 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
1884 goto lend;
1885 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1886 MAX_REPLY_LEN, 0, 0, 0);
1887 if (nResCode)
1889 if (nResCode == 150)
1890 bSuccess = TRUE;
1891 else
1892 FTP_SetResponseError(nResCode);
1895 lend:
1896 if (!bSuccess && lpwfs->lstnSocket != -1)
1898 close(lpwfs->lstnSocket);
1899 lpwfs->lstnSocket = -1;
1902 return bSuccess;
1906 /***********************************************************************
1907 * FTP_InitListenSocket (internal)
1909 * Create a socket to listen for server response
1911 * RETURNS
1912 * TRUE on success
1913 * FALSE on failure
1916 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs)
1918 BOOL bSuccess = FALSE;
1919 size_t namelen = sizeof(struct sockaddr_in);
1921 TRACE("\n");
1923 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
1924 if (lpwfs->lstnSocket == -1)
1926 TRACE("Unable to create listening socket\n");
1927 goto lend;
1930 /* We obtain our ip addr from the name of the command channel socket */
1931 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
1933 /* and get the system to assign us a port */
1934 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
1936 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
1938 TRACE("Unable to bind socket\n");
1939 goto lend;
1942 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
1944 TRACE("listen failed\n");
1945 goto lend;
1948 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
1949 bSuccess = TRUE;
1951 lend:
1952 if (!bSuccess && lpwfs->lstnSocket == -1)
1954 close(lpwfs->lstnSocket);
1955 lpwfs->lstnSocket = -1;
1958 return bSuccess;
1962 /***********************************************************************
1963 * FTP_SendType (internal)
1965 * Tell server type of data being transferred
1967 * RETURNS
1968 * TRUE on success
1969 * FALSE on failure
1971 * W98SE doesn't cache the type that's currently set
1972 * (i.e. it sends it always),
1973 * so we probably don't want to do that either.
1975 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType)
1977 INT nResCode;
1978 CHAR type[2] = { "I" };
1979 BOOL bSuccess = FALSE;
1981 TRACE("\n");
1982 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
1983 *type = 'A';
1985 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
1986 goto lend;
1988 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1989 MAX_REPLY_LEN, 0, 0, 0)/100;
1990 if (nResCode)
1992 if (nResCode == 2)
1993 bSuccess = TRUE;
1994 else
1995 FTP_SetResponseError(nResCode);
1998 lend:
1999 return bSuccess;
2002 /***********************************************************************
2003 * FTP_GetFileSize (internal)
2005 * Retrieves from the server the size of the given file
2007 * RETURNS
2008 * TRUE on success
2009 * FALSE on failure
2012 BOOL FTP_GetFileSize(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD *dwSize)
2014 INT nResCode;
2015 BOOL bSuccess = FALSE;
2017 TRACE("\n");
2019 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2020 goto lend;
2022 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2023 MAX_REPLY_LEN, 0, 0, 0);
2024 if (nResCode)
2026 if (nResCode == 213) {
2027 /* Now parses the output to get the actual file size */
2028 int i;
2029 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2031 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2032 if (lpszResponseBuffer[i] == '\0') return FALSE;
2033 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2035 bSuccess = TRUE;
2036 } else {
2037 FTP_SetResponseError(nResCode);
2041 lend:
2042 return bSuccess;
2046 /***********************************************************************
2047 * FTP_SendPort (internal)
2049 * Tell server which port to use
2051 * RETURNS
2052 * TRUE on success
2053 * FALSE on failure
2056 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs)
2058 INT nResCode;
2059 CHAR szIPAddress[64];
2060 BOOL bSuccess = FALSE;
2061 TRACE("\n");
2063 sprintf(szIPAddress, "%d,%d,%d,%d,%d,%d",
2064 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2065 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2066 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2067 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2068 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2069 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2071 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2072 goto lend;
2074 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2075 MAX_REPLY_LEN,0, 0, 0);
2076 if (nResCode)
2078 if (nResCode == 200)
2079 bSuccess = TRUE;
2080 else
2081 FTP_SetResponseError(nResCode);
2084 lend:
2085 return bSuccess;
2089 /***********************************************************************
2090 * FTP_DoPassive (internal)
2092 * Tell server that we want to do passive transfers
2093 * and connect data socket
2095 * RETURNS
2096 * TRUE on success
2097 * FALSE on failure
2100 BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs)
2102 INT nResCode;
2103 BOOL bSuccess = FALSE;
2105 TRACE("\n");
2106 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2107 goto lend;
2109 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2110 MAX_REPLY_LEN,0, 0, 0);
2111 if (nResCode)
2113 if (nResCode == 227)
2115 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2116 LPSTR p;
2117 int f[6];
2118 int i;
2119 char *pAddr, *pPort;
2120 INT nsocket = -1;
2121 struct sockaddr_in dataSocketAddress;
2123 p = lpszResponseBuffer+4; /* skip status code */
2125 /* do a very strict check; we can improve that later. */
2127 if (strncmp(p, "Entering Passive Mode", 21))
2129 ERR("unknown response '%.*s', aborting\n", 21, p);
2130 goto lend;
2132 p += 21; /* skip string */
2133 if ((*p++ != ' ') || (*p++ != '('))
2135 ERR("unknown response format, aborting\n");
2136 goto lend;
2139 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2140 &f[4], &f[5]) != 6)
2142 ERR("unknown response address format '%s', aborting\n", p);
2143 goto lend;
2145 for (i=0; i < 6; i++)
2146 f[i] = f[i] & 0xff;
2148 dataSocketAddress = lpwfs->socketAddress;
2149 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2150 pPort = (char *)&(dataSocketAddress.sin_port);
2151 pAddr[0] = f[0];
2152 pAddr[1] = f[1];
2153 pAddr[2] = f[2];
2154 pAddr[3] = f[3];
2155 pPort[0] = f[4];
2156 pPort[1] = f[5];
2158 nsocket = socket(AF_INET,SOCK_STREAM,0);
2159 if (nsocket == -1)
2160 goto lend;
2162 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2164 ERR("can't connect passive FTP data port.\n");
2165 goto lend;
2167 lpwfs->pasvSocket = nsocket;
2168 bSuccess = TRUE;
2170 else
2171 FTP_SetResponseError(nResCode);
2174 lend:
2175 return bSuccess;
2179 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs)
2181 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2183 if (!FTP_DoPassive(lpwfs))
2184 return FALSE;
2186 else
2188 if (!FTP_SendPort(lpwfs))
2189 return FALSE;
2191 return TRUE;
2195 /***********************************************************************
2196 * FTP_GetDataSocket (internal)
2198 * Either accepts an incoming data socket connection from the server
2199 * or just returns the already opened socket after a PASV command
2200 * in case of passive FTP.
2203 * RETURNS
2204 * TRUE on success
2205 * FALSE on failure
2208 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket)
2210 struct sockaddr_in saddr;
2211 size_t addrlen = sizeof(struct sockaddr);
2213 TRACE("\n");
2214 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2216 *nDataSocket = lpwfs->pasvSocket;
2218 else
2220 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2221 close(lpwfs->lstnSocket);
2222 lpwfs->lstnSocket = -1;
2224 return *nDataSocket != -1;
2228 /***********************************************************************
2229 * FTP_SendData (internal)
2231 * Send data to the server
2233 * RETURNS
2234 * TRUE on success
2235 * FALSE on failure
2238 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile)
2240 BY_HANDLE_FILE_INFORMATION fi;
2241 DWORD nBytesRead = 0;
2242 DWORD nBytesSent = 0;
2243 DWORD nTotalSent = 0;
2244 DWORD nBytesToSend, nLen, nRC = 1;
2245 time_t s_long_time, e_long_time;
2246 LONG nSeconds;
2247 CHAR *lpszBuffer;
2249 TRACE("\n");
2250 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2251 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2253 /* Get the size of the file. */
2254 GetFileInformationByHandle(hFile, &fi);
2255 time(&s_long_time);
2259 nBytesToSend = nBytesRead - nBytesSent;
2261 if (nBytesToSend <= 0)
2263 /* Read data from file. */
2264 nBytesSent = 0;
2265 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2266 ERR("Failed reading from file\n");
2268 if (nBytesRead > 0)
2269 nBytesToSend = nBytesRead;
2270 else
2271 break;
2274 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2275 DATA_PACKET_SIZE : nBytesToSend;
2276 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2278 if (nRC != -1)
2280 nBytesSent += nRC;
2281 nTotalSent += nRC;
2284 /* Do some computation to display the status. */
2285 time(&e_long_time);
2286 nSeconds = e_long_time - s_long_time;
2287 if( nSeconds / 60 > 0 )
2289 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
2290 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2291 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2293 else
2295 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
2296 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2297 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2299 } while (nRC != -1);
2301 TRACE("file transfer complete!\n");
2303 if(lpszBuffer != NULL)
2304 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2306 return nTotalSent;
2310 /***********************************************************************
2311 * FTP_SendRetrieve (internal)
2313 * Send request to retrieve a file
2315 * RETURNS
2316 * Number of bytes to be received on success
2317 * 0 on failure
2320 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
2322 INT nResCode;
2323 DWORD nResult = 0;
2325 TRACE("\n");
2326 if (!FTP_InitListenSocket(lpwfs))
2327 goto lend;
2329 if (!FTP_SendType(lpwfs, dwType))
2330 goto lend;
2332 if (!FTP_SendPortOrPasv(lpwfs))
2333 goto lend;
2335 if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2336 goto lend;
2338 TRACE("Waiting to receive %ld bytes\n", nResult);
2340 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2341 goto lend;
2343 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2344 MAX_REPLY_LEN, 0, 0, 0);
2345 if ((nResCode != 125) && (nResCode != 150)) {
2346 /* That means that we got an error getting the file. */
2347 nResult = 0;
2350 lend:
2351 if (0 == nResult && lpwfs->lstnSocket != -1)
2353 close(lpwfs->lstnSocket);
2354 lpwfs->lstnSocket = -1;
2357 return nResult;
2361 /***********************************************************************
2362 * FTP_RetrieveData (internal)
2364 * Retrieve data from server
2366 * RETURNS
2367 * TRUE on success
2368 * FALSE on failure
2371 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2373 DWORD nBytesWritten;
2374 DWORD nBytesReceived = 0;
2375 INT nRC = 0;
2376 CHAR *lpszBuffer;
2378 TRACE("\n");
2380 if (INVALID_HANDLE_VALUE == hFile)
2381 return FALSE;
2383 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2384 if (NULL == lpszBuffer)
2386 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2387 return FALSE;
2390 while (nBytesReceived < nBytes && nRC != -1)
2392 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2393 if (nRC != -1)
2395 /* other side closed socket. */
2396 if (nRC == 0)
2397 goto recv_end;
2398 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2399 nBytesReceived += nRC;
2402 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
2403 nBytesReceived * 100 / nBytes);
2406 TRACE("Data transfer complete\n");
2407 if (NULL != lpszBuffer)
2408 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2410 recv_end:
2411 return (nRC != -1);
2415 /***********************************************************************
2416 * FTP_CloseSessionHandle (internal)
2418 * Deallocate session handle
2420 * RETURNS
2421 * TRUE on success
2422 * FALSE on failure
2425 BOOL FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs)
2427 TRACE("\n");
2429 if (lpwfs->download_in_progress != NULL)
2430 lpwfs->download_in_progress->session_deleted = TRUE;
2432 if (lpwfs->sndSocket != -1)
2433 close(lpwfs->sndSocket);
2435 if (lpwfs->lstnSocket != -1)
2436 close(lpwfs->lstnSocket);
2438 if (lpwfs->lpszPassword)
2439 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2441 if (lpwfs->lpszUserName)
2442 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2444 HeapFree(GetProcessHeap(), 0, lpwfs);
2446 return TRUE;
2450 /***********************************************************************
2451 * FTP_CloseFindNextHandle (internal)
2453 * Deallocate session handle
2455 * RETURNS
2456 * TRUE on success
2457 * FALSE on failure
2460 BOOL FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn)
2462 INT i;
2464 TRACE("\n");
2466 for (i = 0; i < lpwfn->size; i++)
2468 if (NULL != lpwfn->lpafp[i].lpszName)
2469 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2472 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2473 HeapFree(GetProcessHeap(), 0, lpwfn);
2475 return TRUE;
2478 /***********************************************************************
2479 * FTP_CloseFileTransferHandle (internal)
2481 * Closes the file transfer handle. This also 'cleans' the data queue of
2482 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2484 * RETURNS
2485 * TRUE on success
2486 * FALSE on failure
2489 BOOL FTP_CloseFileTransferHandle(LPWININETFILE lpwh)
2491 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) lpwh->hdr.lpwhparent;
2492 INT nResCode;
2494 TRACE("\n");
2496 if (!lpwh->session_deleted)
2497 lpwfs->download_in_progress = NULL;
2499 /* This just serves to flush the control socket of any spurrious lines written
2500 to it (like '226 Transfer complete.').
2502 Wonder what to do if the server sends us an error code though...
2504 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2505 MAX_REPLY_LEN, 0, 0, 0);
2507 if (lpwh->nDataSocket != -1)
2508 close(lpwh->nDataSocket);
2510 HeapFree(GetProcessHeap(), 0, lpwh);
2512 return TRUE;
2515 /***********************************************************************
2516 * FTP_ReceiveFileList (internal)
2518 * Read file list from server
2520 * RETURNS
2521 * Handle to file list on success
2522 * NULL on failure
2525 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
2526 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext)
2528 DWORD dwSize = 0;
2529 LPFILEPROPERTIESA lpafp = NULL;
2530 LPWININETFINDNEXTA lpwfn = NULL;
2531 HINTERNET handle = 0;
2533 TRACE("\n");
2535 if (FTP_ParseDirectory(lpwfs, nSocket, &lpafp, &dwSize))
2537 FTP_ConvertFileProp(lpafp, lpFindFileData);
2539 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTA));
2540 if (lpwfn)
2542 handle = WININET_AllocHandle( &lpwfn->hdr );
2543 if( handle )
2545 lpwfn->hdr.htype = WH_HFINDNEXT;
2546 lpwfn->hdr.lpwhparent = &lpwfs->hdr;
2547 lpwfn->hdr.dwContext = dwContext;
2548 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2549 lpwfn->size = dwSize;
2550 lpwfn->lpafp = lpafp;
2552 else
2553 HeapFree( GetProcessHeap(), 0, lpwfn );
2557 TRACE("Matched %ld files\n", dwSize);
2558 return handle;
2562 /***********************************************************************
2563 * FTP_ConvertFileProp (internal)
2565 * Converts FILEPROPERTIESA struct to WIN32_FIND_DATAA
2567 * RETURNS
2568 * TRUE on success
2569 * FALSE on failure
2572 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESA lpafp, LPWIN32_FIND_DATAA lpFindFileData)
2574 BOOL bSuccess = FALSE;
2576 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2578 if (lpafp)
2580 /* Convert 'Unix' time to Windows time */
2581 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
2582 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
2584 /* Not all fields are filled in */
2585 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2586 lpFindFileData->nFileSizeLow = lpafp->nSize;
2588 if (lpafp->bIsDirectory)
2589 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2591 if (lpafp->lpszName)
2592 strncpy(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2594 bSuccess = TRUE;
2597 return bSuccess;
2601 /***********************************************************************
2602 * FTP_ParseDirectory (internal)
2604 * Parse string of directory information
2606 * RETURNS
2607 * TRUE on success
2608 * FALSE on failure
2610 * FIXME: - This function needs serious clea-up
2611 * - We should consider both UNIX and NT list formats
2613 #define MAX_MONTH_LEN 10
2614 #define MIN_LEN_DIR_ENTRY 15
2616 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp)
2619 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2621 * For instance:
2622 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2624 CHAR* pszMinutes;
2625 CHAR* pszHour;
2626 time_t aTime;
2627 struct tm* apTM;
2628 CHAR pszMonth[MAX_MONTH_LEN];
2629 CHAR* pszMatch;
2630 BOOL bSuccess = TRUE;
2631 DWORD nBufLen = MAX_REPLY_LEN;
2632 LPFILEPROPERTIESA curFileProp = NULL;
2633 CHAR* pszLine = NULL;
2634 CHAR* pszToken = NULL;
2635 INT nTokenToSkip = 3;
2636 INT nCount = 0;
2637 INT nSeconds = 0;
2638 INT nMinutes = 0;
2639 INT nHour = 0;
2640 INT nDay = 0;
2641 INT nMonth = 0;
2642 INT nYear = 0;
2643 INT sizeFilePropArray = 20;
2644 INT indexFilePropArray = 0;
2646 TRACE("\n");
2648 /* Allocate intial file properties array */
2649 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESA)*(sizeFilePropArray));
2650 if (NULL == lpafp)
2652 bSuccess = FALSE;
2653 goto lend;
2656 while ((pszLine = INTERNET_GetNextLine(nSocket, INTERNET_GetResponseBuffer(), &nBufLen)) != NULL)
2658 if (sizeFilePropArray <= indexFilePropArray)
2660 LPFILEPROPERTIESA tmpafp;
2662 sizeFilePropArray *= 2;
2663 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
2664 sizeof(FILEPROPERTIESA)*sizeFilePropArray);
2665 if (NULL == tmpafp)
2667 bSuccess = FALSE;
2668 goto lend;
2671 *lpafp = tmpafp;
2674 curFileProp = &((*lpafp)[indexFilePropArray]);
2676 /* First Parse the permissions. */
2677 pszToken = strtok(pszLine, " \t" );
2679 /* HACK! If this is not a file listing skip the line */
2680 if (!pszToken || nBufLen <= MIN_LEN_DIR_ENTRY)
2682 nBufLen = MAX_REPLY_LEN;
2683 continue;
2685 if (10 == strlen(pszToken)) {
2686 /* Unix way of parsing ... */
2687 FTP_ParsePermission(pszToken, curFileProp);
2689 nTokenToSkip = 3;
2690 nCount = 0;
2691 do {
2692 pszToken = strtok( NULL, " \t" );
2693 nCount++;
2694 } while( nCount <= nTokenToSkip );
2696 /* Store the size of the file in the param list. */
2697 TRACE("nSize-> %s\n", pszToken);
2698 if (pszToken != NULL)
2699 curFileProp->nSize = atol(pszToken);
2701 /* Parse last modified time. */
2702 nSeconds = 0;
2703 nMinutes = 0;
2704 nHour = 0;
2705 nDay = 0;
2706 nMonth = 0;
2707 nYear = 0;
2709 pszToken = strtok( NULL, " \t" );
2710 strncpy(pszMonth, pszToken, MAX_MONTH_LEN);
2711 CharUpperA(pszMonth);
2712 pszMatch = strstr(szMonths, pszMonth);
2713 if( pszMatch != NULL )
2714 nMonth = (pszMatch - szMonths) / 3;
2716 pszToken = strtok(NULL, " \t");
2717 TRACE("nDay -> %s\n", pszToken);
2718 if (pszToken != NULL)
2719 nDay = atoi(pszToken);
2721 pszToken = strtok(NULL, " \t");
2722 pszMinutes = strchr(pszToken, ':');
2723 if( pszMinutes != NULL ) {
2724 pszMinutes++;
2725 nMinutes = atoi(pszMinutes);
2726 pszHour = pszMinutes - 3;
2727 if (pszHour != NULL)
2728 nHour = atoi(pszHour);
2729 time(&aTime);
2730 apTM = localtime( &aTime );
2731 nYear = apTM->tm_year;
2732 } else {
2733 nYear = atoi(pszToken);
2734 nYear -= 1900;
2735 nHour = 12;
2738 curFileProp->tmLastModified.tm_sec = nSeconds;
2739 curFileProp->tmLastModified.tm_min = nMinutes;
2740 curFileProp->tmLastModified.tm_hour = nHour;
2741 curFileProp->tmLastModified.tm_mday = nDay;
2742 curFileProp->tmLastModified.tm_mon = nMonth;
2743 curFileProp->tmLastModified.tm_year = nYear;
2745 pszToken = strtok(NULL, " \t");
2746 if(pszToken != NULL) {
2747 curFileProp->lpszName = FTP_strdup(pszToken);
2748 TRACE(": %s\n", curFileProp->lpszName);
2751 nBufLen = MAX_REPLY_LEN;
2752 indexFilePropArray++;
2753 } else if (8 == strlen(pszToken)) {
2754 /* NT way of parsing ... :
2756 07-13-03 08:55PM <DIR> sakpatch
2757 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
2760 curFileProp->permissions = 0xFFFF; /* No idea, put full permission :-) */
2762 sscanf(pszToken, "%d-%d-%d",
2763 &curFileProp->tmLastModified.tm_mon,
2764 &curFileProp->tmLastModified.tm_mday,
2765 &curFileProp->tmLastModified.tm_year);
2767 /* Hacky and bad Y2K protection :-) */
2768 if (curFileProp->tmLastModified.tm_year < 70)
2769 curFileProp->tmLastModified.tm_year += 100;
2771 pszToken = strtok(NULL, " \t");
2772 if (pszToken == NULL) {
2773 nBufLen = MAX_REPLY_LEN;
2774 continue;
2776 sscanf(pszToken, "%d:%d",
2777 &curFileProp->tmLastModified.tm_hour,
2778 &curFileProp->tmLastModified.tm_min);
2779 if ((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
2780 curFileProp->tmLastModified.tm_hour += 12;
2782 curFileProp->tmLastModified.tm_sec = 0;
2784 TRACE("Mod time: %2d:%2d:%2d %2d/%2d/%2d\n",
2785 curFileProp->tmLastModified.tm_hour, curFileProp->tmLastModified.tm_min, curFileProp->tmLastModified.tm_sec,
2786 (curFileProp->tmLastModified.tm_year >= 100) ? curFileProp->tmLastModified.tm_year - 100 : curFileProp->tmLastModified.tm_year,
2787 curFileProp->tmLastModified.tm_mon, curFileProp->tmLastModified.tm_mday);
2789 pszToken = strtok(NULL, " \t");
2790 if (pszToken == NULL) {
2791 nBufLen = MAX_REPLY_LEN;
2792 continue;
2794 if (!strcasecmp(pszToken, "<DIR>")) {
2795 curFileProp->bIsDirectory = TRUE;
2796 TRACE("Is directory\n");
2797 } else {
2798 curFileProp->bIsDirectory = FALSE;
2799 curFileProp->nSize = atol(pszToken);
2800 TRACE("nSize: %ld\n", curFileProp->nSize);
2803 pszToken = strtok(NULL, " \t");
2804 if (pszToken == NULL) {
2805 nBufLen = MAX_REPLY_LEN;
2806 continue;
2808 curFileProp->lpszName = FTP_strdup(pszToken);
2809 TRACE("Name: %s\n", curFileProp->lpszName);
2811 nBufLen = MAX_REPLY_LEN;
2812 indexFilePropArray++;
2813 } else {
2814 nBufLen = MAX_REPLY_LEN;
2818 if (bSuccess && indexFilePropArray)
2820 if (indexFilePropArray < sizeFilePropArray - 1)
2822 LPFILEPROPERTIESA tmpafp;
2824 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
2825 sizeof(FILEPROPERTIESA)*indexFilePropArray);
2826 if (NULL == tmpafp)
2827 *lpafp = tmpafp;
2829 *dwfp = indexFilePropArray;
2831 else
2833 HeapFree(GetProcessHeap(), 0, *lpafp);
2834 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2835 bSuccess = FALSE;
2838 lend:
2839 return bSuccess;
2843 /***********************************************************************
2844 * FTP_ParsePermission (internal)
2846 * Parse permission string of directory information
2848 * RETURNS
2849 * TRUE on success
2850 * FALSE on failure
2853 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp)
2855 BOOL bSuccess = TRUE;
2856 unsigned short nPermission = 0;
2857 INT nPos = 1;
2858 INT nLast = 9;
2860 TRACE("\n");
2861 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
2863 bSuccess = FALSE;
2864 return bSuccess;
2867 lpfp->bIsDirectory = (*lpszPermission == 'd');
2870 switch (nPos)
2872 case 1:
2873 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
2874 break;
2875 case 2:
2876 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
2877 break;
2878 case 3:
2879 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
2880 break;
2881 case 4:
2882 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
2883 break;
2884 case 5:
2885 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
2886 break;
2887 case 6:
2888 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
2889 break;
2890 case 7:
2891 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
2892 break;
2893 case 8:
2894 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
2895 break;
2896 case 9:
2897 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
2898 break;
2900 nPos++;
2901 }while (nPos <= nLast);
2903 lpfp->permissions = nPermission;
2904 return bSuccess;
2908 /***********************************************************************
2909 * FTP_SetResponseError (internal)
2911 * Set the appropriate error code for a given response from the server
2913 * RETURNS
2916 DWORD FTP_SetResponseError(DWORD dwResponse)
2918 DWORD dwCode = 0;
2920 switch(dwResponse)
2922 case 421: /* Service not available - Server may be shutting down. */
2923 dwCode = ERROR_INTERNET_TIMEOUT;
2924 break;
2926 case 425: /* Cannot open data connection. */
2927 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
2928 break;
2930 case 426: /* Connection closed, transer aborted. */
2931 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
2932 break;
2934 case 500: /* Syntax error. Command unrecognized. */
2935 case 501: /* Syntax error. Error in parameters or arguments. */
2936 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
2937 break;
2939 case 530: /* Not logged in. Login incorrect. */
2940 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
2941 break;
2943 case 550: /* File action not taken. File not found or no access. */
2944 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
2945 break;
2947 case 450: /* File action not taken. File may be busy. */
2948 case 451: /* Action aborted. Server error. */
2949 case 452: /* Action not taken. Insufficient storage space on server. */
2950 case 502: /* Command not implemented. */
2951 case 503: /* Bad sequence of command. */
2952 case 504: /* Command not implemented for that parameter. */
2953 case 532: /* Need account for storing files */
2954 case 551: /* Requested action aborted. Page type unknown */
2955 case 552: /* Action aborted. Exceeded storage allocation */
2956 case 553: /* Action not taken. File name not allowed. */
2958 default:
2959 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
2960 break;
2963 INTERNET_SetLastError(dwCode);
2964 return dwCode;