Use correct check to see if xserver supports xvidmode.
[wine] / dlls / wininet / ftp.c
1 /*
2  * WININET - Ftp implementation
3  *
4  * Copyright 1999 Corel Corporation
5  *
6  * Ulrich Czekalla
7  * Noureddine Jemmali
8  *
9  * Copyright 2000 Andreas Mohr
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  */
25
26 #include "config.h"
27 #include "wine/port.h"
28
29 #include <errno.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/types.h>
34 #ifdef HAVE_SYS_SOCKET_H
35 # include <sys/socket.h>
36 #endif
37 #ifdef HAVE_UNISTD_H
38 # include <unistd.h>
39 #endif
40 #include <time.h>
41
42 #include "winbase.h"
43 #include "wingdi.h"
44 #include "winuser.h"
45 #include "wininet.h"
46 #include "winerror.h"
47
48 #include "wine/debug.h"
49 #include "internet.h"
50
51 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
52
53 #define NOACCOUNT               "noaccount"
54 #define DATA_PACKET_SIZE        0x2000
55 #define szCRLF                  "\r\n"
56 #define MAX_BACKLOG             5
57
58 typedef enum {
59   /* FTP commands with arguments. */
60   FTP_CMD_ACCT,
61   FTP_CMD_CWD,
62   FTP_CMD_DELE,
63   FTP_CMD_MKD,
64   FTP_CMD_PASS,
65   FTP_CMD_PORT,
66   FTP_CMD_RETR,
67   FTP_CMD_RMD,
68   FTP_CMD_RNFR,
69   FTP_CMD_RNTO,
70   FTP_CMD_STOR,
71   FTP_CMD_TYPE,
72   FTP_CMD_USER,
73
74   /* FTP commands without arguments. */
75   FTP_CMD_ABOR,
76   FTP_CMD_LIST,
77   FTP_CMD_NLST,
78   FTP_CMD_PASV,
79   FTP_CMD_PWD,
80   FTP_CMD_QUIT,
81 } FTP_COMMAND;
82
83 static const CHAR *szFtpCommands[] = {
84   "ACCT",
85   "CWD",
86   "DELE",
87   "MKD",
88   "PASS",
89   "PORT",
90   "RETR",
91   "RMD",
92   "RNFR",
93   "RNTO",
94   "STOR",
95   "TYPE",
96   "USER",
97   "ABOR",
98   "LIST",
99   "NLST",
100   "PASV",
101   "PWD",
102   "QUIT",
103 };
104
105 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
106
107 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
108         INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
109 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
110 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket);
111 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile);
112 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
113         INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
114 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
115 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile);
116 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs);
117 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs);
118 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs);
119 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs);
120 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType);
121 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs);
122 BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs);
123 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs);
124 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp);
125 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp);
126 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
127         LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext);
128 DWORD FTP_SetResponseError(DWORD dwResponse);
129
130 inline static LPSTR FTP_strdup( LPCSTR str )
131 {
132     LPSTR ret = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
133     if (ret) strcpy( ret, str );
134     return ret;
135 }
136
137 /***********************************************************************
138  *           FtpPutFileA (WININET.@)
139  *
140  * Uploads a file to the FTP server
141  *
142  * RETURNS
143  *    TRUE on success
144  *    FALSE on failure
145  *
146  */
147 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
148     LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
149 {
150     LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
151     LPWININETAPPINFOA hIC = NULL;
152
153     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
154     {
155         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
156         return FALSE;
157     }
158
159     hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
160     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
161     {
162         WORKREQUEST workRequest;
163
164         workRequest.asyncall = FTPPUTFILEA;
165         workRequest.HFTPSESSION = (DWORD)hConnect;
166         workRequest.LPSZLOCALFILE = (DWORD)FTP_strdup(lpszLocalFile);
167         workRequest.LPSZNEWREMOTEFILE = (DWORD)FTP_strdup(lpszNewRemoteFile);
168         workRequest.DWFLAGS = dwFlags;
169         workRequest.DWCONTEXT = dwContext;
170
171         return INTERNET_AsyncCall(&workRequest);
172     }
173     else
174     {
175         return FTP_FtpPutFileA(hConnect, lpszLocalFile,
176                 lpszNewRemoteFile, dwFlags, dwContext);
177     }
178 }
179
180 /***********************************************************************
181  *           FTP_FtpPutFileA (Internal)
182  *
183  * Uploads a file to the FTP server
184  *
185  * RETURNS
186  *    TRUE on success
187  *    FALSE on failure
188  *
189  */
190 BOOL WINAPI FTP_FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
191     LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
192 {
193     HANDLE hFile = (HANDLE)NULL;
194     BOOL bSuccess = FALSE;
195     LPWININETAPPINFOA hIC = NULL;
196     LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
197     INT nResCode;
198
199     TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", lpszLocalFile, lpszNewRemoteFile);
200     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
201     {
202         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
203         return FALSE;
204     }
205
206     /* Clear any error information */
207     INTERNET_SetLastError(0);
208
209     /* Open file to be uploaded */
210     if (INVALID_HANDLE_VALUE ==
211         (hFile = CreateFileA(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
212     {
213         INTERNET_SetLastError(ERROR_FILE_NOT_FOUND);
214         goto lend;
215     }
216
217     hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
218     if (hIC->lpfnStatusCB)
219         hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
220
221     if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
222     {
223         INT nDataSocket;
224
225         /* Get data socket to server */
226         if (FTP_GetDataSocket(lpwfs, &nDataSocket))
227         {
228             FTP_SendData(lpwfs, nDataSocket, hFile);
229             close(nDataSocket);
230             nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
231                                            MAX_REPLY_LEN, 0, 0, 0);
232             if (nResCode)
233             {
234                 if (nResCode == 226)
235                     bSuccess = TRUE;
236                 else
237                     FTP_SetResponseError(nResCode);
238             }
239         }
240     }
241
242 lend:
243     if (lpwfs->lstnSocket != -1)
244         close(lpwfs->lstnSocket);
245
246     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC  && hIC->lpfnStatusCB)
247     {
248         INTERNET_ASYNC_RESULT iar;
249
250         iar.dwResult = (DWORD)bSuccess;
251         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
252         hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
253             &iar, sizeof(INTERNET_ASYNC_RESULT));
254     }
255
256     if (hFile)
257         CloseHandle(hFile);
258
259     return bSuccess;
260 }
261
262
263 /***********************************************************************
264  *           FtpSetCurrentDirectoryA (WININET.@)
265  *
266  * Change the working directory on the FTP server
267  *
268  * RETURNS
269  *    TRUE on success
270  *    FALSE on failure
271  *
272  */
273 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
274 {
275     LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
276     LPWININETAPPINFOA hIC = NULL;
277
278     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
279     {
280         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
281         return FALSE;
282     }
283
284     TRACE("lpszDirectory(%s)\n", lpszDirectory);
285
286     hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
287     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
288     {
289         WORKREQUEST workRequest;
290
291         workRequest.asyncall = FTPSETCURRENTDIRECTORYA;
292         workRequest.HFTPSESSION = (DWORD)hConnect;
293         workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
294
295         return INTERNET_AsyncCall(&workRequest);
296     }
297     else
298     {
299         return FTP_FtpSetCurrentDirectoryA(hConnect, lpszDirectory);
300     }
301 }
302
303
304 /***********************************************************************
305  *           FTP_FtpSetCurrentDirectoryA (Internal)
306  *
307  * Change the working directory on the FTP server
308  *
309  * RETURNS
310  *    TRUE on success
311  *    FALSE on failure
312  *
313  */
314 BOOL WINAPI FTP_FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
315 {
316     INT nResCode;
317     LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
318     LPWININETAPPINFOA hIC = NULL;
319     DWORD bSuccess = FALSE;
320
321     TRACE("lpszDirectory(%s)\n", lpszDirectory);
322
323     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
324     {
325         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
326         return FALSE;
327     }
328
329     /* Clear any error information */
330     INTERNET_SetLastError(0);
331
332     hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
333     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
334         hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
335         goto lend;
336
337     nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
338         MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
339
340     if (nResCode)
341     {
342         if (nResCode == 250)
343             bSuccess = TRUE;
344         else
345             FTP_SetResponseError(nResCode);
346     }
347
348 lend:
349     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
350     {
351         INTERNET_ASYNC_RESULT iar;
352
353         iar.dwResult = (DWORD)bSuccess;
354         iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
355         hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
356             &iar, sizeof(INTERNET_ASYNC_RESULT));
357     }
358     return bSuccess;
359 }
360
361
362 /***********************************************************************
363  *           FtpCreateDirectoryA (WININET.@)
364  *
365  * Create new directory on the FTP server
366  *
367  * RETURNS
368  *    TRUE on success
369  *    FALSE on failure
370  *
371  */
372 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
373 {
374     LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
375     LPWININETAPPINFOA hIC = NULL;
376
377     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
378     {
379         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
380         return FALSE;
381     }
382
383     hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
384     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
385     {
386         WORKREQUEST workRequest;
387
388         workRequest.asyncall = FTPCREATEDIRECTORYA;
389         workRequest.HFTPSESSION = (DWORD)hConnect;
390         workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
391
392         return INTERNET_AsyncCall(&workRequest);
393     }
394     else
395     {
396         return FTP_FtpCreateDirectoryA(hConnect, lpszDirectory);
397     }
398 }
399
400
401 /***********************************************************************
402  *           FTP_FtpCreateDirectoryA (Internal)
403  *
404  * Create new directory on the FTP server
405  *
406  * RETURNS
407  *    TRUE on success
408  *    FALSE on failure
409  *
410  */
411 BOOL WINAPI FTP_FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
412 {
413     INT nResCode;
414     BOOL bSuccess = FALSE;
415     LPWININETAPPINFOA hIC = NULL;
416     LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
417
418     TRACE("\n");
419     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
420     {
421         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
422         return FALSE;
423     }
424
425     /* Clear any error information */
426     INTERNET_SetLastError(0);
427
428     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
429         goto lend;
430
431     nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
432         MAX_REPLY_LEN, 0, 0, 0);
433     if (nResCode)
434     {
435         if (nResCode == 257)
436             bSuccess = TRUE;
437         else
438             FTP_SetResponseError(nResCode);
439     }
440
441 lend:
442     hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
443     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
444     {
445         INTERNET_ASYNC_RESULT iar;
446
447         iar.dwResult = (DWORD)bSuccess;
448         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
449         hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
450             &iar, sizeof(INTERNET_ASYNC_RESULT));
451     }
452
453     return bSuccess;
454 }
455
456
457 /***********************************************************************
458  *           FtpFindFirstFileA (WININET.@)
459  *
460  * Search the specified directory
461  *
462  * RETURNS
463  *    HINTERNET on success
464  *    NULL on failure
465  *
466  */
467 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
468     LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
469 {
470     LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
471     LPWININETAPPINFOA hIC = NULL;
472
473     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
474     {
475         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
476         return FALSE;
477     }
478
479     hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
480     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
481     {
482         WORKREQUEST workRequest;
483
484         workRequest.asyncall = FTPFINDFIRSTFILEA;
485         workRequest.HFTPSESSION = (DWORD)hConnect;
486         workRequest.LPSZSEARCHFILE = (DWORD)FTP_strdup(lpszSearchFile);
487         workRequest.LPFINDFILEDATA = (DWORD)lpFindFileData;
488         workRequest.DWFLAGS = dwFlags;
489         workRequest.DWCONTEXT= dwContext;
490
491         INTERNET_AsyncCall(&workRequest);
492         return NULL;
493     }
494     else
495     {
496         return FTP_FtpFindFirstFileA(hConnect, lpszSearchFile, lpFindFileData,
497                 dwFlags, dwContext);
498     }
499 }
500
501
502 /***********************************************************************
503  *           FTP_FtpFindFirstFileA (Internal)
504  *
505  * Search the specified directory
506  *
507  * RETURNS
508  *    HINTERNET on success
509  *    NULL on failure
510  *
511  */
512 HINTERNET WINAPI FTP_FtpFindFirstFileA(HINTERNET hConnect,
513     LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
514 {
515     INT nResCode;
516     LPWININETAPPINFOA hIC = NULL;
517     LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
518     LPWININETFINDNEXTA hFindNext = NULL;
519
520     TRACE("\n");
521
522     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
523     {
524         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
525         return FALSE;
526     }
527
528     /* Clear any error information */
529     INTERNET_SetLastError(0);
530
531     if (!FTP_InitListenSocket(lpwfs))
532         goto lend;
533
534     if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
535         goto lend;
536
537     if (!FTP_SendPortOrPasv(lpwfs))
538         goto lend;
539
540     hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
541     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, lpszSearchFile,
542         hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
543         goto lend;
544
545     nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
546         MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
547     if (nResCode)
548     {
549         if (nResCode == 125 || nResCode == 150)
550         {
551             INT nDataSocket;
552
553             /* Get data socket to server */
554             if (FTP_GetDataSocket(lpwfs, &nDataSocket))
555             {
556                 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpFindFileData, dwContext);
557
558                 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
559                     MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
560                 if (nResCode != 226 && nResCode != 250)
561                     INTERNET_SetLastError(ERROR_NO_MORE_FILES);
562
563                 close(nDataSocket);
564             }
565         }
566         else
567             FTP_SetResponseError(nResCode);
568     }
569
570 lend:
571     if (lpwfs->lstnSocket != -1)
572         close(lpwfs->lstnSocket);
573
574     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
575     {
576         INTERNET_ASYNC_RESULT iar;
577
578         if (hFindNext)
579         {
580             iar.dwResult = (DWORD)hFindNext;
581             iar.dwError = ERROR_SUCCESS;
582             hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
583                 &iar, sizeof(INTERNET_ASYNC_RESULT));
584         }
585
586         iar.dwResult = (DWORD)hFindNext;
587         iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
588         hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
589             &iar, sizeof(INTERNET_ASYNC_RESULT));
590     }
591
592     return (HINTERNET)hFindNext;
593 }
594
595
596 /***********************************************************************
597  *           FtpGetCurrentDirectoryA (WININET.@)
598  *
599  * Retrieves the current directory
600  *
601  * RETURNS
602  *    TRUE on success
603  *    FALSE on failure
604  *
605  */
606 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
607         LPDWORD lpdwCurrentDirectory)
608 {
609     LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
610     LPWININETAPPINFOA hIC = NULL;
611
612     TRACE("len(%ld)\n", *lpdwCurrentDirectory);
613
614     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
615     {
616         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
617         return FALSE;
618     }
619
620     hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
621     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
622     {
623         WORKREQUEST workRequest;
624
625         workRequest.asyncall =  FTPGETCURRENTDIRECTORYA;
626         workRequest.HFTPSESSION = (DWORD)hFtpSession;
627         workRequest.LPSZDIRECTORY = (DWORD)lpszCurrentDirectory;
628         workRequest.LPDWDIRECTORY = (DWORD)lpdwCurrentDirectory;
629
630         return INTERNET_AsyncCall(&workRequest);
631     }
632     else
633     {
634         return FTP_FtpGetCurrentDirectoryA(hFtpSession, lpszCurrentDirectory,
635                 lpdwCurrentDirectory);
636     }
637 }
638
639
640 /***********************************************************************
641  *           FTP_FtpGetCurrentDirectoryA (Internal)
642  *
643  * Retrieves the current directory
644  *
645  * RETURNS
646  *    TRUE on success
647  *    FALSE on failure
648  *
649  */
650 BOOL WINAPI FTP_FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
651         LPDWORD lpdwCurrentDirectory)
652 {
653     INT nResCode;
654     LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
655     LPWININETAPPINFOA hIC = NULL;
656     DWORD bSuccess = FALSE;
657
658     TRACE("len(%ld)\n", *lpdwCurrentDirectory);
659
660     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
661     {
662         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
663         return FALSE;
664     }
665
666     /* Clear any error information */
667     INTERNET_SetLastError(0);
668
669     ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
670
671     hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
672     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
673         hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext))
674         goto lend;
675
676     nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
677         MAX_REPLY_LEN, hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext);
678     if (nResCode)
679     {
680         if (nResCode == 257) /* Extract directory name */
681         {
682             INT firstpos, lastpos, len;
683             LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
684
685             for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
686             {
687                 if ('"' == lpszResponseBuffer[lastpos])
688                 {
689                     if (!firstpos)
690                         firstpos = lastpos;
691                     else
692                         break;
693                 }
694             }
695
696             len = lastpos - firstpos - 1;
697             strncpy(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1],
698                 len < *lpdwCurrentDirectory ? len : *lpdwCurrentDirectory);
699             *lpdwCurrentDirectory = len;
700             bSuccess = TRUE;
701         }
702         else
703             FTP_SetResponseError(nResCode);
704     }
705
706 lend:
707     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
708     {
709         INTERNET_ASYNC_RESULT iar;
710
711         iar.dwResult = (DWORD)bSuccess;
712         iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
713         hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
714             &iar, sizeof(INTERNET_ASYNC_RESULT));
715     }
716
717     return (DWORD) bSuccess;
718 }
719
720 /***********************************************************************
721  *           FtpOpenFileA (WININET.@)
722  *
723  * Open a remote file for writing or reading
724  *
725  * RETURNS
726  *    HINTERNET handle on success
727  *    NULL on failure
728  *
729  */
730 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
731         LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
732         DWORD dwContext)
733 {
734     LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
735     LPWININETAPPINFOA hIC = NULL;
736
737     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
738     {
739         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
740         return FALSE;
741     }
742
743     hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
744     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
745     {
746         WORKREQUEST workRequest;
747
748         workRequest.asyncall = FTPOPENFILEA;
749         workRequest.HFTPSESSION = (DWORD)hFtpSession;
750         workRequest.LPSZFILENAME = (DWORD)FTP_strdup(lpszFileName);
751         workRequest.FDWACCESS = fdwAccess;
752         workRequest.DWFLAGS = dwFlags;
753         workRequest.DWCONTEXT = dwContext;
754
755         INTERNET_AsyncCall(&workRequest);
756         return NULL;
757     }
758     else
759     {
760         return FTP_FtpOpenFileA(hFtpSession, lpszFileName, fdwAccess, dwFlags, dwContext);
761     }
762 }
763
764
765 /***********************************************************************
766  *           FTP_FtpOpenFileA (Internal)
767  *
768  * Open a remote file for writing or reading
769  *
770  * RETURNS
771  *    HINTERNET handle on success
772  *    NULL on failure
773  *
774  */
775 HINTERNET FTP_FtpOpenFileA(HINTERNET hFtpSession,
776         LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
777         DWORD dwContext)
778 {
779     INT nDataSocket;
780     BOOL bSuccess = FALSE;
781     LPWININETFILE hFile = NULL;
782     LPWININETAPPINFOA hIC = NULL;
783     LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
784
785     TRACE("\n");
786
787     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
788     {
789         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
790         return FALSE;
791     }
792
793     /* Clear any error information */
794     INTERNET_SetLastError(0);
795
796     if (GENERIC_READ == fdwAccess)
797     {
798         /* Set up socket to retrieve data */
799         bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
800     }
801     else if (GENERIC_WRITE == fdwAccess)
802     {
803         /* Set up socket to send data */
804         bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
805     }
806
807     /* Get data socket to server */
808     if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
809     {
810         hFile = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE));
811         hFile->hdr.htype = WH_HFILE;
812         hFile->hdr.dwFlags = dwFlags;
813         hFile->hdr.dwContext = dwContext;
814         hFile->hdr.lpwhparent = hFtpSession;
815         hFile->nDataSocket = nDataSocket;
816     }
817
818     if (lpwfs->lstnSocket != -1)
819         close(lpwfs->lstnSocket);
820
821     hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
822     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
823     {
824         INTERNET_ASYNC_RESULT iar;
825
826         if (hFile)
827         {
828             iar.dwResult = (DWORD)hFile;
829             iar.dwError = ERROR_SUCCESS;
830             hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
831                 &iar, sizeof(INTERNET_ASYNC_RESULT));
832         }
833
834         iar.dwResult = (DWORD)bSuccess;
835         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
836         hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
837             &iar, sizeof(INTERNET_ASYNC_RESULT));
838     }
839
840     return (HINTERNET)hFile;
841 }
842
843
844 /***********************************************************************
845  *           FtpGetFileA (WININET.@)
846  *
847  * Retrieve file from the FTP server
848  *
849  * RETURNS
850  *    TRUE on success
851  *    FALSE on failure
852  *
853  */
854 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
855         BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
856         DWORD dwContext)
857 {
858     LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet;
859     LPWININETAPPINFOA hIC = NULL;
860
861     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
862     {
863         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
864         return FALSE;
865     }
866
867     hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
868     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
869     {
870         WORKREQUEST workRequest;
871
872         workRequest.asyncall = FTPGETFILEA;
873         workRequest.HFTPSESSION = (DWORD)hInternet;
874         workRequest.LPSZREMOTEFILE = (DWORD)FTP_strdup(lpszRemoteFile);
875         workRequest.LPSZNEWFILE = (DWORD)FTP_strdup(lpszNewFile);
876         workRequest.DWLOCALFLAGSATTRIBUTE  = dwLocalFlagsAttribute;
877         workRequest.FFAILIFEXISTS = (DWORD)fFailIfExists;
878         workRequest.DWFLAGS = dwInternetFlags;
879         workRequest.DWCONTEXT = dwContext;
880
881         return INTERNET_AsyncCall(&workRequest);
882     }
883     else
884     {
885         return FTP_FtpGetFileA(hInternet, lpszRemoteFile, lpszNewFile,
886            fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
887     }
888 }
889
890
891 /***********************************************************************
892  *           FTP_FtpGetFileA (Internal)
893  *
894  * Retrieve file from the FTP server
895  *
896  * RETURNS
897  *    TRUE on success
898  *    FALSE on failure
899  *
900  */
901 BOOL WINAPI FTP_FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
902         BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
903         DWORD dwContext)
904 {
905     DWORD nBytes;
906     BOOL bSuccess = FALSE;
907     HANDLE hFile;
908     LPWININETAPPINFOA hIC = NULL;
909     LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet;
910
911     TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", lpszRemoteFile, lpszNewFile);
912     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
913     {
914         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
915         return FALSE;
916     }
917
918     /* Clear any error information */
919     INTERNET_SetLastError(0);
920
921     /* Ensure we can write to lpszNewfile by opening it */
922     hFile = CreateFileA(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
923         CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
924     if (INVALID_HANDLE_VALUE == hFile)
925         goto lend;
926
927     /* Set up socket to retrieve data */
928     nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
929
930     if (nBytes > 0)
931     {
932         INT nDataSocket;
933
934         /* Get data socket to server */
935         if (FTP_GetDataSocket(lpwfs, &nDataSocket))
936         {
937             INT nResCode;
938
939             /* Receive data */
940             FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
941             nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
942             MAX_REPLY_LEN, 0, 0, 0);
943             if (nResCode)
944             {
945                 if (nResCode == 226)
946                     bSuccess = TRUE;
947                 else
948                     FTP_SetResponseError(nResCode);
949             }
950             close(nDataSocket);
951         }
952     }
953
954 lend:
955     if (lpwfs->lstnSocket != -1)
956         close(lpwfs->lstnSocket);
957
958     if (hFile)
959         CloseHandle(hFile);
960
961     hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
962     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
963     {
964         INTERNET_ASYNC_RESULT iar;
965
966         iar.dwResult = (DWORD)bSuccess;
967         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
968         hIC->lpfnStatusCB(hInternet, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
969             &iar, sizeof(INTERNET_ASYNC_RESULT));
970     }
971
972     return bSuccess;
973 }
974
975
976 /***********************************************************************
977  *           FtpDeleteFileA  (WININET.@)
978  *
979  * Delete a file on the ftp server
980  *
981  * RETURNS
982  *    TRUE on success
983  *    FALSE on failure
984  *
985  */
986 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
987 {
988     LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
989     LPWININETAPPINFOA hIC = NULL;
990
991     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
992     {
993         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
994         return FALSE;
995     }
996
997     hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
998     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
999     {
1000         WORKREQUEST workRequest;
1001
1002         workRequest.asyncall = FTPRENAMEFILEA;
1003         workRequest.HFTPSESSION = (DWORD)hFtpSession;
1004         workRequest.LPSZFILENAME = (DWORD)FTP_strdup(lpszFileName);
1005
1006         return INTERNET_AsyncCall(&workRequest);
1007     }
1008     else
1009     {
1010         return FTP_FtpDeleteFileA(hFtpSession, lpszFileName);
1011     }
1012 }
1013
1014
1015 /***********************************************************************
1016  *           FTP_FtpDeleteFileA  (Internal)
1017  *
1018  * Delete a file on the ftp server
1019  *
1020  * RETURNS
1021  *    TRUE on success
1022  *    FALSE on failure
1023  *
1024  */
1025 BOOL FTP_FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1026 {
1027     INT nResCode;
1028     BOOL bSuccess = FALSE;
1029     LPWININETAPPINFOA hIC = NULL;
1030     LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1031
1032     TRACE("0x%08lx\n", (ULONG) hFtpSession);
1033     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1034     {
1035         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1036         return FALSE;
1037     }
1038
1039     /* Clear any error information */
1040     INTERNET_SetLastError(0);
1041
1042     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1043         goto lend;
1044
1045     nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1046         MAX_REPLY_LEN, 0, 0, 0);
1047     if (nResCode)
1048     {
1049         if (nResCode == 250)
1050             bSuccess = TRUE;
1051         else
1052             FTP_SetResponseError(nResCode);
1053     }
1054 lend:
1055     hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1056     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1057     {
1058         INTERNET_ASYNC_RESULT iar;
1059
1060         iar.dwResult = (DWORD)bSuccess;
1061         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1062         hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1063             &iar, sizeof(INTERNET_ASYNC_RESULT));
1064     }
1065
1066     return bSuccess;
1067 }
1068
1069
1070 /***********************************************************************
1071  *           FtpRemoveDirectoryA  (WININET.@)
1072  *
1073  * Remove a directory on the ftp server
1074  *
1075  * RETURNS
1076  *    TRUE on success
1077  *    FALSE on failure
1078  *
1079  */
1080 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1081 {
1082     LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1083     LPWININETAPPINFOA hIC = NULL;
1084
1085     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1086     {
1087         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1088         return FALSE;
1089     }
1090
1091     hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1092     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1093     {
1094         WORKREQUEST workRequest;
1095
1096         workRequest.asyncall = FTPREMOVEDIRECTORYA;
1097         workRequest.HFTPSESSION = (DWORD)hFtpSession;
1098         workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
1099
1100         return INTERNET_AsyncCall(&workRequest);
1101     }
1102     else
1103     {
1104         return FTP_FtpRemoveDirectoryA(hFtpSession, lpszDirectory);
1105     }
1106 }
1107
1108
1109 /***********************************************************************
1110  *           FTP_FtpRemoveDirectoryA  (Internal)
1111  *
1112  * Remove a directory on the ftp server
1113  *
1114  * RETURNS
1115  *    TRUE on success
1116  *    FALSE on failure
1117  *
1118  */
1119 BOOL FTP_FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1120 {
1121     INT nResCode;
1122     BOOL bSuccess = FALSE;
1123     LPWININETAPPINFOA hIC = NULL;
1124     LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1125
1126     TRACE("\n");
1127     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1128     {
1129         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1130         return FALSE;
1131     }
1132
1133     /* Clear any error information */
1134     INTERNET_SetLastError(0);
1135
1136     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1137         goto lend;
1138
1139     nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1140         MAX_REPLY_LEN, 0, 0, 0);
1141     if (nResCode)
1142     {
1143         if (nResCode == 250)
1144             bSuccess = TRUE;
1145         else
1146             FTP_SetResponseError(nResCode);
1147     }
1148
1149 lend:
1150     hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1151     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1152     {
1153         INTERNET_ASYNC_RESULT iar;
1154
1155         iar.dwResult = (DWORD)bSuccess;
1156         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1157         hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1158             &iar, sizeof(INTERNET_ASYNC_RESULT));
1159     }
1160
1161     return bSuccess;
1162 }
1163
1164
1165 /***********************************************************************
1166  *           FtpRenameFileA  (WININET.@)
1167  *
1168  * Rename a file on the ftp server
1169  *
1170  * RETURNS
1171  *    TRUE on success
1172  *    FALSE on failure
1173  *
1174  */
1175 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1176 {
1177     LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1178     LPWININETAPPINFOA hIC = NULL;
1179
1180     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1181     {
1182         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1183         return FALSE;
1184     }
1185
1186     hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1187     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1188     {
1189         WORKREQUEST workRequest;
1190
1191         workRequest.asyncall = FTPRENAMEFILEA;
1192         workRequest.HFTPSESSION = (DWORD)hFtpSession;
1193         workRequest.LPSZSRCFILE = (DWORD)FTP_strdup(lpszSrc);
1194         workRequest.LPSZDESTFILE = (DWORD)FTP_strdup(lpszDest);
1195
1196         return INTERNET_AsyncCall(&workRequest);
1197     }
1198     else
1199     {
1200         return FTP_FtpRenameFileA(hFtpSession, lpszSrc, lpszDest);
1201     }
1202 }
1203
1204 /***********************************************************************
1205  *           FTP_FtpRenameFileA  (Internal)
1206  *
1207  * Rename a file on the ftp server
1208  *
1209  * RETURNS
1210  *    TRUE on success
1211  *    FALSE on failure
1212  *
1213  */
1214 BOOL FTP_FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1215 {
1216     INT nResCode;
1217     BOOL bSuccess = FALSE;
1218     LPWININETAPPINFOA hIC = NULL;
1219     LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1220
1221     TRACE("\n");
1222     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1223     {
1224         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1225         return FALSE;
1226     }
1227
1228     /* Clear any error information */
1229     INTERNET_SetLastError(0);
1230
1231     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1232         goto lend;
1233
1234     nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1235         INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1236     if (nResCode == 350)
1237     {
1238         if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1239             goto lend;
1240
1241         nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1242                     INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1243     }
1244
1245     if (nResCode == 250)
1246         bSuccess = TRUE;
1247     else
1248         FTP_SetResponseError(nResCode);
1249
1250 lend:
1251     hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1252     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1253     {
1254         INTERNET_ASYNC_RESULT iar;
1255
1256         iar.dwResult = (DWORD)bSuccess;
1257         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1258         hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1259             &iar, sizeof(INTERNET_ASYNC_RESULT));
1260     }
1261
1262     return bSuccess;
1263 }
1264
1265
1266 /***********************************************************************
1267  *           FTP_Connect (internal)
1268  *
1269  * Connect to a ftp server
1270  *
1271  * RETURNS
1272  *   HINTERNET a session handle on success
1273  *   NULL on failure
1274  *
1275  */
1276
1277 HINTERNET FTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
1278         INTERNET_PORT nServerPort, LPCSTR lpszUserName,
1279         LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
1280 {
1281     struct sockaddr_in socketAddr;
1282     struct hostent *phe = NULL;
1283     INT nsocket = -1, sock_namelen;
1284     LPWININETAPPINFOA hIC = NULL;
1285     BOOL bSuccess = FALSE;
1286     LPWININETFTPSESSIONA lpwfs = NULL;
1287
1288     TRACE("0x%08lx  Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1289             (ULONG) hInternet, lpszServerName,
1290             nServerPort, lpszUserName, lpszPassword);
1291
1292     if (((LPWININETHANDLEHEADER)hInternet)->htype != WH_HINIT)
1293         goto lerror;
1294
1295     hIC = (LPWININETAPPINFOA) hInternet;
1296
1297     if (NULL == lpszUserName && NULL != lpszPassword)
1298     {
1299         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_USER_NAME);
1300         goto lerror;
1301     }
1302
1303     if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1304         nServerPort = INTERNET_DEFAULT_FTP_PORT;
1305
1306     if (hIC->lpfnStatusCB)
1307         hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1308             (LPSTR) lpszServerName, strlen(lpszServerName));
1309
1310     if (!GetAddress(lpszServerName, nServerPort, &phe, &socketAddr))
1311     {
1312         INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1313         goto lerror;
1314     }
1315
1316     if (hIC->lpfnStatusCB)
1317         hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1318             (LPSTR) lpszServerName, strlen(lpszServerName));
1319
1320     nsocket = socket(AF_INET,SOCK_STREAM,0);
1321     if (nsocket == -1)
1322     {
1323         INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1324         goto lerror;
1325     }
1326
1327     if (hIC->lpfnStatusCB)
1328         hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1329              &socketAddr, sizeof(struct sockaddr_in));
1330
1331     if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1332     {
1333         ERR("Unable to connect (%s)\n", strerror(errno));
1334         INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1335     }
1336     else
1337     {
1338         TRACE("Connected to server\n");
1339         if (hIC->lpfnStatusCB)
1340             hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1341                 &socketAddr, sizeof(struct sockaddr_in));
1342
1343         lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONA));
1344         if (NULL == lpwfs)
1345         {
1346             INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1347             goto lerror;
1348         }
1349
1350         lpwfs->hdr.htype = WH_HFTPSESSION;
1351         lpwfs->hdr.dwFlags = dwFlags;
1352         lpwfs->hdr.dwContext = dwContext;
1353         lpwfs->hdr.lpwhparent = (LPWININETHANDLEHEADER)hInternet;
1354         lpwfs->sndSocket = nsocket;
1355         sock_namelen = sizeof(lpwfs->socketAddress);
1356         getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1357         lpwfs->phostent = phe;
1358
1359         if (NULL == lpszUserName)
1360         {
1361             lpwfs->lpszUserName = FTP_strdup("anonymous");
1362             lpwfs->lpszPassword = FTP_strdup("user@server");
1363         }
1364         else
1365         {
1366             lpwfs->lpszUserName = FTP_strdup(lpszUserName);
1367             lpwfs->lpszPassword = FTP_strdup(lpszPassword);
1368         }
1369
1370         if (FTP_ConnectToHost(lpwfs))
1371         {
1372             if (hIC->lpfnStatusCB)
1373             {
1374                 INTERNET_ASYNC_RESULT iar;
1375
1376                 iar.dwResult = (DWORD)lpwfs;
1377                 iar.dwError = ERROR_SUCCESS;
1378
1379                 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_HANDLE_CREATED,
1380                     &iar, sizeof(INTERNET_ASYNC_RESULT));
1381             }
1382             TRACE("Successfully logged into server\n");
1383             bSuccess = TRUE;
1384         }
1385     }
1386
1387 lerror:
1388     if (!bSuccess && nsocket == -1)
1389         close(nsocket);
1390
1391     if (!bSuccess && lpwfs)
1392     {
1393         HeapFree(GetProcessHeap(), 0, lpwfs);
1394         lpwfs = NULL;
1395     }
1396
1397     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1398     {
1399         INTERNET_ASYNC_RESULT iar;
1400
1401         iar.dwResult = (DWORD)lpwfs;
1402         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1403         hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1404             &iar, sizeof(INTERNET_ASYNC_RESULT));
1405     }
1406
1407     return (HINTERNET) lpwfs;
1408 }
1409
1410
1411 /***********************************************************************
1412  *           FTP_ConnectToHost (internal)
1413  *
1414  * Connect to a ftp server
1415  *
1416  * RETURNS
1417  *   TRUE on success
1418  *   NULL on failure
1419  *
1420  */
1421 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs)
1422 {
1423     INT nResCode;
1424     BOOL bSuccess = FALSE;
1425
1426     TRACE("\n");
1427     FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1428
1429     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1430         goto lend;
1431
1432     nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1433         MAX_REPLY_LEN, 0, 0, 0);
1434     if (nResCode)
1435     {
1436         /* Login successful... */
1437         if (nResCode == 230)
1438             bSuccess = TRUE;
1439         /* User name okay, need password... */
1440         else if (nResCode == 331)
1441             bSuccess = FTP_SendPassword(lpwfs);
1442         /* Need account for login... */
1443         else if (nResCode == 332)
1444             bSuccess = FTP_SendAccount(lpwfs);
1445         else
1446             FTP_SetResponseError(nResCode);
1447     }
1448
1449     TRACE("Returning %d\n", bSuccess);
1450 lend:
1451     return bSuccess;
1452 }
1453
1454
1455 /***********************************************************************
1456  *           FTP_SendCommand (internal)
1457  *
1458  * Send command to server
1459  *
1460  * RETURNS
1461  *   TRUE on success
1462  *   NULL on failure
1463  *
1464  */
1465 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1466         INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1467 {
1468         DWORD len;
1469         CHAR *buf;
1470         DWORD nBytesSent = 0;
1471         DWORD nRC = 0;
1472         BOOL bParamHasLen;
1473
1474         TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1475
1476         if (lpfnStatusCB)
1477                 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1478
1479         bParamHasLen = lpszParam && strlen(lpszParam) > 0;
1480         len = (bParamHasLen ? strlen(lpszParam) : -1) + strlen(szFtpCommands[ftpCmd]) +
1481             strlen(szCRLF)+ 1;
1482         if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1483         {
1484             INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1485             return FALSE;
1486         }
1487         sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], bParamHasLen ? " " : "",
1488                 bParamHasLen ? lpszParam : "", szCRLF);
1489
1490         TRACE("Sending (%s) len(%ld)\n", buf, len);
1491         while((nBytesSent < len) && (nRC != -1))
1492         {
1493                 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1494                 nBytesSent += nRC;
1495         }
1496
1497         HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
1498
1499         if (lpfnStatusCB)
1500                 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_REQUEST_SENT,
1501                         &nBytesSent, sizeof(DWORD));
1502
1503         TRACE("Sent %ld bytes\n", nBytesSent);
1504         return (nRC != -1);
1505 }
1506
1507
1508 /***********************************************************************
1509  *           FTP_ReceiveResponse (internal)
1510  *
1511  * Receive response from server
1512  *
1513  * RETURNS
1514  *   Reply code on success
1515  *   0 on failure
1516  *
1517  */
1518
1519 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
1520         INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1521 {
1522     DWORD nRecv;
1523     INT rc = 0;
1524     char firstprefix[5];
1525     BOOL multiline = FALSE;
1526
1527
1528     TRACE("socket(%d) \n", nSocket);
1529
1530     if (lpfnStatusCB)
1531         lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1532
1533     while(1)
1534     {
1535         nRecv = dwResponse;
1536         if (!INTERNET_GetNextLine(nSocket, lpszResponse, &nRecv))
1537             goto lerror;
1538
1539         if (nRecv >= 3)
1540         {
1541             if(!multiline)
1542             {
1543                 if(lpszResponse[3] != '-')
1544                     break;
1545                 else
1546                 {  /* Start of multiline repsonse.  Loop until we get "nnn " */
1547                     multiline = TRUE;
1548                     memcpy(firstprefix, lpszResponse, 3);
1549                     firstprefix[3] = ' ';
1550                     firstprefix[4] = '\0';
1551                 }
1552             }
1553             else
1554             {
1555                 if(!memcmp(firstprefix, lpszResponse, 4))
1556                     break;
1557             }
1558         }
1559     }
1560
1561     if (nRecv >= 3)
1562     {
1563         lpszResponse[nRecv] = '\0';
1564         rc = atoi(lpszResponse);
1565
1566         if (lpfnStatusCB)
1567             lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
1568                     &nRecv, sizeof(DWORD));
1569     }
1570
1571 lerror:
1572     TRACE("return %d\n", rc);
1573     return rc;
1574 }
1575
1576
1577 /***********************************************************************
1578  *           FTP_SendPassword (internal)
1579  *
1580  * Send password to ftp server
1581  *
1582  * RETURNS
1583  *   TRUE on success
1584  *   NULL on failure
1585  *
1586  */
1587 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs)
1588 {
1589     INT nResCode;
1590     BOOL bSuccess = FALSE;
1591
1592     TRACE("\n");
1593     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
1594         goto lend;
1595
1596     nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1597         MAX_REPLY_LEN, 0, 0, 0);
1598     if (nResCode)
1599     {
1600         TRACE("Received reply code %d\n", nResCode);
1601         /* Login successful... */
1602         if (nResCode == 230)
1603             bSuccess = TRUE;
1604         /* Command not implemented, superfluous at the server site... */
1605         /* Need account for login... */
1606         else if (nResCode == 332)
1607             bSuccess = FTP_SendAccount(lpwfs);
1608         else
1609             FTP_SetResponseError(nResCode);
1610     }
1611
1612 lend:
1613     TRACE("Returning %d\n", bSuccess);
1614     return bSuccess;
1615 }
1616
1617
1618 /***********************************************************************
1619  *           FTP_SendAccount (internal)
1620  *
1621  *
1622  *
1623  * RETURNS
1624  *   TRUE on success
1625  *   FALSE on failure
1626  *
1627  */
1628 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs)
1629 {
1630     INT nResCode;
1631     BOOL bSuccess = FALSE;
1632
1633     TRACE("\n");
1634     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, NOACCOUNT, 0, 0, 0))
1635         goto lend;
1636
1637     nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1638         MAX_REPLY_LEN, 0,  0, 0);
1639     if (nResCode)
1640         bSuccess = TRUE;
1641     else
1642         FTP_SetResponseError(nResCode);
1643
1644 lend:
1645     return bSuccess;
1646 }
1647
1648
1649 /***********************************************************************
1650  *           FTP_SendStore (internal)
1651  *
1652  * Send request to upload file to ftp server
1653  *
1654  * RETURNS
1655  *   TRUE on success
1656  *   FALSE on failure
1657  *
1658  */
1659 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
1660 {
1661     INT nResCode;
1662     BOOL bSuccess = FALSE;
1663
1664     TRACE("\n");
1665     if (!FTP_InitListenSocket(lpwfs))
1666         goto lend;
1667
1668     if (!FTP_SendType(lpwfs, dwType))
1669         goto lend;
1670
1671     if (!FTP_SendPortOrPasv(lpwfs))
1672         goto lend;
1673
1674     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
1675             goto lend;
1676     nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1677        MAX_REPLY_LEN, 0, 0, 0);
1678     if (nResCode)
1679     {
1680         if (nResCode == 150)
1681             bSuccess = TRUE;
1682         else
1683             FTP_SetResponseError(nResCode);
1684     }
1685
1686 lend:
1687     if (!bSuccess && lpwfs->lstnSocket != -1)
1688     {
1689         close(lpwfs->lstnSocket);
1690         lpwfs->lstnSocket = -1;
1691     }
1692
1693     return bSuccess;
1694 }
1695
1696
1697 /***********************************************************************
1698  *           FTP_InitListenSocket (internal)
1699  *
1700  * Create a socket to listen for server response
1701  *
1702  * RETURNS
1703  *   TRUE on success
1704  *   FALSE on failure
1705  *
1706  */
1707 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs)
1708 {
1709     BOOL bSuccess = FALSE;
1710     size_t namelen = sizeof(struct sockaddr_in);
1711
1712     TRACE("\n");
1713
1714     lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
1715     if (lpwfs->lstnSocket == -1)
1716     {
1717         TRACE("Unable to create listening socket\n");
1718             goto lend;
1719     }
1720
1721     /* We obtain our ip addr from the name of the command channel socket */
1722     lpwfs->lstnSocketAddress = lpwfs->socketAddress;
1723
1724     /* and get the system to assign us a port */
1725     lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
1726
1727     if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
1728     {
1729         TRACE("Unable to bind socket\n");
1730         goto lend;
1731     }
1732
1733     if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
1734     {
1735         TRACE("listen failed\n");
1736         goto lend;
1737     }
1738
1739     if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
1740         bSuccess = TRUE;
1741
1742 lend:
1743     if (!bSuccess && lpwfs->lstnSocket == -1)
1744     {
1745         close(lpwfs->lstnSocket);
1746         lpwfs->lstnSocket = -1;
1747     }
1748
1749     return bSuccess;
1750 }
1751
1752
1753 /***********************************************************************
1754  *           FTP_SendType (internal)
1755  *
1756  * Tell server type of data being transferred
1757  *
1758  * RETURNS
1759  *   TRUE on success
1760  *   FALSE on failure
1761  *
1762  * W98SE doesn't cache the type that's currently set
1763  * (i.e. it sends it always),
1764  * so we probably don't want to do that either.
1765  */
1766 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType)
1767 {
1768     INT nResCode;
1769     CHAR type[2] = { "I\0" };
1770     BOOL bSuccess = FALSE;
1771
1772     TRACE("\n");
1773     if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
1774         *type = 'A';
1775
1776     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
1777         goto lend;
1778
1779     nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1780         MAX_REPLY_LEN, 0, 0, 0)/100;
1781     if (nResCode)
1782     {
1783         if (nResCode == 2)
1784             bSuccess = TRUE;
1785         else
1786             FTP_SetResponseError(nResCode);
1787     }
1788
1789 lend:
1790     return bSuccess;
1791 }
1792
1793
1794 /***********************************************************************
1795  *           FTP_SendPort (internal)
1796  *
1797  * Tell server which port to use
1798  *
1799  * RETURNS
1800  *   TRUE on success
1801  *   FALSE on failure
1802  *
1803  */
1804 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs)
1805 {
1806     INT nResCode;
1807     CHAR szIPAddress[64];
1808     BOOL bSuccess = FALSE;
1809     TRACE("\n");
1810
1811     sprintf(szIPAddress, "%d,%d,%d,%d,%d,%d",
1812          lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
1813         (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
1814         (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
1815         (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
1816         lpwfs->lstnSocketAddress.sin_port & 0xFF,
1817         (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
1818
1819     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
1820         goto lend;
1821
1822     nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1823         MAX_REPLY_LEN,0, 0, 0);
1824     if (nResCode)
1825     {
1826         if (nResCode == 200)
1827             bSuccess = TRUE;
1828         else
1829             FTP_SetResponseError(nResCode);
1830     }
1831
1832 lend:
1833     return bSuccess;
1834 }
1835
1836
1837 /***********************************************************************
1838  *           FTP_DoPassive (internal)
1839  *
1840  * Tell server that we want to do passive transfers
1841  * and connect data socket
1842  *
1843  * RETURNS
1844  *   TRUE on success
1845  *   FALSE on failure
1846  *
1847  */
1848 BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs)
1849 {
1850     INT nResCode;
1851     BOOL bSuccess = FALSE;
1852
1853     TRACE("\n");
1854     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
1855         goto lend;
1856
1857     nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1858         MAX_REPLY_LEN,0, 0, 0);
1859     if (nResCode)
1860     {
1861         if (nResCode == 227)
1862         {
1863             LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
1864             LPSTR p;
1865             int f[6];
1866             int i;
1867             char *pAddr, *pPort;
1868             INT nsocket = -1;
1869             struct sockaddr_in dataSocketAddress;
1870
1871             p = lpszResponseBuffer+4; /* skip status code */
1872
1873             /* do a very strict check; we can improve that later. */
1874
1875             if (strncmp(p, "Entering Passive Mode", 21))
1876             {
1877                 ERR("unknown response '%.*s', aborting\n", 21, p);
1878                 goto lend;
1879             }
1880             p += 21; /* skip string */
1881             if ((*p++ != ' ') || (*p++ != '('))
1882             {
1883                 ERR("unknown response format, aborting\n");
1884                 goto lend;
1885             }
1886
1887             if (sscanf(p, "%d,%d,%d,%d,%d,%d",  &f[0], &f[1], &f[2], &f[3],
1888                                                 &f[4], &f[5]) != 6)
1889             {
1890                 ERR("unknown response address format '%s', aborting\n", p);
1891                 goto lend;
1892             }
1893             for (i=0; i < 6; i++)
1894                 f[i] = f[i] & 0xff;
1895
1896             dataSocketAddress = lpwfs->socketAddress;
1897             pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
1898             pPort = (char *)&(dataSocketAddress.sin_port);
1899             pAddr[0] = f[0];
1900             pAddr[1] = f[1];
1901             pAddr[2] = f[2];
1902             pAddr[3] = f[3];
1903             pPort[0] = f[4];
1904             pPort[1] = f[5];
1905
1906             nsocket = socket(AF_INET,SOCK_STREAM,0);
1907             if (nsocket == -1)
1908                 goto lend;
1909
1910             if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
1911             {
1912                 ERR("can't connect passive FTP data port.\n");
1913                 goto lend;
1914             }
1915             lpwfs->pasvSocket = nsocket;
1916             bSuccess = TRUE;
1917         }
1918         else
1919             FTP_SetResponseError(nResCode);
1920     }
1921
1922 lend:
1923     return bSuccess;
1924 }
1925
1926
1927 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs)
1928 {
1929     if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
1930     {
1931         if (!FTP_DoPassive(lpwfs))
1932             return FALSE;
1933     }
1934     else
1935     {
1936         if (!FTP_SendPort(lpwfs))
1937             return FALSE;
1938     }
1939     return TRUE;
1940 }
1941
1942
1943 /***********************************************************************
1944  *           FTP_GetDataSocket (internal)
1945  *
1946  * Either accepts an incoming data socket connection from the server
1947  * or just returns the already opened socket after a PASV command
1948  * in case of passive FTP.
1949  *
1950  *
1951  * RETURNS
1952  *   TRUE on success
1953  *   FALSE on failure
1954  *
1955  */
1956 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket)
1957 {
1958     struct sockaddr_in saddr;
1959     size_t addrlen = sizeof(struct sockaddr);
1960
1961     TRACE("\n");
1962     if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
1963     {
1964         *nDataSocket = lpwfs->pasvSocket;
1965     }
1966     else
1967     {
1968         *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
1969         close(lpwfs->lstnSocket);
1970         lpwfs->lstnSocket = -1;
1971     }
1972     return *nDataSocket != -1;
1973 }
1974
1975
1976 /***********************************************************************
1977  *           FTP_SendData (internal)
1978  *
1979  * Send data to the server
1980  *
1981  * RETURNS
1982  *   TRUE on success
1983  *   FALSE on failure
1984  *
1985  */
1986 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile)
1987 {
1988     BY_HANDLE_FILE_INFORMATION fi;
1989     DWORD nBytesRead = 0;
1990     DWORD nBytesSent = 0;
1991     DWORD nTotalSent = 0;
1992     DWORD nBytesToSend, nLen, nRC = 1;
1993     time_t s_long_time, e_long_time;
1994     LONG nSeconds;
1995     CHAR *lpszBuffer;
1996
1997     TRACE("\n");
1998     lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
1999     memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2000
2001     /* Get the size of the file. */
2002     GetFileInformationByHandle(hFile, &fi);
2003     time(&s_long_time);
2004
2005     do
2006     {
2007         nBytesToSend = nBytesRead - nBytesSent;
2008
2009         if (nBytesToSend <= 0)
2010         {
2011             /* Read data from file. */
2012             nBytesSent = 0;
2013             if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2014             ERR("Failed reading from file\n");
2015
2016             if (nBytesRead > 0)
2017                 nBytesToSend = nBytesRead;
2018             else
2019                 break;
2020         }
2021
2022         nLen = DATA_PACKET_SIZE < nBytesToSend ?
2023             DATA_PACKET_SIZE : nBytesToSend;
2024         nRC  = send(nDataSocket, lpszBuffer, nLen, 0);
2025
2026         if (nRC != -1)
2027         {
2028             nBytesSent += nRC;
2029             nTotalSent += nRC;
2030         }
2031
2032         /* Do some computation to display the status. */
2033         time(&e_long_time);
2034         nSeconds = e_long_time - s_long_time;
2035         if( nSeconds / 60 > 0 )
2036         {
2037             TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
2038             nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2039             nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2040         }
2041         else
2042         {
2043             TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
2044             nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2045             (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2046         }
2047     } while (nRC != -1);
2048
2049     TRACE("file transfer complete!\n");
2050
2051     if(lpszBuffer != NULL)
2052         HeapFree(GetProcessHeap(), 0, lpszBuffer);
2053
2054     return nTotalSent;
2055 }
2056
2057
2058 /***********************************************************************
2059  *           FTP_SendRetrieve (internal)
2060  *
2061  * Send request to retrieve a file
2062  *
2063  * RETURNS
2064  *   Number of bytes to be received on success
2065  *   0 on failure
2066  *
2067  */
2068 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
2069 {
2070     INT nResCode;
2071     DWORD nResult = 0;
2072
2073     TRACE("\n");
2074     if (!FTP_InitListenSocket(lpwfs))
2075         goto lend;
2076
2077     if (!FTP_SendType(lpwfs, dwType))
2078         goto lend;
2079
2080     if (!FTP_SendPortOrPasv(lpwfs))
2081         goto lend;
2082
2083     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2084         goto lend;
2085
2086     nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2087         MAX_REPLY_LEN, 0, 0, 0);
2088     if (nResCode)
2089     {
2090         if (nResCode == 125 || nResCode == 150)
2091         {
2092             /* Parse size of data to be retrieved */
2093             INT i, sizepos = -1;
2094             LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2095             for (i = strlen(lpszResponseBuffer) - 1; i >= 0; i--)
2096             {
2097                 if ('(' == lpszResponseBuffer[i])
2098                 {
2099                     sizepos = i;
2100                     break;
2101                 }
2102             }
2103
2104             if (sizepos >= 0)
2105             {
2106                 nResult = atol(&lpszResponseBuffer[sizepos+1]);
2107                 TRACE("Waiting to receive %ld bytes\n", nResult);
2108             }
2109         }
2110     }
2111
2112 lend:
2113     if (0 == nResult && lpwfs->lstnSocket != -1)
2114     {
2115         close(lpwfs->lstnSocket);
2116         lpwfs->lstnSocket = -1;
2117     }
2118
2119     return nResult;
2120 }
2121
2122
2123 /***********************************************************************
2124  *           FTP_RetrieveData  (internal)
2125  *
2126  * Retrieve data from server
2127  *
2128  * RETURNS
2129  *   TRUE on success
2130  *   FALSE on failure
2131  *
2132  */
2133 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2134 {
2135     DWORD nBytesWritten;
2136     DWORD nBytesReceived = 0;
2137     INT nRC = 0;
2138     CHAR *lpszBuffer;
2139
2140     TRACE("\n");
2141
2142     if (INVALID_HANDLE_VALUE == hFile)
2143         return FALSE;
2144
2145     lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2146     if (NULL == lpszBuffer)
2147     {
2148         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2149         return FALSE;
2150     }
2151
2152     while (nBytesReceived < nBytes && nRC != -1)
2153     {
2154         nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2155         if (nRC != -1)
2156         {
2157             /* other side closed socket. */
2158             if (nRC == 0)
2159                 goto recv_end;
2160             WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2161             nBytesReceived += nRC;
2162         }
2163
2164         TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
2165            nBytesReceived * 100 / nBytes);
2166     }
2167
2168     TRACE("Data transfer complete\n");
2169     if (NULL != lpszBuffer)
2170         HeapFree(GetProcessHeap(), 0, lpszBuffer);
2171
2172 recv_end:
2173     return  (nRC != -1);
2174 }
2175
2176
2177 /***********************************************************************
2178  *           FTP_CloseSessionHandle (internal)
2179  *
2180  * Deallocate session handle
2181  *
2182  * RETURNS
2183  *   TRUE on success
2184  *   FALSE on failure
2185  *
2186  */
2187 BOOL FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs)
2188 {
2189     if (lpwfs->sndSocket != -1)
2190         close(lpwfs->sndSocket);
2191
2192     if (lpwfs->lstnSocket != -1)
2193         close(lpwfs->lstnSocket);
2194
2195     if (lpwfs->lpszPassword)
2196         HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2197
2198     if (lpwfs->lpszUserName)
2199         HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2200
2201     HeapFree(GetProcessHeap(), 0, lpwfs);
2202
2203     return TRUE;
2204 }
2205
2206
2207 /***********************************************************************
2208  *           FTP_CloseSessionHandle (internal)
2209  *
2210  * Deallocate session handle
2211  *
2212  * RETURNS
2213  *   TRUE on success
2214  *   FALSE on failure
2215  *
2216  */
2217 BOOL FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn)
2218 {
2219     INT i;
2220
2221     TRACE("\n");
2222
2223     for (i = 0; i < lpwfn->size; i++)
2224     {
2225         if (NULL != lpwfn->lpafp[i].lpszName)
2226             HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2227     }
2228
2229     HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2230     HeapFree(GetProcessHeap(), 0, lpwfn);
2231
2232     return TRUE;
2233 }
2234
2235
2236 /***********************************************************************
2237  *           FTP_ReceiveFileList (internal)
2238  *
2239  * Read file list from server
2240  *
2241  * RETURNS
2242  *   Handle to file list on success
2243  *   NULL on failure
2244  *
2245  */
2246 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
2247         LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext)
2248 {
2249     DWORD dwSize = 0;
2250     LPFILEPROPERTIESA lpafp = NULL;
2251     LPWININETFINDNEXTA lpwfn = NULL;
2252
2253     TRACE("\n");
2254
2255     if (FTP_ParseDirectory(lpwfs, nSocket, &lpafp, &dwSize))
2256     {
2257         FTP_ConvertFileProp(lpafp, lpFindFileData);
2258
2259         lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTA));
2260         if (NULL != lpwfn)
2261         {
2262             lpwfn->hdr.htype = WH_HFINDNEXT;
2263             lpwfn->hdr.lpwhparent = (LPWININETHANDLEHEADER)lpwfs;
2264             lpwfn->hdr.dwContext = dwContext;
2265             lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2266             lpwfn->size = dwSize;
2267             lpwfn->lpafp = lpafp;
2268         }
2269     }
2270
2271     TRACE("Matched %ld files\n", dwSize);
2272     return (HINTERNET)lpwfn;
2273 }
2274
2275
2276 /***********************************************************************
2277  *           FTP_ConvertFileProp (internal)
2278  *
2279  * Converts FILEPROPERTIESA struct to WIN32_FIND_DATAA
2280  *
2281  * RETURNS
2282  *   TRUE on success
2283  *   FALSE on failure
2284  *
2285  */
2286 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESA lpafp, LPWIN32_FIND_DATAA lpFindFileData)
2287 {
2288     BOOL bSuccess = FALSE;
2289
2290     ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2291
2292     if (lpafp)
2293     {
2294         DWORD access = mktime(&lpafp->tmLastModified);
2295
2296         /* Not all fields are filled in */
2297         lpFindFileData->ftLastAccessTime.dwHighDateTime = HIWORD(access);
2298         lpFindFileData->ftLastAccessTime.dwLowDateTime  = LOWORD(access);
2299         lpFindFileData->nFileSizeHigh = HIWORD(lpafp->nSize);
2300         lpFindFileData->nFileSizeLow = LOWORD(lpafp->nSize);
2301
2302         if (lpafp->bIsDirectory)
2303             lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2304
2305         if (lpafp->lpszName)
2306             strncpy(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2307
2308         bSuccess = TRUE;
2309     }
2310
2311     return bSuccess;
2312 }
2313
2314
2315 /***********************************************************************
2316  *           FTP_ParseDirectory (internal)
2317  *
2318  * Parse string of directory information
2319  *
2320  * RETURNS
2321  *   TRUE on success
2322  *   FALSE on failure
2323  *
2324  * FIXME: - This function needs serious clea-up
2325  *        - We should consider both UNIX and NT list formats
2326  */
2327 #define MAX_MONTH_LEN 10
2328 #define MIN_LEN_DIR_ENTRY 15
2329
2330 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp)
2331 {
2332   /*
2333    * <Permissions> <NoLinks> <owner>   <group> <size> <date>  <time or year> <filename>
2334    *
2335    * For instance:
2336    * drwx--s---     2         pcarrier  ens     512    Sep 28  1995           pcarrier
2337    */
2338     CHAR* pszMinutes;
2339     CHAR* pszHour;
2340     time_t aTime;
2341     struct tm* apTM;
2342     CHAR pszMonth[MAX_MONTH_LEN];
2343     CHAR* pszMatch;
2344     BOOL bSuccess = TRUE;
2345     DWORD nBufLen = MAX_REPLY_LEN;
2346     LPFILEPROPERTIESA curFileProp = NULL;
2347     CHAR* pszLine  = NULL;
2348     CHAR* pszToken = NULL;
2349     INT nTokenToSkip = 3;
2350     INT nCount = 0;
2351     INT nSeconds = 0;
2352     INT nMinutes = 0;
2353     INT nHour    = 0;
2354     INT nDay     = 0;
2355     INT nMonth   = 0;
2356     INT nYear    = 0;
2357     INT sizeFilePropArray = 20;
2358     INT indexFilePropArray = 0;
2359
2360     TRACE("\n");
2361
2362     /* Allocate intial file properties array */
2363     *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESA)*(sizeFilePropArray));
2364     if (NULL == lpafp)
2365     {
2366         bSuccess = FALSE;
2367         goto lend;
2368     }
2369
2370     while ((pszLine = INTERNET_GetNextLine(nSocket, INTERNET_GetResponseBuffer(), &nBufLen)) != NULL)
2371     {
2372         if (sizeFilePropArray <= indexFilePropArray)
2373         {
2374             LPFILEPROPERTIESA tmpafp;
2375
2376             sizeFilePropArray *= 2;
2377             tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
2378                 sizeof(FILEPROPERTIESA)*sizeFilePropArray);
2379             if (NULL == tmpafp)
2380             {
2381                 bSuccess = FALSE;
2382                 goto lend;
2383             }
2384
2385             *lpafp = tmpafp;
2386         }
2387
2388         curFileProp = &((*lpafp)[indexFilePropArray]);
2389
2390         /* First Parse the permissions. */
2391         pszToken = strtok(pszLine, " \t" );
2392
2393         /* HACK! If this is not a file listing skip the line */
2394         if (!pszToken || 10 != strlen(pszToken) || nBufLen <= MIN_LEN_DIR_ENTRY)
2395         {
2396             nBufLen = MAX_REPLY_LEN;
2397             continue;
2398         }
2399
2400         FTP_ParsePermission(pszToken, curFileProp);
2401
2402         nTokenToSkip = 3;
2403         nCount = 0;
2404         do
2405         {
2406             pszToken = strtok( NULL, " \t" );
2407             nCount++;
2408         } while( nCount <= nTokenToSkip );
2409
2410         /* Store the size of the file in the param list. */
2411         TRACE("nSize-> %s\n", pszToken);
2412         if (pszToken != NULL)
2413             curFileProp->nSize = atol(pszToken);
2414
2415         /* Parse last modified time. */
2416         nSeconds = 0;
2417         nMinutes = 0;
2418         nHour    = 0;
2419         nDay     = 0;
2420         nMonth   = 0;
2421         nYear    = 0;
2422
2423         pszToken = strtok( NULL, " \t" );
2424         strncpy(pszMonth, pszToken, MAX_MONTH_LEN);
2425         CharUpperA(pszMonth);
2426         pszMatch = strstr(szMonths, pszMonth);
2427         if( pszMatch != NULL )
2428             nMonth = (pszMatch - szMonths) / 3;
2429
2430         pszToken = strtok(NULL, " \t");
2431         TRACE("nDay -> %s\n", pszToken);
2432         if (pszToken != NULL)
2433             nDay = atoi(pszToken);
2434
2435         pszToken = strtok(NULL, " \t");
2436         pszMinutes = strchr(pszToken, ':');
2437         if( pszMinutes != NULL )
2438         {
2439             pszMinutes++;
2440             nMinutes = atoi(pszMinutes);
2441             pszHour = pszMinutes - 3;
2442             if (pszHour != NULL)
2443                 nHour = atoi(pszHour);
2444             time(&aTime);
2445             apTM = localtime( &aTime );
2446             nYear = apTM->tm_year;
2447         }
2448         else
2449         {
2450             nYear  = atoi(pszToken);
2451             nYear -= 1900;
2452             nHour  = 12;
2453         }
2454
2455         curFileProp->tmLastModified.tm_sec  = nSeconds;
2456         curFileProp->tmLastModified.tm_min  = nMinutes;
2457         curFileProp->tmLastModified.tm_hour = nHour;
2458         curFileProp->tmLastModified.tm_mday = nDay;
2459         curFileProp->tmLastModified.tm_mon  = nMonth;
2460         curFileProp->tmLastModified.tm_year = nYear;
2461
2462         pszToken = strtok(NULL, " \t");
2463         if(pszToken != NULL)
2464         {
2465             curFileProp->lpszName = FTP_strdup(pszToken);
2466             TRACE(": %s\n", curFileProp->lpszName);
2467         }
2468
2469         nBufLen = MAX_REPLY_LEN;
2470         indexFilePropArray++;
2471     }
2472
2473     if (bSuccess && indexFilePropArray)
2474     {
2475         if (indexFilePropArray < sizeFilePropArray - 1)
2476         {
2477             LPFILEPROPERTIESA tmpafp;
2478
2479             tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
2480                 sizeof(FILEPROPERTIESA)*indexFilePropArray);
2481             if (NULL == tmpafp)
2482                 *lpafp = tmpafp;
2483         }
2484         *dwfp = indexFilePropArray;
2485     }
2486     else
2487     {
2488         HeapFree(GetProcessHeap(), 0, *lpafp);
2489         INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2490         bSuccess = FALSE;
2491     }
2492
2493 lend:
2494     return bSuccess;
2495 }
2496
2497
2498 /***********************************************************************
2499  *           FTP_ParsePermission (internal)
2500  *
2501  * Parse permission string of directory information
2502  *
2503  * RETURNS
2504  *   TRUE on success
2505  *   FALSE on failure
2506  *
2507  */
2508 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp)
2509 {
2510     BOOL bSuccess = TRUE;
2511     unsigned short nPermission = 0;
2512     INT nPos = 1;
2513     INT nLast  = 9;
2514
2515     TRACE("\n");
2516     if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
2517     {
2518         bSuccess = FALSE;
2519         return bSuccess;
2520     }
2521
2522     lpfp->bIsDirectory = (*lpszPermission == 'd');
2523     do
2524     {
2525         switch (nPos)
2526         {
2527             case 1:
2528                 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
2529                 break;
2530             case 2:
2531                 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
2532                 break;
2533             case 3:
2534                 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
2535                 break;
2536             case 4:
2537                 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
2538                 break;
2539             case 5:
2540                 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
2541                 break;
2542             case 6:
2543                 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
2544                 break;
2545             case 7:
2546                 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
2547                 break;
2548             case 8:
2549                 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
2550                 break;
2551             case 9:
2552                 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
2553                 break;
2554         }
2555         nPos++;
2556     }while (nPos <= nLast);
2557
2558     lpfp->permissions = nPermission;
2559     return bSuccess;
2560 }
2561
2562
2563 /***********************************************************************
2564  *           FTP_SetResponseError (internal)
2565  *
2566  * Set the appropriate error code for a given response from the server
2567  *
2568  * RETURNS
2569  *
2570  */
2571 DWORD FTP_SetResponseError(DWORD dwResponse)
2572 {
2573     DWORD dwCode = 0;
2574
2575     switch(dwResponse)
2576     {
2577         case 421: /* Service not available - Server may be shutting down. */
2578             dwCode = ERROR_INTERNET_TIMEOUT;
2579             break;
2580
2581         case 425: /* Cannot open data connection. */
2582             dwCode = ERROR_INTERNET_CANNOT_CONNECT;
2583             break;
2584
2585         case 426: /* Connection closed, transer aborted. */
2586             dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
2587             break;
2588
2589         case 500: /* Syntax error. Command unrecognized. */
2590         case 501: /* Syntax error. Error in parameters or arguments. */
2591             dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
2592             break;
2593
2594         case 530: /* Not logged in. Login incorrect. */
2595             dwCode = ERROR_INTERNET_LOGIN_FAILURE;
2596             break;
2597
2598         case 550: /* File action not taken. File not found or no access. */
2599             dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
2600             break;
2601
2602         case 450: /* File action not taken. File may be busy. */
2603         case 451: /* Action aborted. Server error. */
2604         case 452: /* Action not taken. Insufficient storage space on server. */
2605         case 502: /* Command not implemented. */
2606         case 503: /* Bad sequence of command. */
2607         case 504: /* Command not implemented for that parameter. */
2608         case 532: /* Need account for storing files */
2609         case 551: /* Requested action aborted. Page type unknown */
2610         case 552: /* Action aborted. Exceeded storage allocation */
2611         case 553: /* Action not taken. File name not allowed. */
2612
2613         default:
2614             dwCode = ERROR_INTERNET_INTERNAL_ERROR;
2615             break;
2616     }
2617
2618     INTERNET_SetLastError(dwCode);
2619     return dwCode;
2620 }