Add missing #include <netinet/in.h> to get struct in_addr on all platforms.
[wine/multimedia.git] / dlls / wininet / ftp.c
blob2963a0aecadcd3e5e55ca7844f566c094263d502
1 /*
2 * WININET - Ftp implementation
4 * Copyright 1999 Corel Corporation
6 * Ulrich Czekalla
7 * Noureddine Jemmali
8 */
10 #include "config.h"
12 #include <errno.h>
13 #ifdef HAVE_NETDB_H
14 # include <netdb.h>
15 #endif
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/types.h>
20 #ifdef HAVE_SYS_SOCKET_H
21 # include <sys/socket.h>
22 #endif
23 #include <sys/stat.h>
24 #include <unistd.h>
25 #include <netinet/in_systm.h>
26 #ifdef HAVE_NETINET_IH_H
27 # include <netinet/in.h>
28 #endif
29 #include <netinet/in.h>
30 #include <netinet/ip.h>
32 #include "winbase.h"
33 #include "wingdi.h"
34 #include "winuser.h"
35 #include "wininet.h"
36 #include "winerror.h"
37 #include "winsock.h"
38 #include "heap.h"
40 #include "debugtools.h"
41 #include "internet.h"
43 DEFAULT_DEBUG_CHANNEL(wininet);
45 #define NOACCOUNT "noaccount"
46 #define DATA_PACKET_SIZE 0x2000
47 #define szCRLF "\r\n"
48 #define MAX_BACKLOG 5
50 typedef enum {
51 /* FTP commands with arguments. */
52 FTP_CMD_ACCT,
53 FTP_CMD_CWD,
54 FTP_CMD_DELE,
55 FTP_CMD_MKD,
56 FTP_CMD_PASS,
57 FTP_CMD_PORT,
58 FTP_CMD_RETR,
59 FTP_CMD_RMD,
60 FTP_CMD_RNFR,
61 FTP_CMD_RNTO,
62 FTP_CMD_STOR,
63 FTP_CMD_TYPE,
64 FTP_CMD_USER,
66 /* FTP commands without arguments. */
67 FTP_CMD_ABOR,
68 FTP_CMD_LIST,
69 FTP_CMD_NLST,
70 FTP_CMD_PWD,
71 FTP_CMD_QUIT,
72 } FTP_COMMAND;
74 static const CHAR *szFtpCommands[] = {
75 "ACCT",
76 "CWD",
77 "DELE",
78 "MKD",
79 "PASS",
80 "PORT",
81 "RETR",
82 "RMD",
83 "RNFR",
84 "RNTO",
85 "STOR",
86 "TYPE",
87 "USER",
88 "ABOR",
89 "LIST",
90 "NLST",
91 "PWD",
92 "QUIT",
95 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
97 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
98 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
99 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
100 BOOL FTP_InitDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket);
101 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile);
102 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
103 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
104 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
105 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile);
106 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs);
107 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs);
108 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs);
109 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs);
110 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType);
111 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs);
112 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp);
113 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp);
114 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
115 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext);
116 DWORD FTP_SetResponseError(DWORD dwResponse);
118 inline static LPSTR FTP_strdup( LPCSTR str )
120 LPSTR ret = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
121 if (ret) strcpy( ret, str );
122 return ret;
125 /***********************************************************************
126 * FtpPutFileA (WININET.43)
128 * Uploads a file to the FTP server
130 * RETURNS
131 * TRUE on success
132 * FALSE on failure
135 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
136 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
138 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
139 LPWININETAPPINFOA hIC = NULL;
141 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
143 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
144 return FALSE;
147 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
148 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
150 WORKREQUEST workRequest;
152 workRequest.asyncall = FTPPUTFILEA;
153 workRequest.HFTPSESSION = (DWORD)hConnect;
154 workRequest.LPSZLOCALFILE = (DWORD)FTP_strdup(lpszLocalFile);
155 workRequest.LPSZNEWREMOTEFILE = (DWORD)FTP_strdup(lpszNewRemoteFile);
156 workRequest.DWFLAGS = dwFlags;
157 workRequest.DWCONTEXT = dwContext;
159 return INTERNET_AsyncCall(&workRequest);
161 else
163 return FTP_FtpPutFileA(hConnect, lpszLocalFile,
164 lpszNewRemoteFile, dwFlags, dwContext);
168 /***********************************************************************
169 * FTP_FtpPutFileA (Internal)
171 * Uploads a file to the FTP server
173 * RETURNS
174 * TRUE on success
175 * FALSE on failure
178 BOOL WINAPI FTP_FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
179 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
181 HANDLE hFile = (HANDLE)NULL;
182 BOOL bSuccess = FALSE;
183 LPWININETAPPINFOA hIC = NULL;
184 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
185 INT nResCode;
187 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", lpszLocalFile, lpszNewRemoteFile);
188 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
190 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
191 return FALSE;
194 /* Clear any error information */
195 INTERNET_SetLastError(0);
197 /* Open file to be uploaded */
198 if (INVALID_HANDLE_VALUE ==
199 (hFile = CreateFileA(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
201 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND);
202 goto lend;
205 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
206 if (hIC->lpfnStatusCB)
207 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
209 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
211 INT nDataSocket;
213 /* Accept connection from ftp server */
214 if (FTP_InitDataSocket(lpwfs, &nDataSocket))
216 FTP_SendData(lpwfs, nDataSocket, hFile);
217 close(nDataSocket);
218 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
219 MAX_REPLY_LEN,0, 0, 0);
220 if (nResCode)
222 if (nResCode == 226)
223 bSuccess = TRUE;
224 else
225 FTP_SetResponseError(nResCode);
230 lend:
231 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
233 INTERNET_ASYNC_RESULT iar;
235 iar.dwResult = (DWORD)bSuccess;
236 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
237 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
238 &iar, sizeof(INTERNET_ASYNC_RESULT));
241 if (hFile)
242 CloseHandle(hFile);
244 return bSuccess;
248 /***********************************************************************
249 * FtpSetCurrentDirectoryA (WININET.49)
251 * Change the working directory on the FTP server
253 * RETURNS
254 * TRUE on success
255 * FALSE on failure
258 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
260 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
261 LPWININETAPPINFOA hIC = NULL;
263 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
265 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
266 return FALSE;
269 TRACE("lpszDirectory(%s)\n", lpszDirectory);
271 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
272 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
274 WORKREQUEST workRequest;
276 workRequest.asyncall = FTPSETCURRENTDIRECTORYA;
277 workRequest.HFTPSESSION = (DWORD)hConnect;
278 workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
280 return INTERNET_AsyncCall(&workRequest);
282 else
284 return FTP_FtpSetCurrentDirectoryA(hConnect, lpszDirectory);
289 /***********************************************************************
290 * FTP_FtpSetCurrentDirectoryA (Internal)
292 * Change the working directory on the FTP server
294 * RETURNS
295 * TRUE on success
296 * FALSE on failure
299 BOOL WINAPI FTP_FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
301 INT nResCode;
302 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
303 LPWININETAPPINFOA hIC = NULL;
304 DWORD bSuccess = FALSE;
306 TRACE("lpszDirectory(%s)\n", lpszDirectory);
308 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
310 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
311 return FALSE;
314 /* Clear any error information */
315 INTERNET_SetLastError(0);
317 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
318 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
319 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
320 goto lend;
322 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
323 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
325 if (nResCode)
327 if (nResCode == 250)
328 bSuccess = TRUE;
329 else
330 FTP_SetResponseError(nResCode);
333 lend:
334 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
336 INTERNET_ASYNC_RESULT iar;
338 iar.dwResult = (DWORD)bSuccess;
339 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
340 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
341 &iar, sizeof(INTERNET_ASYNC_RESULT));
343 return bSuccess;
347 /***********************************************************************
348 * FtpCreateDirectoryA (WININET.31)
350 * Create new directory on the FTP server
352 * RETURNS
353 * TRUE on success
354 * FALSE on failure
357 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
359 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
360 LPWININETAPPINFOA hIC = NULL;
362 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
364 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
365 return FALSE;
368 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
369 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
371 WORKREQUEST workRequest;
373 workRequest.asyncall = FTPCREATEDIRECTORYA;
374 workRequest.HFTPSESSION = (DWORD)hConnect;
375 workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
377 return INTERNET_AsyncCall(&workRequest);
379 else
381 return FTP_FtpCreateDirectoryA(hConnect, lpszDirectory);
386 /***********************************************************************
387 * FTP_FtpCreateDirectoryA (Internal)
389 * Create new directory on the FTP server
391 * RETURNS
392 * TRUE on success
393 * FALSE on failure
396 BOOL WINAPI FTP_FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
398 INT nResCode;
399 BOOL bSuccess = FALSE;
400 LPWININETAPPINFOA hIC = NULL;
401 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
403 TRACE("\n");
404 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
406 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
407 return FALSE;
410 /* Clear any error information */
411 INTERNET_SetLastError(0);
413 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
414 goto lend;
416 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
417 MAX_REPLY_LEN, 0, 0, 0);
418 if (nResCode)
420 if (nResCode == 257)
421 bSuccess = TRUE;
422 else
423 FTP_SetResponseError(nResCode);
426 lend:
427 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
428 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
430 INTERNET_ASYNC_RESULT iar;
432 iar.dwResult = (DWORD)bSuccess;
433 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
434 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
435 &iar, sizeof(INTERNET_ASYNC_RESULT));
438 return bSuccess;
442 /***********************************************************************
443 * FtpFindFirstFileA (WININET.35)
445 * Search the specified directory
447 * RETURNS
448 * HINTERNET on success
449 * NULL on failure
452 INTERNETAPI HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
453 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
455 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
456 LPWININETAPPINFOA hIC = NULL;
458 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
460 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
461 return FALSE;
464 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
465 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
467 WORKREQUEST workRequest;
469 workRequest.asyncall = FTPFINDFIRSTFILEA;
470 workRequest.HFTPSESSION = (DWORD)hConnect;
471 workRequest.LPSZSEARCHFILE = (DWORD)FTP_strdup(lpszSearchFile);
472 workRequest.LPFINDFILEDATA = (DWORD)lpFindFileData;
473 workRequest.DWFLAGS = dwFlags;
474 workRequest.DWCONTEXT= dwContext;
476 INTERNET_AsyncCall(&workRequest);
477 return NULL;
479 else
481 return FTP_FtpFindFirstFileA(hConnect, lpszSearchFile, lpFindFileData,
482 dwFlags, dwContext);
487 /***********************************************************************
488 * FTP_FtpFindFirstFileA (Internal)
490 * Search the specified directory
492 * RETURNS
493 * HINTERNET on success
494 * NULL on failure
497 INTERNETAPI HINTERNET WINAPI FTP_FtpFindFirstFileA(HINTERNET hConnect,
498 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
500 INT nResCode;
501 LPWININETAPPINFOA hIC = NULL;
502 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
503 LPWININETFINDNEXTA hFindNext = NULL;
505 TRACE("\n");
507 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
509 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
510 return FALSE;
513 /* Clear any error information */
514 INTERNET_SetLastError(0);
516 if (!FTP_InitListenSocket(lpwfs))
517 goto lend;
519 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
520 goto lend;
522 if (!FTP_SendPort(lpwfs))
523 goto lend;
525 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
526 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, lpszSearchFile,
527 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
528 goto lend;
530 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
531 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
532 if (nResCode)
534 if (nResCode == 125 || nResCode == 150)
536 INT nDataSocket;
538 if (FTP_InitDataSocket(lpwfs, &nDataSocket))
540 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpFindFileData, dwContext);
542 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
543 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
544 if (nResCode != 226 && nResCode != 250)
545 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
547 close(nDataSocket);
550 else
551 FTP_SetResponseError(nResCode);
554 lend:
555 if (lpwfs->lstnSocket != INVALID_SOCKET)
556 close(lpwfs->lstnSocket);
558 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
560 INTERNET_ASYNC_RESULT iar;
562 if (hFindNext)
564 iar.dwResult = (DWORD)hFindNext;
565 iar.dwError = ERROR_SUCCESS;
566 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
567 &iar, sizeof(INTERNET_ASYNC_RESULT));
570 iar.dwResult = (DWORD)hFindNext;
571 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
572 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
573 &iar, sizeof(INTERNET_ASYNC_RESULT));
576 return (HINTERNET)hFindNext;
580 /***********************************************************************
581 * FtpGetCurrentDirectoryA (WININET.37)
583 * Retrieves the current directory
585 * RETURNS
586 * TRUE on success
587 * FALSE on failure
590 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
591 LPDWORD lpdwCurrentDirectory)
593 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
594 LPWININETAPPINFOA hIC = NULL;
596 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
598 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
600 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
601 return FALSE;
604 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
605 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
607 WORKREQUEST workRequest;
609 workRequest.asyncall = FTPGETCURRENTDIRECTORYA;
610 workRequest.HFTPSESSION = (DWORD)hFtpSession;
611 workRequest.LPSZDIRECTORY = (DWORD)lpszCurrentDirectory;
612 workRequest.LPDWDIRECTORY = (DWORD)lpdwCurrentDirectory;
614 return INTERNET_AsyncCall(&workRequest);
616 else
618 return FTP_FtpGetCurrentDirectoryA(hFtpSession, lpszCurrentDirectory,
619 lpdwCurrentDirectory);
624 /***********************************************************************
625 * FTP_FtpGetCurrentDirectoryA (Internal)
627 * Retrieves the current directory
629 * RETURNS
630 * TRUE on success
631 * FALSE on failure
634 BOOL WINAPI FTP_FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
635 LPDWORD lpdwCurrentDirectory)
637 INT nResCode;
638 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
639 LPWININETAPPINFOA hIC = NULL;
640 DWORD bSuccess = FALSE;
642 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
644 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
646 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
647 return FALSE;
650 /* Clear any error information */
651 INTERNET_SetLastError(0);
653 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
655 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
656 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
657 hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext))
658 goto lend;
660 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
661 MAX_REPLY_LEN, hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext);
662 if (nResCode)
664 if (nResCode == 257) /* Extract directory name */
666 INT firstpos, lastpos, len;
667 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
669 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
671 if ('"' == lpszResponseBuffer[lastpos])
673 if (!firstpos)
674 firstpos = lastpos;
675 else
676 break;
680 len = lastpos - firstpos - 1;
681 strncpy(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1],
682 len < *lpdwCurrentDirectory ? len : *lpdwCurrentDirectory);
683 *lpdwCurrentDirectory = len;
684 bSuccess = TRUE;
686 else
687 FTP_SetResponseError(nResCode);
690 lend:
691 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
693 INTERNET_ASYNC_RESULT iar;
695 iar.dwResult = (DWORD)bSuccess;
696 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
697 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
698 &iar, sizeof(INTERNET_ASYNC_RESULT));
701 return (DWORD) bSuccess;
704 /***********************************************************************
705 * FtpOpenFileA (WININET.41)
707 * Open a remote file for writing or reading
709 * RETURNS
710 * HINTERNET handle on success
711 * NULL on failure
714 INTERNETAPI HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
715 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
716 DWORD dwContext)
718 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
719 LPWININETAPPINFOA hIC = NULL;
721 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
723 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
724 return FALSE;
727 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
728 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
730 WORKREQUEST workRequest;
732 workRequest.asyncall = FTPOPENFILEA;
733 workRequest.HFTPSESSION = (DWORD)hFtpSession;
734 workRequest.LPSZFILENAME = (DWORD)FTP_strdup(lpszFileName);
735 workRequest.FDWACCESS = fdwAccess;
736 workRequest.DWFLAGS = dwFlags;
737 workRequest.DWCONTEXT = dwContext;
739 INTERNET_AsyncCall(&workRequest);
740 return NULL;
742 else
744 return FTP_FtpOpenFileA(hFtpSession, lpszFileName, fdwAccess, dwFlags, dwContext);
749 /***********************************************************************
750 * FTP_FtpOpenFileA (Internal)
752 * Open a remote file for writing or reading
754 * RETURNS
755 * HINTERNET handle on success
756 * NULL on failure
759 HINTERNET FTP_FtpOpenFileA(HINTERNET hFtpSession,
760 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
761 DWORD dwContext)
763 INT nDataSocket;
764 BOOL bSuccess = FALSE;
765 LPWININETFILE hFile = NULL;
766 LPWININETAPPINFOA hIC = NULL;
767 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
769 TRACE("\n");
771 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
773 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
774 return FALSE;
777 /* Clear any error information */
778 INTERNET_SetLastError(0);
780 if (GENERIC_READ == fdwAccess)
782 /* Set up socket to retrieve data */
783 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
785 else if (GENERIC_WRITE == fdwAccess)
787 /* Set up socket to send data */
788 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
791 /* Accept connection from server */
792 if (bSuccess && FTP_InitDataSocket(lpwfs, &nDataSocket))
794 hFile = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE));
795 hFile->hdr.htype = WH_HFILE;
796 hFile->hdr.dwFlags = dwFlags;
797 hFile->hdr.dwContext = dwContext;
798 hFile->hdr.lpwhparent = hFtpSession;
799 hFile->nDataSocket = nDataSocket;
802 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
803 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
805 INTERNET_ASYNC_RESULT iar;
807 if (hFile)
809 iar.dwResult = (DWORD)hFile;
810 iar.dwError = ERROR_SUCCESS;
811 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
812 &iar, sizeof(INTERNET_ASYNC_RESULT));
815 iar.dwResult = (DWORD)bSuccess;
816 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
817 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
818 &iar, sizeof(INTERNET_ASYNC_RESULT));
821 return (HINTERNET)hFile;
825 /***********************************************************************
826 * FtpGetFileA (WININET.39)
828 * Retrieve file from the FTP server
830 * RETURNS
831 * TRUE on success
832 * FALSE on failure
835 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
836 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
837 DWORD dwContext)
839 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet;
840 LPWININETAPPINFOA hIC = NULL;
842 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
844 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
845 return FALSE;
848 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
849 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
851 WORKREQUEST workRequest;
853 workRequest.asyncall = FTPGETFILEA;
854 workRequest.HFTPSESSION = (DWORD)hInternet;
855 workRequest.LPSZREMOTEFILE = (DWORD)FTP_strdup(lpszRemoteFile);
856 workRequest.LPSZNEWFILE = (DWORD)FTP_strdup(lpszNewFile);
857 workRequest.DWLOCALFLAGSATTRIBUTE = dwLocalFlagsAttribute;
858 workRequest.FFAILIFEXISTS = (DWORD)fFailIfExists;
859 workRequest.DWFLAGS = dwInternetFlags;
860 workRequest.DWCONTEXT = dwContext;
862 return INTERNET_AsyncCall(&workRequest);
864 else
866 return FTP_FtpGetFileA(hInternet, lpszRemoteFile, lpszNewFile,
867 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
872 /***********************************************************************
873 * FTP_FtpGetFileA (Internal)
875 * Retrieve file from the FTP server
877 * RETURNS
878 * TRUE on success
879 * FALSE on failure
882 BOOL WINAPI FTP_FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
883 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
884 DWORD dwContext)
886 DWORD nBytes;
887 BOOL bSuccess = FALSE;
888 HANDLE hFile;
889 LPWININETAPPINFOA hIC = NULL;
890 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet;
892 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", lpszRemoteFile, lpszNewFile);
893 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
895 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
896 return FALSE;
899 /* Clear any error information */
900 INTERNET_SetLastError(0);
902 /* Ensure we can write to lpszNewfile by opening it */
903 hFile = CreateFileA(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
904 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
905 if (INVALID_HANDLE_VALUE == hFile)
906 goto lend;
908 /* Set up socket to retrieve data */
909 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
911 if (nBytes > 0)
913 INT nDataSocket;
915 /* Accept connection from ftp server */
916 if (FTP_InitDataSocket(lpwfs, &nDataSocket))
918 INT nResCode;
920 /* Receive data */
921 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
922 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
923 MAX_REPLY_LEN, 0, 0, 0);
924 if (nResCode)
926 if (nResCode == 226)
927 bSuccess = TRUE;
928 else
929 FTP_SetResponseError(nResCode);
931 close(nDataSocket);
935 lend:
936 if (hFile)
937 CloseHandle(hFile);
939 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
940 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
942 INTERNET_ASYNC_RESULT iar;
944 iar.dwResult = (DWORD)bSuccess;
945 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
946 hIC->lpfnStatusCB(hInternet, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
947 &iar, sizeof(INTERNET_ASYNC_RESULT));
950 return bSuccess;
954 /***********************************************************************
955 * FtpDeleteFileA (WININET.33)
957 * Delete a file on the ftp server
959 * RETURNS
960 * TRUE on success
961 * FALSE on failure
964 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
966 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
967 LPWININETAPPINFOA hIC = NULL;
969 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
971 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
972 return FALSE;
975 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
976 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
978 WORKREQUEST workRequest;
980 workRequest.asyncall = FTPRENAMEFILEA;
981 workRequest.HFTPSESSION = (DWORD)hFtpSession;
982 workRequest.LPSZFILENAME = (DWORD)FTP_strdup(lpszFileName);
984 return INTERNET_AsyncCall(&workRequest);
986 else
988 return FTP_FtpDeleteFileA(hFtpSession, lpszFileName);
993 /***********************************************************************
994 * FTP_FtpDeleteFileA (Internal)
996 * Delete a file on the ftp server
998 * RETURNS
999 * TRUE on success
1000 * FALSE on failure
1003 BOOL FTP_FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1005 INT nResCode;
1006 BOOL bSuccess = FALSE;
1007 LPWININETAPPINFOA hIC = NULL;
1008 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1010 TRACE("0x%08lx\n", (ULONG) hFtpSession);
1011 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1013 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1014 return FALSE;
1017 /* Clear any error information */
1018 INTERNET_SetLastError(0);
1020 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1021 goto lend;
1023 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1024 MAX_REPLY_LEN, 0, 0, 0);
1025 if (nResCode)
1027 if (nResCode == 250)
1028 bSuccess = TRUE;
1029 else
1030 FTP_SetResponseError(nResCode);
1032 lend:
1033 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1034 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1036 INTERNET_ASYNC_RESULT iar;
1038 iar.dwResult = (DWORD)bSuccess;
1039 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1040 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1041 &iar, sizeof(INTERNET_ASYNC_RESULT));
1044 return bSuccess;
1048 /***********************************************************************
1049 * FtpRemoveDirectoryA (WININET.45)
1051 * Remove a directory on the ftp server
1053 * RETURNS
1054 * TRUE on success
1055 * FALSE on failure
1058 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1060 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1061 LPWININETAPPINFOA hIC = NULL;
1063 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1065 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1066 return FALSE;
1069 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1070 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1072 WORKREQUEST workRequest;
1074 workRequest.asyncall = FTPREMOVEDIRECTORYA;
1075 workRequest.HFTPSESSION = (DWORD)hFtpSession;
1076 workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
1078 return INTERNET_AsyncCall(&workRequest);
1080 else
1082 return FTP_FtpRemoveDirectoryA(hFtpSession, lpszDirectory);
1087 /***********************************************************************
1088 * FTP_FtpRemoveDirectoryA (Internal)
1090 * Remove a directory on the ftp server
1092 * RETURNS
1093 * TRUE on success
1094 * FALSE on failure
1097 BOOL FTP_FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1099 INT nResCode;
1100 BOOL bSuccess = FALSE;
1101 LPWININETAPPINFOA hIC = NULL;
1102 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1104 TRACE("\n");
1105 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1107 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1108 return FALSE;
1111 /* Clear any error information */
1112 INTERNET_SetLastError(0);
1114 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1115 goto lend;
1117 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1118 MAX_REPLY_LEN, 0, 0, 0);
1119 if (nResCode)
1121 if (nResCode == 250)
1122 bSuccess = TRUE;
1123 else
1124 FTP_SetResponseError(nResCode);
1127 lend:
1128 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1129 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1131 INTERNET_ASYNC_RESULT iar;
1133 iar.dwResult = (DWORD)bSuccess;
1134 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1135 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1136 &iar, sizeof(INTERNET_ASYNC_RESULT));
1139 return bSuccess;
1143 /***********************************************************************
1144 * FtpRenameFileA (WININET.47)
1146 * Rename a file on the ftp server
1148 * RETURNS
1149 * TRUE on success
1150 * FALSE on failure
1153 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1155 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1156 LPWININETAPPINFOA hIC = NULL;
1158 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1160 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1161 return FALSE;
1164 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1165 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1167 WORKREQUEST workRequest;
1169 workRequest.asyncall = FTPRENAMEFILEA;
1170 workRequest.HFTPSESSION = (DWORD)hFtpSession;
1171 workRequest.LPSZSRCFILE = (DWORD)FTP_strdup(lpszSrc);
1172 workRequest.LPSZDESTFILE = (DWORD)FTP_strdup(lpszDest);
1174 return INTERNET_AsyncCall(&workRequest);
1176 else
1178 return FTP_FtpRenameFileA(hFtpSession, lpszSrc, lpszDest);
1182 /***********************************************************************
1183 * FTP_FtpRenameFileA (Internal)
1185 * Rename a file on the ftp server
1187 * RETURNS
1188 * TRUE on success
1189 * FALSE on failure
1192 BOOL FTP_FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1194 INT nResCode;
1195 BOOL bSuccess = FALSE;
1196 LPWININETAPPINFOA hIC = NULL;
1197 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1199 TRACE("\n");
1200 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1202 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1203 return FALSE;
1206 /* Clear any error information */
1207 INTERNET_SetLastError(0);
1209 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1210 goto lend;
1212 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1213 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1214 if (nResCode == 350)
1216 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1217 goto lend;
1219 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1220 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1223 if (nResCode == 250)
1224 bSuccess = TRUE;
1225 else
1226 FTP_SetResponseError(nResCode);
1228 lend:
1229 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1230 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1232 INTERNET_ASYNC_RESULT iar;
1234 iar.dwResult = (DWORD)bSuccess;
1235 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1236 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1237 &iar, sizeof(INTERNET_ASYNC_RESULT));
1240 return bSuccess;
1244 /***********************************************************************
1245 * FTP_Connect (internal)
1247 * Connect to a ftp server
1249 * RETURNS
1250 * HINTERNET a session handle on success
1251 * NULL on failure
1255 HINTERNET FTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
1256 INTERNET_PORT nServerPort, LPCSTR lpszUserName,
1257 LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
1259 struct sockaddr_in socketAddr;
1260 struct hostent *phe = NULL;
1261 INT nsocket = INVALID_SOCKET, sock_namelen;
1262 LPWININETAPPINFOA hIC = NULL;
1263 BOOL bSuccess = FALSE;
1264 LPWININETFTPSESSIONA lpwfs = NULL;
1266 TRACE("0x%08lx Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1267 (ULONG) hInternet, lpszServerName,
1268 nServerPort, lpszUserName, lpszPassword);
1270 if (((LPWININETHANDLEHEADER)hInternet)->htype != WH_HINIT)
1271 goto lerror;
1273 hIC = (LPWININETAPPINFOA) hInternet;
1275 if (NULL == lpszUserName && NULL != lpszPassword)
1277 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_USER_NAME);
1278 goto lerror;
1281 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1282 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1284 if (hIC->lpfnStatusCB)
1285 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1286 (LPSTR) lpszServerName, strlen(lpszServerName));
1288 if (!GetAddress(lpszServerName, nServerPort, &phe, &socketAddr))
1290 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1291 goto lerror;
1294 if (hIC->lpfnStatusCB)
1295 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1296 (LPSTR) lpszServerName, strlen(lpszServerName));
1298 if (INVALID_SOCKET == (nsocket = socket(AF_INET,SOCK_STREAM,0)))
1300 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1301 goto lerror;
1304 if (hIC->lpfnStatusCB)
1305 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1306 &socketAddr, sizeof(struct sockaddr_in));
1308 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1310 ERR("Unable to connect (%s)\n", strerror(errno));
1311 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1313 else
1315 TRACE("Connected to server\n");
1316 if (hIC->lpfnStatusCB)
1317 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1318 &socketAddr, sizeof(struct sockaddr_in));
1320 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONA));
1321 if (NULL == lpwfs)
1323 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1324 goto lerror;
1327 lpwfs->hdr.htype = WH_HFTPSESSION;
1328 lpwfs->hdr.dwFlags = dwFlags;
1329 lpwfs->hdr.dwContext = dwContext;
1330 lpwfs->hdr.lpwhparent = (LPWININETHANDLEHEADER)hInternet;
1331 lpwfs->sndSocket = nsocket;
1332 sock_namelen = sizeof(lpwfs->socketAddress);
1333 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1334 lpwfs->phostent = phe;
1336 if (NULL == lpszUserName)
1338 lpwfs->lpszUserName = FTP_strdup("anonymous");
1339 lpwfs->lpszPassword = FTP_strdup("user@server");
1341 else
1343 lpwfs->lpszUserName = FTP_strdup(lpszUserName);
1344 lpwfs->lpszPassword = FTP_strdup(lpszPassword);
1347 if (FTP_ConnectToHost(lpwfs))
1349 if (hIC->lpfnStatusCB)
1351 INTERNET_ASYNC_RESULT iar;
1353 iar.dwResult = (DWORD)lpwfs;
1354 iar.dwError = ERROR_SUCCESS;
1356 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_HANDLE_CREATED,
1357 &iar, sizeof(INTERNET_ASYNC_RESULT));
1359 TRACE("Successfully logged into server\n");
1360 bSuccess = TRUE;
1364 lerror:
1365 if (!bSuccess && INVALID_SOCKET != nsocket)
1366 close(nsocket);
1368 if (!bSuccess && lpwfs)
1370 HeapFree(GetProcessHeap(), 0, lpwfs);
1371 lpwfs = NULL;
1374 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1376 INTERNET_ASYNC_RESULT iar;
1378 iar.dwResult = (DWORD)lpwfs;
1379 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1380 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1381 &iar, sizeof(INTERNET_ASYNC_RESULT));
1384 return (HINTERNET) lpwfs;
1388 /***********************************************************************
1389 * FTP_ConnectHost (internal)
1391 * Connect to a ftp server
1393 * RETURNS
1394 * TRUE on success
1395 * NULL on failure
1398 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs)
1400 INT nResCode;
1401 BOOL bSuccess = FALSE;
1403 TRACE("\n");
1404 FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1406 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1407 goto lend;
1409 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1410 MAX_REPLY_LEN, 0, 0, 0);
1411 if (nResCode)
1413 /* Login successful... */
1414 if (nResCode == 230)
1415 bSuccess = TRUE;
1416 /* User name okay, need password... */
1417 else if (nResCode == 331)
1418 bSuccess = FTP_SendPassword(lpwfs);
1419 /* Need account for login... */
1420 else if (nResCode == 332)
1421 bSuccess = FTP_SendAccount(lpwfs);
1422 else
1423 FTP_SetResponseError(nResCode);
1426 TRACE("Returning %d\n", bSuccess);
1427 lend:
1428 return bSuccess;
1432 /***********************************************************************
1433 * FTP_SendCommand (internal)
1435 * Send command to server
1437 * RETURNS
1438 * TRUE on success
1439 * NULL on failure
1442 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1443 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1445 DWORD len;
1446 CHAR *buf;
1447 DWORD nBytesSent = 0;
1448 DWORD nRC = 0;
1449 BOOL bParamHasLen;
1451 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1453 if (lpfnStatusCB)
1454 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1456 bParamHasLen = lpszParam && strlen(lpszParam) > 0;
1457 len = (bParamHasLen ? strlen(lpszParam) : -1) + strlen(szFtpCommands[ftpCmd]) +
1458 strlen(szCRLF)+ 1;
1459 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1461 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1462 return FALSE;
1464 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], bParamHasLen ? " " : "",
1465 bParamHasLen ? lpszParam : "", szCRLF);
1467 TRACE("Sending (%s) len(%ld)\n", buf, len);
1468 while((nBytesSent < len) && (nRC != SOCKET_ERROR))
1470 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1471 nBytesSent += nRC;
1474 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
1476 if (lpfnStatusCB)
1477 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_REQUEST_SENT,
1478 &nBytesSent, sizeof(DWORD));
1480 TRACE("Sent %ld bytes\n", nBytesSent);
1481 return (nRC != SOCKET_ERROR);
1485 /***********************************************************************
1486 * FTP_ReceiveResponse (internal)
1488 * Receive response from server
1490 * RETURNS
1491 * Reply code on success
1492 * 0 on failure
1496 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
1497 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1499 DWORD nRecv;
1500 INT rc = 0;
1501 char firstprefix[5];
1502 BOOL multiline = FALSE;
1505 TRACE("socket(%d) \n", nSocket);
1507 if (lpfnStatusCB)
1508 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1510 while(1)
1512 nRecv = dwResponse;
1513 if (!INTERNET_GetNextLine(nSocket, lpszResponse, &nRecv))
1514 goto lerror;
1516 if (nRecv >= 3)
1518 if(!multiline)
1520 if(lpszResponse[3] != '-')
1521 break;
1522 else
1523 { /* Start of multiline repsonse. Loop until we get "nnn " */
1524 multiline = TRUE;
1525 memcpy(firstprefix, lpszResponse, 3);
1526 firstprefix[3] = ' ';
1527 firstprefix[4] = '\0';
1530 else
1532 if(!memcmp(firstprefix, lpszResponse, 4))
1533 break;
1538 if (nRecv >= 3)
1540 lpszResponse[nRecv] = '\0';
1541 rc = atoi(lpszResponse);
1543 if (lpfnStatusCB)
1544 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
1545 &nRecv, sizeof(DWORD));
1548 lerror:
1549 TRACE("return %d\n", rc);
1550 return rc;
1554 /***********************************************************************
1555 * FTP_SendPassword (internal)
1557 * Send password to ftp server
1559 * RETURNS
1560 * TRUE on success
1561 * NULL on failure
1564 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs)
1566 INT nResCode;
1567 BOOL bSuccess = FALSE;
1569 TRACE("\n");
1570 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
1571 goto lend;
1573 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1574 MAX_REPLY_LEN, 0, 0, 0);
1575 if (nResCode)
1577 TRACE("Received reply code %d\n", nResCode);
1578 /* Login successful... */
1579 if (nResCode == 230)
1580 bSuccess = TRUE;
1581 /* Command not implemented, superfluous at the server site... */
1582 /* Need account for login... */
1583 else if (nResCode == 332)
1584 bSuccess = FTP_SendAccount(lpwfs);
1585 else
1586 FTP_SetResponseError(nResCode);
1589 lend:
1590 TRACE("Returning %d\n", bSuccess);
1591 return bSuccess;
1595 /***********************************************************************
1596 * FTP_SendAccount (internal)
1600 * RETURNS
1601 * TRUE on success
1602 * FALSE on failure
1605 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs)
1607 INT nResCode;
1608 BOOL bSuccess = FALSE;
1610 TRACE("\n");
1611 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, NOACCOUNT, 0, 0, 0))
1612 goto lend;
1614 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1615 MAX_REPLY_LEN, 0, 0, 0);
1616 if (nResCode)
1617 bSuccess = TRUE;
1618 else
1619 FTP_SetResponseError(nResCode);
1621 lend:
1622 return bSuccess;
1626 /***********************************************************************
1627 * FTP_SendStore (internal)
1629 * Send request to upload file to ftp server
1631 * RETURNS
1632 * TRUE on success
1633 * FALSE on failure
1636 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
1638 INT nResCode;
1639 BOOL bSuccess = FALSE;
1641 TRACE("\n");
1642 if (!FTP_InitListenSocket(lpwfs))
1643 goto lend;
1645 if (!FTP_SendType(lpwfs, dwType))
1646 goto lend;
1648 if (!FTP_SendPort(lpwfs))
1649 goto lend;
1651 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
1652 goto lend;
1653 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1654 MAX_REPLY_LEN, 0, 0, 0);
1655 if (nResCode)
1657 if (nResCode == 150)
1658 bSuccess = TRUE;
1659 else
1660 FTP_SetResponseError(nResCode);
1663 lend:
1664 if (!bSuccess && INVALID_SOCKET != lpwfs->lstnSocket)
1666 close(lpwfs->lstnSocket);
1667 lpwfs->lstnSocket = INVALID_SOCKET;
1670 return bSuccess;
1674 /***********************************************************************
1675 * FTP_InitListenSocket (internal)
1677 * Create a socket to listen for server response
1679 * RETURNS
1680 * TRUE on success
1681 * FALSE on failure
1684 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs)
1686 BOOL bSuccess = FALSE;
1687 size_t namelen = sizeof(struct sockaddr_in);
1689 TRACE("\n");
1691 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
1692 if (INVALID_SOCKET == lpwfs->lstnSocket)
1694 TRACE("Unable to create listening socket\n");
1695 goto lend;
1698 /* We obtain our ip addr from the name of the command channel socket */
1699 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
1701 /* and get the system to assign us a port */
1702 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
1704 if (SOCKET_ERROR == bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)))
1706 TRACE("Unable to bind socket\n");
1707 goto lend;
1710 if (SOCKET_ERROR == listen(lpwfs->lstnSocket, MAX_BACKLOG))
1712 TRACE("listen failed\n");
1713 goto lend;
1716 if (SOCKET_ERROR != getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen))
1717 bSuccess = TRUE;
1719 lend:
1720 if (!bSuccess && INVALID_SOCKET == lpwfs->lstnSocket)
1722 close(lpwfs->lstnSocket);
1723 lpwfs->lstnSocket = INVALID_SOCKET;
1726 return bSuccess;
1730 /***********************************************************************
1731 * FTP_SendType (internal)
1733 * Tell server type of data being transfered
1735 * RETURNS
1736 * TRUE on success
1737 * FALSE on failure
1740 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType)
1742 INT nResCode;
1743 CHAR type[2] = { "I\0" };
1744 BOOL bSuccess = FALSE;
1746 TRACE("\n");
1747 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
1748 *type = 'A';
1750 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
1751 goto lend;
1753 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1754 MAX_REPLY_LEN, 0, 0, 0)/100;
1755 if (nResCode)
1757 if (nResCode == 2)
1758 bSuccess = TRUE;
1759 else
1760 FTP_SetResponseError(nResCode);
1763 lend:
1764 return bSuccess;
1768 /***********************************************************************
1769 * FTP_SendPort (internal)
1771 * Tell server which port to use
1773 * RETURNS
1774 * TRUE on success
1775 * FALSE on failure
1778 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs)
1780 INT nResCode;
1781 CHAR szIPAddress[64];
1782 BOOL bSuccess = FALSE;
1783 TRACE("\n");
1785 sprintf(szIPAddress, "%d,%d,%d,%d,%d,%d",
1786 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
1787 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
1788 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
1789 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
1790 lpwfs->lstnSocketAddress.sin_port & 0xFF,
1791 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
1793 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
1794 goto lend;
1796 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1797 MAX_REPLY_LEN,0, 0, 0);
1798 if (nResCode)
1800 if (nResCode == 200)
1801 bSuccess = TRUE;
1802 else
1803 FTP_SetResponseError(nResCode);
1806 lend:
1807 return bSuccess;
1811 /***********************************************************************
1812 * FTP_InitDataSocket (internal)
1816 * RETURNS
1817 * TRUE on success
1818 * FALSE on failure
1821 BOOL FTP_InitDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket)
1823 struct sockaddr_in saddr;
1824 size_t addrlen = sizeof(struct sockaddr);
1826 TRACE("\n");
1827 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
1828 close(lpwfs->lstnSocket);
1829 lpwfs->lstnSocket = INVALID_SOCKET;
1831 return *nDataSocket != INVALID_SOCKET;
1835 /***********************************************************************
1836 * FTP_SendData (internal)
1838 * Send data to the server
1840 * RETURNS
1841 * TRUE on success
1842 * FALSE on failure
1845 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile)
1847 BY_HANDLE_FILE_INFORMATION fi;
1848 DWORD nBytesRead = 0;
1849 DWORD nBytesSent = 0;
1850 DWORD nTotalSent = 0;
1851 DWORD nBytesToSend, nLen, nRC = 1;
1852 time_t s_long_time, e_long_time;
1853 LONG nSeconds;
1854 CHAR *lpszBuffer;
1856 TRACE("\n");
1857 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
1858 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
1860 /* Get the size of the file. */
1861 GetFileInformationByHandle(hFile, &fi);
1862 time(&s_long_time);
1866 nBytesToSend = nBytesRead - nBytesSent;
1868 if (nBytesToSend <= 0)
1870 /* Read data from file. */
1871 nBytesSent = 0;
1872 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
1873 ERR("Failed reading from file\n");
1875 if (nBytesRead > 0)
1876 nBytesToSend = nBytesRead;
1877 else
1878 break;
1881 nLen = DATA_PACKET_SIZE < nBytesToSend ?
1882 DATA_PACKET_SIZE : nBytesToSend;
1883 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
1885 if (nRC != SOCKET_ERROR)
1887 nBytesSent += nRC;
1888 nTotalSent += nRC;
1891 /* Do some computation to display the status. */
1892 time(&e_long_time);
1893 nSeconds = e_long_time - s_long_time;
1894 if( nSeconds / 60 > 0 )
1896 TRACE( "%ld bytes of %d bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
1897 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
1898 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
1900 else
1902 TRACE( "%ld bytes of %d bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
1903 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
1904 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
1906 } while (nRC != SOCKET_ERROR);
1908 TRACE("file transfer complete!\n");
1910 if(lpszBuffer != NULL)
1911 HeapFree(GetProcessHeap(), 0, lpszBuffer);
1913 return nTotalSent;
1917 /***********************************************************************
1918 * FTP_SendRetrieve (internal)
1920 * Send request to retrieve a file
1922 * RETURNS
1923 * Number of bytes to be received on success
1924 * 0 on failure
1927 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
1929 INT nResCode;
1930 DWORD nResult = 0;
1932 TRACE("\n");
1933 if (!FTP_InitListenSocket(lpwfs))
1934 goto lend;
1936 if (!FTP_SendType(lpwfs, dwType))
1937 goto lend;
1939 if (!FTP_SendPort(lpwfs))
1940 goto lend;
1942 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
1943 goto lend;
1945 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1946 MAX_REPLY_LEN, 0, 0, 0);
1947 if (nResCode)
1949 if (nResCode == 125 || nResCode == 150)
1951 /* Parse size of data to be retrieved */
1952 INT i, sizepos = -1;
1953 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
1954 for (i = strlen(lpszResponseBuffer) - 1; i >= 0; i--)
1956 if ('(' == lpszResponseBuffer[i])
1958 sizepos = i;
1959 break;
1963 if (sizepos >= 0)
1965 nResult = atol(&lpszResponseBuffer[sizepos+1]);
1966 TRACE("Waiting to receive %ld bytes\n", nResult);
1971 lend:
1972 if (0 == nResult && INVALID_SOCKET != lpwfs->lstnSocket)
1974 close(lpwfs->lstnSocket);
1975 lpwfs->lstnSocket = INVALID_SOCKET;
1978 return nResult;
1982 /***********************************************************************
1983 * FTP_RetrieveData (internal)
1985 * Retrieve data from server
1987 * RETURNS
1988 * TRUE on success
1989 * FALSE on failure
1992 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
1994 DWORD nBytesWritten;
1995 DWORD nBytesReceived = 0;
1996 INT nRC = 0;
1997 CHAR *lpszBuffer;
1999 TRACE("\n");
2001 if (INVALID_HANDLE_VALUE == hFile)
2002 return FALSE;
2004 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2005 if (NULL == lpszBuffer)
2007 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2008 return FALSE;
2011 while (nBytesReceived < nBytes && nRC != SOCKET_ERROR)
2013 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2014 if (nRC != SOCKET_ERROR)
2016 /* other side closed socket. */
2017 if (nRC == 0)
2018 goto recv_end;
2019 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2020 nBytesReceived += nRC;
2023 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
2024 nBytesReceived * 100 / nBytes);
2027 TRACE("Data transfer complete\n");
2028 if (NULL != lpszBuffer)
2029 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2031 recv_end:
2032 return (nRC != SOCKET_ERROR);
2036 /***********************************************************************
2037 * FTP_CloseSessionHandle (internal)
2039 * Deallocate session handle
2041 * RETURNS
2042 * TRUE on success
2043 * FALSE on failure
2046 BOOL FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs)
2048 if (INVALID_SOCKET != lpwfs->sndSocket)
2049 close(lpwfs->sndSocket);
2051 if (INVALID_SOCKET != lpwfs->lstnSocket)
2052 close(lpwfs->lstnSocket);
2054 if (lpwfs->lpszPassword)
2055 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2057 if (lpwfs->lpszUserName)
2058 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2060 HeapFree(GetProcessHeap(), 0, lpwfs);
2062 return TRUE;
2066 /***********************************************************************
2067 * FTP_CloseSessionHandle (internal)
2069 * Deallocate session handle
2071 * RETURNS
2072 * TRUE on success
2073 * FALSE on failure
2076 BOOL FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn)
2078 INT i;
2080 TRACE("\n");
2082 for (i = 0; i < lpwfn->size; i++)
2084 if (NULL != lpwfn->lpafp[i].lpszName)
2085 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2088 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2089 HeapFree(GetProcessHeap(), 0, lpwfn);
2091 return TRUE;
2095 /***********************************************************************
2096 * FTP_ReceiveFileList (internal)
2098 * Read file list from server
2100 * RETURNS
2101 * Handle to file list on success
2102 * NULL on failure
2105 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
2106 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext)
2108 DWORD dwSize = 0;
2109 LPFILEPROPERTIESA lpafp = NULL;
2110 LPWININETFINDNEXTA lpwfn = NULL;
2112 TRACE("\n");
2114 if (FTP_ParseDirectory(lpwfs, nSocket, &lpafp, &dwSize))
2116 FTP_ConvertFileProp(lpafp, lpFindFileData);
2118 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTA));
2119 if (NULL != lpwfn)
2121 lpwfn->hdr.htype = WH_HFINDNEXT;
2122 lpwfn->hdr.lpwhparent = (LPWININETHANDLEHEADER)lpwfs;
2123 lpwfn->hdr.dwContext = dwContext;
2124 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2125 lpwfn->size = dwSize;
2126 lpwfn->lpafp = lpafp;
2130 TRACE("Matched %ld files\n", dwSize);
2131 return (HINTERNET)lpwfn;
2135 /***********************************************************************
2136 * FTP_ConvertFileProp (internal)
2138 * Converts FILEPROPERTIESA struct to WIN32_FIND_DATAA
2140 * RETURNS
2141 * TRUE on success
2142 * FALSE on failure
2145 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESA lpafp, LPWIN32_FIND_DATAA lpFindFileData)
2147 BOOL bSuccess = FALSE;
2149 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2151 if (lpafp)
2153 DWORD access = mktime(&lpafp->tmLastModified);
2155 /* Not all fields are filled in */
2156 lpFindFileData->ftLastAccessTime.dwHighDateTime = HIWORD(access);
2157 lpFindFileData->ftLastAccessTime.dwLowDateTime = LOWORD(access);
2158 lpFindFileData->nFileSizeHigh = HIWORD(lpafp->nSize);
2159 lpFindFileData->nFileSizeLow = LOWORD(lpafp->nSize);
2161 if (lpafp->bIsDirectory)
2162 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2164 if (lpafp->lpszName)
2165 strncpy(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2167 bSuccess = TRUE;
2170 return bSuccess;
2174 /***********************************************************************
2175 * FTP_ParseDirectory (internal)
2177 * Parse string of directory information
2179 * RETURNS
2180 * TRUE on success
2181 * FALSE on failure
2183 * FIXME: - This function needs serious clea-up
2184 * - We should consider both UNIX and NT list formats
2186 #define MAX_MONTH_LEN 10
2187 #define MIN_LEN_DIR_ENTRY 15
2189 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp)
2192 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2194 * For instance:
2195 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2197 CHAR* pszMinutes;
2198 CHAR* pszHour;
2199 time_t aTime;
2200 struct tm* apTM;
2201 CHAR pszMonth[MAX_MONTH_LEN];
2202 CHAR* pszMatch;
2203 BOOL bSuccess = TRUE;
2204 DWORD nBufLen = MAX_REPLY_LEN;
2205 LPFILEPROPERTIESA curFileProp = NULL;
2206 CHAR* pszLine = NULL;
2207 CHAR* pszToken = NULL;
2208 INT nTokenToSkip = 3;
2209 INT nCount = 0;
2210 INT nSeconds = 0;
2211 INT nMinutes = 0;
2212 INT nHour = 0;
2213 INT nDay = 0;
2214 INT nMonth = 0;
2215 INT nYear = 0;
2216 INT sizeFilePropArray = 20;
2217 INT indexFilePropArray = 0;
2219 TRACE("\n");
2221 /* Allocate intial file properties array */
2222 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESA)*(sizeFilePropArray));
2223 if (NULL == lpafp)
2225 bSuccess = FALSE;
2226 goto lend;
2229 while ((pszLine = INTERNET_GetNextLine(nSocket, INTERNET_GetResponseBuffer(), &nBufLen)) != NULL)
2231 if (sizeFilePropArray <= indexFilePropArray)
2233 LPFILEPROPERTIESA tmpafp;
2235 sizeFilePropArray *= 2;
2236 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
2237 sizeof(FILEPROPERTIESA)*sizeFilePropArray);
2238 if (NULL == tmpafp)
2240 bSuccess = FALSE;
2241 goto lend;
2244 *lpafp = tmpafp;
2247 curFileProp = &((*lpafp)[indexFilePropArray]);
2249 /* First Parse the permissions. */
2250 pszToken = strtok(pszLine, " \t" );
2252 /* HACK! If this is not a file listing skip the line */
2253 if (!pszToken || 10 != strlen(pszToken) || nBufLen <= MIN_LEN_DIR_ENTRY)
2255 nBufLen = MAX_REPLY_LEN;
2256 continue;
2259 FTP_ParsePermission(pszToken, curFileProp);
2261 nTokenToSkip = 3;
2262 nCount = 0;
2265 pszToken = strtok( NULL, " \t" );
2266 nCount++;
2267 } while( nCount <= nTokenToSkip );
2269 /* Store the size of the file in the param list. */
2270 TRACE("nSize-> %s\n", pszToken);
2271 if (pszToken != NULL)
2272 curFileProp->nSize = atol(pszToken);
2274 /* Parse last modified time. */
2275 nSeconds = 0;
2276 nMinutes = 0;
2277 nHour = 0;
2278 nDay = 0;
2279 nMonth = 0;
2280 nYear = 0;
2282 pszToken = strtok( NULL, " \t" );
2283 strncpy(pszMonth, pszToken, MAX_MONTH_LEN);
2284 CharUpperA(pszMonth);
2285 pszMatch = strstr(szMonths, pszMonth);
2286 if( pszMatch != NULL )
2287 nMonth = (pszMatch - szMonths) / 3;
2289 pszToken = strtok(NULL, " \t");
2290 TRACE("nDay -> %s\n", pszToken);
2291 if (pszToken != NULL)
2292 nDay = atoi(pszToken);
2294 pszToken = strtok(NULL, " \t");
2295 pszMinutes = strchr(pszToken, ':');
2296 if( pszMinutes != NULL )
2298 pszMinutes++;
2299 nMinutes = atoi(pszMinutes);
2300 pszHour = pszMinutes - 3;
2301 if (pszHour != NULL)
2302 nHour = atoi(pszHour);
2303 time(&aTime);
2304 apTM = localtime( &aTime );
2305 nYear = apTM->tm_year;
2307 else
2309 nYear = atoi(pszToken);
2310 nYear -= 1900;
2311 nHour = 12;
2314 curFileProp->tmLastModified.tm_sec = nSeconds;
2315 curFileProp->tmLastModified.tm_min = nMinutes;
2316 curFileProp->tmLastModified.tm_hour = nHour;
2317 curFileProp->tmLastModified.tm_mday = nDay;
2318 curFileProp->tmLastModified.tm_mon = nMonth;
2319 curFileProp->tmLastModified.tm_year = nYear;
2321 pszToken = strtok(NULL, " \t");
2322 if(pszToken != NULL)
2324 curFileProp->lpszName = FTP_strdup(pszToken);
2325 TRACE(": %s\n", curFileProp->lpszName);
2328 nBufLen = MAX_REPLY_LEN;
2329 indexFilePropArray++;
2332 if (bSuccess && indexFilePropArray)
2334 if (indexFilePropArray < sizeFilePropArray - 1)
2336 LPFILEPROPERTIESA tmpafp;
2338 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
2339 sizeof(FILEPROPERTIESA)*indexFilePropArray);
2340 if (NULL == tmpafp)
2341 *lpafp = tmpafp;
2343 *dwfp = indexFilePropArray;
2345 else
2347 HeapFree(GetProcessHeap(), 0, *lpafp);
2348 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2349 bSuccess = FALSE;
2352 lend:
2353 return bSuccess;
2357 /***********************************************************************
2358 * FTP_ParsePermission (internal)
2360 * Parse permission string of directory information
2362 * RETURNS
2363 * TRUE on success
2364 * FALSE on failure
2367 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp)
2369 BOOL bSuccess = TRUE;
2370 unsigned short nPermission = 0;
2371 INT nPos = 1;
2372 INT nLast = 9;
2374 TRACE("\n");
2375 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
2377 bSuccess = FALSE;
2378 return bSuccess;
2381 lpfp->bIsDirectory = (*lpszPermission == 'd');
2384 switch (nPos)
2386 case 1:
2387 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
2388 break;
2389 case 2:
2390 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
2391 break;
2392 case 3:
2393 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
2394 break;
2395 case 4:
2396 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
2397 break;
2398 case 5:
2399 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
2400 break;
2401 case 6:
2402 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
2403 break;
2404 case 7:
2405 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
2406 break;
2407 case 8:
2408 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
2409 break;
2410 case 9:
2411 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
2412 break;
2414 nPos++;
2415 }while (nPos <= nLast);
2417 lpfp->permissions = nPermission;
2418 return bSuccess;
2422 /***********************************************************************
2423 * FTP_SetResponseError (internal)
2425 * Set the appropriate error code for a given response from the server
2427 * RETURNS
2430 DWORD FTP_SetResponseError(DWORD dwResponse)
2432 DWORD dwCode = 0;
2434 switch(dwResponse)
2436 case 421: /* Service not available - Server may be shutting down. */
2437 dwCode = ERROR_INTERNET_TIMEOUT;
2438 break;
2440 case 425: /* Cannot open data connection. */
2441 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
2442 break;
2444 case 426: /* Connection closed, transer aborted. */
2445 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
2446 break;
2448 case 500: /* Syntax error. Command unrecognized. */
2449 case 501: /* Syntax error. Error in parameters or arguments. */
2450 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
2451 break;
2453 case 530: /* Not logged in. Login incorrect. */
2454 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
2455 break;
2457 case 550: /* File action not taken. File not found or no access. */
2458 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
2459 break;
2461 case 450: /* File action not taken. File may be busy. */
2462 case 451: /* Action aborted. Server error. */
2463 case 452: /* Action not taken. Insufficient storage space on server. */
2464 case 502: /* Command not implemented. */
2465 case 503: /* Bad sequence of command. */
2466 case 504: /* Command not implemented for that parameter. */
2467 case 532: /* Need account for storing files */
2468 case 551: /* Requested action aborted. Page type unknown */
2469 case 552: /* Action aborted. Exceeded storage allocation */
2470 case 553: /* Action not taken. File name not allowed. */
2472 default:
2473 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
2474 break;
2477 INTERNET_SetLastError(dwCode);
2478 return dwCode;