Fixed some issues found by winapi_check.
[wine.git] / dlls / wininet / ftp.c
blob9d70c625edf442f9f4921e75a1c1fda05329441b
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/in_systm.h>
24 #include <netinet/in.h>
25 #include <netinet/ip.h>
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "wininet.h"
31 #include "winerror.h"
32 #include "winsock.h"
33 #include "heap.h"
35 #include "debugtools.h"
36 #include "internet.h"
38 DEFAULT_DEBUG_CHANNEL(wininet);
40 #define NOACCOUNT "noaccount"
41 #define DATA_PACKET_SIZE 0x2000
42 #define szCRLF "\r\n"
43 #define MAX_BACKLOG 5
45 typedef enum {
46 /* FTP commands with arguments. */
47 FTP_CMD_ACCT,
48 FTP_CMD_CWD,
49 FTP_CMD_DELE,
50 FTP_CMD_MKD,
51 FTP_CMD_PASS,
52 FTP_CMD_PORT,
53 FTP_CMD_RETR,
54 FTP_CMD_RMD,
55 FTP_CMD_RNFR,
56 FTP_CMD_RNTO,
57 FTP_CMD_STOR,
58 FTP_CMD_TYPE,
59 FTP_CMD_USER,
61 /* FTP commands without arguments. */
62 FTP_CMD_ABOR,
63 FTP_CMD_LIST,
64 FTP_CMD_NLST,
65 FTP_CMD_PWD,
66 FTP_CMD_QUIT,
67 } FTP_COMMAND;
69 static const CHAR *szFtpCommands[] = {
70 "ACCT",
71 "CWD",
72 "DELE",
73 "MKD",
74 "PASS",
75 "PORT",
76 "RETR",
77 "RMD",
78 "RNFR",
79 "RNTO",
80 "STOR",
81 "TYPE",
82 "USER",
83 "ABOR",
84 "LIST",
85 "NLST",
86 "PWD",
87 "QUIT",
90 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
92 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
93 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
94 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
95 BOOL FTP_InitDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket);
96 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile);
97 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
98 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
99 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
100 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile);
101 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs);
102 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs);
103 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs);
104 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs);
105 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType);
106 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs);
107 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp);
108 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp);
109 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
110 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext);
111 DWORD FTP_SetResponseError(DWORD dwResponse);
113 inline static LPSTR FTP_strdup( LPCSTR str )
115 LPSTR ret = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
116 if (ret) strcpy( ret, str );
117 return ret;
120 /***********************************************************************
121 * FtpPutFileA (WININET.43)
123 * Uploads a file to the FTP server
125 * RETURNS
126 * TRUE on success
127 * FALSE on failure
130 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
131 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
133 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
134 LPWININETAPPINFOA hIC = NULL;
136 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
138 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
139 return FALSE;
142 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
143 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
145 WORKREQUEST workRequest;
147 workRequest.asyncall = FTPPUTFILEA;
148 workRequest.HFTPSESSION = (DWORD)hConnect;
149 workRequest.LPSZLOCALFILE = (DWORD)FTP_strdup(lpszLocalFile);
150 workRequest.LPSZNEWREMOTEFILE = (DWORD)FTP_strdup(lpszNewRemoteFile);
151 workRequest.DWFLAGS = dwFlags;
152 workRequest.DWCONTEXT = dwContext;
154 return INTERNET_AsyncCall(&workRequest);
156 else
158 return FTP_FtpPutFileA(hConnect, lpszLocalFile,
159 lpszNewRemoteFile, dwFlags, dwContext);
163 /***********************************************************************
164 * FTP_FtpPutFileA (Internal)
166 * Uploads a file to the FTP server
168 * RETURNS
169 * TRUE on success
170 * FALSE on failure
173 BOOL WINAPI FTP_FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
174 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
176 HANDLE hFile = (HANDLE)NULL;
177 BOOL bSuccess = FALSE;
178 LPWININETAPPINFOA hIC = NULL;
179 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
180 INT nResCode;
182 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", lpszLocalFile, lpszNewRemoteFile);
183 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
185 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
186 return FALSE;
189 /* Clear any error information */
190 INTERNET_SetLastError(0);
192 /* Open file to be uploaded */
193 if (INVALID_HANDLE_VALUE ==
194 (hFile = CreateFileA(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
196 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND);
197 goto lend;
200 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
201 if (hIC->lpfnStatusCB)
202 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
204 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
206 INT nDataSocket;
208 /* Accept connection from ftp server */
209 if (FTP_InitDataSocket(lpwfs, &nDataSocket))
211 FTP_SendData(lpwfs, nDataSocket, hFile);
212 close(nDataSocket);
213 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
214 MAX_REPLY_LEN,0, 0, 0);
215 if (nResCode)
217 if (nResCode == 226)
218 bSuccess = TRUE;
219 else
220 FTP_SetResponseError(nResCode);
225 lend:
226 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
228 INTERNET_ASYNC_RESULT iar;
230 iar.dwResult = (DWORD)bSuccess;
231 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
232 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
233 &iar, sizeof(INTERNET_ASYNC_RESULT));
236 if (hFile)
237 CloseHandle(hFile);
239 return bSuccess;
243 /***********************************************************************
244 * FtpSetCurrentDirectoryA (WININET.49)
246 * Change the working directory on the FTP server
248 * RETURNS
249 * TRUE on success
250 * FALSE on failure
253 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
255 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
256 LPWININETAPPINFOA hIC = NULL;
258 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
260 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
261 return FALSE;
264 TRACE("lpszDirectory(%s)\n", lpszDirectory);
266 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
267 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
269 WORKREQUEST workRequest;
271 workRequest.asyncall = FTPSETCURRENTDIRECTORYA;
272 workRequest.HFTPSESSION = (DWORD)hConnect;
273 workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
275 return INTERNET_AsyncCall(&workRequest);
277 else
279 return FTP_FtpSetCurrentDirectoryA(hConnect, lpszDirectory);
284 /***********************************************************************
285 * FTP_FtpSetCurrentDirectoryA (Internal)
287 * Change the working directory on the FTP server
289 * RETURNS
290 * TRUE on success
291 * FALSE on failure
294 BOOL WINAPI FTP_FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
296 INT nResCode;
297 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
298 LPWININETAPPINFOA hIC = NULL;
299 DWORD bSuccess = FALSE;
301 TRACE("lpszDirectory(%s)\n", lpszDirectory);
303 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
305 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
306 return FALSE;
309 /* Clear any error information */
310 INTERNET_SetLastError(0);
312 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
313 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
314 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
315 goto lend;
317 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
318 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
320 if (nResCode)
322 if (nResCode == 250)
323 bSuccess = TRUE;
324 else
325 FTP_SetResponseError(nResCode);
328 lend:
329 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
331 INTERNET_ASYNC_RESULT iar;
333 iar.dwResult = (DWORD)bSuccess;
334 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
335 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
336 &iar, sizeof(INTERNET_ASYNC_RESULT));
338 return bSuccess;
342 /***********************************************************************
343 * FtpCreateDirectoryA (WININET.31)
345 * Create new directory on the FTP server
347 * RETURNS
348 * TRUE on success
349 * FALSE on failure
352 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
354 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
355 LPWININETAPPINFOA hIC = NULL;
357 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
359 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
360 return FALSE;
363 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
364 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
366 WORKREQUEST workRequest;
368 workRequest.asyncall = FTPCREATEDIRECTORYA;
369 workRequest.HFTPSESSION = (DWORD)hConnect;
370 workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
372 return INTERNET_AsyncCall(&workRequest);
374 else
376 return FTP_FtpCreateDirectoryA(hConnect, lpszDirectory);
381 /***********************************************************************
382 * FTP_FtpCreateDirectoryA (Internal)
384 * Create new directory on the FTP server
386 * RETURNS
387 * TRUE on success
388 * FALSE on failure
391 BOOL WINAPI FTP_FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
393 INT nResCode;
394 BOOL bSuccess = FALSE;
395 LPWININETAPPINFOA hIC = NULL;
396 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
398 TRACE("\n");
399 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
401 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
402 return FALSE;
405 /* Clear any error information */
406 INTERNET_SetLastError(0);
408 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
409 goto lend;
411 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
412 MAX_REPLY_LEN, 0, 0, 0);
413 if (nResCode)
415 if (nResCode == 257)
416 bSuccess = TRUE;
417 else
418 FTP_SetResponseError(nResCode);
421 lend:
422 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
423 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
425 INTERNET_ASYNC_RESULT iar;
427 iar.dwResult = (DWORD)bSuccess;
428 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
429 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
430 &iar, sizeof(INTERNET_ASYNC_RESULT));
433 return bSuccess;
437 /***********************************************************************
438 * FtpFindFirstFileA (WININET.35)
440 * Search the specified directory
442 * RETURNS
443 * HINTERNET on success
444 * NULL on failure
447 INTERNETAPI HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
448 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
450 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
451 LPWININETAPPINFOA hIC = NULL;
453 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
455 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
456 return FALSE;
459 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
460 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
462 WORKREQUEST workRequest;
464 workRequest.asyncall = FTPFINDFIRSTFILEA;
465 workRequest.HFTPSESSION = (DWORD)hConnect;
466 workRequest.LPSZSEARCHFILE = (DWORD)FTP_strdup(lpszSearchFile);
467 workRequest.LPFINDFILEDATA = (DWORD)lpFindFileData;
468 workRequest.DWFLAGS = dwFlags;
469 workRequest.DWCONTEXT= dwContext;
471 INTERNET_AsyncCall(&workRequest);
472 return NULL;
474 else
476 return FTP_FtpFindFirstFileA(hConnect, lpszSearchFile, lpFindFileData,
477 dwFlags, dwContext);
482 /***********************************************************************
483 * FTP_FtpFindFirstFileA (Internal)
485 * Search the specified directory
487 * RETURNS
488 * HINTERNET on success
489 * NULL on failure
492 INTERNETAPI HINTERNET WINAPI FTP_FtpFindFirstFileA(HINTERNET hConnect,
493 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
495 INT nResCode;
496 LPWININETAPPINFOA hIC = NULL;
497 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
498 LPWININETFINDNEXTA hFindNext = NULL;
500 TRACE("\n");
502 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
504 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
505 return FALSE;
508 /* Clear any error information */
509 INTERNET_SetLastError(0);
511 if (!FTP_InitListenSocket(lpwfs))
512 goto lend;
514 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
515 goto lend;
517 if (!FTP_SendPort(lpwfs))
518 goto lend;
520 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
521 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, lpszSearchFile,
522 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
523 goto lend;
525 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
526 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
527 if (nResCode)
529 if (nResCode == 125 || nResCode == 150)
531 INT nDataSocket;
533 if (FTP_InitDataSocket(lpwfs, &nDataSocket))
535 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpFindFileData, dwContext);
537 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
538 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
539 if (nResCode != 226 && nResCode != 250)
540 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
542 close(nDataSocket);
545 else
546 FTP_SetResponseError(nResCode);
549 lend:
550 if (lpwfs->lstnSocket != INVALID_SOCKET)
551 close(lpwfs->lstnSocket);
553 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
555 INTERNET_ASYNC_RESULT iar;
557 if (hFindNext)
559 iar.dwResult = (DWORD)hFindNext;
560 iar.dwError = ERROR_SUCCESS;
561 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
562 &iar, sizeof(INTERNET_ASYNC_RESULT));
565 iar.dwResult = (DWORD)hFindNext;
566 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
567 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
568 &iar, sizeof(INTERNET_ASYNC_RESULT));
571 return (HINTERNET)hFindNext;
575 /***********************************************************************
576 * FtpGetCurrentDirectoryA (WININET.37)
578 * Retrieves the current directory
580 * RETURNS
581 * TRUE on success
582 * FALSE on failure
585 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
586 LPDWORD lpdwCurrentDirectory)
588 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
589 LPWININETAPPINFOA hIC = NULL;
591 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
593 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
595 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
596 return FALSE;
599 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
600 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
602 WORKREQUEST workRequest;
604 workRequest.asyncall = FTPGETCURRENTDIRECTORYA;
605 workRequest.HFTPSESSION = (DWORD)hFtpSession;
606 workRequest.LPSZDIRECTORY = (DWORD)lpszCurrentDirectory;
607 workRequest.LPDWDIRECTORY = (DWORD)lpdwCurrentDirectory;
609 return INTERNET_AsyncCall(&workRequest);
611 else
613 return FTP_FtpGetCurrentDirectoryA(hFtpSession, lpszCurrentDirectory,
614 lpdwCurrentDirectory);
619 /***********************************************************************
620 * FTP_FtpGetCurrentDirectoryA (Internal)
622 * Retrieves the current directory
624 * RETURNS
625 * TRUE on success
626 * FALSE on failure
629 BOOL WINAPI FTP_FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
630 LPDWORD lpdwCurrentDirectory)
632 INT nResCode;
633 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
634 LPWININETAPPINFOA hIC = NULL;
635 DWORD bSuccess = FALSE;
637 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
639 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
641 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
642 return FALSE;
645 /* Clear any error information */
646 INTERNET_SetLastError(0);
648 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
650 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
651 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
652 hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext))
653 goto lend;
655 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
656 MAX_REPLY_LEN, hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext);
657 if (nResCode)
659 if (nResCode == 257) /* Extract directory name */
661 INT firstpos, lastpos, len;
662 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
664 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
666 if ('"' == lpszResponseBuffer[lastpos])
668 if (!firstpos)
669 firstpos = lastpos;
670 else
671 break;
675 len = lastpos - firstpos - 1;
676 strncpy(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1],
677 len < *lpdwCurrentDirectory ? len : *lpdwCurrentDirectory);
678 *lpdwCurrentDirectory = len;
679 bSuccess = TRUE;
681 else
682 FTP_SetResponseError(nResCode);
685 lend:
686 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
688 INTERNET_ASYNC_RESULT iar;
690 iar.dwResult = (DWORD)bSuccess;
691 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
692 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
693 &iar, sizeof(INTERNET_ASYNC_RESULT));
696 return (DWORD) bSuccess;
699 /***********************************************************************
700 * FtpOpenFileA (WININET.41)
702 * Open a remote file for writing or reading
704 * RETURNS
705 * HINTERNET handle on success
706 * NULL on failure
709 INTERNETAPI HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
710 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
711 DWORD dwContext)
713 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
714 LPWININETAPPINFOA hIC = NULL;
716 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
718 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
719 return FALSE;
722 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
723 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
725 WORKREQUEST workRequest;
727 workRequest.asyncall = FTPOPENFILEA;
728 workRequest.HFTPSESSION = (DWORD)hFtpSession;
729 workRequest.LPSZFILENAME = (DWORD)FTP_strdup(lpszFileName);
730 workRequest.FDWACCESS = fdwAccess;
731 workRequest.DWFLAGS = dwFlags;
732 workRequest.DWCONTEXT = dwContext;
734 INTERNET_AsyncCall(&workRequest);
735 return NULL;
737 else
739 return FTP_FtpOpenFileA(hFtpSession, lpszFileName, fdwAccess, dwFlags, dwContext);
744 /***********************************************************************
745 * FTP_FtpOpenFileA (Internal)
747 * Open a remote file for writing or reading
749 * RETURNS
750 * HINTERNET handle on success
751 * NULL on failure
754 HINTERNET FTP_FtpOpenFileA(HINTERNET hFtpSession,
755 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
756 DWORD dwContext)
758 INT nDataSocket;
759 BOOL bSuccess = FALSE;
760 LPWININETFILE hFile = NULL;
761 LPWININETAPPINFOA hIC = NULL;
762 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
764 TRACE("\n");
766 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
768 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
769 return FALSE;
772 /* Clear any error information */
773 INTERNET_SetLastError(0);
775 if (GENERIC_READ == fdwAccess)
777 /* Set up socket to retrieve data */
778 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
780 else if (GENERIC_WRITE == fdwAccess)
782 /* Set up socket to send data */
783 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
786 /* Accept connection from server */
787 if (bSuccess && FTP_InitDataSocket(lpwfs, &nDataSocket))
789 hFile = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE));
790 hFile->hdr.htype = WH_HFILE;
791 hFile->hdr.dwFlags = dwFlags;
792 hFile->hdr.dwContext = dwContext;
793 hFile->hdr.lpwhparent = hFtpSession;
794 hFile->nDataSocket = nDataSocket;
797 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
798 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
800 INTERNET_ASYNC_RESULT iar;
802 if (hFile)
804 iar.dwResult = (DWORD)hFile;
805 iar.dwError = ERROR_SUCCESS;
806 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
807 &iar, sizeof(INTERNET_ASYNC_RESULT));
810 iar.dwResult = (DWORD)bSuccess;
811 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
812 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
813 &iar, sizeof(INTERNET_ASYNC_RESULT));
816 return (HINTERNET)hFile;
820 /***********************************************************************
821 * FtpGetFileA (WININET.39)
823 * Retrieve file from the FTP server
825 * RETURNS
826 * TRUE on success
827 * FALSE on failure
830 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
831 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
832 DWORD dwContext)
834 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet;
835 LPWININETAPPINFOA hIC = NULL;
837 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
839 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
840 return FALSE;
843 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
844 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
846 WORKREQUEST workRequest;
848 workRequest.asyncall = FTPGETFILEA;
849 workRequest.HFTPSESSION = (DWORD)hInternet;
850 workRequest.LPSZREMOTEFILE = (DWORD)FTP_strdup(lpszRemoteFile);
851 workRequest.LPSZNEWFILE = (DWORD)FTP_strdup(lpszNewFile);
852 workRequest.DWLOCALFLAGSATTRIBUTE = dwLocalFlagsAttribute;
853 workRequest.FFAILIFEXISTS = (DWORD)fFailIfExists;
854 workRequest.DWFLAGS = dwInternetFlags;
855 workRequest.DWCONTEXT = dwContext;
857 return INTERNET_AsyncCall(&workRequest);
859 else
861 return FTP_FtpGetFileA(hInternet, lpszRemoteFile, lpszNewFile,
862 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
867 /***********************************************************************
868 * FTP_FtpGetFileA (Internal)
870 * Retrieve file from the FTP server
872 * RETURNS
873 * TRUE on success
874 * FALSE on failure
877 BOOL WINAPI FTP_FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
878 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
879 DWORD dwContext)
881 DWORD nBytes;
882 BOOL bSuccess = FALSE;
883 HANDLE hFile;
884 LPWININETAPPINFOA hIC = NULL;
885 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet;
887 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", lpszRemoteFile, lpszNewFile);
888 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
890 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
891 return FALSE;
894 /* Clear any error information */
895 INTERNET_SetLastError(0);
897 /* Ensure we can write to lpszNewfile by opening it */
898 hFile = CreateFileA(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
899 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
900 if (INVALID_HANDLE_VALUE == hFile)
901 goto lend;
903 /* Set up socket to retrieve data */
904 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
906 if (nBytes > 0)
908 INT nDataSocket;
910 /* Accept connection from ftp server */
911 if (FTP_InitDataSocket(lpwfs, &nDataSocket))
913 INT nResCode;
915 /* Receive data */
916 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
917 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
918 MAX_REPLY_LEN, 0, 0, 0);
919 if (nResCode)
921 if (nResCode == 226)
922 bSuccess = TRUE;
923 else
924 FTP_SetResponseError(nResCode);
926 close(nDataSocket);
930 lend:
931 if (hFile)
932 CloseHandle(hFile);
934 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
935 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
937 INTERNET_ASYNC_RESULT iar;
939 iar.dwResult = (DWORD)bSuccess;
940 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
941 hIC->lpfnStatusCB(hInternet, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
942 &iar, sizeof(INTERNET_ASYNC_RESULT));
945 return bSuccess;
949 /***********************************************************************
950 * FtpDeleteFileA (WININET.33)
952 * Delete a file on the ftp server
954 * RETURNS
955 * TRUE on success
956 * FALSE on failure
959 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
961 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
962 LPWININETAPPINFOA hIC = NULL;
964 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
966 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
967 return FALSE;
970 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
971 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
973 WORKREQUEST workRequest;
975 workRequest.asyncall = FTPRENAMEFILEA;
976 workRequest.HFTPSESSION = (DWORD)hFtpSession;
977 workRequest.LPSZFILENAME = (DWORD)FTP_strdup(lpszFileName);
979 return INTERNET_AsyncCall(&workRequest);
981 else
983 return FTP_FtpDeleteFileA(hFtpSession, lpszFileName);
988 /***********************************************************************
989 * FTP_FtpDeleteFileA (Internal)
991 * Delete a file on the ftp server
993 * RETURNS
994 * TRUE on success
995 * FALSE on failure
998 BOOL FTP_FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1000 INT nResCode;
1001 BOOL bSuccess = FALSE;
1002 LPWININETAPPINFOA hIC = NULL;
1003 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1005 TRACE("0x%08lx\n", (ULONG) hFtpSession);
1006 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1008 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1009 return FALSE;
1012 /* Clear any error information */
1013 INTERNET_SetLastError(0);
1015 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1016 goto lend;
1018 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1019 MAX_REPLY_LEN, 0, 0, 0);
1020 if (nResCode)
1022 if (nResCode == 250)
1023 bSuccess = TRUE;
1024 else
1025 FTP_SetResponseError(nResCode);
1027 lend:
1028 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1029 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1031 INTERNET_ASYNC_RESULT iar;
1033 iar.dwResult = (DWORD)bSuccess;
1034 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1035 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1036 &iar, sizeof(INTERNET_ASYNC_RESULT));
1039 return bSuccess;
1043 /***********************************************************************
1044 * FtpRemoveDirectoryA (WININET.45)
1046 * Remove a directory on the ftp server
1048 * RETURNS
1049 * TRUE on success
1050 * FALSE on failure
1053 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1055 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1056 LPWININETAPPINFOA hIC = NULL;
1058 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1060 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1061 return FALSE;
1064 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1065 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1067 WORKREQUEST workRequest;
1069 workRequest.asyncall = FTPREMOVEDIRECTORYA;
1070 workRequest.HFTPSESSION = (DWORD)hFtpSession;
1071 workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
1073 return INTERNET_AsyncCall(&workRequest);
1075 else
1077 return FTP_FtpRemoveDirectoryA(hFtpSession, lpszDirectory);
1082 /***********************************************************************
1083 * FTP_FtpRemoveDirectoryA (Internal)
1085 * Remove a directory on the ftp server
1087 * RETURNS
1088 * TRUE on success
1089 * FALSE on failure
1092 BOOL FTP_FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1094 INT nResCode;
1095 BOOL bSuccess = FALSE;
1096 LPWININETAPPINFOA hIC = NULL;
1097 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1099 TRACE("\n");
1100 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1102 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1103 return FALSE;
1106 /* Clear any error information */
1107 INTERNET_SetLastError(0);
1109 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1110 goto lend;
1112 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1113 MAX_REPLY_LEN, 0, 0, 0);
1114 if (nResCode)
1116 if (nResCode == 250)
1117 bSuccess = TRUE;
1118 else
1119 FTP_SetResponseError(nResCode);
1122 lend:
1123 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1124 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1126 INTERNET_ASYNC_RESULT iar;
1128 iar.dwResult = (DWORD)bSuccess;
1129 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1130 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1131 &iar, sizeof(INTERNET_ASYNC_RESULT));
1134 return bSuccess;
1138 /***********************************************************************
1139 * FtpRenameFileA (WININET.47)
1141 * Rename a file on the ftp server
1143 * RETURNS
1144 * TRUE on success
1145 * FALSE on failure
1148 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1150 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1151 LPWININETAPPINFOA hIC = NULL;
1153 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1155 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1156 return FALSE;
1159 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1160 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1162 WORKREQUEST workRequest;
1164 workRequest.asyncall = FTPRENAMEFILEA;
1165 workRequest.HFTPSESSION = (DWORD)hFtpSession;
1166 workRequest.LPSZSRCFILE = (DWORD)FTP_strdup(lpszSrc);
1167 workRequest.LPSZDESTFILE = (DWORD)FTP_strdup(lpszDest);
1169 return INTERNET_AsyncCall(&workRequest);
1171 else
1173 return FTP_FtpRenameFileA(hFtpSession, lpszSrc, lpszDest);
1177 /***********************************************************************
1178 * FTP_FtpRenameFileA (Internal)
1180 * Rename a file on the ftp server
1182 * RETURNS
1183 * TRUE on success
1184 * FALSE on failure
1187 BOOL FTP_FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1189 INT nResCode;
1190 BOOL bSuccess = FALSE;
1191 LPWININETAPPINFOA hIC = NULL;
1192 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1194 TRACE("\n");
1195 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1197 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1198 return FALSE;
1201 /* Clear any error information */
1202 INTERNET_SetLastError(0);
1204 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1205 goto lend;
1207 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1208 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1209 if (nResCode == 350)
1211 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1212 goto lend;
1214 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1215 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1218 if (nResCode == 250)
1219 bSuccess = TRUE;
1220 else
1221 FTP_SetResponseError(nResCode);
1223 lend:
1224 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1225 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1227 INTERNET_ASYNC_RESULT iar;
1229 iar.dwResult = (DWORD)bSuccess;
1230 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1231 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1232 &iar, sizeof(INTERNET_ASYNC_RESULT));
1235 return bSuccess;
1239 /***********************************************************************
1240 * FTP_Connect (internal)
1242 * Connect to a ftp server
1244 * RETURNS
1245 * HINTERNET a session handle on success
1246 * NULL on failure
1250 HINTERNET FTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
1251 INTERNET_PORT nServerPort, LPCSTR lpszUserName,
1252 LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
1254 struct sockaddr_in socketAddr;
1255 struct hostent *phe = NULL;
1256 INT nsocket = INVALID_SOCKET, sock_namelen;
1257 LPWININETAPPINFOA hIC = NULL;
1258 BOOL bSuccess = FALSE;
1259 LPWININETFTPSESSIONA lpwfs = NULL;
1261 TRACE("0x%08lx Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1262 (ULONG) hInternet, lpszServerName,
1263 nServerPort, lpszUserName, lpszPassword);
1265 if (((LPWININETHANDLEHEADER)hInternet)->htype != WH_HINIT)
1266 goto lerror;
1268 hIC = (LPWININETAPPINFOA) hInternet;
1270 if (NULL == lpszUserName && NULL != lpszPassword)
1272 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_USER_NAME);
1273 goto lerror;
1276 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1277 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1279 if (hIC->lpfnStatusCB)
1280 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1281 (LPSTR) lpszServerName, strlen(lpszServerName));
1283 if (!GetAddress(lpszServerName, nServerPort, &phe, &socketAddr))
1285 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1286 goto lerror;
1289 if (hIC->lpfnStatusCB)
1290 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1291 (LPSTR) lpszServerName, strlen(lpszServerName));
1293 if (INVALID_SOCKET == (nsocket = socket(AF_INET,SOCK_STREAM,0)))
1295 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1296 goto lerror;
1299 if (hIC->lpfnStatusCB)
1300 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1301 &socketAddr, sizeof(struct sockaddr_in));
1303 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1305 ERR("Unable to connect (%s)\n", strerror(errno));
1306 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1308 else
1310 TRACE("Connected to server\n");
1311 if (hIC->lpfnStatusCB)
1312 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1313 &socketAddr, sizeof(struct sockaddr_in));
1315 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONA));
1316 if (NULL == lpwfs)
1318 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1319 goto lerror;
1322 lpwfs->hdr.htype = WH_HFTPSESSION;
1323 lpwfs->hdr.dwFlags = dwFlags;
1324 lpwfs->hdr.dwContext = dwContext;
1325 lpwfs->hdr.lpwhparent = (LPWININETHANDLEHEADER)hInternet;
1326 lpwfs->sndSocket = nsocket;
1327 sock_namelen = sizeof(lpwfs->socketAddress);
1328 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1329 lpwfs->phostent = phe;
1331 if (NULL == lpszUserName)
1333 lpwfs->lpszUserName = FTP_strdup("anonymous");
1334 lpwfs->lpszPassword = FTP_strdup("user@server");
1336 else
1338 lpwfs->lpszUserName = FTP_strdup(lpszUserName);
1339 lpwfs->lpszPassword = FTP_strdup(lpszPassword);
1342 if (FTP_ConnectToHost(lpwfs))
1344 if (hIC->lpfnStatusCB)
1346 INTERNET_ASYNC_RESULT iar;
1348 iar.dwResult = (DWORD)lpwfs;
1349 iar.dwError = ERROR_SUCCESS;
1351 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_HANDLE_CREATED,
1352 &iar, sizeof(INTERNET_ASYNC_RESULT));
1354 TRACE("Successfully logged into server\n");
1355 bSuccess = TRUE;
1359 lerror:
1360 if (!bSuccess && INVALID_SOCKET != nsocket)
1361 close(nsocket);
1363 if (!bSuccess && lpwfs)
1365 HeapFree(GetProcessHeap(), 0, lpwfs);
1366 lpwfs = NULL;
1369 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1371 INTERNET_ASYNC_RESULT iar;
1373 iar.dwResult = (DWORD)lpwfs;
1374 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1375 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1376 &iar, sizeof(INTERNET_ASYNC_RESULT));
1379 return (HINTERNET) lpwfs;
1383 /***********************************************************************
1384 * FTP_ConnectHost (internal)
1386 * Connect to a ftp server
1388 * RETURNS
1389 * TRUE on success
1390 * NULL on failure
1393 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs)
1395 INT nResCode;
1396 BOOL bSuccess = FALSE;
1398 TRACE("\n");
1399 FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1401 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1402 goto lend;
1404 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1405 MAX_REPLY_LEN, 0, 0, 0);
1406 if (nResCode)
1408 /* Login successful... */
1409 if (nResCode == 230)
1410 bSuccess = TRUE;
1411 /* User name okay, need password... */
1412 else if (nResCode == 331)
1413 bSuccess = FTP_SendPassword(lpwfs);
1414 /* Need account for login... */
1415 else if (nResCode == 332)
1416 bSuccess = FTP_SendAccount(lpwfs);
1417 else
1418 FTP_SetResponseError(nResCode);
1421 TRACE("Returning %d\n", bSuccess);
1422 lend:
1423 return bSuccess;
1427 /***********************************************************************
1428 * FTP_SendCommand (internal)
1430 * Send command to server
1432 * RETURNS
1433 * TRUE on success
1434 * NULL on failure
1437 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1438 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1440 DWORD len;
1441 CHAR *buf;
1442 DWORD nBytesSent = 0;
1443 DWORD nRC = 0;
1444 BOOL bParamHasLen;
1446 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1448 if (lpfnStatusCB)
1449 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1451 bParamHasLen = lpszParam && strlen(lpszParam) > 0;
1452 len = (bParamHasLen ? strlen(lpszParam) : -1) + strlen(szFtpCommands[ftpCmd]) +
1453 strlen(szCRLF)+ 1;
1454 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1456 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1457 return FALSE;
1459 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], bParamHasLen ? " " : "",
1460 bParamHasLen ? lpszParam : "", szCRLF);
1462 TRACE("Sending (%s) len(%ld)\n", buf, len);
1463 while((nBytesSent < len) && (nRC != SOCKET_ERROR))
1465 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1466 nBytesSent += nRC;
1469 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
1471 if (lpfnStatusCB)
1472 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_REQUEST_SENT,
1473 &nBytesSent, sizeof(DWORD));
1475 TRACE("Sent %ld bytes\n", nBytesSent);
1476 return (nRC != SOCKET_ERROR);
1480 /***********************************************************************
1481 * FTP_ReceiveResponse (internal)
1483 * Receive response from server
1485 * RETURNS
1486 * Reply code on success
1487 * 0 on failure
1491 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
1492 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1494 DWORD nRecv;
1495 INT rc = 0;
1496 char firstprefix[5];
1497 BOOL multiline = FALSE;
1500 TRACE("socket(%d) \n", nSocket);
1502 if (lpfnStatusCB)
1503 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1505 while(1)
1507 nRecv = dwResponse;
1508 if (!INTERNET_GetNextLine(nSocket, lpszResponse, &nRecv))
1509 goto lerror;
1511 if (nRecv >= 3)
1513 if(!multiline)
1515 if(lpszResponse[3] != '-')
1516 break;
1517 else
1518 { /* Start of multiline repsonse. Loop until we get "nnn " */
1519 multiline = TRUE;
1520 memcpy(firstprefix, lpszResponse, 3);
1521 firstprefix[3] = ' ';
1522 firstprefix[4] = '\0';
1525 else
1527 if(!memcmp(firstprefix, lpszResponse, 4))
1528 break;
1533 if (nRecv >= 3)
1535 lpszResponse[nRecv] = '\0';
1536 rc = atoi(lpszResponse);
1538 if (lpfnStatusCB)
1539 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
1540 &nRecv, sizeof(DWORD));
1543 lerror:
1544 TRACE("return %d\n", rc);
1545 return rc;
1549 /***********************************************************************
1550 * FTP_SendPassword (internal)
1552 * Send password to ftp server
1554 * RETURNS
1555 * TRUE on success
1556 * NULL on failure
1559 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs)
1561 INT nResCode;
1562 BOOL bSuccess = FALSE;
1564 TRACE("\n");
1565 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
1566 goto lend;
1568 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1569 MAX_REPLY_LEN, 0, 0, 0);
1570 if (nResCode)
1572 TRACE("Received reply code %d\n", nResCode);
1573 /* Login successful... */
1574 if (nResCode == 230)
1575 bSuccess = TRUE;
1576 /* Command not implemented, superfluous at the server site... */
1577 /* Need account for login... */
1578 else if (nResCode == 332)
1579 bSuccess = FTP_SendAccount(lpwfs);
1580 else
1581 FTP_SetResponseError(nResCode);
1584 lend:
1585 TRACE("Returning %d\n", bSuccess);
1586 return bSuccess;
1590 /***********************************************************************
1591 * FTP_SendAccount (internal)
1595 * RETURNS
1596 * TRUE on success
1597 * FALSE on failure
1600 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs)
1602 INT nResCode;
1603 BOOL bSuccess = FALSE;
1605 TRACE("\n");
1606 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, NOACCOUNT, 0, 0, 0))
1607 goto lend;
1609 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1610 MAX_REPLY_LEN, 0, 0, 0);
1611 if (nResCode)
1612 bSuccess = TRUE;
1613 else
1614 FTP_SetResponseError(nResCode);
1616 lend:
1617 return bSuccess;
1621 /***********************************************************************
1622 * FTP_SendStore (internal)
1624 * Send request to upload file to ftp server
1626 * RETURNS
1627 * TRUE on success
1628 * FALSE on failure
1631 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
1633 INT nResCode;
1634 BOOL bSuccess = FALSE;
1636 TRACE("\n");
1637 if (!FTP_InitListenSocket(lpwfs))
1638 goto lend;
1640 if (!FTP_SendType(lpwfs, dwType))
1641 goto lend;
1643 if (!FTP_SendPort(lpwfs))
1644 goto lend;
1646 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
1647 goto lend;
1648 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1649 MAX_REPLY_LEN, 0, 0, 0);
1650 if (nResCode)
1652 if (nResCode == 150)
1653 bSuccess = TRUE;
1654 else
1655 FTP_SetResponseError(nResCode);
1658 lend:
1659 if (!bSuccess && INVALID_SOCKET != lpwfs->lstnSocket)
1661 close(lpwfs->lstnSocket);
1662 lpwfs->lstnSocket = INVALID_SOCKET;
1665 return bSuccess;
1669 /***********************************************************************
1670 * FTP_InitListenSocket (internal)
1672 * Create a socket to listen for server response
1674 * RETURNS
1675 * TRUE on success
1676 * FALSE on failure
1679 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs)
1681 BOOL bSuccess = FALSE;
1682 size_t namelen = sizeof(struct sockaddr_in);
1684 TRACE("\n");
1686 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
1687 if (INVALID_SOCKET == lpwfs->lstnSocket)
1689 TRACE("Unable to create listening socket\n");
1690 goto lend;
1693 /* We obtain our ip addr from the name of the command channel socket */
1694 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
1696 /* and get the system to assign us a port */
1697 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
1699 if (SOCKET_ERROR == bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)))
1701 TRACE("Unable to bind socket\n");
1702 goto lend;
1705 if (SOCKET_ERROR == listen(lpwfs->lstnSocket, MAX_BACKLOG))
1707 TRACE("listen failed\n");
1708 goto lend;
1711 if (SOCKET_ERROR != getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen))
1712 bSuccess = TRUE;
1714 lend:
1715 if (!bSuccess && INVALID_SOCKET == lpwfs->lstnSocket)
1717 close(lpwfs->lstnSocket);
1718 lpwfs->lstnSocket = INVALID_SOCKET;
1721 return bSuccess;
1725 /***********************************************************************
1726 * FTP_SendType (internal)
1728 * Tell server type of data being transfered
1730 * RETURNS
1731 * TRUE on success
1732 * FALSE on failure
1735 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType)
1737 INT nResCode;
1738 CHAR type[2] = { "I\0" };
1739 BOOL bSuccess = FALSE;
1741 TRACE("\n");
1742 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
1743 *type = 'A';
1745 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
1746 goto lend;
1748 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1749 MAX_REPLY_LEN, 0, 0, 0)/100;
1750 if (nResCode)
1752 if (nResCode == 2)
1753 bSuccess = TRUE;
1754 else
1755 FTP_SetResponseError(nResCode);
1758 lend:
1759 return bSuccess;
1763 /***********************************************************************
1764 * FTP_SendPort (internal)
1766 * Tell server which port to use
1768 * RETURNS
1769 * TRUE on success
1770 * FALSE on failure
1773 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs)
1775 INT nResCode;
1776 CHAR szIPAddress[64];
1777 BOOL bSuccess = FALSE;
1778 TRACE("\n");
1780 sprintf(szIPAddress, "%d,%d,%d,%d,%d,%d",
1781 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
1782 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
1783 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
1784 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
1785 lpwfs->lstnSocketAddress.sin_port & 0xFF,
1786 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
1788 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
1789 goto lend;
1791 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1792 MAX_REPLY_LEN,0, 0, 0);
1793 if (nResCode)
1795 if (nResCode == 200)
1796 bSuccess = TRUE;
1797 else
1798 FTP_SetResponseError(nResCode);
1801 lend:
1802 return bSuccess;
1806 /***********************************************************************
1807 * FTP_InitDataSocket (internal)
1811 * RETURNS
1812 * TRUE on success
1813 * FALSE on failure
1816 BOOL FTP_InitDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket)
1818 struct sockaddr_in saddr;
1819 size_t addrlen = sizeof(struct sockaddr);
1821 TRACE("\n");
1822 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
1823 close(lpwfs->lstnSocket);
1824 lpwfs->lstnSocket = INVALID_SOCKET;
1826 return *nDataSocket != INVALID_SOCKET;
1830 /***********************************************************************
1831 * FTP_SendData (internal)
1833 * Send data to the server
1835 * RETURNS
1836 * TRUE on success
1837 * FALSE on failure
1840 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile)
1842 BY_HANDLE_FILE_INFORMATION fi;
1843 DWORD nBytesRead = 0;
1844 DWORD nBytesSent = 0;
1845 DWORD nTotalSent = 0;
1846 DWORD nBytesToSend, nLen, nRC = 1;
1847 time_t s_long_time, e_long_time;
1848 LONG nSeconds;
1849 CHAR *lpszBuffer;
1851 TRACE("\n");
1852 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
1853 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
1855 /* Get the size of the file. */
1856 GetFileInformationByHandle(hFile, &fi);
1857 time(&s_long_time);
1861 nBytesToSend = nBytesRead - nBytesSent;
1863 if (nBytesToSend <= 0)
1865 /* Read data from file. */
1866 nBytesSent = 0;
1867 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
1868 ERR("Failed reading from file\n");
1870 if (nBytesRead > 0)
1871 nBytesToSend = nBytesRead;
1872 else
1873 break;
1876 nLen = DATA_PACKET_SIZE < nBytesToSend ?
1877 DATA_PACKET_SIZE : nBytesToSend;
1878 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
1880 if (nRC != SOCKET_ERROR)
1882 nBytesSent += nRC;
1883 nTotalSent += nRC;
1886 /* Do some computation to display the status. */
1887 time(&e_long_time);
1888 nSeconds = e_long_time - s_long_time;
1889 if( nSeconds / 60 > 0 )
1891 TRACE( "%ld bytes of %d bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
1892 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
1893 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
1895 else
1897 TRACE( "%ld bytes of %d bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
1898 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
1899 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
1901 } while (nRC != SOCKET_ERROR);
1903 TRACE("file transfer complete!\n");
1905 if(lpszBuffer != NULL)
1906 HeapFree(GetProcessHeap(), 0, lpszBuffer);
1908 return nTotalSent;
1912 /***********************************************************************
1913 * FTP_SendRetrieve (internal)
1915 * Send request to retrieve a file
1917 * RETURNS
1918 * Number of bytes to be received on success
1919 * 0 on failure
1922 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
1924 INT nResCode;
1925 DWORD nResult = 0;
1927 TRACE("\n");
1928 if (!FTP_InitListenSocket(lpwfs))
1929 goto lend;
1931 if (!FTP_SendType(lpwfs, dwType))
1932 goto lend;
1934 if (!FTP_SendPort(lpwfs))
1935 goto lend;
1937 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
1938 goto lend;
1940 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1941 MAX_REPLY_LEN, 0, 0, 0);
1942 if (nResCode)
1944 if (nResCode == 125 || nResCode == 150)
1946 /* Parse size of data to be retrieved */
1947 INT i, sizepos = -1;
1948 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
1949 for (i = strlen(lpszResponseBuffer) - 1; i >= 0; i--)
1951 if ('(' == lpszResponseBuffer[i])
1953 sizepos = i;
1954 break;
1958 if (sizepos >= 0)
1960 nResult = atol(&lpszResponseBuffer[sizepos+1]);
1961 TRACE("Waiting to receive %ld bytes\n", nResult);
1966 lend:
1967 if (0 == nResult && INVALID_SOCKET != lpwfs->lstnSocket)
1969 close(lpwfs->lstnSocket);
1970 lpwfs->lstnSocket = INVALID_SOCKET;
1973 return nResult;
1977 /***********************************************************************
1978 * FTP_RetrieveData (internal)
1980 * Retrieve data from server
1982 * RETURNS
1983 * TRUE on success
1984 * FALSE on failure
1987 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
1989 DWORD nBytesWritten;
1990 DWORD nBytesReceived = 0;
1991 INT nRC = 0;
1992 CHAR *lpszBuffer;
1994 TRACE("\n");
1996 if (INVALID_HANDLE_VALUE == hFile)
1997 return FALSE;
1999 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2000 if (NULL == lpszBuffer)
2002 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2003 return FALSE;
2006 while (nBytesReceived < nBytes && nRC != SOCKET_ERROR)
2008 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2009 if (nRC != SOCKET_ERROR)
2011 /* other side closed socket. */
2012 if (nRC == 0)
2013 goto recv_end;
2014 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2015 nBytesReceived += nRC;
2018 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
2019 nBytesReceived * 100 / nBytes);
2022 TRACE("Data transfer complete\n");
2023 if (NULL != lpszBuffer)
2024 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2026 recv_end:
2027 return (nRC != SOCKET_ERROR);
2031 /***********************************************************************
2032 * FTP_CloseSessionHandle (internal)
2034 * Deallocate session handle
2036 * RETURNS
2037 * TRUE on success
2038 * FALSE on failure
2041 BOOL FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs)
2043 if (INVALID_SOCKET != lpwfs->sndSocket)
2044 close(lpwfs->sndSocket);
2046 if (INVALID_SOCKET != lpwfs->lstnSocket)
2047 close(lpwfs->lstnSocket);
2049 if (lpwfs->lpszPassword)
2050 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2052 if (lpwfs->lpszUserName)
2053 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2055 HeapFree(GetProcessHeap(), 0, lpwfs);
2057 return TRUE;
2061 /***********************************************************************
2062 * FTP_CloseSessionHandle (internal)
2064 * Deallocate session handle
2066 * RETURNS
2067 * TRUE on success
2068 * FALSE on failure
2071 BOOL FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn)
2073 INT i;
2075 TRACE("\n");
2077 for (i = 0; i < lpwfn->size; i++)
2079 if (NULL != lpwfn->lpafp[i].lpszName)
2080 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2083 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2084 HeapFree(GetProcessHeap(), 0, lpwfn);
2086 return TRUE;
2090 /***********************************************************************
2091 * FTP_ReceiveFileList (internal)
2093 * Read file list from server
2095 * RETURNS
2096 * Handle to file list on success
2097 * NULL on failure
2100 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
2101 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext)
2103 DWORD dwSize = 0;
2104 LPFILEPROPERTIESA lpafp = NULL;
2105 LPWININETFINDNEXTA lpwfn = NULL;
2107 TRACE("\n");
2109 if (FTP_ParseDirectory(lpwfs, nSocket, &lpafp, &dwSize))
2111 FTP_ConvertFileProp(lpafp, lpFindFileData);
2113 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTA));
2114 if (NULL != lpwfn)
2116 lpwfn->hdr.htype = WH_HFINDNEXT;
2117 lpwfn->hdr.lpwhparent = (LPWININETHANDLEHEADER)lpwfs;
2118 lpwfn->hdr.dwContext = dwContext;
2119 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2120 lpwfn->size = dwSize;
2121 lpwfn->lpafp = lpafp;
2125 TRACE("Matched %ld files\n", dwSize);
2126 return (HINTERNET)lpwfn;
2130 /***********************************************************************
2131 * FTP_ConvertFileProp (internal)
2133 * Converts FILEPROPERTIESA struct to WIN32_FIND_DATAA
2135 * RETURNS
2136 * TRUE on success
2137 * FALSE on failure
2140 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESA lpafp, LPWIN32_FIND_DATAA lpFindFileData)
2142 BOOL bSuccess = FALSE;
2144 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2146 if (lpafp)
2148 DWORD access = mktime(&lpafp->tmLastModified);
2150 /* Not all fields are filled in */
2151 lpFindFileData->ftLastAccessTime.dwHighDateTime = HIWORD(access);
2152 lpFindFileData->ftLastAccessTime.dwLowDateTime = LOWORD(access);
2153 lpFindFileData->nFileSizeHigh = HIWORD(lpafp->nSize);
2154 lpFindFileData->nFileSizeLow = LOWORD(lpafp->nSize);
2156 if (lpafp->bIsDirectory)
2157 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2159 if (lpafp->lpszName)
2160 strncpy(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2162 bSuccess = TRUE;
2165 return bSuccess;
2169 /***********************************************************************
2170 * FTP_ParseDirectory (internal)
2172 * Parse string of directory information
2174 * RETURNS
2175 * TRUE on success
2176 * FALSE on failure
2178 * FIXME: - This function needs serious clea-up
2179 * - We should consider both UNIX and NT list formats
2181 #define MAX_MONTH_LEN 10
2182 #define MIN_LEN_DIR_ENTRY 15
2184 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp)
2187 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2189 * For instance:
2190 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2192 CHAR* pszMinutes;
2193 CHAR* pszHour;
2194 time_t aTime;
2195 struct tm* apTM;
2196 CHAR pszMonth[MAX_MONTH_LEN];
2197 CHAR* pszMatch;
2198 BOOL bSuccess = TRUE;
2199 DWORD nBufLen = MAX_REPLY_LEN;
2200 LPFILEPROPERTIESA curFileProp = NULL;
2201 CHAR* pszLine = NULL;
2202 CHAR* pszToken = NULL;
2203 INT nTokenToSkip = 3;
2204 INT nCount = 0;
2205 INT nSeconds = 0;
2206 INT nMinutes = 0;
2207 INT nHour = 0;
2208 INT nDay = 0;
2209 INT nMonth = 0;
2210 INT nYear = 0;
2211 INT sizeFilePropArray = 20;
2212 INT indexFilePropArray = 0;
2214 TRACE("\n");
2216 /* Allocate intial file properties array */
2217 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESA)*(sizeFilePropArray));
2218 if (NULL == lpafp)
2220 bSuccess = FALSE;
2221 goto lend;
2224 while ((pszLine = INTERNET_GetNextLine(nSocket, INTERNET_GetResponseBuffer(), &nBufLen)) != NULL)
2226 if (sizeFilePropArray <= indexFilePropArray)
2228 LPFILEPROPERTIESA tmpafp;
2230 sizeFilePropArray *= 2;
2231 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
2232 sizeof(FILEPROPERTIESA)*sizeFilePropArray);
2233 if (NULL == tmpafp)
2235 bSuccess = FALSE;
2236 goto lend;
2239 *lpafp = tmpafp;
2242 curFileProp = &((*lpafp)[indexFilePropArray]);
2244 /* First Parse the permissions. */
2245 pszToken = strtok(pszLine, " \t" );
2247 /* HACK! If this is not a file listing skip the line */
2248 if (!pszToken || 10 != strlen(pszToken) || nBufLen <= MIN_LEN_DIR_ENTRY)
2250 nBufLen = MAX_REPLY_LEN;
2251 continue;
2254 FTP_ParsePermission(pszToken, curFileProp);
2256 nTokenToSkip = 3;
2257 nCount = 0;
2260 pszToken = strtok( NULL, " \t" );
2261 nCount++;
2262 } while( nCount <= nTokenToSkip );
2264 /* Store the size of the file in the param list. */
2265 TRACE("nSize-> %s\n", pszToken);
2266 if (pszToken != NULL)
2267 curFileProp->nSize = atol(pszToken);
2269 /* Parse last modified time. */
2270 nSeconds = 0;
2271 nMinutes = 0;
2272 nHour = 0;
2273 nDay = 0;
2274 nMonth = 0;
2275 nYear = 0;
2277 pszToken = strtok( NULL, " \t" );
2278 strncpy(pszMonth, pszToken, MAX_MONTH_LEN);
2279 CharUpperA(pszMonth);
2280 pszMatch = strstr(szMonths, pszMonth);
2281 if( pszMatch != NULL )
2282 nMonth = (pszMatch - szMonths) / 3;
2284 pszToken = strtok(NULL, " \t");
2285 TRACE("nDay -> %s\n", pszToken);
2286 if (pszToken != NULL)
2287 nDay = atoi(pszToken);
2289 pszToken = strtok(NULL, " \t");
2290 pszMinutes = strchr(pszToken, ':');
2291 if( pszMinutes != NULL )
2293 pszMinutes++;
2294 nMinutes = atoi(pszMinutes);
2295 pszHour = pszMinutes - 3;
2296 if (pszHour != NULL)
2297 nHour = atoi(pszHour);
2298 time(&aTime);
2299 apTM = localtime( &aTime );
2300 nYear = apTM->tm_year;
2302 else
2304 nYear = atoi(pszToken);
2305 nYear -= 1900;
2306 nHour = 12;
2309 curFileProp->tmLastModified.tm_sec = nSeconds;
2310 curFileProp->tmLastModified.tm_min = nMinutes;
2311 curFileProp->tmLastModified.tm_hour = nHour;
2312 curFileProp->tmLastModified.tm_mday = nDay;
2313 curFileProp->tmLastModified.tm_mon = nMonth;
2314 curFileProp->tmLastModified.tm_year = nYear;
2316 pszToken = strtok(NULL, " \t");
2317 if(pszToken != NULL)
2319 curFileProp->lpszName = FTP_strdup(pszToken);
2320 TRACE(": %s\n", curFileProp->lpszName);
2323 nBufLen = MAX_REPLY_LEN;
2324 indexFilePropArray++;
2327 if (bSuccess && indexFilePropArray)
2329 if (indexFilePropArray < sizeFilePropArray - 1)
2331 LPFILEPROPERTIESA tmpafp;
2333 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
2334 sizeof(FILEPROPERTIESA)*indexFilePropArray);
2335 if (NULL == tmpafp)
2336 *lpafp = tmpafp;
2338 *dwfp = indexFilePropArray;
2340 else
2342 HeapFree(GetProcessHeap(), 0, *lpafp);
2343 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2344 bSuccess = FALSE;
2347 lend:
2348 return bSuccess;
2352 /***********************************************************************
2353 * FTP_ParsePermission (internal)
2355 * Parse permission string of directory information
2357 * RETURNS
2358 * TRUE on success
2359 * FALSE on failure
2362 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp)
2364 BOOL bSuccess = TRUE;
2365 unsigned short nPermission = 0;
2366 INT nPos = 1;
2367 INT nLast = 9;
2369 TRACE("\n");
2370 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
2372 bSuccess = FALSE;
2373 return bSuccess;
2376 lpfp->bIsDirectory = (*lpszPermission == 'd');
2379 switch (nPos)
2381 case 1:
2382 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
2383 break;
2384 case 2:
2385 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
2386 break;
2387 case 3:
2388 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
2389 break;
2390 case 4:
2391 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
2392 break;
2393 case 5:
2394 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
2395 break;
2396 case 6:
2397 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
2398 break;
2399 case 7:
2400 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
2401 break;
2402 case 8:
2403 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
2404 break;
2405 case 9:
2406 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
2407 break;
2409 nPos++;
2410 }while (nPos <= nLast);
2412 lpfp->permissions = nPermission;
2413 return bSuccess;
2417 /***********************************************************************
2418 * FTP_SetResponseError (internal)
2420 * Set the appropriate error code for a given response from the server
2422 * RETURNS
2425 DWORD FTP_SetResponseError(DWORD dwResponse)
2427 DWORD dwCode = 0;
2429 switch(dwResponse)
2431 case 421: /* Service not available - Server may be shutting down. */
2432 dwCode = ERROR_INTERNET_TIMEOUT;
2433 break;
2435 case 425: /* Cannot open data connection. */
2436 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
2437 break;
2439 case 426: /* Connection closed, transer aborted. */
2440 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
2441 break;
2443 case 500: /* Syntax error. Command unrecognized. */
2444 case 501: /* Syntax error. Error in parameters or arguments. */
2445 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
2446 break;
2448 case 530: /* Not logged in. Login incorrect. */
2449 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
2450 break;
2452 case 550: /* File action not taken. File not found or no access. */
2453 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
2454 break;
2456 case 450: /* File action not taken. File may be busy. */
2457 case 451: /* Action aborted. Server error. */
2458 case 452: /* Action not taken. Insufficient storage space on server. */
2459 case 502: /* Command not implemented. */
2460 case 503: /* Bad sequence of command. */
2461 case 504: /* Command not implemented for that parameter. */
2462 case 532: /* Need account for storing files */
2463 case 551: /* Requested action aborted. Page type unknown */
2464 case 552: /* Action aborted. Exceeded storage allocation */
2465 case 553: /* Action not taken. File name not allowed. */
2467 default:
2468 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
2469 break;
2472 INTERNET_SetLastError(dwCode);
2473 return dwCode;