Send the local ip address with the PORT command and not that of the
[wine.git] / dlls / wininet / ftp.c
blob56aefb33e7cf2d00cd8670912d30301665656a1f
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 #include <netdb.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/types.h>
18 #ifdef HAVE_SYS_SOCKET_H
19 # include <sys/socket.h>
20 #endif
21 #include <sys/stat.h>
22 #include <unistd.h>
23 #include <netinet/ip.h>
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "wininet.h"
29 #include "winerror.h"
30 #include "winsock.h"
31 #include "heap.h"
33 #include "debugtools.h"
34 #include "internet.h"
36 DEFAULT_DEBUG_CHANNEL(wininet);
38 #define NOACCOUNT "noaccount"
39 #define DATA_PACKET_SIZE 0x2000
40 #define szCRLF "\r\n"
41 #define MAX_BACKLOG 5
43 typedef enum {
44 /* FTP commands with arguments. */
45 FTP_CMD_ACCT,
46 FTP_CMD_CWD,
47 FTP_CMD_DELE,
48 FTP_CMD_MKD,
49 FTP_CMD_PASS,
50 FTP_CMD_PORT,
51 FTP_CMD_RETR,
52 FTP_CMD_RMD,
53 FTP_CMD_RNFR,
54 FTP_CMD_RNTO,
55 FTP_CMD_STOR,
56 FTP_CMD_TYPE,
57 FTP_CMD_USER,
59 /* FTP commands without arguments. */
60 FTP_CMD_ABOR,
61 FTP_CMD_LIST,
62 FTP_CMD_NLST,
63 FTP_CMD_PWD,
64 FTP_CMD_QUIT,
65 } FTP_COMMAND;
67 static const CHAR *szFtpCommands[] = {
68 "ACCT",
69 "CWD",
70 "DELE",
71 "MKD",
72 "PASS",
73 "PORT",
74 "RETR",
75 "RMD",
76 "RNFR",
77 "RNTO",
78 "STOR",
79 "TYPE",
80 "USER",
81 "ABOR",
82 "LIST",
83 "NLST",
84 "PWD",
85 "QUIT",
88 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
90 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
91 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
92 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
93 BOOL FTP_InitDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket);
94 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile);
95 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
96 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
97 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
98 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile);
99 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs);
100 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs);
101 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs);
102 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs);
103 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType);
104 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs);
105 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp);
106 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp);
107 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
108 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext);
109 DWORD FTP_SetResponseError(DWORD dwResponse);
111 /***********************************************************************
112 * FtpPutFileA (WININET.43)
114 * Uploads a file to the FTP server
116 * RETURNS
117 * TRUE on success
118 * FALSE on failure
121 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
122 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
124 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
125 LPWININETAPPINFOA hIC = NULL;
127 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
129 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
130 return FALSE;
133 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
134 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
136 WORKREQUEST workRequest;
138 workRequest.asyncall = FTPPUTFILEA;
139 workRequest.HFTPSESSION = (DWORD)hConnect;
140 workRequest.LPSZLOCALFILE = (DWORD)HEAP_strdupA(GetProcessHeap(),0,lpszLocalFile);
141 workRequest.LPSZNEWREMOTEFILE = (DWORD)HEAP_strdupA(GetProcessHeap(),0,lpszNewRemoteFile);
142 workRequest.DWFLAGS = dwFlags;
143 workRequest.DWCONTEXT = dwContext;
145 return INTERNET_AsyncCall(&workRequest);
147 else
149 return FTP_FtpPutFileA(hConnect, lpszLocalFile,
150 lpszNewRemoteFile, dwFlags, dwContext);
154 /***********************************************************************
155 * FTP_FtpPutFileA (Internal)
157 * Uploads a file to the FTP server
159 * RETURNS
160 * TRUE on success
161 * FALSE on failure
164 BOOL WINAPI FTP_FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
165 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
167 HANDLE hFile = (HANDLE)NULL;
168 BOOL bSuccess = FALSE;
169 LPWININETAPPINFOA hIC = NULL;
170 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
171 INT nResCode;
173 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", lpszLocalFile, lpszNewRemoteFile);
174 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
176 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
177 return FALSE;
180 /* Clear any error information */
181 INTERNET_SetLastError(0);
183 /* Open file to be uploaded */
184 if (INVALID_HANDLE_VALUE ==
185 (hFile = CreateFileA(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
187 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND);
188 goto lend;
191 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
192 if (hIC->lpfnStatusCB)
193 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
195 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
197 INT nDataSocket;
199 /* Accept connection from ftp server */
200 if (FTP_InitDataSocket(lpwfs, &nDataSocket))
202 FTP_SendData(lpwfs, nDataSocket, hFile);
203 close(nDataSocket);
204 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
205 MAX_REPLY_LEN,0, 0, 0);
206 if (nResCode)
208 if (nResCode == 226)
209 bSuccess = TRUE;
210 else
211 FTP_SetResponseError(nResCode);
216 lend:
217 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
219 INTERNET_ASYNC_RESULT iar;
221 iar.dwResult = (DWORD)bSuccess;
222 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
223 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
224 &iar, sizeof(INTERNET_ASYNC_RESULT));
227 if (hFile)
228 CloseHandle(hFile);
230 return bSuccess;
234 /***********************************************************************
235 * FtpSetCurrentDirectoryA (WININET.49)
237 * Change the working directory on the FTP server
239 * RETURNS
240 * TRUE on success
241 * FALSE on failure
244 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
246 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
247 LPWININETAPPINFOA hIC = NULL;
249 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
251 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
252 return FALSE;
255 TRACE("lpszDirectory(%s)\n", lpszDirectory);
257 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
258 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
260 WORKREQUEST workRequest;
262 workRequest.asyncall = FTPSETCURRENTDIRECTORYA;
263 workRequest.HFTPSESSION = (DWORD)hConnect;
264 workRequest.LPSZDIRECTORY = (DWORD)HEAP_strdupA(GetProcessHeap(),0,lpszDirectory);
266 return INTERNET_AsyncCall(&workRequest);
268 else
270 return FTP_FtpSetCurrentDirectoryA(hConnect, lpszDirectory);
275 /***********************************************************************
276 * FTP_FtpSetCurrentDirectoryA (Internal)
278 * Change the working directory on the FTP server
280 * RETURNS
281 * TRUE on success
282 * FALSE on failure
285 BOOL WINAPI FTP_FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
287 INT nResCode;
288 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
289 LPWININETAPPINFOA hIC = NULL;
290 DWORD bSuccess = FALSE;
292 TRACE("lpszDirectory(%s)\n", lpszDirectory);
294 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
296 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
297 return FALSE;
300 /* Clear any error information */
301 INTERNET_SetLastError(0);
303 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
304 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
305 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
306 goto lend;
308 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
309 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
311 if (nResCode)
313 if (nResCode == 250)
314 bSuccess = TRUE;
315 else
316 FTP_SetResponseError(nResCode);
319 lend:
320 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
322 INTERNET_ASYNC_RESULT iar;
324 iar.dwResult = (DWORD)bSuccess;
325 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
326 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
327 &iar, sizeof(INTERNET_ASYNC_RESULT));
329 return bSuccess;
333 /***********************************************************************
334 * FtpCreateDirectoryA (WININET.31)
336 * Create new directory on the FTP server
338 * RETURNS
339 * TRUE on success
340 * FALSE on failure
343 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
345 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
346 LPWININETAPPINFOA hIC = NULL;
348 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
350 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
351 return FALSE;
354 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
355 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
357 WORKREQUEST workRequest;
359 workRequest.asyncall = FTPCREATEDIRECTORYA;
360 workRequest.HFTPSESSION = (DWORD)hConnect;
361 workRequest.LPSZDIRECTORY = (DWORD)HEAP_strdupA(GetProcessHeap(),0,lpszDirectory);
363 return INTERNET_AsyncCall(&workRequest);
365 else
367 return FTP_FtpCreateDirectoryA(hConnect, lpszDirectory);
372 /***********************************************************************
373 * FTP_FtpCreateDirectoryA (Internal)
375 * Create new directory on the FTP server
377 * RETURNS
378 * TRUE on success
379 * FALSE on failure
382 BOOL WINAPI FTP_FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
384 INT nResCode;
385 BOOL bSuccess = FALSE;
386 LPWININETAPPINFOA hIC = NULL;
387 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
389 TRACE("\n");
390 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
392 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
393 return FALSE;
396 /* Clear any error information */
397 INTERNET_SetLastError(0);
399 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
400 goto lend;
402 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
403 MAX_REPLY_LEN, 0, 0, 0);
404 if (nResCode)
406 if (nResCode == 257)
407 bSuccess = TRUE;
408 else
409 FTP_SetResponseError(nResCode);
412 lend:
413 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
414 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
416 INTERNET_ASYNC_RESULT iar;
418 iar.dwResult = (DWORD)bSuccess;
419 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
420 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
421 &iar, sizeof(INTERNET_ASYNC_RESULT));
424 return bSuccess;
428 /***********************************************************************
429 * FtpFindFirstFileA (WININET.35)
431 * Search the specified directory
433 * RETURNS
434 * HINTERNET on success
435 * NULL on failure
438 INTERNETAPI HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
439 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
441 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
442 LPWININETAPPINFOA hIC = NULL;
444 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
446 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
447 return FALSE;
450 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
451 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
453 WORKREQUEST workRequest;
455 workRequest.asyncall = FTPFINDFIRSTFILEA;
456 workRequest.HFTPSESSION = (DWORD)hConnect;
457 workRequest.LPSZSEARCHFILE = (DWORD)HEAP_strdupA(GetProcessHeap(),0,lpszSearchFile);
458 workRequest.LPFINDFILEDATA = (DWORD)lpFindFileData;
459 workRequest.DWFLAGS = dwFlags;
460 workRequest.DWCONTEXT= dwContext;
462 INTERNET_AsyncCall(&workRequest);
463 return NULL;
465 else
467 return FTP_FtpFindFirstFileA(hConnect, lpszSearchFile, lpFindFileData,
468 dwFlags, dwContext);
473 /***********************************************************************
474 * FTP_FtpFindFirstFileA (Internal)
476 * Search the specified directory
478 * RETURNS
479 * HINTERNET on success
480 * NULL on failure
483 INTERNETAPI HINTERNET WINAPI FTP_FtpFindFirstFileA(HINTERNET hConnect,
484 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
486 INT nResCode;
487 LPWININETAPPINFOA hIC = NULL;
488 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
489 LPWININETFINDNEXTA hFindNext = NULL;
491 TRACE("\n");
493 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
495 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
496 return FALSE;
499 /* Clear any error information */
500 INTERNET_SetLastError(0);
502 if (!FTP_InitListenSocket(lpwfs))
503 goto lend;
505 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
506 goto lend;
508 if (!FTP_SendPort(lpwfs))
509 goto lend;
511 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
512 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, lpszSearchFile,
513 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
514 goto lend;
516 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
517 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
518 if (nResCode)
520 if (nResCode == 125 || nResCode == 150)
522 INT nDataSocket;
524 if (FTP_InitDataSocket(lpwfs, &nDataSocket))
526 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpFindFileData, dwContext);
528 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
529 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
530 if (nResCode != 226 && nResCode != 250)
531 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
533 close(nDataSocket);
536 else
537 FTP_SetResponseError(nResCode);
540 lend:
541 if (lpwfs->lstnSocket != INVALID_SOCKET)
542 close(lpwfs->lstnSocket);
544 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
546 INTERNET_ASYNC_RESULT iar;
548 if (hFindNext)
550 iar.dwResult = (DWORD)hFindNext;
551 iar.dwError = ERROR_SUCCESS;
552 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
553 &iar, sizeof(INTERNET_ASYNC_RESULT));
556 iar.dwResult = (DWORD)hFindNext;
557 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
558 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
559 &iar, sizeof(INTERNET_ASYNC_RESULT));
562 return (HINTERNET)hFindNext;
566 /***********************************************************************
567 * FtpGetCurrentDirectoryA (WININET.37)
569 * Retrieves the current directory
571 * RETURNS
572 * TRUE on success
573 * FALSE on failure
576 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
577 LPDWORD lpdwCurrentDirectory)
579 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
580 LPWININETAPPINFOA hIC = NULL;
582 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
584 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
586 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
587 return FALSE;
590 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
591 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
593 WORKREQUEST workRequest;
595 workRequest.asyncall = FTPGETCURRENTDIRECTORYA;
596 workRequest.HFTPSESSION = (DWORD)hFtpSession;
597 workRequest.LPSZDIRECTORY = (DWORD)lpszCurrentDirectory;
598 workRequest.LPDWDIRECTORY = (DWORD)lpdwCurrentDirectory;
600 return INTERNET_AsyncCall(&workRequest);
602 else
604 return FTP_FtpGetCurrentDirectoryA(hFtpSession, lpszCurrentDirectory,
605 lpdwCurrentDirectory);
610 /***********************************************************************
611 * FTP_FtpGetCurrentDirectoryA (Internal)
613 * Retrieves the current directory
615 * RETURNS
616 * TRUE on success
617 * FALSE on failure
620 BOOL WINAPI FTP_FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
621 LPDWORD lpdwCurrentDirectory)
623 INT nResCode;
624 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
625 LPWININETAPPINFOA hIC = NULL;
626 DWORD bSuccess = FALSE;
628 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
630 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
632 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
633 return FALSE;
636 /* Clear any error information */
637 INTERNET_SetLastError(0);
639 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
641 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
642 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
643 hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext))
644 goto lend;
646 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
647 MAX_REPLY_LEN, hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext);
648 if (nResCode)
650 if (nResCode == 257) /* Extract directory name */
652 INT firstpos, lastpos, len;
653 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
655 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
657 if ('"' == lpszResponseBuffer[lastpos])
659 if (!firstpos)
660 firstpos = lastpos;
661 else
662 break;
666 len = lastpos - firstpos - 1;
667 strncpy(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1],
668 len < *lpdwCurrentDirectory ? len : *lpdwCurrentDirectory);
669 *lpdwCurrentDirectory = len;
670 bSuccess = TRUE;
672 else
673 FTP_SetResponseError(nResCode);
676 lend:
677 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
679 INTERNET_ASYNC_RESULT iar;
681 iar.dwResult = (DWORD)bSuccess;
682 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
683 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
684 &iar, sizeof(INTERNET_ASYNC_RESULT));
687 return (DWORD) bSuccess;
690 /***********************************************************************
691 * FtpOpenFileA (WININET.41)
693 * Open a remote file for writing or reading
695 * RETURNS
696 * HINTERNET handle on success
697 * NULL on failure
700 INTERNETAPI HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
701 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
702 DWORD dwContext)
704 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
705 LPWININETAPPINFOA hIC = NULL;
707 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
709 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
710 return FALSE;
713 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
714 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
716 WORKREQUEST workRequest;
718 workRequest.asyncall = FTPOPENFILEA;
719 workRequest.HFTPSESSION = (DWORD)hFtpSession;
720 workRequest.LPSZFILENAME = (DWORD)HEAP_strdupA(GetProcessHeap(),0,lpszFileName);
721 workRequest.FDWACCESS = fdwAccess;
722 workRequest.DWFLAGS = dwFlags;
723 workRequest.DWCONTEXT = dwContext;
725 INTERNET_AsyncCall(&workRequest);
726 return NULL;
728 else
730 return FTP_FtpOpenFileA(hFtpSession, lpszFileName, fdwAccess, dwFlags, dwContext);
735 /***********************************************************************
736 * FTP_FtpOpenFileA (Internal)
738 * Open a remote file for writing or reading
740 * RETURNS
741 * HINTERNET handle on success
742 * NULL on failure
745 HINTERNET FTP_FtpOpenFileA(HINTERNET hFtpSession,
746 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
747 DWORD dwContext)
749 INT nDataSocket;
750 BOOL bSuccess = FALSE;
751 LPWININETFILE hFile = NULL;
752 LPWININETAPPINFOA hIC = NULL;
753 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
755 TRACE("\n");
757 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
759 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
760 return FALSE;
763 /* Clear any error information */
764 INTERNET_SetLastError(0);
766 if (GENERIC_READ == fdwAccess)
768 /* Set up socket to retrieve data */
769 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
771 else if (GENERIC_WRITE == fdwAccess)
773 /* Set up socket to send data */
774 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
777 /* Accept connection from server */
778 if (bSuccess && FTP_InitDataSocket(lpwfs, &nDataSocket))
780 hFile = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE));
781 hFile->hdr.htype = WH_HFILE;
782 hFile->hdr.dwFlags = dwFlags;
783 hFile->hdr.dwContext = dwContext;
784 hFile->hdr.lpwhparent = hFtpSession;
785 hFile->nDataSocket = nDataSocket;
788 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
789 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
791 INTERNET_ASYNC_RESULT iar;
793 if (hFile)
795 iar.dwResult = (DWORD)hFile;
796 iar.dwError = ERROR_SUCCESS;
797 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
798 &iar, sizeof(INTERNET_ASYNC_RESULT));
801 iar.dwResult = (DWORD)bSuccess;
802 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
803 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
804 &iar, sizeof(INTERNET_ASYNC_RESULT));
807 return (HINTERNET)hFile;
811 /***********************************************************************
812 * FtpGetFileA (WININET.39)
814 * Retrieve file from the FTP server
816 * RETURNS
817 * TRUE on success
818 * FALSE on failure
821 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
822 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
823 DWORD dwContext)
825 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet;
826 LPWININETAPPINFOA hIC = NULL;
828 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
830 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
831 return FALSE;
834 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
835 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
837 WORKREQUEST workRequest;
839 workRequest.asyncall = FTPGETFILEA;
840 workRequest.HFTPSESSION = (DWORD)hInternet;
841 workRequest.LPSZREMOTEFILE = (DWORD)HEAP_strdupA(GetProcessHeap(),0,lpszRemoteFile);
842 workRequest.LPSZNEWFILE = (DWORD)HEAP_strdupA(GetProcessHeap(),0,lpszNewFile);
843 workRequest.DWLOCALFLAGSATTRIBUTE = dwLocalFlagsAttribute;
844 workRequest.FFAILIFEXISTS = (DWORD)fFailIfExists;
845 workRequest.DWFLAGS = dwInternetFlags;
846 workRequest.DWCONTEXT = dwContext;
848 return INTERNET_AsyncCall(&workRequest);
850 else
852 return FTP_FtpGetFileA(hInternet, lpszRemoteFile, lpszNewFile,
853 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
858 /***********************************************************************
859 * FTP_FtpGetFileA (Internal)
861 * Retrieve file from the FTP server
863 * RETURNS
864 * TRUE on success
865 * FALSE on failure
868 BOOL WINAPI FTP_FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
869 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
870 DWORD dwContext)
872 DWORD nBytes;
873 BOOL bSuccess = FALSE;
874 HANDLE hFile;
875 LPWININETAPPINFOA hIC = NULL;
876 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet;
878 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", lpszRemoteFile, lpszNewFile);
879 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
881 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
882 return FALSE;
885 /* Clear any error information */
886 INTERNET_SetLastError(0);
888 /* Ensure we can write to lpszNewfile by opening it */
889 hFile = CreateFileA(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
890 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
891 if (INVALID_HANDLE_VALUE == hFile)
892 goto lend;
894 /* Set up socket to retrieve data */
895 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
897 if (nBytes > 0)
899 INT nDataSocket;
901 /* Accept connection from ftp server */
902 if (FTP_InitDataSocket(lpwfs, &nDataSocket))
904 INT nResCode;
906 /* Receive data */
907 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
908 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
909 MAX_REPLY_LEN, 0, 0, 0);
910 if (nResCode)
912 if (nResCode == 226)
913 bSuccess = TRUE;
914 else
915 FTP_SetResponseError(nResCode);
917 close(nDataSocket);
921 lend:
922 if (hFile)
923 CloseHandle(hFile);
925 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
926 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
928 INTERNET_ASYNC_RESULT iar;
930 iar.dwResult = (DWORD)bSuccess;
931 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
932 hIC->lpfnStatusCB(hInternet, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
933 &iar, sizeof(INTERNET_ASYNC_RESULT));
936 return bSuccess;
940 /***********************************************************************
941 * FtpDeleteFileA (WININET.33)
943 * Delete a file on the ftp server
945 * RETURNS
946 * TRUE on success
947 * FALSE on failure
950 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
952 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
953 LPWININETAPPINFOA hIC = NULL;
955 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
957 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
958 return FALSE;
961 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
962 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
964 WORKREQUEST workRequest;
966 workRequest.asyncall = FTPRENAMEFILEA;
967 workRequest.HFTPSESSION = (DWORD)hFtpSession;
968 workRequest.LPSZFILENAME = (DWORD)HEAP_strdupA(GetProcessHeap(),0,lpszFileName);
970 return INTERNET_AsyncCall(&workRequest);
972 else
974 return FTP_FtpDeleteFileA(hFtpSession, lpszFileName);
979 /***********************************************************************
980 * FTP_FtpDeleteFileA (Internal)
982 * Delete a file on the ftp server
984 * RETURNS
985 * TRUE on success
986 * FALSE on failure
989 BOOL FTP_FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
991 INT nResCode;
992 BOOL bSuccess = FALSE;
993 LPWININETAPPINFOA hIC = NULL;
994 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
996 TRACE("0x%08lx\n", (ULONG) hFtpSession);
997 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
999 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1000 return FALSE;
1003 /* Clear any error information */
1004 INTERNET_SetLastError(0);
1006 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1007 goto lend;
1009 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1010 MAX_REPLY_LEN, 0, 0, 0);
1011 if (nResCode)
1013 if (nResCode == 250)
1014 bSuccess = TRUE;
1015 else
1016 FTP_SetResponseError(nResCode);
1018 lend:
1019 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1020 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1022 INTERNET_ASYNC_RESULT iar;
1024 iar.dwResult = (DWORD)bSuccess;
1025 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1026 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1027 &iar, sizeof(INTERNET_ASYNC_RESULT));
1030 return bSuccess;
1034 /***********************************************************************
1035 * FtpRemoveDirectoryA (WININET.45)
1037 * Remove a directory on the ftp server
1039 * RETURNS
1040 * TRUE on success
1041 * FALSE on failure
1044 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1046 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1047 LPWININETAPPINFOA hIC = NULL;
1049 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1051 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1052 return FALSE;
1055 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1056 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1058 WORKREQUEST workRequest;
1060 workRequest.asyncall = FTPREMOVEDIRECTORYA;
1061 workRequest.HFTPSESSION = (DWORD)hFtpSession;
1062 workRequest.LPSZDIRECTORY = (DWORD)HEAP_strdupA(GetProcessHeap(),0,lpszDirectory);
1064 return INTERNET_AsyncCall(&workRequest);
1066 else
1068 return FTP_FtpRemoveDirectoryA(hFtpSession, lpszDirectory);
1073 /***********************************************************************
1074 * FTP_FtpRemoveDirectoryA (Internal)
1076 * Remove a directory on the ftp server
1078 * RETURNS
1079 * TRUE on success
1080 * FALSE on failure
1083 BOOL FTP_FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1085 INT nResCode;
1086 BOOL bSuccess = FALSE;
1087 LPWININETAPPINFOA hIC = NULL;
1088 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1090 TRACE("\n");
1091 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1093 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1094 return FALSE;
1097 /* Clear any error information */
1098 INTERNET_SetLastError(0);
1100 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1101 goto lend;
1103 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1104 MAX_REPLY_LEN, 0, 0, 0);
1105 if (nResCode)
1107 if (nResCode == 250)
1108 bSuccess = TRUE;
1109 else
1110 FTP_SetResponseError(nResCode);
1113 lend:
1114 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1115 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1117 INTERNET_ASYNC_RESULT iar;
1119 iar.dwResult = (DWORD)bSuccess;
1120 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1121 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1122 &iar, sizeof(INTERNET_ASYNC_RESULT));
1125 return bSuccess;
1129 /***********************************************************************
1130 * FtpRenameFileA (WININET.47)
1132 * Rename a file on the ftp server
1134 * RETURNS
1135 * TRUE on success
1136 * FALSE on failure
1139 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1141 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1142 LPWININETAPPINFOA hIC = NULL;
1144 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1146 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1147 return FALSE;
1150 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1151 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1153 WORKREQUEST workRequest;
1155 workRequest.asyncall = FTPRENAMEFILEA;
1156 workRequest.HFTPSESSION = (DWORD)hFtpSession;
1157 workRequest.LPSZSRCFILE = (DWORD)HEAP_strdupA(GetProcessHeap(),0,lpszSrc);
1158 workRequest.LPSZDESTFILE = (DWORD)HEAP_strdupA(GetProcessHeap(),0,lpszDest);
1160 return INTERNET_AsyncCall(&workRequest);
1162 else
1164 return FTP_FtpRenameFileA(hFtpSession, lpszSrc, lpszDest);
1168 /***********************************************************************
1169 * FTP_FtpRenameFileA (Internal)
1171 * Rename a file on the ftp server
1173 * RETURNS
1174 * TRUE on success
1175 * FALSE on failure
1178 BOOL FTP_FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1180 INT nResCode;
1181 BOOL bSuccess = FALSE;
1182 LPWININETAPPINFOA hIC = NULL;
1183 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1185 TRACE("\n");
1186 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1188 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1189 return FALSE;
1192 /* Clear any error information */
1193 INTERNET_SetLastError(0);
1195 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1196 goto lend;
1198 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1199 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1200 if (nResCode == 350)
1202 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1203 goto lend;
1205 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1206 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1209 if (nResCode == 250)
1210 bSuccess = TRUE;
1211 else
1212 FTP_SetResponseError(nResCode);
1214 lend:
1215 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1216 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1218 INTERNET_ASYNC_RESULT iar;
1220 iar.dwResult = (DWORD)bSuccess;
1221 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1222 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1223 &iar, sizeof(INTERNET_ASYNC_RESULT));
1226 return bSuccess;
1230 /***********************************************************************
1231 * FTP_Connect (internal)
1233 * Connect to a ftp server
1235 * RETURNS
1236 * HINTERNET a session handle on success
1237 * NULL on failure
1241 HINTERNET FTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
1242 INTERNET_PORT nServerPort, LPCSTR lpszUserName,
1243 LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
1245 struct sockaddr_in socketAddr;
1246 struct hostent *phe = NULL;
1247 INT nsocket = INVALID_SOCKET, sock_namelen;
1248 LPWININETAPPINFOA hIC = NULL;
1249 BOOL bSuccess = FALSE;
1250 LPWININETFTPSESSIONA lpwfs = NULL;
1252 TRACE("0x%08lx Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1253 (ULONG) hInternet, lpszServerName,
1254 nServerPort, lpszUserName, lpszPassword);
1256 if (((LPWININETHANDLEHEADER)hInternet)->htype != WH_HINIT)
1257 goto lerror;
1259 hIC = (LPWININETAPPINFOA) hInternet;
1261 if (NULL == lpszUserName && NULL != lpszPassword)
1263 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_USER_NAME);
1264 goto lerror;
1267 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1268 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1270 if (hIC->lpfnStatusCB)
1271 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1272 (LPSTR) lpszServerName, strlen(lpszServerName));
1274 if (!GetAddress(lpszServerName, nServerPort, &phe, &socketAddr))
1276 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1277 goto lerror;
1280 if (hIC->lpfnStatusCB)
1281 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1282 (LPSTR) lpszServerName, strlen(lpszServerName));
1284 if (INVALID_SOCKET == (nsocket = socket(AF_INET,SOCK_STREAM,0)))
1286 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1287 goto lerror;
1290 if (hIC->lpfnStatusCB)
1291 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1292 &socketAddr, sizeof(struct sockaddr_in));
1294 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1296 ERR("Unable to connect (%s)\n", strerror(errno));
1297 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1299 else
1301 TRACE("Connected to server\n");
1302 if (hIC->lpfnStatusCB)
1303 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1304 &socketAddr, sizeof(struct sockaddr_in));
1306 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONA));
1307 if (NULL == lpwfs)
1309 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1310 goto lerror;
1313 lpwfs->hdr.htype = WH_HFTPSESSION;
1314 lpwfs->hdr.dwFlags = dwFlags;
1315 lpwfs->hdr.dwContext = dwContext;
1316 lpwfs->hdr.lpwhparent = (LPWININETHANDLEHEADER)hInternet;
1317 lpwfs->sndSocket = nsocket;
1318 sock_namelen = sizeof(lpwfs->socketAddress);
1319 getsockname(nsocket, &lpwfs->socketAddress, &sock_namelen);
1320 lpwfs->phostent = phe;
1322 if (NULL == lpszUserName)
1324 lpwfs->lpszUserName = HEAP_strdupA(GetProcessHeap(),0,"anonymous");
1325 lpwfs->lpszPassword = HEAP_strdupA(GetProcessHeap(),0,"user@server");
1327 else
1329 lpwfs->lpszUserName = HEAP_strdupA(GetProcessHeap(),0,lpszUserName);
1330 lpwfs->lpszPassword = HEAP_strdupA(GetProcessHeap(),0,lpszPassword);
1333 if (FTP_ConnectToHost(lpwfs))
1335 if (hIC->lpfnStatusCB)
1337 INTERNET_ASYNC_RESULT iar;
1339 iar.dwResult = (DWORD)lpwfs;
1340 iar.dwError = ERROR_SUCCESS;
1342 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_HANDLE_CREATED,
1343 &iar, sizeof(INTERNET_ASYNC_RESULT));
1345 TRACE("Successfully logged into server\n");
1346 bSuccess = TRUE;
1350 lerror:
1351 if (!bSuccess && INVALID_SOCKET != nsocket)
1352 close(nsocket);
1354 if (!bSuccess && lpwfs)
1356 HeapFree(GetProcessHeap(), 0, lpwfs);
1357 lpwfs = NULL;
1360 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1362 INTERNET_ASYNC_RESULT iar;
1364 iar.dwResult = (DWORD)lpwfs;
1365 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1366 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1367 &iar, sizeof(INTERNET_ASYNC_RESULT));
1370 return (HINTERNET) lpwfs;
1374 /***********************************************************************
1375 * FTP_ConnectHost (internal)
1377 * Connect to a ftp server
1379 * RETURNS
1380 * TRUE on success
1381 * NULL on failure
1384 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs)
1386 INT nResCode;
1387 BOOL bSuccess = FALSE;
1389 TRACE("\n");
1390 FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1392 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1393 goto lend;
1395 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1396 MAX_REPLY_LEN, 0, 0, 0);
1397 if (nResCode)
1399 /* Login successful... */
1400 if (nResCode == 230)
1401 bSuccess = TRUE;
1402 /* User name okay, need password... */
1403 else if (nResCode == 331)
1404 bSuccess = FTP_SendPassword(lpwfs);
1405 /* Need account for login... */
1406 else if (nResCode == 332)
1407 bSuccess = FTP_SendAccount(lpwfs);
1408 else
1409 FTP_SetResponseError(nResCode);
1412 TRACE("Returning %d\n", bSuccess);
1413 lend:
1414 return bSuccess;
1418 /***********************************************************************
1419 * FTP_SendCommand (internal)
1421 * Send command to server
1423 * RETURNS
1424 * TRUE on success
1425 * NULL on failure
1428 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1429 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1431 DWORD len;
1432 CHAR *buf;
1433 DWORD nBytesSent = 0;
1434 DWORD nRC = 0;
1435 BOOL bParamHasLen;
1437 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1439 if (lpfnStatusCB)
1440 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1442 bParamHasLen = lpszParam && strlen(lpszParam) > 0;
1443 len = (bParamHasLen ? strlen(lpszParam) : -1) + strlen(szFtpCommands[ftpCmd]) +
1444 strlen(szCRLF)+ 1;
1445 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1447 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1448 return FALSE;
1450 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], bParamHasLen ? " " : "",
1451 bParamHasLen ? lpszParam : "", szCRLF);
1453 TRACE("Sending (%s) len(%ld)\n", buf, len);
1454 while((nBytesSent < len) && (nRC != SOCKET_ERROR))
1456 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1457 nBytesSent += nRC;
1460 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
1462 if (lpfnStatusCB)
1463 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_REQUEST_SENT,
1464 &nBytesSent, sizeof(DWORD));
1466 TRACE("Sent %ld bytes\n", nBytesSent);
1467 return (nRC != SOCKET_ERROR);
1471 /***********************************************************************
1472 * FTP_ReceiveResponse (internal)
1474 * Receive response from server
1476 * RETURNS
1477 * Reply code on success
1478 * 0 on failure
1482 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
1483 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1485 DWORD nRecv;
1486 INT rc = 0;
1487 char firstprefix[5];
1488 BOOL multiline = FALSE;
1491 TRACE("socket(%d) \n", nSocket);
1493 if (lpfnStatusCB)
1494 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1496 while(1)
1498 nRecv = dwResponse;
1499 if (!INTERNET_GetNextLine(nSocket, lpszResponse, &nRecv))
1500 goto lerror;
1502 if (nRecv >= 3)
1504 if(!multiline)
1506 if(lpszResponse[3] != '-')
1507 break;
1508 else
1509 { /* Start of multiline repsonse. Loop until we get "nnn " */
1510 multiline = TRUE;
1511 memcpy(firstprefix, lpszResponse, 3);
1512 firstprefix[3] = ' ';
1513 firstprefix[4] = '\0';
1516 else
1518 if(!memcmp(firstprefix, lpszResponse, 4))
1519 break;
1524 if (nRecv >= 3)
1526 lpszResponse[nRecv] = '\0';
1527 rc = atoi(lpszResponse);
1529 if (lpfnStatusCB)
1530 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
1531 &nRecv, sizeof(DWORD));
1534 lerror:
1535 TRACE("return %d\n", rc);
1536 return rc;
1540 /***********************************************************************
1541 * FTP_SendPassword (internal)
1543 * Send password to ftp server
1545 * RETURNS
1546 * TRUE on success
1547 * NULL on failure
1550 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs)
1552 INT nResCode;
1553 BOOL bSuccess = FALSE;
1555 TRACE("\n");
1556 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
1557 goto lend;
1559 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1560 MAX_REPLY_LEN, 0, 0, 0);
1561 if (nResCode)
1563 TRACE("Received reply code %d\n", nResCode);
1564 /* Login successful... */
1565 if (nResCode == 230)
1566 bSuccess = TRUE;
1567 /* Command not implemented, superfluous at the server site... */
1568 /* Need account for login... */
1569 else if (nResCode == 332)
1570 bSuccess = FTP_SendAccount(lpwfs);
1571 else
1572 FTP_SetResponseError(nResCode);
1575 lend:
1576 TRACE("Returning %d\n", bSuccess);
1577 return bSuccess;
1581 /***********************************************************************
1582 * FTP_SendAccount (internal)
1586 * RETURNS
1587 * TRUE on success
1588 * FALSE on failure
1591 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs)
1593 INT nResCode;
1594 BOOL bSuccess = FALSE;
1596 TRACE("\n");
1597 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, NOACCOUNT, 0, 0, 0))
1598 goto lend;
1600 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1601 MAX_REPLY_LEN, 0, 0, 0);
1602 if (nResCode)
1603 bSuccess = TRUE;
1604 else
1605 FTP_SetResponseError(nResCode);
1607 lend:
1608 return bSuccess;
1612 /***********************************************************************
1613 * FTP_SendStore (internal)
1615 * Send request to upload file to ftp server
1617 * RETURNS
1618 * TRUE on success
1619 * FALSE on failure
1622 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
1624 INT nResCode;
1625 BOOL bSuccess = FALSE;
1627 TRACE("\n");
1628 if (!FTP_InitListenSocket(lpwfs))
1629 goto lend;
1631 if (!FTP_SendType(lpwfs, dwType))
1632 goto lend;
1634 if (!FTP_SendPort(lpwfs))
1635 goto lend;
1637 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
1638 goto lend;
1639 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1640 MAX_REPLY_LEN, 0, 0, 0);
1641 if (nResCode)
1643 if (nResCode == 150)
1644 bSuccess = TRUE;
1645 else
1646 FTP_SetResponseError(nResCode);
1649 lend:
1650 if (!bSuccess && INVALID_SOCKET != lpwfs->lstnSocket)
1652 close(lpwfs->lstnSocket);
1653 lpwfs->lstnSocket = INVALID_SOCKET;
1656 return bSuccess;
1660 /***********************************************************************
1661 * FTP_InitListenSocket (internal)
1663 * Create a socket to listen for server response
1665 * RETURNS
1666 * TRUE on success
1667 * FALSE on failure
1670 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs)
1672 BOOL bSuccess = FALSE;
1673 size_t namelen = sizeof(struct sockaddr_in);
1675 TRACE("\n");
1677 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
1678 if (INVALID_SOCKET == lpwfs->lstnSocket)
1680 TRACE("Unable to create listening socket\n");
1681 goto lend;
1684 /* We obtain our ip addr from the name of the command channel socket */
1685 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
1687 /* and get the system to assign us a port */
1688 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
1690 if (SOCKET_ERROR == bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)))
1692 TRACE("Unable to bind socket\n");
1693 goto lend;
1696 if (SOCKET_ERROR == listen(lpwfs->lstnSocket, MAX_BACKLOG))
1698 TRACE("listen failed\n");
1699 goto lend;
1702 if (SOCKET_ERROR != getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen))
1703 bSuccess = TRUE;
1705 lend:
1706 if (!bSuccess && INVALID_SOCKET == lpwfs->lstnSocket)
1708 close(lpwfs->lstnSocket);
1709 lpwfs->lstnSocket = INVALID_SOCKET;
1712 return bSuccess;
1716 /***********************************************************************
1717 * FTP_SendType (internal)
1719 * Tell server type of data being transfered
1721 * RETURNS
1722 * TRUE on success
1723 * FALSE on failure
1726 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType)
1728 INT nResCode;
1729 CHAR type[2] = { "I\0" };
1730 BOOL bSuccess = FALSE;
1732 TRACE("\n");
1733 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
1734 *type = 'A';
1736 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
1737 goto lend;
1739 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1740 MAX_REPLY_LEN, 0, 0, 0)/100;
1741 if (nResCode)
1743 if (nResCode == 2)
1744 bSuccess = TRUE;
1745 else
1746 FTP_SetResponseError(nResCode);
1749 lend:
1750 return bSuccess;
1754 /***********************************************************************
1755 * FTP_SendPort (internal)
1757 * Tell server which port to use
1759 * RETURNS
1760 * TRUE on success
1761 * FALSE on failure
1764 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs)
1766 INT nResCode;
1767 CHAR szIPAddress[64];
1768 BOOL bSuccess = FALSE;
1769 TRACE("\n");
1771 sprintf(szIPAddress, "%d,%d,%d,%d,%d,%d",
1772 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
1773 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
1774 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
1775 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
1776 lpwfs->lstnSocketAddress.sin_port & 0xFF,
1777 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
1779 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
1780 goto lend;
1782 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1783 MAX_REPLY_LEN,0, 0, 0);
1784 if (nResCode)
1786 if (nResCode == 200)
1787 bSuccess = TRUE;
1788 else
1789 FTP_SetResponseError(nResCode);
1792 lend:
1793 return bSuccess;
1797 /***********************************************************************
1798 * FTP_InitDataSocket (internal)
1802 * RETURNS
1803 * TRUE on success
1804 * FALSE on failure
1807 BOOL FTP_InitDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket)
1809 struct sockaddr_in saddr;
1810 size_t addrlen = sizeof(struct sockaddr);
1812 TRACE("\n");
1813 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
1814 close(lpwfs->lstnSocket);
1815 lpwfs->lstnSocket = INVALID_SOCKET;
1817 return *nDataSocket != INVALID_SOCKET;
1821 /***********************************************************************
1822 * FTP_SendData (internal)
1824 * Send data to the server
1826 * RETURNS
1827 * TRUE on success
1828 * FALSE on failure
1831 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile)
1833 BY_HANDLE_FILE_INFORMATION fi;
1834 DWORD nBytesRead = 0;
1835 DWORD nBytesSent = 0;
1836 DWORD nTotalSent = 0;
1837 DWORD nBytesToSend, nLen, nRC = 1;
1838 time_t s_long_time, e_long_time;
1839 LONG nSeconds;
1840 CHAR *lpszBuffer;
1842 TRACE("\n");
1843 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
1844 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
1846 /* Get the size of the file. */
1847 GetFileInformationByHandle(hFile, &fi);
1848 time(&s_long_time);
1852 nBytesToSend = nBytesRead - nBytesSent;
1854 if (nBytesToSend <= 0)
1856 /* Read data from file. */
1857 nBytesSent = 0;
1858 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
1859 ERR("Failed reading from file\n");
1861 if (nBytesRead > 0)
1862 nBytesToSend = nBytesRead;
1863 else
1864 break;
1867 nLen = DATA_PACKET_SIZE < nBytesToSend ?
1868 DATA_PACKET_SIZE : nBytesToSend;
1869 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
1871 if (nRC != SOCKET_ERROR)
1873 nBytesSent += nRC;
1874 nTotalSent += nRC;
1877 /* Do some computation to display the status. */
1878 time(&e_long_time);
1879 nSeconds = e_long_time - s_long_time;
1880 if( nSeconds / 60 > 0 )
1882 TRACE( "%ld bytes of %d bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
1883 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
1884 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
1886 else
1888 TRACE( "%ld bytes of %d bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
1889 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
1890 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
1892 } while (nRC != SOCKET_ERROR);
1894 TRACE("file transfer complete!\n");
1896 if(lpszBuffer != NULL)
1897 HeapFree(GetProcessHeap(), 0, lpszBuffer);
1899 return nTotalSent;
1903 /***********************************************************************
1904 * FTP_SendRetrieve (internal)
1906 * Send request to retrieve a file
1908 * RETURNS
1909 * Number of bytes to be received on success
1910 * 0 on failure
1913 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
1915 INT nResCode;
1916 DWORD nResult = 0;
1918 TRACE("\n");
1919 if (!FTP_InitListenSocket(lpwfs))
1920 goto lend;
1922 if (!FTP_SendType(lpwfs, dwType))
1923 goto lend;
1925 if (!FTP_SendPort(lpwfs))
1926 goto lend;
1928 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
1929 goto lend;
1931 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1932 MAX_REPLY_LEN, 0, 0, 0);
1933 if (nResCode)
1935 if (nResCode == 125 || nResCode == 150)
1937 /* Parse size of data to be retrieved */
1938 INT i, sizepos = -1;
1939 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
1940 for (i = strlen(lpszResponseBuffer) - 1; i >= 0; i--)
1942 if ('(' == lpszResponseBuffer[i])
1944 sizepos = i;
1945 break;
1949 if (sizepos >= 0)
1951 nResult = atol(&lpszResponseBuffer[sizepos+1]);
1952 TRACE("Waiting to receive %ld bytes\n", nResult);
1957 lend:
1958 if (0 == nResult && INVALID_SOCKET != lpwfs->lstnSocket)
1960 close(lpwfs->lstnSocket);
1961 lpwfs->lstnSocket = INVALID_SOCKET;
1964 return nResult;
1968 /***********************************************************************
1969 * FTP_RetrieveData (internal)
1971 * Retrieve data from server
1973 * RETURNS
1974 * TRUE on success
1975 * FALSE on failure
1978 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
1980 DWORD nBytesWritten;
1981 DWORD nBytesReceived = 0;
1982 INT nRC = 0;
1983 CHAR *lpszBuffer;
1985 TRACE("\n");
1987 if (INVALID_HANDLE_VALUE == hFile)
1988 return FALSE;
1990 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
1991 if (NULL == lpszBuffer)
1993 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1994 return FALSE;
1997 while (nBytesReceived < nBytes && nRC != SOCKET_ERROR)
1999 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2000 if (nRC != SOCKET_ERROR)
2002 /* other side closed socket. */
2003 if (nRC == 0)
2004 goto recv_end;
2005 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2006 nBytesReceived += nRC;
2009 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
2010 nBytesReceived * 100 / nBytes);
2013 TRACE("Data transfer complete\n");
2014 if (NULL != lpszBuffer)
2015 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2017 recv_end:
2018 return (nRC != SOCKET_ERROR);
2022 /***********************************************************************
2023 * FTP_CloseSessionHandle (internal)
2025 * Deallocate session handle
2027 * RETURNS
2028 * TRUE on success
2029 * FALSE on failure
2032 BOOL FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs)
2034 if (INVALID_SOCKET != lpwfs->sndSocket)
2035 close(lpwfs->sndSocket);
2037 if (INVALID_SOCKET != lpwfs->lstnSocket)
2038 close(lpwfs->lstnSocket);
2040 if (lpwfs->lpszPassword)
2041 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2043 if (lpwfs->lpszUserName)
2044 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2046 HeapFree(GetProcessHeap(), 0, lpwfs);
2048 return TRUE;
2052 /***********************************************************************
2053 * FTP_CloseSessionHandle (internal)
2055 * Deallocate session handle
2057 * RETURNS
2058 * TRUE on success
2059 * FALSE on failure
2062 BOOL FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn)
2064 INT i;
2066 TRACE("\n");
2068 for (i = 0; i < lpwfn->size; i++)
2070 if (NULL != lpwfn->lpafp[i].lpszName)
2071 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2074 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2075 HeapFree(GetProcessHeap(), 0, lpwfn);
2077 return TRUE;
2081 /***********************************************************************
2082 * FTP_ReceiveFileList (internal)
2084 * Read file list from server
2086 * RETURNS
2087 * Handle to file list on success
2088 * NULL on failure
2091 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
2092 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext)
2094 DWORD dwSize = 0;
2095 LPFILEPROPERTIESA lpafp = NULL;
2096 LPWININETFINDNEXTA lpwfn = NULL;
2098 TRACE("\n");
2100 if (FTP_ParseDirectory(lpwfs, nSocket, &lpafp, &dwSize))
2102 FTP_ConvertFileProp(lpafp, lpFindFileData);
2104 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTA));
2105 if (NULL != lpwfn)
2107 lpwfn->hdr.htype = WH_HFINDNEXT;
2108 lpwfn->hdr.lpwhparent = (LPWININETHANDLEHEADER)lpwfs;
2109 lpwfn->hdr.dwContext = dwContext;
2110 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2111 lpwfn->size = dwSize;
2112 lpwfn->lpafp = lpafp;
2116 TRACE("Matched %ld files\n", dwSize);
2117 return (HINTERNET)lpwfn;
2121 /***********************************************************************
2122 * FTP_ConvertFileProp (internal)
2124 * Converts FILEPROPERTIESA struct to WIN32_FIND_DATAA
2126 * RETURNS
2127 * TRUE on success
2128 * FALSE on failure
2131 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESA lpafp, LPWIN32_FIND_DATAA lpFindFileData)
2133 BOOL bSuccess = FALSE;
2135 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2137 if (lpafp)
2139 DWORD access = mktime(&lpafp->tmLastModified);
2141 /* Not all fields are filled in */
2142 lpFindFileData->ftLastAccessTime.dwHighDateTime = HIWORD(access);
2143 lpFindFileData->ftLastAccessTime.dwLowDateTime = LOWORD(access);
2144 lpFindFileData->nFileSizeHigh = HIWORD(lpafp->nSize);
2145 lpFindFileData->nFileSizeLow = LOWORD(lpafp->nSize);
2147 if (lpafp->bIsDirectory)
2148 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2150 if (lpafp->lpszName)
2151 strncpy(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2153 bSuccess = TRUE;
2156 return bSuccess;
2160 /***********************************************************************
2161 * FTP_ParseDirectory (internal)
2163 * Parse string of directory information
2165 * RETURNS
2166 * TRUE on success
2167 * FALSE on failure
2169 * FIXME: - This function needs serious clea-up
2170 * - We should consider both UNIX and NT list formats
2172 #define MAX_MONTH_LEN 10
2173 #define MIN_LEN_DIR_ENTRY 15
2175 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp)
2178 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2180 * For instance:
2181 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2183 CHAR* pszMinutes;
2184 CHAR* pszHour;
2185 time_t aTime;
2186 struct tm* apTM;
2187 CHAR pszMonth[MAX_MONTH_LEN];
2188 CHAR* pszMatch;
2189 BOOL bSuccess = TRUE;
2190 DWORD nBufLen = MAX_REPLY_LEN;
2191 LPFILEPROPERTIESA curFileProp = NULL;
2192 CHAR* pszLine = NULL;
2193 CHAR* pszToken = NULL;
2194 INT nTokenToSkip = 3;
2195 INT nCount = 0;
2196 INT nSeconds = 0;
2197 INT nMinutes = 0;
2198 INT nHour = 0;
2199 INT nDay = 0;
2200 INT nMonth = 0;
2201 INT nYear = 0;
2202 INT sizeFilePropArray = 20;
2203 INT indexFilePropArray = 0;
2205 TRACE("\n");
2207 /* Allocate intial file properties array */
2208 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESA)*(sizeFilePropArray));
2209 if (NULL == lpafp)
2211 bSuccess = FALSE;
2212 goto lend;
2215 while ((pszLine = INTERNET_GetNextLine(nSocket, INTERNET_GetResponseBuffer(), &nBufLen)) != NULL)
2217 if (sizeFilePropArray <= indexFilePropArray)
2219 LPFILEPROPERTIESA tmpafp;
2221 sizeFilePropArray *= 2;
2222 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
2223 sizeof(FILEPROPERTIESA)*sizeFilePropArray);
2224 if (NULL == tmpafp)
2226 bSuccess = FALSE;
2227 goto lend;
2230 *lpafp = tmpafp;
2233 curFileProp = &((*lpafp)[indexFilePropArray]);
2235 /* First Parse the permissions. */
2236 pszToken = strtok(pszLine, " \t" );
2238 /* HACK! If this is not a file listing skip the line */
2239 if (!pszToken || 10 != strlen(pszToken) || nBufLen <= MIN_LEN_DIR_ENTRY)
2241 nBufLen = MAX_REPLY_LEN;
2242 continue;
2245 FTP_ParsePermission(pszToken, curFileProp);
2247 nTokenToSkip = 3;
2248 nCount = 0;
2251 pszToken = strtok( NULL, " \t" );
2252 nCount++;
2253 } while( nCount <= nTokenToSkip );
2255 /* Store the size of the file in the param list. */
2256 TRACE("nSize-> %s\n", pszToken);
2257 if (pszToken != NULL)
2258 curFileProp->nSize = atol(pszToken);
2260 /* Parse last modified time. */
2261 nSeconds = 0;
2262 nMinutes = 0;
2263 nHour = 0;
2264 nDay = 0;
2265 nMonth = 0;
2266 nYear = 0;
2268 pszToken = strtok( NULL, " \t" );
2269 strncpy(pszMonth, pszToken, MAX_MONTH_LEN);
2270 CharUpperA(pszMonth);
2271 pszMatch = strstr(szMonths, pszMonth);
2272 if( pszMatch != NULL )
2273 nMonth = (pszMatch - szMonths) / 3;
2275 pszToken = strtok(NULL, " \t");
2276 TRACE("nDay -> %s\n", pszToken);
2277 if (pszToken != NULL)
2278 nDay = atoi(pszToken);
2280 pszToken = strtok(NULL, " \t");
2281 pszMinutes = strchr(pszToken, ':');
2282 if( pszMinutes != NULL )
2284 pszMinutes++;
2285 nMinutes = atoi(pszMinutes);
2286 pszHour = pszMinutes - 3;
2287 if (pszHour != NULL)
2288 nHour = atoi(pszHour);
2289 time(&aTime);
2290 apTM = localtime( &aTime );
2291 nYear = apTM->tm_year;
2293 else
2295 nYear = atoi(pszToken);
2296 nYear -= 1900;
2297 nHour = 12;
2300 curFileProp->tmLastModified.tm_sec = nSeconds;
2301 curFileProp->tmLastModified.tm_min = nMinutes;
2302 curFileProp->tmLastModified.tm_hour = nHour;
2303 curFileProp->tmLastModified.tm_mday = nDay;
2304 curFileProp->tmLastModified.tm_mon = nMonth;
2305 curFileProp->tmLastModified.tm_year = nYear;
2307 pszToken = strtok(NULL, " \t");
2308 if(pszToken != NULL)
2310 curFileProp->lpszName = HEAP_strdupA(GetProcessHeap(),0,pszToken);
2311 TRACE(": %s\n", curFileProp->lpszName);
2314 nBufLen = MAX_REPLY_LEN;
2315 indexFilePropArray++;
2318 if (bSuccess && indexFilePropArray)
2320 if (indexFilePropArray < sizeFilePropArray - 1)
2322 LPFILEPROPERTIESA tmpafp;
2324 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
2325 sizeof(FILEPROPERTIESA)*indexFilePropArray);
2326 if (NULL == tmpafp)
2327 *lpafp = tmpafp;
2329 *dwfp = indexFilePropArray;
2331 else
2333 HeapFree(GetProcessHeap(), 0, *lpafp);
2334 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2335 bSuccess = FALSE;
2338 lend:
2339 return bSuccess;
2343 /***********************************************************************
2344 * FTP_ParsePermission (internal)
2346 * Parse permission string of directory information
2348 * RETURNS
2349 * TRUE on success
2350 * FALSE on failure
2353 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp)
2355 BOOL bSuccess = TRUE;
2356 unsigned short nPermission = 0;
2357 INT nPos = 1;
2358 INT nLast = 9;
2360 TRACE("\n");
2361 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
2363 bSuccess = FALSE;
2364 return bSuccess;
2367 lpfp->bIsDirectory = (*lpszPermission == 'd');
2370 switch (nPos)
2372 case 1:
2373 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
2374 break;
2375 case 2:
2376 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
2377 break;
2378 case 3:
2379 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
2380 break;
2381 case 4:
2382 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
2383 break;
2384 case 5:
2385 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
2386 break;
2387 case 6:
2388 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
2389 break;
2390 case 7:
2391 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
2392 break;
2393 case 8:
2394 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
2395 break;
2396 case 9:
2397 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
2398 break;
2400 nPos++;
2401 }while (nPos <= nLast);
2403 lpfp->permissions = nPermission;
2404 return bSuccess;
2408 /***********************************************************************
2409 * FTP_SetResponseError (internal)
2411 * Set the appropriate error code for a given response from the server
2413 * RETURNS
2416 DWORD FTP_SetResponseError(DWORD dwResponse)
2418 DWORD dwCode = 0;
2420 switch(dwResponse)
2422 case 421: /* Service not available - Server may be shutting down. */
2423 dwCode = ERROR_INTERNET_TIMEOUT;
2424 break;
2426 case 425: /* Cannot open data connection. */
2427 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
2428 break;
2430 case 426: /* Connection closed, transer aborted. */
2431 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
2432 break;
2434 case 500: /* Syntax error. Command unrecognized. */
2435 case 501: /* Syntax error. Error in parameters or arguments. */
2436 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
2437 break;
2439 case 530: /* Not logged in. Login incorrect. */
2440 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
2441 break;
2443 case 550: /* File action not taken. File not found or no access. */
2444 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
2445 break;
2447 case 450: /* File action not taken. File may be busy. */
2448 case 451: /* Action aborted. Server error. */
2449 case 452: /* Action not taken. Insufficient storage space on server. */
2450 case 502: /* Command not implemented. */
2451 case 503: /* Bad sequence of command. */
2452 case 504: /* Command not implemented for that parameter. */
2453 case 532: /* Need account for storing files */
2454 case 551: /* Requested action aborted. Page type unknown */
2455 case 552: /* Action aborted. Exceeded storage allocation */
2456 case 553: /* Action not taken. File name not allowed. */
2458 default:
2459 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
2460 break;
2463 INTERNET_SetLastError(dwCode);
2464 return dwCode;