Add some specific afmdirs as examples.
[wine/testsucceed.git] / dlls / wininet / ftp.c
blobea4604b0ba608000d5381b8438a8640568204f2b
1 /*
2 * WININET - Ftp implementation
4 * Copyright 1999 Corel Corporation
6 * Ulrich Czekalla
7 * Noureddine Jemmali
9 * Copyright 2000 Andreas Mohr
12 #include "config.h"
14 #include <errno.h>
15 #ifdef HAVE_NETDB_H
16 # include <netdb.h>
17 #endif
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <sys/types.h>
22 #ifdef HAVE_SYS_SOCKET_H
23 # include <sys/socket.h>
24 #endif
25 #include <sys/stat.h>
26 #include <unistd.h>
27 #include <time.h>
28 #ifdef HAVE_NETINET_IN_SYSTM_H
29 # include <netinet/in_systm.h>
30 #endif
31 #ifdef HAVE_NETINET_IN_H
32 # include <netinet/in.h>
33 #endif
34 #ifdef HAVE_NETINET_IP_H
35 # include <netinet/ip.h>
36 #endif
38 #include "winbase.h"
39 #include "wingdi.h"
40 #include "winuser.h"
41 #include "wininet.h"
42 #include "winerror.h"
43 #include "winsock.h"
44 #include "heap.h"
46 #include "debugtools.h"
47 #include "internet.h"
49 DEFAULT_DEBUG_CHANNEL(wininet);
51 #define NOACCOUNT "noaccount"
52 #define DATA_PACKET_SIZE 0x2000
53 #define szCRLF "\r\n"
54 #define MAX_BACKLOG 5
56 typedef enum {
57 /* FTP commands with arguments. */
58 FTP_CMD_ACCT,
59 FTP_CMD_CWD,
60 FTP_CMD_DELE,
61 FTP_CMD_MKD,
62 FTP_CMD_PASS,
63 FTP_CMD_PORT,
64 FTP_CMD_RETR,
65 FTP_CMD_RMD,
66 FTP_CMD_RNFR,
67 FTP_CMD_RNTO,
68 FTP_CMD_STOR,
69 FTP_CMD_TYPE,
70 FTP_CMD_USER,
72 /* FTP commands without arguments. */
73 FTP_CMD_ABOR,
74 FTP_CMD_LIST,
75 FTP_CMD_NLST,
76 FTP_CMD_PASV,
77 FTP_CMD_PWD,
78 FTP_CMD_QUIT,
79 } FTP_COMMAND;
81 static const CHAR *szFtpCommands[] = {
82 "ACCT",
83 "CWD",
84 "DELE",
85 "MKD",
86 "PASS",
87 "PORT",
88 "RETR",
89 "RMD",
90 "RNFR",
91 "RNTO",
92 "STOR",
93 "TYPE",
94 "USER",
95 "ABOR",
96 "LIST",
97 "NLST",
98 "PASV",
99 "PWD",
100 "QUIT",
103 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
105 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
106 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
107 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
108 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket);
109 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile);
110 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
111 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
112 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
113 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile);
114 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs);
115 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs);
116 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs);
117 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs);
118 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType);
119 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs);
120 BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs);
121 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs);
122 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp);
123 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp);
124 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
125 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext);
126 DWORD FTP_SetResponseError(DWORD dwResponse);
128 inline static LPSTR FTP_strdup( LPCSTR str )
130 LPSTR ret = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
131 if (ret) strcpy( ret, str );
132 return ret;
135 /***********************************************************************
136 * FtpPutFileA (WININET.43)
138 * Uploads a file to the FTP server
140 * RETURNS
141 * TRUE on success
142 * FALSE on failure
145 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
146 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
148 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
149 LPWININETAPPINFOA hIC = NULL;
151 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
153 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
154 return FALSE;
157 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
158 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
160 WORKREQUEST workRequest;
162 workRequest.asyncall = FTPPUTFILEA;
163 workRequest.HFTPSESSION = (DWORD)hConnect;
164 workRequest.LPSZLOCALFILE = (DWORD)FTP_strdup(lpszLocalFile);
165 workRequest.LPSZNEWREMOTEFILE = (DWORD)FTP_strdup(lpszNewRemoteFile);
166 workRequest.DWFLAGS = dwFlags;
167 workRequest.DWCONTEXT = dwContext;
169 return INTERNET_AsyncCall(&workRequest);
171 else
173 return FTP_FtpPutFileA(hConnect, lpszLocalFile,
174 lpszNewRemoteFile, dwFlags, dwContext);
178 /***********************************************************************
179 * FTP_FtpPutFileA (Internal)
181 * Uploads a file to the FTP server
183 * RETURNS
184 * TRUE on success
185 * FALSE on failure
188 BOOL WINAPI FTP_FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
189 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
191 HANDLE hFile = (HANDLE)NULL;
192 BOOL bSuccess = FALSE;
193 LPWININETAPPINFOA hIC = NULL;
194 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
195 INT nResCode;
197 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", lpszLocalFile, lpszNewRemoteFile);
198 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
200 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
201 return FALSE;
204 /* Clear any error information */
205 INTERNET_SetLastError(0);
207 /* Open file to be uploaded */
208 if (INVALID_HANDLE_VALUE ==
209 (hFile = CreateFileA(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
211 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND);
212 goto lend;
215 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
216 if (hIC->lpfnStatusCB)
217 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
219 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
221 INT nDataSocket;
223 /* Get data socket to server */
224 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
226 FTP_SendData(lpwfs, nDataSocket, hFile);
227 close(nDataSocket);
228 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
229 MAX_REPLY_LEN, 0, 0, 0);
230 if (nResCode)
232 if (nResCode == 226)
233 bSuccess = TRUE;
234 else
235 FTP_SetResponseError(nResCode);
240 lend:
241 if (lpwfs->lstnSocket != INVALID_SOCKET)
242 close(lpwfs->lstnSocket);
244 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
246 INTERNET_ASYNC_RESULT iar;
248 iar.dwResult = (DWORD)bSuccess;
249 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
250 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
251 &iar, sizeof(INTERNET_ASYNC_RESULT));
254 if (hFile)
255 CloseHandle(hFile);
257 return bSuccess;
261 /***********************************************************************
262 * FtpSetCurrentDirectoryA (WININET.49)
264 * Change the working directory on the FTP server
266 * RETURNS
267 * TRUE on success
268 * FALSE on failure
271 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
273 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
274 LPWININETAPPINFOA hIC = NULL;
276 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
278 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
279 return FALSE;
282 TRACE("lpszDirectory(%s)\n", lpszDirectory);
284 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
285 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
287 WORKREQUEST workRequest;
289 workRequest.asyncall = FTPSETCURRENTDIRECTORYA;
290 workRequest.HFTPSESSION = (DWORD)hConnect;
291 workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
293 return INTERNET_AsyncCall(&workRequest);
295 else
297 return FTP_FtpSetCurrentDirectoryA(hConnect, lpszDirectory);
302 /***********************************************************************
303 * FTP_FtpSetCurrentDirectoryA (Internal)
305 * Change the working directory on the FTP server
307 * RETURNS
308 * TRUE on success
309 * FALSE on failure
312 BOOL WINAPI FTP_FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
314 INT nResCode;
315 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
316 LPWININETAPPINFOA hIC = NULL;
317 DWORD bSuccess = FALSE;
319 TRACE("lpszDirectory(%s)\n", lpszDirectory);
321 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
323 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
324 return FALSE;
327 /* Clear any error information */
328 INTERNET_SetLastError(0);
330 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
331 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
332 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
333 goto lend;
335 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
336 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
338 if (nResCode)
340 if (nResCode == 250)
341 bSuccess = TRUE;
342 else
343 FTP_SetResponseError(nResCode);
346 lend:
347 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
349 INTERNET_ASYNC_RESULT iar;
351 iar.dwResult = (DWORD)bSuccess;
352 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
353 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
354 &iar, sizeof(INTERNET_ASYNC_RESULT));
356 return bSuccess;
360 /***********************************************************************
361 * FtpCreateDirectoryA (WININET.31)
363 * Create new directory on the FTP server
365 * RETURNS
366 * TRUE on success
367 * FALSE on failure
370 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
372 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
373 LPWININETAPPINFOA hIC = NULL;
375 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
377 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
378 return FALSE;
381 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
382 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
384 WORKREQUEST workRequest;
386 workRequest.asyncall = FTPCREATEDIRECTORYA;
387 workRequest.HFTPSESSION = (DWORD)hConnect;
388 workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
390 return INTERNET_AsyncCall(&workRequest);
392 else
394 return FTP_FtpCreateDirectoryA(hConnect, lpszDirectory);
399 /***********************************************************************
400 * FTP_FtpCreateDirectoryA (Internal)
402 * Create new directory on the FTP server
404 * RETURNS
405 * TRUE on success
406 * FALSE on failure
409 BOOL WINAPI FTP_FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
411 INT nResCode;
412 BOOL bSuccess = FALSE;
413 LPWININETAPPINFOA hIC = NULL;
414 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
416 TRACE("\n");
417 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
419 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
420 return FALSE;
423 /* Clear any error information */
424 INTERNET_SetLastError(0);
426 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
427 goto lend;
429 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
430 MAX_REPLY_LEN, 0, 0, 0);
431 if (nResCode)
433 if (nResCode == 257)
434 bSuccess = TRUE;
435 else
436 FTP_SetResponseError(nResCode);
439 lend:
440 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
441 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
443 INTERNET_ASYNC_RESULT iar;
445 iar.dwResult = (DWORD)bSuccess;
446 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
447 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
448 &iar, sizeof(INTERNET_ASYNC_RESULT));
451 return bSuccess;
455 /***********************************************************************
456 * FtpFindFirstFileA (WININET.35)
458 * Search the specified directory
460 * RETURNS
461 * HINTERNET on success
462 * NULL on failure
465 INTERNETAPI HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
466 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
468 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
469 LPWININETAPPINFOA hIC = NULL;
471 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
473 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
474 return FALSE;
477 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
478 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
480 WORKREQUEST workRequest;
482 workRequest.asyncall = FTPFINDFIRSTFILEA;
483 workRequest.HFTPSESSION = (DWORD)hConnect;
484 workRequest.LPSZSEARCHFILE = (DWORD)FTP_strdup(lpszSearchFile);
485 workRequest.LPFINDFILEDATA = (DWORD)lpFindFileData;
486 workRequest.DWFLAGS = dwFlags;
487 workRequest.DWCONTEXT= dwContext;
489 INTERNET_AsyncCall(&workRequest);
490 return NULL;
492 else
494 return FTP_FtpFindFirstFileA(hConnect, lpszSearchFile, lpFindFileData,
495 dwFlags, dwContext);
500 /***********************************************************************
501 * FTP_FtpFindFirstFileA (Internal)
503 * Search the specified directory
505 * RETURNS
506 * HINTERNET on success
507 * NULL on failure
510 INTERNETAPI HINTERNET WINAPI FTP_FtpFindFirstFileA(HINTERNET hConnect,
511 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
513 INT nResCode;
514 LPWININETAPPINFOA hIC = NULL;
515 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
516 LPWININETFINDNEXTA hFindNext = NULL;
518 TRACE("\n");
520 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
522 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
523 return FALSE;
526 /* Clear any error information */
527 INTERNET_SetLastError(0);
529 if (!FTP_InitListenSocket(lpwfs))
530 goto lend;
532 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
533 goto lend;
535 if (!FTP_SendPortOrPasv(lpwfs))
536 goto lend;
538 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
539 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, lpszSearchFile,
540 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
541 goto lend;
543 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
544 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
545 if (nResCode)
547 if (nResCode == 125 || nResCode == 150)
549 INT nDataSocket;
551 /* Get data socket to server */
552 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
554 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpFindFileData, dwContext);
556 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
557 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
558 if (nResCode != 226 && nResCode != 250)
559 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
561 close(nDataSocket);
564 else
565 FTP_SetResponseError(nResCode);
568 lend:
569 if (lpwfs->lstnSocket != INVALID_SOCKET)
570 close(lpwfs->lstnSocket);
572 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
574 INTERNET_ASYNC_RESULT iar;
576 if (hFindNext)
578 iar.dwResult = (DWORD)hFindNext;
579 iar.dwError = ERROR_SUCCESS;
580 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
581 &iar, sizeof(INTERNET_ASYNC_RESULT));
584 iar.dwResult = (DWORD)hFindNext;
585 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
586 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
587 &iar, sizeof(INTERNET_ASYNC_RESULT));
590 return (HINTERNET)hFindNext;
594 /***********************************************************************
595 * FtpGetCurrentDirectoryA (WININET.37)
597 * Retrieves the current directory
599 * RETURNS
600 * TRUE on success
601 * FALSE on failure
604 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
605 LPDWORD lpdwCurrentDirectory)
607 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
608 LPWININETAPPINFOA hIC = NULL;
610 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
612 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
614 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
615 return FALSE;
618 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
619 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
621 WORKREQUEST workRequest;
623 workRequest.asyncall = FTPGETCURRENTDIRECTORYA;
624 workRequest.HFTPSESSION = (DWORD)hFtpSession;
625 workRequest.LPSZDIRECTORY = (DWORD)lpszCurrentDirectory;
626 workRequest.LPDWDIRECTORY = (DWORD)lpdwCurrentDirectory;
628 return INTERNET_AsyncCall(&workRequest);
630 else
632 return FTP_FtpGetCurrentDirectoryA(hFtpSession, lpszCurrentDirectory,
633 lpdwCurrentDirectory);
638 /***********************************************************************
639 * FTP_FtpGetCurrentDirectoryA (Internal)
641 * Retrieves the current directory
643 * RETURNS
644 * TRUE on success
645 * FALSE on failure
648 BOOL WINAPI FTP_FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
649 LPDWORD lpdwCurrentDirectory)
651 INT nResCode;
652 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
653 LPWININETAPPINFOA hIC = NULL;
654 DWORD bSuccess = FALSE;
656 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
658 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
660 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
661 return FALSE;
664 /* Clear any error information */
665 INTERNET_SetLastError(0);
667 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
669 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
670 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
671 hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext))
672 goto lend;
674 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
675 MAX_REPLY_LEN, hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext);
676 if (nResCode)
678 if (nResCode == 257) /* Extract directory name */
680 INT firstpos, lastpos, len;
681 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
683 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
685 if ('"' == lpszResponseBuffer[lastpos])
687 if (!firstpos)
688 firstpos = lastpos;
689 else
690 break;
694 len = lastpos - firstpos - 1;
695 strncpy(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1],
696 len < *lpdwCurrentDirectory ? len : *lpdwCurrentDirectory);
697 *lpdwCurrentDirectory = len;
698 bSuccess = TRUE;
700 else
701 FTP_SetResponseError(nResCode);
704 lend:
705 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
707 INTERNET_ASYNC_RESULT iar;
709 iar.dwResult = (DWORD)bSuccess;
710 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
711 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
712 &iar, sizeof(INTERNET_ASYNC_RESULT));
715 return (DWORD) bSuccess;
718 /***********************************************************************
719 * FtpOpenFileA (WININET.41)
721 * Open a remote file for writing or reading
723 * RETURNS
724 * HINTERNET handle on success
725 * NULL on failure
728 INTERNETAPI HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
729 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
730 DWORD dwContext)
732 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
733 LPWININETAPPINFOA hIC = NULL;
735 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
737 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
738 return FALSE;
741 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
742 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
744 WORKREQUEST workRequest;
746 workRequest.asyncall = FTPOPENFILEA;
747 workRequest.HFTPSESSION = (DWORD)hFtpSession;
748 workRequest.LPSZFILENAME = (DWORD)FTP_strdup(lpszFileName);
749 workRequest.FDWACCESS = fdwAccess;
750 workRequest.DWFLAGS = dwFlags;
751 workRequest.DWCONTEXT = dwContext;
753 INTERNET_AsyncCall(&workRequest);
754 return NULL;
756 else
758 return FTP_FtpOpenFileA(hFtpSession, lpszFileName, fdwAccess, dwFlags, dwContext);
763 /***********************************************************************
764 * FTP_FtpOpenFileA (Internal)
766 * Open a remote file for writing or reading
768 * RETURNS
769 * HINTERNET handle on success
770 * NULL on failure
773 HINTERNET FTP_FtpOpenFileA(HINTERNET hFtpSession,
774 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
775 DWORD dwContext)
777 INT nDataSocket;
778 BOOL bSuccess = FALSE;
779 LPWININETFILE hFile = NULL;
780 LPWININETAPPINFOA hIC = NULL;
781 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
783 TRACE("\n");
785 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
787 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
788 return FALSE;
791 /* Clear any error information */
792 INTERNET_SetLastError(0);
794 if (GENERIC_READ == fdwAccess)
796 /* Set up socket to retrieve data */
797 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
799 else if (GENERIC_WRITE == fdwAccess)
801 /* Set up socket to send data */
802 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
805 /* Get data socket to server */
806 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
808 hFile = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE));
809 hFile->hdr.htype = WH_HFILE;
810 hFile->hdr.dwFlags = dwFlags;
811 hFile->hdr.dwContext = dwContext;
812 hFile->hdr.lpwhparent = hFtpSession;
813 hFile->nDataSocket = nDataSocket;
816 if (lpwfs->lstnSocket != INVALID_SOCKET)
817 close(lpwfs->lstnSocket);
819 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
820 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
822 INTERNET_ASYNC_RESULT iar;
824 if (hFile)
826 iar.dwResult = (DWORD)hFile;
827 iar.dwError = ERROR_SUCCESS;
828 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
829 &iar, sizeof(INTERNET_ASYNC_RESULT));
832 iar.dwResult = (DWORD)bSuccess;
833 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
834 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
835 &iar, sizeof(INTERNET_ASYNC_RESULT));
838 return (HINTERNET)hFile;
842 /***********************************************************************
843 * FtpGetFileA (WININET.39)
845 * Retrieve file from the FTP server
847 * RETURNS
848 * TRUE on success
849 * FALSE on failure
852 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
853 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
854 DWORD dwContext)
856 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet;
857 LPWININETAPPINFOA hIC = NULL;
859 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
861 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
862 return FALSE;
865 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
866 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
868 WORKREQUEST workRequest;
870 workRequest.asyncall = FTPGETFILEA;
871 workRequest.HFTPSESSION = (DWORD)hInternet;
872 workRequest.LPSZREMOTEFILE = (DWORD)FTP_strdup(lpszRemoteFile);
873 workRequest.LPSZNEWFILE = (DWORD)FTP_strdup(lpszNewFile);
874 workRequest.DWLOCALFLAGSATTRIBUTE = dwLocalFlagsAttribute;
875 workRequest.FFAILIFEXISTS = (DWORD)fFailIfExists;
876 workRequest.DWFLAGS = dwInternetFlags;
877 workRequest.DWCONTEXT = dwContext;
879 return INTERNET_AsyncCall(&workRequest);
881 else
883 return FTP_FtpGetFileA(hInternet, lpszRemoteFile, lpszNewFile,
884 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
889 /***********************************************************************
890 * FTP_FtpGetFileA (Internal)
892 * Retrieve file from the FTP server
894 * RETURNS
895 * TRUE on success
896 * FALSE on failure
899 BOOL WINAPI FTP_FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
900 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
901 DWORD dwContext)
903 DWORD nBytes;
904 BOOL bSuccess = FALSE;
905 HANDLE hFile;
906 LPWININETAPPINFOA hIC = NULL;
907 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet;
909 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", lpszRemoteFile, lpszNewFile);
910 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
912 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
913 return FALSE;
916 /* Clear any error information */
917 INTERNET_SetLastError(0);
919 /* Ensure we can write to lpszNewfile by opening it */
920 hFile = CreateFileA(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
921 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
922 if (INVALID_HANDLE_VALUE == hFile)
923 goto lend;
925 /* Set up socket to retrieve data */
926 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
928 if (nBytes > 0)
930 INT nDataSocket;
932 /* Get data socket to server */
933 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
935 INT nResCode;
937 /* Receive data */
938 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
939 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
940 MAX_REPLY_LEN, 0, 0, 0);
941 if (nResCode)
943 if (nResCode == 226)
944 bSuccess = TRUE;
945 else
946 FTP_SetResponseError(nResCode);
948 close(nDataSocket);
952 lend:
953 if (lpwfs->lstnSocket != INVALID_SOCKET)
954 close(lpwfs->lstnSocket);
956 if (hFile)
957 CloseHandle(hFile);
959 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
960 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
962 INTERNET_ASYNC_RESULT iar;
964 iar.dwResult = (DWORD)bSuccess;
965 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
966 hIC->lpfnStatusCB(hInternet, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
967 &iar, sizeof(INTERNET_ASYNC_RESULT));
970 return bSuccess;
974 /***********************************************************************
975 * FtpDeleteFileA (WININET.33)
977 * Delete a file on the ftp server
979 * RETURNS
980 * TRUE on success
981 * FALSE on failure
984 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
986 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
987 LPWININETAPPINFOA hIC = NULL;
989 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
991 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
992 return FALSE;
995 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
996 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
998 WORKREQUEST workRequest;
1000 workRequest.asyncall = FTPRENAMEFILEA;
1001 workRequest.HFTPSESSION = (DWORD)hFtpSession;
1002 workRequest.LPSZFILENAME = (DWORD)FTP_strdup(lpszFileName);
1004 return INTERNET_AsyncCall(&workRequest);
1006 else
1008 return FTP_FtpDeleteFileA(hFtpSession, lpszFileName);
1013 /***********************************************************************
1014 * FTP_FtpDeleteFileA (Internal)
1016 * Delete a file on the ftp server
1018 * RETURNS
1019 * TRUE on success
1020 * FALSE on failure
1023 BOOL FTP_FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1025 INT nResCode;
1026 BOOL bSuccess = FALSE;
1027 LPWININETAPPINFOA hIC = NULL;
1028 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1030 TRACE("0x%08lx\n", (ULONG) hFtpSession);
1031 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1033 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1034 return FALSE;
1037 /* Clear any error information */
1038 INTERNET_SetLastError(0);
1040 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1041 goto lend;
1043 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1044 MAX_REPLY_LEN, 0, 0, 0);
1045 if (nResCode)
1047 if (nResCode == 250)
1048 bSuccess = TRUE;
1049 else
1050 FTP_SetResponseError(nResCode);
1052 lend:
1053 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1054 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1056 INTERNET_ASYNC_RESULT iar;
1058 iar.dwResult = (DWORD)bSuccess;
1059 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1060 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1061 &iar, sizeof(INTERNET_ASYNC_RESULT));
1064 return bSuccess;
1068 /***********************************************************************
1069 * FtpRemoveDirectoryA (WININET.45)
1071 * Remove a directory on the ftp server
1073 * RETURNS
1074 * TRUE on success
1075 * FALSE on failure
1078 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1080 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1081 LPWININETAPPINFOA hIC = NULL;
1083 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1085 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1086 return FALSE;
1089 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1090 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1092 WORKREQUEST workRequest;
1094 workRequest.asyncall = FTPREMOVEDIRECTORYA;
1095 workRequest.HFTPSESSION = (DWORD)hFtpSession;
1096 workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
1098 return INTERNET_AsyncCall(&workRequest);
1100 else
1102 return FTP_FtpRemoveDirectoryA(hFtpSession, lpszDirectory);
1107 /***********************************************************************
1108 * FTP_FtpRemoveDirectoryA (Internal)
1110 * Remove a directory on the ftp server
1112 * RETURNS
1113 * TRUE on success
1114 * FALSE on failure
1117 BOOL FTP_FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1119 INT nResCode;
1120 BOOL bSuccess = FALSE;
1121 LPWININETAPPINFOA hIC = NULL;
1122 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1124 TRACE("\n");
1125 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1127 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1128 return FALSE;
1131 /* Clear any error information */
1132 INTERNET_SetLastError(0);
1134 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1135 goto lend;
1137 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1138 MAX_REPLY_LEN, 0, 0, 0);
1139 if (nResCode)
1141 if (nResCode == 250)
1142 bSuccess = TRUE;
1143 else
1144 FTP_SetResponseError(nResCode);
1147 lend:
1148 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1149 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1151 INTERNET_ASYNC_RESULT iar;
1153 iar.dwResult = (DWORD)bSuccess;
1154 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1155 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1156 &iar, sizeof(INTERNET_ASYNC_RESULT));
1159 return bSuccess;
1163 /***********************************************************************
1164 * FtpRenameFileA (WININET.47)
1166 * Rename a file on the ftp server
1168 * RETURNS
1169 * TRUE on success
1170 * FALSE on failure
1173 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1175 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1176 LPWININETAPPINFOA hIC = NULL;
1178 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1180 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1181 return FALSE;
1184 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1185 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1187 WORKREQUEST workRequest;
1189 workRequest.asyncall = FTPRENAMEFILEA;
1190 workRequest.HFTPSESSION = (DWORD)hFtpSession;
1191 workRequest.LPSZSRCFILE = (DWORD)FTP_strdup(lpszSrc);
1192 workRequest.LPSZDESTFILE = (DWORD)FTP_strdup(lpszDest);
1194 return INTERNET_AsyncCall(&workRequest);
1196 else
1198 return FTP_FtpRenameFileA(hFtpSession, lpszSrc, lpszDest);
1202 /***********************************************************************
1203 * FTP_FtpRenameFileA (Internal)
1205 * Rename a file on the ftp server
1207 * RETURNS
1208 * TRUE on success
1209 * FALSE on failure
1212 BOOL FTP_FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1214 INT nResCode;
1215 BOOL bSuccess = FALSE;
1216 LPWININETAPPINFOA hIC = NULL;
1217 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1219 TRACE("\n");
1220 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1222 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1223 return FALSE;
1226 /* Clear any error information */
1227 INTERNET_SetLastError(0);
1229 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1230 goto lend;
1232 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1233 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1234 if (nResCode == 350)
1236 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1237 goto lend;
1239 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1240 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1243 if (nResCode == 250)
1244 bSuccess = TRUE;
1245 else
1246 FTP_SetResponseError(nResCode);
1248 lend:
1249 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1250 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1252 INTERNET_ASYNC_RESULT iar;
1254 iar.dwResult = (DWORD)bSuccess;
1255 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1256 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1257 &iar, sizeof(INTERNET_ASYNC_RESULT));
1260 return bSuccess;
1264 /***********************************************************************
1265 * FTP_Connect (internal)
1267 * Connect to a ftp server
1269 * RETURNS
1270 * HINTERNET a session handle on success
1271 * NULL on failure
1275 HINTERNET FTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
1276 INTERNET_PORT nServerPort, LPCSTR lpszUserName,
1277 LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
1279 struct sockaddr_in socketAddr;
1280 struct hostent *phe = NULL;
1281 INT nsocket = INVALID_SOCKET, sock_namelen;
1282 LPWININETAPPINFOA hIC = NULL;
1283 BOOL bSuccess = FALSE;
1284 LPWININETFTPSESSIONA lpwfs = NULL;
1286 TRACE("0x%08lx Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1287 (ULONG) hInternet, lpszServerName,
1288 nServerPort, lpszUserName, lpszPassword);
1290 if (((LPWININETHANDLEHEADER)hInternet)->htype != WH_HINIT)
1291 goto lerror;
1293 hIC = (LPWININETAPPINFOA) hInternet;
1295 if (NULL == lpszUserName && NULL != lpszPassword)
1297 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_USER_NAME);
1298 goto lerror;
1301 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1302 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1304 if (hIC->lpfnStatusCB)
1305 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1306 (LPSTR) lpszServerName, strlen(lpszServerName));
1308 if (!GetAddress(lpszServerName, nServerPort, &phe, &socketAddr))
1310 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1311 goto lerror;
1314 if (hIC->lpfnStatusCB)
1315 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1316 (LPSTR) lpszServerName, strlen(lpszServerName));
1318 if (INVALID_SOCKET == (nsocket = socket(AF_INET,SOCK_STREAM,0)))
1320 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1321 goto lerror;
1324 if (hIC->lpfnStatusCB)
1325 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1326 &socketAddr, sizeof(struct sockaddr_in));
1328 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1330 ERR("Unable to connect (%s)\n", strerror(errno));
1331 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1333 else
1335 TRACE("Connected to server\n");
1336 if (hIC->lpfnStatusCB)
1337 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1338 &socketAddr, sizeof(struct sockaddr_in));
1340 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONA));
1341 if (NULL == lpwfs)
1343 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1344 goto lerror;
1347 lpwfs->hdr.htype = WH_HFTPSESSION;
1348 lpwfs->hdr.dwFlags = dwFlags;
1349 lpwfs->hdr.dwContext = dwContext;
1350 lpwfs->hdr.lpwhparent = (LPWININETHANDLEHEADER)hInternet;
1351 lpwfs->sndSocket = nsocket;
1352 sock_namelen = sizeof(lpwfs->socketAddress);
1353 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1354 lpwfs->phostent = phe;
1356 if (NULL == lpszUserName)
1358 lpwfs->lpszUserName = FTP_strdup("anonymous");
1359 lpwfs->lpszPassword = FTP_strdup("user@server");
1361 else
1363 lpwfs->lpszUserName = FTP_strdup(lpszUserName);
1364 lpwfs->lpszPassword = FTP_strdup(lpszPassword);
1367 if (FTP_ConnectToHost(lpwfs))
1369 if (hIC->lpfnStatusCB)
1371 INTERNET_ASYNC_RESULT iar;
1373 iar.dwResult = (DWORD)lpwfs;
1374 iar.dwError = ERROR_SUCCESS;
1376 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_HANDLE_CREATED,
1377 &iar, sizeof(INTERNET_ASYNC_RESULT));
1379 TRACE("Successfully logged into server\n");
1380 bSuccess = TRUE;
1384 lerror:
1385 if (!bSuccess && INVALID_SOCKET != nsocket)
1386 close(nsocket);
1388 if (!bSuccess && lpwfs)
1390 HeapFree(GetProcessHeap(), 0, lpwfs);
1391 lpwfs = NULL;
1394 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1396 INTERNET_ASYNC_RESULT iar;
1398 iar.dwResult = (DWORD)lpwfs;
1399 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1400 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1401 &iar, sizeof(INTERNET_ASYNC_RESULT));
1404 return (HINTERNET) lpwfs;
1408 /***********************************************************************
1409 * FTP_ConnectToHost (internal)
1411 * Connect to a ftp server
1413 * RETURNS
1414 * TRUE on success
1415 * NULL on failure
1418 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs)
1420 INT nResCode;
1421 BOOL bSuccess = FALSE;
1423 TRACE("\n");
1424 FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1426 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1427 goto lend;
1429 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1430 MAX_REPLY_LEN, 0, 0, 0);
1431 if (nResCode)
1433 /* Login successful... */
1434 if (nResCode == 230)
1435 bSuccess = TRUE;
1436 /* User name okay, need password... */
1437 else if (nResCode == 331)
1438 bSuccess = FTP_SendPassword(lpwfs);
1439 /* Need account for login... */
1440 else if (nResCode == 332)
1441 bSuccess = FTP_SendAccount(lpwfs);
1442 else
1443 FTP_SetResponseError(nResCode);
1446 TRACE("Returning %d\n", bSuccess);
1447 lend:
1448 return bSuccess;
1452 /***********************************************************************
1453 * FTP_SendCommand (internal)
1455 * Send command to server
1457 * RETURNS
1458 * TRUE on success
1459 * NULL on failure
1462 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1463 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1465 DWORD len;
1466 CHAR *buf;
1467 DWORD nBytesSent = 0;
1468 DWORD nRC = 0;
1469 BOOL bParamHasLen;
1471 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1473 if (lpfnStatusCB)
1474 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1476 bParamHasLen = lpszParam && strlen(lpszParam) > 0;
1477 len = (bParamHasLen ? strlen(lpszParam) : -1) + strlen(szFtpCommands[ftpCmd]) +
1478 strlen(szCRLF)+ 1;
1479 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1481 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1482 return FALSE;
1484 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], bParamHasLen ? " " : "",
1485 bParamHasLen ? lpszParam : "", szCRLF);
1487 TRACE("Sending (%s) len(%ld)\n", buf, len);
1488 while((nBytesSent < len) && (nRC != SOCKET_ERROR))
1490 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1491 nBytesSent += nRC;
1494 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
1496 if (lpfnStatusCB)
1497 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_REQUEST_SENT,
1498 &nBytesSent, sizeof(DWORD));
1500 TRACE("Sent %ld bytes\n", nBytesSent);
1501 return (nRC != SOCKET_ERROR);
1505 /***********************************************************************
1506 * FTP_ReceiveResponse (internal)
1508 * Receive response from server
1510 * RETURNS
1511 * Reply code on success
1512 * 0 on failure
1516 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
1517 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1519 DWORD nRecv;
1520 INT rc = 0;
1521 char firstprefix[5];
1522 BOOL multiline = FALSE;
1525 TRACE("socket(%d) \n", nSocket);
1527 if (lpfnStatusCB)
1528 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1530 while(1)
1532 nRecv = dwResponse;
1533 if (!INTERNET_GetNextLine(nSocket, lpszResponse, &nRecv))
1534 goto lerror;
1536 if (nRecv >= 3)
1538 if(!multiline)
1540 if(lpszResponse[3] != '-')
1541 break;
1542 else
1543 { /* Start of multiline repsonse. Loop until we get "nnn " */
1544 multiline = TRUE;
1545 memcpy(firstprefix, lpszResponse, 3);
1546 firstprefix[3] = ' ';
1547 firstprefix[4] = '\0';
1550 else
1552 if(!memcmp(firstprefix, lpszResponse, 4))
1553 break;
1558 if (nRecv >= 3)
1560 lpszResponse[nRecv] = '\0';
1561 rc = atoi(lpszResponse);
1563 if (lpfnStatusCB)
1564 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
1565 &nRecv, sizeof(DWORD));
1568 lerror:
1569 TRACE("return %d\n", rc);
1570 return rc;
1574 /***********************************************************************
1575 * FTP_SendPassword (internal)
1577 * Send password to ftp server
1579 * RETURNS
1580 * TRUE on success
1581 * NULL on failure
1584 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs)
1586 INT nResCode;
1587 BOOL bSuccess = FALSE;
1589 TRACE("\n");
1590 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
1591 goto lend;
1593 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1594 MAX_REPLY_LEN, 0, 0, 0);
1595 if (nResCode)
1597 TRACE("Received reply code %d\n", nResCode);
1598 /* Login successful... */
1599 if (nResCode == 230)
1600 bSuccess = TRUE;
1601 /* Command not implemented, superfluous at the server site... */
1602 /* Need account for login... */
1603 else if (nResCode == 332)
1604 bSuccess = FTP_SendAccount(lpwfs);
1605 else
1606 FTP_SetResponseError(nResCode);
1609 lend:
1610 TRACE("Returning %d\n", bSuccess);
1611 return bSuccess;
1615 /***********************************************************************
1616 * FTP_SendAccount (internal)
1620 * RETURNS
1621 * TRUE on success
1622 * FALSE on failure
1625 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs)
1627 INT nResCode;
1628 BOOL bSuccess = FALSE;
1630 TRACE("\n");
1631 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, NOACCOUNT, 0, 0, 0))
1632 goto lend;
1634 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1635 MAX_REPLY_LEN, 0, 0, 0);
1636 if (nResCode)
1637 bSuccess = TRUE;
1638 else
1639 FTP_SetResponseError(nResCode);
1641 lend:
1642 return bSuccess;
1646 /***********************************************************************
1647 * FTP_SendStore (internal)
1649 * Send request to upload file to ftp server
1651 * RETURNS
1652 * TRUE on success
1653 * FALSE on failure
1656 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
1658 INT nResCode;
1659 BOOL bSuccess = FALSE;
1661 TRACE("\n");
1662 if (!FTP_InitListenSocket(lpwfs))
1663 goto lend;
1665 if (!FTP_SendType(lpwfs, dwType))
1666 goto lend;
1668 if (!FTP_SendPortOrPasv(lpwfs))
1669 goto lend;
1671 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
1672 goto lend;
1673 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1674 MAX_REPLY_LEN, 0, 0, 0);
1675 if (nResCode)
1677 if (nResCode == 150)
1678 bSuccess = TRUE;
1679 else
1680 FTP_SetResponseError(nResCode);
1683 lend:
1684 if (!bSuccess && INVALID_SOCKET != lpwfs->lstnSocket)
1686 close(lpwfs->lstnSocket);
1687 lpwfs->lstnSocket = INVALID_SOCKET;
1690 return bSuccess;
1694 /***********************************************************************
1695 * FTP_InitListenSocket (internal)
1697 * Create a socket to listen for server response
1699 * RETURNS
1700 * TRUE on success
1701 * FALSE on failure
1704 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs)
1706 BOOL bSuccess = FALSE;
1707 size_t namelen = sizeof(struct sockaddr_in);
1709 TRACE("\n");
1711 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
1712 if (INVALID_SOCKET == lpwfs->lstnSocket)
1714 TRACE("Unable to create listening socket\n");
1715 goto lend;
1718 /* We obtain our ip addr from the name of the command channel socket */
1719 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
1721 /* and get the system to assign us a port */
1722 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
1724 if (SOCKET_ERROR == bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)))
1726 TRACE("Unable to bind socket\n");
1727 goto lend;
1730 if (SOCKET_ERROR == listen(lpwfs->lstnSocket, MAX_BACKLOG))
1732 TRACE("listen failed\n");
1733 goto lend;
1736 if (SOCKET_ERROR != getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen))
1737 bSuccess = TRUE;
1739 lend:
1740 if (!bSuccess && INVALID_SOCKET == lpwfs->lstnSocket)
1742 close(lpwfs->lstnSocket);
1743 lpwfs->lstnSocket = INVALID_SOCKET;
1746 return bSuccess;
1750 /***********************************************************************
1751 * FTP_SendType (internal)
1753 * Tell server type of data being transfered
1755 * RETURNS
1756 * TRUE on success
1757 * FALSE on failure
1759 * W98SE doesn't cache the type that's currently set
1760 * (i.e. it sends it always),
1761 * so we probably don't want to do that either.
1763 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType)
1765 INT nResCode;
1766 CHAR type[2] = { "I\0" };
1767 BOOL bSuccess = FALSE;
1769 TRACE("\n");
1770 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
1771 *type = 'A';
1773 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
1774 goto lend;
1776 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1777 MAX_REPLY_LEN, 0, 0, 0)/100;
1778 if (nResCode)
1780 if (nResCode == 2)
1781 bSuccess = TRUE;
1782 else
1783 FTP_SetResponseError(nResCode);
1786 lend:
1787 return bSuccess;
1791 /***********************************************************************
1792 * FTP_SendPort (internal)
1794 * Tell server which port to use
1796 * RETURNS
1797 * TRUE on success
1798 * FALSE on failure
1801 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs)
1803 INT nResCode;
1804 CHAR szIPAddress[64];
1805 BOOL bSuccess = FALSE;
1806 TRACE("\n");
1808 sprintf(szIPAddress, "%d,%d,%d,%d,%d,%d",
1809 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
1810 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
1811 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
1812 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
1813 lpwfs->lstnSocketAddress.sin_port & 0xFF,
1814 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
1816 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
1817 goto lend;
1819 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1820 MAX_REPLY_LEN,0, 0, 0);
1821 if (nResCode)
1823 if (nResCode == 200)
1824 bSuccess = TRUE;
1825 else
1826 FTP_SetResponseError(nResCode);
1829 lend:
1830 return bSuccess;
1834 /***********************************************************************
1835 * FTP_DoPassive (internal)
1837 * Tell server that we want to do passive transfers
1838 * and connect data socket
1840 * RETURNS
1841 * TRUE on success
1842 * FALSE on failure
1845 BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs)
1847 INT nResCode;
1848 BOOL bSuccess = FALSE;
1850 TRACE("\n");
1851 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
1852 goto lend;
1854 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1855 MAX_REPLY_LEN,0, 0, 0);
1856 if (nResCode)
1858 if (nResCode == 227)
1860 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
1861 LPSTR p;
1862 int f[6];
1863 int i;
1864 char *pAddr, *pPort;
1865 INT nsocket = INVALID_SOCKET;
1866 struct sockaddr_in dataSocketAddress;
1868 p = lpszResponseBuffer+4; /* skip status code */
1870 /* do a very strict check; we can improve that later. */
1872 if (strncmp(p, "Entering Passive Mode", 21))
1874 ERR("unknown response '%.*s', aborting\n", 21, p);
1875 goto lend;
1877 p += 21; /* skip string */
1878 if ((*p++ != ' ') || (*p++ != '('))
1880 ERR("unknown response format, aborting\n");
1881 goto lend;
1884 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
1885 &f[4], &f[5]) != 6)
1887 ERR("unknown response address format '%s', aborting\n", p);
1888 goto lend;
1890 for (i=0; i < 6; i++)
1891 f[i] = f[i] & 0xff;
1893 dataSocketAddress = lpwfs->socketAddress;
1894 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
1895 pPort = (char *)&(dataSocketAddress.sin_port);
1896 pAddr[0] = f[0];
1897 pAddr[1] = f[1];
1898 pAddr[2] = f[2];
1899 pAddr[3] = f[3];
1900 pPort[0] = f[4];
1901 pPort[1] = f[5];
1903 if (INVALID_SOCKET == (nsocket = socket(AF_INET,SOCK_STREAM,0)))
1904 goto lend;
1906 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
1908 ERR("can't connect passive FTP data port.\n");
1909 goto lend;
1911 lpwfs->pasvSocket = nsocket;
1912 bSuccess = TRUE;
1914 else
1915 FTP_SetResponseError(nResCode);
1918 lend:
1919 return bSuccess;
1923 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs)
1925 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
1927 if (!FTP_DoPassive(lpwfs))
1928 return FALSE;
1930 else
1932 if (!FTP_SendPort(lpwfs))
1933 return FALSE;
1935 return TRUE;
1939 /***********************************************************************
1940 * FTP_GetDataSocket (internal)
1942 * Either accepts an incoming data socket connection from the server
1943 * or just returns the already opened socket after a PASV command
1944 * in case of passive FTP.
1947 * RETURNS
1948 * TRUE on success
1949 * FALSE on failure
1952 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket)
1954 struct sockaddr_in saddr;
1955 size_t addrlen = sizeof(struct sockaddr);
1957 TRACE("\n");
1958 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
1960 *nDataSocket = lpwfs->pasvSocket;
1962 else
1964 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
1965 close(lpwfs->lstnSocket);
1966 lpwfs->lstnSocket = INVALID_SOCKET;
1968 return *nDataSocket != INVALID_SOCKET;
1972 /***********************************************************************
1973 * FTP_SendData (internal)
1975 * Send data to the server
1977 * RETURNS
1978 * TRUE on success
1979 * FALSE on failure
1982 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile)
1984 BY_HANDLE_FILE_INFORMATION fi;
1985 DWORD nBytesRead = 0;
1986 DWORD nBytesSent = 0;
1987 DWORD nTotalSent = 0;
1988 DWORD nBytesToSend, nLen, nRC = 1;
1989 time_t s_long_time, e_long_time;
1990 LONG nSeconds;
1991 CHAR *lpszBuffer;
1993 TRACE("\n");
1994 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
1995 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
1997 /* Get the size of the file. */
1998 GetFileInformationByHandle(hFile, &fi);
1999 time(&s_long_time);
2003 nBytesToSend = nBytesRead - nBytesSent;
2005 if (nBytesToSend <= 0)
2007 /* Read data from file. */
2008 nBytesSent = 0;
2009 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2010 ERR("Failed reading from file\n");
2012 if (nBytesRead > 0)
2013 nBytesToSend = nBytesRead;
2014 else
2015 break;
2018 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2019 DATA_PACKET_SIZE : nBytesToSend;
2020 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2022 if (nRC != SOCKET_ERROR)
2024 nBytesSent += nRC;
2025 nTotalSent += nRC;
2028 /* Do some computation to display the status. */
2029 time(&e_long_time);
2030 nSeconds = e_long_time - s_long_time;
2031 if( nSeconds / 60 > 0 )
2033 TRACE( "%ld bytes of %d bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
2034 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2035 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2037 else
2039 TRACE( "%ld bytes of %d bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
2040 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2041 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2043 } while (nRC != SOCKET_ERROR);
2045 TRACE("file transfer complete!\n");
2047 if(lpszBuffer != NULL)
2048 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2050 return nTotalSent;
2054 /***********************************************************************
2055 * FTP_SendRetrieve (internal)
2057 * Send request to retrieve a file
2059 * RETURNS
2060 * Number of bytes to be received on success
2061 * 0 on failure
2064 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
2066 INT nResCode;
2067 DWORD nResult = 0;
2069 TRACE("\n");
2070 if (!FTP_InitListenSocket(lpwfs))
2071 goto lend;
2073 if (!FTP_SendType(lpwfs, dwType))
2074 goto lend;
2076 if (!FTP_SendPortOrPasv(lpwfs))
2077 goto lend;
2079 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2080 goto lend;
2082 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2083 MAX_REPLY_LEN, 0, 0, 0);
2084 if (nResCode)
2086 if (nResCode == 125 || nResCode == 150)
2088 /* Parse size of data to be retrieved */
2089 INT i, sizepos = -1;
2090 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2091 for (i = strlen(lpszResponseBuffer) - 1; i >= 0; i--)
2093 if ('(' == lpszResponseBuffer[i])
2095 sizepos = i;
2096 break;
2100 if (sizepos >= 0)
2102 nResult = atol(&lpszResponseBuffer[sizepos+1]);
2103 TRACE("Waiting to receive %ld bytes\n", nResult);
2108 lend:
2109 if (0 == nResult && INVALID_SOCKET != lpwfs->lstnSocket)
2111 close(lpwfs->lstnSocket);
2112 lpwfs->lstnSocket = INVALID_SOCKET;
2115 return nResult;
2119 /***********************************************************************
2120 * FTP_RetrieveData (internal)
2122 * Retrieve data from server
2124 * RETURNS
2125 * TRUE on success
2126 * FALSE on failure
2129 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2131 DWORD nBytesWritten;
2132 DWORD nBytesReceived = 0;
2133 INT nRC = 0;
2134 CHAR *lpszBuffer;
2136 TRACE("\n");
2138 if (INVALID_HANDLE_VALUE == hFile)
2139 return FALSE;
2141 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2142 if (NULL == lpszBuffer)
2144 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2145 return FALSE;
2148 while (nBytesReceived < nBytes && nRC != SOCKET_ERROR)
2150 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2151 if (nRC != SOCKET_ERROR)
2153 /* other side closed socket. */
2154 if (nRC == 0)
2155 goto recv_end;
2156 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2157 nBytesReceived += nRC;
2160 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
2161 nBytesReceived * 100 / nBytes);
2164 TRACE("Data transfer complete\n");
2165 if (NULL != lpszBuffer)
2166 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2168 recv_end:
2169 return (nRC != SOCKET_ERROR);
2173 /***********************************************************************
2174 * FTP_CloseSessionHandle (internal)
2176 * Deallocate session handle
2178 * RETURNS
2179 * TRUE on success
2180 * FALSE on failure
2183 BOOL FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs)
2185 if (INVALID_SOCKET != lpwfs->sndSocket)
2186 close(lpwfs->sndSocket);
2188 if (INVALID_SOCKET != lpwfs->lstnSocket)
2189 close(lpwfs->lstnSocket);
2191 if (lpwfs->lpszPassword)
2192 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2194 if (lpwfs->lpszUserName)
2195 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2197 HeapFree(GetProcessHeap(), 0, lpwfs);
2199 return TRUE;
2203 /***********************************************************************
2204 * FTP_CloseSessionHandle (internal)
2206 * Deallocate session handle
2208 * RETURNS
2209 * TRUE on success
2210 * FALSE on failure
2213 BOOL FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn)
2215 INT i;
2217 TRACE("\n");
2219 for (i = 0; i < lpwfn->size; i++)
2221 if (NULL != lpwfn->lpafp[i].lpszName)
2222 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2225 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2226 HeapFree(GetProcessHeap(), 0, lpwfn);
2228 return TRUE;
2232 /***********************************************************************
2233 * FTP_ReceiveFileList (internal)
2235 * Read file list from server
2237 * RETURNS
2238 * Handle to file list on success
2239 * NULL on failure
2242 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
2243 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext)
2245 DWORD dwSize = 0;
2246 LPFILEPROPERTIESA lpafp = NULL;
2247 LPWININETFINDNEXTA lpwfn = NULL;
2249 TRACE("\n");
2251 if (FTP_ParseDirectory(lpwfs, nSocket, &lpafp, &dwSize))
2253 FTP_ConvertFileProp(lpafp, lpFindFileData);
2255 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTA));
2256 if (NULL != lpwfn)
2258 lpwfn->hdr.htype = WH_HFINDNEXT;
2259 lpwfn->hdr.lpwhparent = (LPWININETHANDLEHEADER)lpwfs;
2260 lpwfn->hdr.dwContext = dwContext;
2261 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2262 lpwfn->size = dwSize;
2263 lpwfn->lpafp = lpafp;
2267 TRACE("Matched %ld files\n", dwSize);
2268 return (HINTERNET)lpwfn;
2272 /***********************************************************************
2273 * FTP_ConvertFileProp (internal)
2275 * Converts FILEPROPERTIESA struct to WIN32_FIND_DATAA
2277 * RETURNS
2278 * TRUE on success
2279 * FALSE on failure
2282 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESA lpafp, LPWIN32_FIND_DATAA lpFindFileData)
2284 BOOL bSuccess = FALSE;
2286 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2288 if (lpafp)
2290 DWORD access = mktime(&lpafp->tmLastModified);
2292 /* Not all fields are filled in */
2293 lpFindFileData->ftLastAccessTime.dwHighDateTime = HIWORD(access);
2294 lpFindFileData->ftLastAccessTime.dwLowDateTime = LOWORD(access);
2295 lpFindFileData->nFileSizeHigh = HIWORD(lpafp->nSize);
2296 lpFindFileData->nFileSizeLow = LOWORD(lpafp->nSize);
2298 if (lpafp->bIsDirectory)
2299 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2301 if (lpafp->lpszName)
2302 strncpy(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2304 bSuccess = TRUE;
2307 return bSuccess;
2311 /***********************************************************************
2312 * FTP_ParseDirectory (internal)
2314 * Parse string of directory information
2316 * RETURNS
2317 * TRUE on success
2318 * FALSE on failure
2320 * FIXME: - This function needs serious clea-up
2321 * - We should consider both UNIX and NT list formats
2323 #define MAX_MONTH_LEN 10
2324 #define MIN_LEN_DIR_ENTRY 15
2326 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp)
2329 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2331 * For instance:
2332 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2334 CHAR* pszMinutes;
2335 CHAR* pszHour;
2336 time_t aTime;
2337 struct tm* apTM;
2338 CHAR pszMonth[MAX_MONTH_LEN];
2339 CHAR* pszMatch;
2340 BOOL bSuccess = TRUE;
2341 DWORD nBufLen = MAX_REPLY_LEN;
2342 LPFILEPROPERTIESA curFileProp = NULL;
2343 CHAR* pszLine = NULL;
2344 CHAR* pszToken = NULL;
2345 INT nTokenToSkip = 3;
2346 INT nCount = 0;
2347 INT nSeconds = 0;
2348 INT nMinutes = 0;
2349 INT nHour = 0;
2350 INT nDay = 0;
2351 INT nMonth = 0;
2352 INT nYear = 0;
2353 INT sizeFilePropArray = 20;
2354 INT indexFilePropArray = 0;
2356 TRACE("\n");
2358 /* Allocate intial file properties array */
2359 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESA)*(sizeFilePropArray));
2360 if (NULL == lpafp)
2362 bSuccess = FALSE;
2363 goto lend;
2366 while ((pszLine = INTERNET_GetNextLine(nSocket, INTERNET_GetResponseBuffer(), &nBufLen)) != NULL)
2368 if (sizeFilePropArray <= indexFilePropArray)
2370 LPFILEPROPERTIESA tmpafp;
2372 sizeFilePropArray *= 2;
2373 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
2374 sizeof(FILEPROPERTIESA)*sizeFilePropArray);
2375 if (NULL == tmpafp)
2377 bSuccess = FALSE;
2378 goto lend;
2381 *lpafp = tmpafp;
2384 curFileProp = &((*lpafp)[indexFilePropArray]);
2386 /* First Parse the permissions. */
2387 pszToken = strtok(pszLine, " \t" );
2389 /* HACK! If this is not a file listing skip the line */
2390 if (!pszToken || 10 != strlen(pszToken) || nBufLen <= MIN_LEN_DIR_ENTRY)
2392 nBufLen = MAX_REPLY_LEN;
2393 continue;
2396 FTP_ParsePermission(pszToken, curFileProp);
2398 nTokenToSkip = 3;
2399 nCount = 0;
2402 pszToken = strtok( NULL, " \t" );
2403 nCount++;
2404 } while( nCount <= nTokenToSkip );
2406 /* Store the size of the file in the param list. */
2407 TRACE("nSize-> %s\n", pszToken);
2408 if (pszToken != NULL)
2409 curFileProp->nSize = atol(pszToken);
2411 /* Parse last modified time. */
2412 nSeconds = 0;
2413 nMinutes = 0;
2414 nHour = 0;
2415 nDay = 0;
2416 nMonth = 0;
2417 nYear = 0;
2419 pszToken = strtok( NULL, " \t" );
2420 strncpy(pszMonth, pszToken, MAX_MONTH_LEN);
2421 CharUpperA(pszMonth);
2422 pszMatch = strstr(szMonths, pszMonth);
2423 if( pszMatch != NULL )
2424 nMonth = (pszMatch - szMonths) / 3;
2426 pszToken = strtok(NULL, " \t");
2427 TRACE("nDay -> %s\n", pszToken);
2428 if (pszToken != NULL)
2429 nDay = atoi(pszToken);
2431 pszToken = strtok(NULL, " \t");
2432 pszMinutes = strchr(pszToken, ':');
2433 if( pszMinutes != NULL )
2435 pszMinutes++;
2436 nMinutes = atoi(pszMinutes);
2437 pszHour = pszMinutes - 3;
2438 if (pszHour != NULL)
2439 nHour = atoi(pszHour);
2440 time(&aTime);
2441 apTM = localtime( &aTime );
2442 nYear = apTM->tm_year;
2444 else
2446 nYear = atoi(pszToken);
2447 nYear -= 1900;
2448 nHour = 12;
2451 curFileProp->tmLastModified.tm_sec = nSeconds;
2452 curFileProp->tmLastModified.tm_min = nMinutes;
2453 curFileProp->tmLastModified.tm_hour = nHour;
2454 curFileProp->tmLastModified.tm_mday = nDay;
2455 curFileProp->tmLastModified.tm_mon = nMonth;
2456 curFileProp->tmLastModified.tm_year = nYear;
2458 pszToken = strtok(NULL, " \t");
2459 if(pszToken != NULL)
2461 curFileProp->lpszName = FTP_strdup(pszToken);
2462 TRACE(": %s\n", curFileProp->lpszName);
2465 nBufLen = MAX_REPLY_LEN;
2466 indexFilePropArray++;
2469 if (bSuccess && indexFilePropArray)
2471 if (indexFilePropArray < sizeFilePropArray - 1)
2473 LPFILEPROPERTIESA tmpafp;
2475 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
2476 sizeof(FILEPROPERTIESA)*indexFilePropArray);
2477 if (NULL == tmpafp)
2478 *lpafp = tmpafp;
2480 *dwfp = indexFilePropArray;
2482 else
2484 HeapFree(GetProcessHeap(), 0, *lpafp);
2485 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2486 bSuccess = FALSE;
2489 lend:
2490 return bSuccess;
2494 /***********************************************************************
2495 * FTP_ParsePermission (internal)
2497 * Parse permission string of directory information
2499 * RETURNS
2500 * TRUE on success
2501 * FALSE on failure
2504 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp)
2506 BOOL bSuccess = TRUE;
2507 unsigned short nPermission = 0;
2508 INT nPos = 1;
2509 INT nLast = 9;
2511 TRACE("\n");
2512 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
2514 bSuccess = FALSE;
2515 return bSuccess;
2518 lpfp->bIsDirectory = (*lpszPermission == 'd');
2521 switch (nPos)
2523 case 1:
2524 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
2525 break;
2526 case 2:
2527 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
2528 break;
2529 case 3:
2530 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
2531 break;
2532 case 4:
2533 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
2534 break;
2535 case 5:
2536 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
2537 break;
2538 case 6:
2539 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
2540 break;
2541 case 7:
2542 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
2543 break;
2544 case 8:
2545 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
2546 break;
2547 case 9:
2548 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
2549 break;
2551 nPos++;
2552 }while (nPos <= nLast);
2554 lpfp->permissions = nPermission;
2555 return bSuccess;
2559 /***********************************************************************
2560 * FTP_SetResponseError (internal)
2562 * Set the appropriate error code for a given response from the server
2564 * RETURNS
2567 DWORD FTP_SetResponseError(DWORD dwResponse)
2569 DWORD dwCode = 0;
2571 switch(dwResponse)
2573 case 421: /* Service not available - Server may be shutting down. */
2574 dwCode = ERROR_INTERNET_TIMEOUT;
2575 break;
2577 case 425: /* Cannot open data connection. */
2578 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
2579 break;
2581 case 426: /* Connection closed, transer aborted. */
2582 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
2583 break;
2585 case 500: /* Syntax error. Command unrecognized. */
2586 case 501: /* Syntax error. Error in parameters or arguments. */
2587 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
2588 break;
2590 case 530: /* Not logged in. Login incorrect. */
2591 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
2592 break;
2594 case 550: /* File action not taken. File not found or no access. */
2595 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
2596 break;
2598 case 450: /* File action not taken. File may be busy. */
2599 case 451: /* Action aborted. Server error. */
2600 case 452: /* Action not taken. Insufficient storage space on server. */
2601 case 502: /* Command not implemented. */
2602 case 503: /* Bad sequence of command. */
2603 case 504: /* Command not implemented for that parameter. */
2604 case 532: /* Need account for storing files */
2605 case 551: /* Requested action aborted. Page type unknown */
2606 case 552: /* Action aborted. Exceeded storage allocation */
2607 case 553: /* Action not taken. File name not allowed. */
2609 default:
2610 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
2611 break;
2614 INTERNET_SetLastError(dwCode);
2615 return dwCode;