wininet: Use proc instead of enum in FTPFINDFIRSTFILEW request.
[wine] / dlls / wininet / ftp.c
1 /*
2  * WININET - Ftp implementation
3  *
4  * Copyright 1999 Corel Corporation
5  * Copyright 2004 Mike McCormack for CodeWeavers
6  * Copyright 2004 Kevin Koltzau
7  *
8  * Ulrich Czekalla
9  * Noureddine Jemmali
10  *
11  * Copyright 2000 Andreas Mohr
12  * Copyright 2002 Jaco Greeff
13  *
14  * This library is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU Lesser General Public
16  * License as published by the Free Software Foundation; either
17  * version 2.1 of the License, or (at your option) any later version.
18  *
19  * This library is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22  * Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public
25  * License along with this library; if not, write to the Free Software
26  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27  */
28
29 #include "config.h"
30 #include "wine/port.h"
31
32 #include <errno.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/types.h>
38 #ifdef HAVE_SYS_SOCKET_H
39 # include <sys/socket.h>
40 #endif
41 #ifdef HAVE_UNISTD_H
42 # include <unistd.h>
43 #endif
44 #include <time.h>
45 #include <assert.h>
46
47 #include "windef.h"
48 #include "winbase.h"
49 #include "wingdi.h"
50 #include "winuser.h"
51 #include "wininet.h"
52 #include "winnls.h"
53 #include "winerror.h"
54 #include "winreg.h"
55 #include "winternl.h"
56 #include "shlwapi.h"
57
58 #include "wine/debug.h"
59 #include "internet.h"
60
61 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
62
63 #define DATA_PACKET_SIZE        0x2000
64 #define szCRLF                  "\r\n"
65 #define MAX_BACKLOG             5
66
67 typedef enum {
68   /* FTP commands with arguments. */
69   FTP_CMD_ACCT,
70   FTP_CMD_CWD,
71   FTP_CMD_DELE,
72   FTP_CMD_MKD,
73   FTP_CMD_PASS,
74   FTP_CMD_PORT,
75   FTP_CMD_RETR,
76   FTP_CMD_RMD,
77   FTP_CMD_RNFR,
78   FTP_CMD_RNTO,
79   FTP_CMD_STOR,
80   FTP_CMD_TYPE,
81   FTP_CMD_USER,
82   FTP_CMD_SIZE,
83
84   /* FTP commands without arguments. */
85   FTP_CMD_ABOR,
86   FTP_CMD_LIST,
87   FTP_CMD_NLST,
88   FTP_CMD_PASV,
89   FTP_CMD_PWD,
90   FTP_CMD_QUIT,
91 } FTP_COMMAND;
92
93 static const CHAR *szFtpCommands[] = {
94   "ACCT",
95   "CWD",
96   "DELE",
97   "MKD",
98   "PASS",
99   "PORT",
100   "RETR",
101   "RMD",
102   "RNFR",
103   "RNTO",
104   "STOR",
105   "TYPE",
106   "USER",
107   "SIZE",
108   "ABOR",
109   "LIST",
110   "NLST",
111   "PASV",
112   "PWD",
113   "QUIT",
114 };
115
116 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
117 static const WCHAR szNoAccount[] = {'n','o','a','c','c','o','u','n','t','\0'};
118
119 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr);
120 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr);
121 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr);
122 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
123         INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext);
124 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
125 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket);
126 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile);
127 static INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext);
128 static DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
129 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile);
130 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs);
131 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs);
132 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs);
133 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs);
134 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType);
135 static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize);
136 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs);
137 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs);
138 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs);
139 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp);
140 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW fileprop);
141 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
142         LPFILEPROPERTIESW *lpafp, LPDWORD dwfp);
143 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
144         LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext);
145 static DWORD FTP_SetResponseError(DWORD dwResponse);
146
147 /***********************************************************************
148  *           FtpPutFileA (WININET.@)
149  *
150  * Uploads a file to the FTP server
151  *
152  * RETURNS
153  *    TRUE on success
154  *    FALSE on failure
155  *
156  */
157 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
158     LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
159 {
160     LPWSTR lpwzLocalFile;
161     LPWSTR lpwzNewRemoteFile;
162     BOOL ret;
163     
164     lpwzLocalFile = lpszLocalFile?WININET_strdup_AtoW(lpszLocalFile):NULL;
165     lpwzNewRemoteFile = lpszNewRemoteFile?WININET_strdup_AtoW(lpszNewRemoteFile):NULL;
166     ret = FtpPutFileW(hConnect, lpwzLocalFile, lpwzNewRemoteFile,
167                       dwFlags, dwContext);
168     HeapFree(GetProcessHeap(), 0, lpwzLocalFile);
169     HeapFree(GetProcessHeap(), 0, lpwzNewRemoteFile);
170     return ret;
171 }
172
173 /***********************************************************************
174  *           FtpPutFileW (WININET.@)
175  *
176  * Uploads a file to the FTP server
177  *
178  * RETURNS
179  *    TRUE on success
180  *    FALSE on failure
181  *
182  */
183 static void AsyncFtpPutFileProc(WORKREQUEST *workRequest)
184 {
185     struct WORKREQ_FTPPUTFILEW const *req = &workRequest->u.FtpPutFileW;
186     LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
187
188     TRACE("%p\n", lpwfs);
189
190     FTP_FtpPutFileW(lpwfs, req->lpszLocalFile,
191                req->lpszNewRemoteFile, req->dwFlags, req->dwContext);
192
193     HeapFree(GetProcessHeap(), 0, req->lpszLocalFile);
194     HeapFree(GetProcessHeap(), 0, req->lpszNewRemoteFile);
195 }
196
197 BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile,
198     LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
199 {
200     LPWININETFTPSESSIONW lpwfs;
201     LPWININETAPPINFOW hIC = NULL;
202     BOOL r = FALSE;
203
204     lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
205     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
206     {
207         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
208         goto lend;
209     }
210
211     hIC = lpwfs->lpAppInfo;
212     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
213     {
214         WORKREQUEST workRequest;
215         struct WORKREQ_FTPPUTFILEW *req = &workRequest.u.FtpPutFileW;
216
217         workRequest.asyncall = CALLASYNCPROC;
218         workRequest.asyncproc = AsyncFtpPutFileProc;
219         workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
220         req->lpszLocalFile = WININET_strdupW(lpszLocalFile);
221         req->lpszNewRemoteFile = WININET_strdupW(lpszNewRemoteFile);
222         req->dwFlags = dwFlags;
223         req->dwContext = dwContext;
224
225         r = INTERNET_AsyncCall(&workRequest);
226     }
227     else
228     {
229         r = FTP_FtpPutFileW(lpwfs, lpszLocalFile,
230             lpszNewRemoteFile, dwFlags, dwContext);
231     }
232
233 lend:
234     if( lpwfs )
235         WININET_Release( &lpwfs->hdr );
236
237     return r;
238 }
239
240 /***********************************************************************
241  *           FTP_FtpPutFileW (Internal)
242  *
243  * Uploads a file to the FTP server
244  *
245  * RETURNS
246  *    TRUE on success
247  *    FALSE on failure
248  *
249  */
250 BOOL WINAPI FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile,
251     LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
252 {
253     HANDLE hFile = NULL;
254     BOOL bSuccess = FALSE;
255     LPWININETAPPINFOW hIC = NULL;
256     INT nResCode;
257
258     TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", debugstr_w(lpszLocalFile), debugstr_w(lpszNewRemoteFile));
259
260     if (!lpszLocalFile || !lpszNewRemoteFile)
261     {
262         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
263         return FALSE;
264     }
265
266     assert( WH_HFTPSESSION == lpwfs->hdr.htype);
267
268     /* Clear any error information */
269     INTERNET_SetLastError(0);
270     hIC = lpwfs->lpAppInfo;
271
272     /* Open file to be uploaded */
273     if (INVALID_HANDLE_VALUE ==
274         (hFile = CreateFileW(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
275     {
276         INTERNET_SetLastError(ERROR_FILE_NOT_FOUND);
277         goto lend;
278     }
279
280     SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
281
282     if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
283     {
284         INT nDataSocket;
285
286         /* Get data socket to server */
287         if (FTP_GetDataSocket(lpwfs, &nDataSocket))
288         {
289             FTP_SendData(lpwfs, nDataSocket, hFile);
290             closesocket(nDataSocket);
291             nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
292             if (nResCode)
293             {
294                 if (nResCode == 226)
295                     bSuccess = TRUE;
296                 else
297                     FTP_SetResponseError(nResCode);
298             }
299         }
300     }
301
302 lend:
303     if (lpwfs->lstnSocket != -1)
304         closesocket(lpwfs->lstnSocket);
305
306     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
307     {
308         INTERNET_ASYNC_RESULT iar;
309
310         iar.dwResult = (DWORD)bSuccess;
311         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
312         SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
313             &iar, sizeof(INTERNET_ASYNC_RESULT));
314     }
315
316     if (hFile)
317         CloseHandle(hFile);
318
319     return bSuccess;
320 }
321
322
323 /***********************************************************************
324  *           FtpSetCurrentDirectoryA (WININET.@)
325  *
326  * Change the working directory on the FTP server
327  *
328  * RETURNS
329  *    TRUE on success
330  *    FALSE on failure
331  *
332  */
333 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
334 {
335     LPWSTR lpwzDirectory;
336     BOOL ret;
337     
338     lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
339     ret = FtpSetCurrentDirectoryW(hConnect, lpwzDirectory);
340     HeapFree(GetProcessHeap(), 0, lpwzDirectory);
341     return ret;
342 }
343
344
345 /***********************************************************************
346  *           FtpSetCurrentDirectoryW (WININET.@)
347  *
348  * Change the working directory on the FTP server
349  *
350  * RETURNS
351  *    TRUE on success
352  *    FALSE on failure
353  *
354  */
355 static void AsyncFtpSetCurrentDirectoryProc(WORKREQUEST *workRequest)
356 {
357     struct WORKREQ_FTPSETCURRENTDIRECTORYW const *req = &workRequest->u.FtpSetCurrentDirectoryW;
358     LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
359
360     TRACE("%p\n", lpwfs);
361
362     FTP_FtpSetCurrentDirectoryW(lpwfs, req->lpszDirectory);
363     HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
364 }
365
366 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
367 {
368     LPWININETFTPSESSIONW lpwfs = NULL;
369     LPWININETAPPINFOW hIC = NULL;
370     BOOL r = FALSE;
371
372     if (!lpszDirectory)
373     {
374         SetLastError(ERROR_INVALID_PARAMETER);
375         goto lend;
376     }
377
378     lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
379     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
380     {
381         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
382         goto lend;
383     }
384
385     TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
386
387     hIC = lpwfs->lpAppInfo;
388     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
389     {
390         WORKREQUEST workRequest;
391         struct WORKREQ_FTPSETCURRENTDIRECTORYW *req;
392
393         workRequest.asyncall = CALLASYNCPROC;
394         workRequest.asyncproc = AsyncFtpSetCurrentDirectoryProc;
395         workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
396         req = &workRequest.u.FtpSetCurrentDirectoryW;
397         req->lpszDirectory = WININET_strdupW(lpszDirectory);
398
399         r = INTERNET_AsyncCall(&workRequest);
400     }
401     else
402     {
403         r = FTP_FtpSetCurrentDirectoryW(lpwfs, lpszDirectory);
404     }
405
406 lend:
407     if( lpwfs )
408         WININET_Release( &lpwfs->hdr );
409
410     return r;
411 }
412
413
414 /***********************************************************************
415  *           FTP_FtpSetCurrentDirectoryW (Internal)
416  *
417  * Change the working directory on the FTP server
418  *
419  * RETURNS
420  *    TRUE on success
421  *    FALSE on failure
422  *
423  */
424 BOOL WINAPI FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
425 {
426     INT nResCode;
427     LPWININETAPPINFOW hIC = NULL;
428     DWORD bSuccess = FALSE;
429
430     TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
431
432     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
433     {
434         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
435         return FALSE;
436     }
437
438     /* Clear any error information */
439     INTERNET_SetLastError(0);
440
441     hIC = lpwfs->lpAppInfo;
442     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
443         lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
444         goto lend;
445
446     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
447
448     if (nResCode)
449     {
450         if (nResCode == 250)
451             bSuccess = TRUE;
452         else
453             FTP_SetResponseError(nResCode);
454     }
455
456 lend:
457     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
458     {
459         INTERNET_ASYNC_RESULT iar;
460
461         iar.dwResult = (DWORD)bSuccess;
462         iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
463         SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
464             &iar, sizeof(INTERNET_ASYNC_RESULT));
465     }
466     return bSuccess;
467 }
468
469
470 /***********************************************************************
471  *           FtpCreateDirectoryA (WININET.@)
472  *
473  * Create new directory on the FTP server
474  *
475  * RETURNS
476  *    TRUE on success
477  *    FALSE on failure
478  *
479  */
480 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
481 {
482     LPWSTR lpwzDirectory;
483     BOOL ret;
484     
485     lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
486     ret = FtpCreateDirectoryW(hConnect, lpwzDirectory);
487     HeapFree(GetProcessHeap(), 0, lpwzDirectory);
488     return ret;
489 }
490
491
492 /***********************************************************************
493  *           FtpCreateDirectoryW (WININET.@)
494  *
495  * Create new directory on the FTP server
496  *
497  * RETURNS
498  *    TRUE on success
499  *    FALSE on failure
500  *
501  */
502 static void AsyncFtpCreateDirectoryProc(WORKREQUEST *workRequest)
503 {
504     struct WORKREQ_FTPCREATEDIRECTORYW const *req = &workRequest->u.FtpCreateDirectoryW;
505     LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
506
507     TRACE(" %p\n", lpwfs);
508
509     FTP_FtpCreateDirectoryW(lpwfs, req->lpszDirectory);
510     HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
511 }
512
513 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
514 {
515     LPWININETFTPSESSIONW lpwfs;
516     LPWININETAPPINFOW hIC = NULL;
517     BOOL r = FALSE;
518
519     lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
520     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
521     {
522         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
523         goto lend;
524     }
525
526     hIC = lpwfs->lpAppInfo;
527     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
528     {
529         WORKREQUEST workRequest;
530         struct WORKREQ_FTPCREATEDIRECTORYW *req;
531
532         workRequest.asyncall = CALLASYNCPROC;
533         workRequest.asyncproc = AsyncFtpCreateDirectoryProc;
534         workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
535         req = &workRequest.u.FtpCreateDirectoryW;
536         req->lpszDirectory = WININET_strdupW(lpszDirectory);
537
538         r = INTERNET_AsyncCall(&workRequest);
539     }
540     else
541     {
542         r = FTP_FtpCreateDirectoryW(lpwfs, lpszDirectory);
543     }
544 lend:
545     if( lpwfs )
546         WININET_Release( &lpwfs->hdr );
547
548     return r;
549 }
550
551
552 /***********************************************************************
553  *           FTP_FtpCreateDirectoryW (Internal)
554  *
555  * Create new directory on the FTP server
556  *
557  * RETURNS
558  *    TRUE on success
559  *    FALSE on failure
560  *
561  */
562 BOOL WINAPI FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
563 {
564     INT nResCode;
565     BOOL bSuccess = FALSE;
566     LPWININETAPPINFOW hIC = NULL;
567
568     TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
569
570     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
571     {
572         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
573         return FALSE;
574     }
575
576     /* Clear any error information */
577     INTERNET_SetLastError(0);
578
579     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
580         goto lend;
581
582     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
583     if (nResCode)
584     {
585         if (nResCode == 257)
586             bSuccess = TRUE;
587         else
588             FTP_SetResponseError(nResCode);
589     }
590
591 lend:
592     hIC = lpwfs->lpAppInfo;
593     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
594     {
595         INTERNET_ASYNC_RESULT iar;
596
597         iar.dwResult = (DWORD)bSuccess;
598         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
599         SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
600             &iar, sizeof(INTERNET_ASYNC_RESULT));
601     }
602
603     return bSuccess;
604 }
605
606 /***********************************************************************
607  *           FtpFindFirstFileA (WININET.@)
608  *
609  * Search the specified directory
610  *
611  * RETURNS
612  *    HINTERNET on success
613  *    NULL on failure
614  *
615  */
616 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
617     LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
618 {
619     LPWSTR lpwzSearchFile;
620     WIN32_FIND_DATAW wfd;
621     LPWIN32_FIND_DATAW lpFindFileDataW;
622     HINTERNET ret;
623     
624     lpwzSearchFile = lpszSearchFile?WININET_strdup_AtoW(lpszSearchFile):NULL;
625     lpFindFileDataW = lpFindFileData?&wfd:NULL;
626     ret = FtpFindFirstFileW(hConnect, lpwzSearchFile, lpFindFileDataW, dwFlags, dwContext);
627     HeapFree(GetProcessHeap(), 0, lpwzSearchFile);
628     
629     if(lpFindFileData) {
630         WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData);
631     }
632     return ret;
633 }
634
635
636 /***********************************************************************
637  *           FtpFindFirstFileW (WININET.@)
638  *
639  * Search the specified directory
640  *
641  * RETURNS
642  *    HINTERNET on success
643  *    NULL on failure
644  *
645  */
646 static void AsyncFtpFindFirstFileProc(WORKREQUEST *workRequest)
647 {
648     struct WORKREQ_FTPFINDFIRSTFILEW const *req = &workRequest->u.FtpFindFirstFileW;
649     LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
650
651     TRACE("%p\n", lpwfs);
652
653     FTP_FtpFindFirstFileW(lpwfs, req->lpszSearchFile,
654        req->lpFindFileData, req->dwFlags, req->dwContext);
655     HeapFree(GetProcessHeap(), 0, req->lpszSearchFile);
656 }
657
658 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
659     LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
660 {
661     LPWININETFTPSESSIONW lpwfs;
662     LPWININETAPPINFOW hIC = NULL;
663     HINTERNET r = NULL;
664
665     lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
666     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
667     {
668         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
669         goto lend;
670     }
671
672     hIC = lpwfs->lpAppInfo;
673     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
674     {
675         WORKREQUEST workRequest;
676         struct WORKREQ_FTPFINDFIRSTFILEW *req;
677
678         workRequest.asyncall = CALLASYNCPROC;
679         workRequest.asyncproc = AsyncFtpFindFirstFileProc;
680         workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
681         req = &workRequest.u.FtpFindFirstFileW;
682         req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : WININET_strdupW(lpszSearchFile);
683         req->lpFindFileData = lpFindFileData;
684         req->dwFlags = dwFlags;
685         req->dwContext= dwContext;
686
687         INTERNET_AsyncCall(&workRequest);
688         r = NULL;
689     }
690     else
691     {
692         r = FTP_FtpFindFirstFileW(lpwfs, lpszSearchFile, lpFindFileData,
693             dwFlags, dwContext);
694     }
695 lend:
696     if( lpwfs )
697         WININET_Release( &lpwfs->hdr );
698
699     return r;
700 }
701
702
703 /***********************************************************************
704  *           FTP_FtpFindFirstFileW (Internal)
705  *
706  * Search the specified directory
707  *
708  * RETURNS
709  *    HINTERNET on success
710  *    NULL on failure
711  *
712  */
713 HINTERNET WINAPI FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs,
714     LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
715 {
716     INT nResCode;
717     LPWININETAPPINFOW hIC = NULL;
718     HINTERNET hFindNext = NULL;
719
720     TRACE("\n");
721
722     assert(WH_HFTPSESSION == lpwfs->hdr.htype);
723
724     /* Clear any error information */
725     INTERNET_SetLastError(0);
726
727     if (!FTP_InitListenSocket(lpwfs))
728         goto lend;
729
730     if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
731         goto lend;
732
733     if (!FTP_SendPortOrPasv(lpwfs))
734         goto lend;
735
736     hIC = lpwfs->lpAppInfo;
737     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, NULL,
738         lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
739         goto lend;
740
741     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
742     if (nResCode)
743     {
744         if (nResCode == 125 || nResCode == 150)
745         {
746             INT nDataSocket;
747
748             /* Get data socket to server */
749             if (FTP_GetDataSocket(lpwfs, &nDataSocket))
750             {
751                 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpszSearchFile, lpFindFileData, dwContext);
752                 closesocket(nDataSocket);
753                 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
754                 if (nResCode != 226 && nResCode != 250)
755                     INTERNET_SetLastError(ERROR_NO_MORE_FILES);
756             }
757         }
758         else
759             FTP_SetResponseError(nResCode);
760     }
761
762 lend:
763     if (lpwfs->lstnSocket != -1)
764         closesocket(lpwfs->lstnSocket);
765
766     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
767     {
768         INTERNET_ASYNC_RESULT iar;
769
770         if (hFindNext)
771         {
772             iar.dwResult = (DWORD)hFindNext;
773             iar.dwError = ERROR_SUCCESS;
774             SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
775                 &iar, sizeof(INTERNET_ASYNC_RESULT));
776         }
777
778         iar.dwResult = (DWORD)hFindNext;
779         iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
780         SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
781             &iar, sizeof(INTERNET_ASYNC_RESULT));
782     }
783
784     return hFindNext;
785 }
786
787
788 /***********************************************************************
789  *           FtpGetCurrentDirectoryA (WININET.@)
790  *
791  * Retrieves the current directory
792  *
793  * RETURNS
794  *    TRUE on success
795  *    FALSE on failure
796  *
797  */
798 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
799     LPDWORD lpdwCurrentDirectory)
800 {
801     WCHAR *dir = NULL;
802     DWORD len;
803     BOOL ret;
804
805     if(lpdwCurrentDirectory) {
806         len = *lpdwCurrentDirectory;
807         if(lpszCurrentDirectory)
808         {
809             dir = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
810             if (NULL == dir)
811             {
812                 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
813                 return FALSE;
814             }
815         }
816     }
817     ret = FtpGetCurrentDirectoryW(hFtpSession, lpszCurrentDirectory?dir:NULL, lpdwCurrentDirectory?&len:NULL);
818     if(lpdwCurrentDirectory) {
819         *lpdwCurrentDirectory = len;
820         if(lpszCurrentDirectory) { 
821             WideCharToMultiByte(CP_ACP, 0, dir, len, lpszCurrentDirectory, *lpdwCurrentDirectory, NULL, NULL);
822             HeapFree(GetProcessHeap(), 0, dir);
823         }
824     }
825     return ret;
826 }
827
828
829 /***********************************************************************
830  *           FtpGetCurrentDirectoryW (WININET.@)
831  *
832  * Retrieves the current directory
833  *
834  * RETURNS
835  *    TRUE on success
836  *    FALSE on failure
837  *
838  */
839 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
840     LPDWORD lpdwCurrentDirectory)
841 {
842     LPWININETFTPSESSIONW lpwfs;
843     LPWININETAPPINFOW hIC = NULL;
844     BOOL r = FALSE;
845
846     TRACE("len(%d)\n", *lpdwCurrentDirectory);
847
848     lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
849     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
850     {
851         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
852         goto lend;
853     }
854
855     hIC = lpwfs->lpAppInfo;
856     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
857     {
858         WORKREQUEST workRequest;
859         struct WORKREQ_FTPGETCURRENTDIRECTORYW *req;
860
861         workRequest.asyncall =  FTPGETCURRENTDIRECTORYW;
862         workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
863         req = &workRequest.u.FtpGetCurrentDirectoryW;
864         req->lpszDirectory = lpszCurrentDirectory;
865         req->lpdwDirectory = lpdwCurrentDirectory;
866
867         r = INTERNET_AsyncCall(&workRequest);
868     }
869     else
870     {
871         r = FTP_FtpGetCurrentDirectoryW(lpwfs, lpszCurrentDirectory,
872             lpdwCurrentDirectory);
873     }
874
875 lend:
876     if( lpwfs )
877         WININET_Release( &lpwfs->hdr );
878
879     return r;
880 }
881
882
883 /***********************************************************************
884  *           FTP_FtpGetCurrentDirectoryA (Internal)
885  *
886  * Retrieves the current directory
887  *
888  * RETURNS
889  *    TRUE on success
890  *    FALSE on failure
891  *
892  */
893 BOOL WINAPI FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszCurrentDirectory,
894         LPDWORD lpdwCurrentDirectory)
895 {
896     INT nResCode;
897     LPWININETAPPINFOW hIC = NULL;
898     DWORD bSuccess = FALSE;
899
900     TRACE("len(%d)\n", *lpdwCurrentDirectory);
901
902     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
903     {
904         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
905         return FALSE;
906     }
907
908     /* Clear any error information */
909     INTERNET_SetLastError(0);
910
911     ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
912
913     hIC = lpwfs->lpAppInfo;
914     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
915         lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
916         goto lend;
917
918     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
919     if (nResCode)
920     {
921         if (nResCode == 257) /* Extract directory name */
922         {
923             DWORD firstpos, lastpos, len;
924             LPWSTR lpszResponseBuffer = WININET_strdup_AtoW(INTERNET_GetResponseBuffer());
925
926             for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
927             {
928                 if ('"' == lpszResponseBuffer[lastpos])
929                 {
930                     if (!firstpos)
931                         firstpos = lastpos;
932                     else
933                         break;
934                 }
935             }
936
937             len = lastpos - firstpos - 1;
938             lstrcpynW(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1], *lpdwCurrentDirectory);
939             HeapFree(GetProcessHeap(), 0, lpszResponseBuffer);
940             *lpdwCurrentDirectory = len;
941             bSuccess = TRUE;
942         }
943         else
944             FTP_SetResponseError(nResCode);
945     }
946
947 lend:
948     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
949     {
950         INTERNET_ASYNC_RESULT iar;
951
952         iar.dwResult = (DWORD)bSuccess;
953         iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
954         SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
955             &iar, sizeof(INTERNET_ASYNC_RESULT));
956     }
957
958     return (DWORD) bSuccess;
959 }
960
961 /***********************************************************************
962  *           FtpOpenFileA (WININET.@)
963  *
964  * Open a remote file for writing or reading
965  *
966  * RETURNS
967  *    HINTERNET handle on success
968  *    NULL on failure
969  *
970  */
971 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
972     LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
973     DWORD dwContext)
974 {
975     LPWSTR lpwzFileName;
976     HINTERNET ret;
977     
978     lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
979     ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext);
980     HeapFree(GetProcessHeap(), 0, lpwzFileName);
981     return ret;
982 }
983
984
985 /***********************************************************************
986  *           FtpOpenFileW (WININET.@)
987  *
988  * Open a remote file for writing or reading
989  *
990  * RETURNS
991  *    HINTERNET handle on success
992  *    NULL on failure
993  *
994  */
995 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
996     LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
997     DWORD dwContext)
998 {
999     LPWININETFTPSESSIONW lpwfs;
1000     LPWININETAPPINFOW hIC = NULL;
1001     HINTERNET r = NULL;
1002     
1003     TRACE("(%p,%s,0x%08x,0x%08x,0x%08x)\n", hFtpSession,
1004         debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext);
1005
1006     lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1007     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1008     {
1009         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1010         goto lend;
1011     }
1012
1013     if (lpwfs->download_in_progress != NULL) {
1014         INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1015         goto lend;
1016     }
1017     hIC = lpwfs->lpAppInfo;
1018     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1019     {
1020         WORKREQUEST workRequest;
1021         struct WORKREQ_FTPOPENFILEW *req;
1022
1023         workRequest.asyncall = FTPOPENFILEW;
1024         workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1025         req = &workRequest.u.FtpOpenFileW;
1026         req->lpszFilename = WININET_strdupW(lpszFileName);
1027         req->dwAccess = fdwAccess;
1028         req->dwFlags = dwFlags;
1029         req->dwContext = dwContext;
1030
1031         INTERNET_AsyncCall(&workRequest);
1032         r = NULL;
1033     }
1034     else
1035     {
1036         r = FTP_FtpOpenFileW(lpwfs, lpszFileName, fdwAccess, dwFlags, dwContext);
1037     }
1038
1039 lend:
1040     if( lpwfs )
1041         WININET_Release( &lpwfs->hdr );
1042
1043     return r;
1044 }
1045
1046
1047 /***********************************************************************
1048  *           FTP_FtpOpenFileW (Internal)
1049  *
1050  * Open a remote file for writing or reading
1051  *
1052  * RETURNS
1053  *    HINTERNET handle on success
1054  *    NULL on failure
1055  *
1056  */
1057 HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs,
1058         LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1059         DWORD dwContext)
1060 {
1061     INT nDataSocket;
1062     BOOL bSuccess = FALSE;
1063     LPWININETFTPFILE lpwh = NULL;
1064     LPWININETAPPINFOW hIC = NULL;
1065     HINTERNET handle = NULL;
1066
1067     TRACE("\n");
1068
1069     assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1070
1071     /* Clear any error information */
1072     INTERNET_SetLastError(0);
1073
1074     if (GENERIC_READ == fdwAccess)
1075     {
1076         /* Set up socket to retrieve data */
1077         bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
1078     }
1079     else if (GENERIC_WRITE == fdwAccess)
1080     {
1081         /* Set up socket to send data */
1082         bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
1083     }
1084
1085     /* Get data socket to server */
1086     if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
1087     {
1088         lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPFILE));
1089         lpwh->hdr.htype = WH_HFILE;
1090         lpwh->hdr.dwFlags = dwFlags;
1091         lpwh->hdr.dwContext = dwContext;
1092         lpwh->hdr.dwRefCount = 1;
1093         lpwh->hdr.destroy = FTP_CloseFileTransferHandle;
1094         lpwh->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
1095         lpwh->nDataSocket = nDataSocket;
1096         lpwh->session_deleted = FALSE;
1097
1098         WININET_AddRef( &lpwfs->hdr );
1099         lpwh->lpFtpSession = lpwfs;
1100         
1101         handle = WININET_AllocHandle( &lpwh->hdr );
1102         if( !handle )
1103             goto lend;
1104
1105         /* Indicate that a download is currently in progress */
1106         lpwfs->download_in_progress = lpwh;
1107     }
1108
1109     if (lpwfs->lstnSocket != -1)
1110         closesocket(lpwfs->lstnSocket);
1111
1112     hIC = lpwfs->lpAppInfo;
1113     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1114     {
1115         INTERNET_ASYNC_RESULT iar;
1116
1117         if (lpwh)
1118         {
1119             iar.dwResult = (DWORD)handle;
1120             iar.dwError = ERROR_SUCCESS;
1121             SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
1122                 &iar, sizeof(INTERNET_ASYNC_RESULT));
1123         }
1124
1125         iar.dwResult = (DWORD)bSuccess;
1126         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1127         SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1128             &iar, sizeof(INTERNET_ASYNC_RESULT));
1129     }
1130
1131 lend:
1132     if( lpwh )
1133         WININET_Release( &lpwh->hdr );
1134
1135     return handle;
1136 }
1137
1138
1139 /***********************************************************************
1140  *           FtpGetFileA (WININET.@)
1141  *
1142  * Retrieve file from the FTP server
1143  *
1144  * RETURNS
1145  *    TRUE on success
1146  *    FALSE on failure
1147  *
1148  */
1149 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1150     BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1151     DWORD dwContext)
1152 {
1153     LPWSTR lpwzRemoteFile;
1154     LPWSTR lpwzNewFile;
1155     BOOL ret;
1156     
1157     lpwzRemoteFile = lpszRemoteFile?WININET_strdup_AtoW(lpszRemoteFile):NULL;
1158     lpwzNewFile = lpszNewFile?WININET_strdup_AtoW(lpszNewFile):NULL;
1159     ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists,
1160         dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1161     HeapFree(GetProcessHeap(), 0, lpwzRemoteFile);
1162     HeapFree(GetProcessHeap(), 0, lpwzNewFile);
1163     return ret;
1164 }
1165
1166
1167 /***********************************************************************
1168  *           FtpGetFileW (WININET.@)
1169  *
1170  * Retrieve file from the FTP server
1171  *
1172  * RETURNS
1173  *    TRUE on success
1174  *    FALSE on failure
1175  *
1176  */
1177 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1178     BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1179     DWORD dwContext)
1180 {
1181     LPWININETFTPSESSIONW lpwfs;
1182     LPWININETAPPINFOW hIC = NULL;
1183     BOOL r = FALSE;
1184
1185     lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet );
1186     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1187     {
1188         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1189         goto lend;
1190     }
1191
1192     if (lpwfs->download_in_progress != NULL) {
1193         INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1194         goto lend;
1195     }
1196     
1197     hIC = lpwfs->lpAppInfo;
1198     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1199     {
1200         WORKREQUEST workRequest;
1201         struct WORKREQ_FTPGETFILEW *req;
1202
1203         workRequest.asyncall = FTPGETFILEW;
1204         workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1205         req = &workRequest.u.FtpGetFileW;
1206         req->lpszRemoteFile = WININET_strdupW(lpszRemoteFile);
1207         req->lpszNewFile = WININET_strdupW(lpszNewFile);
1208         req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1209         req->fFailIfExists = fFailIfExists;
1210         req->dwFlags = dwInternetFlags;
1211         req->dwContext = dwContext;
1212
1213         r = INTERNET_AsyncCall(&workRequest);
1214     }
1215     else
1216     {
1217         r = FTP_FtpGetFileW(lpwfs, lpszRemoteFile, lpszNewFile,
1218            fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1219     }
1220
1221 lend:
1222     if( lpwfs )
1223         WININET_Release( &lpwfs->hdr );
1224
1225     return r;
1226 }
1227
1228
1229 /***********************************************************************
1230  *           FTP_FtpGetFileW (Internal)
1231  *
1232  * Retrieve file from the FTP server
1233  *
1234  * RETURNS
1235  *    TRUE on success
1236  *    FALSE on failure
1237  *
1238  */
1239 BOOL WINAPI FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1240         BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1241         DWORD dwContext)
1242 {
1243     DWORD nBytes;
1244     BOOL bSuccess = FALSE;
1245     HANDLE hFile;
1246     LPWININETAPPINFOW hIC = NULL;
1247
1248     TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile));
1249
1250     assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1251
1252     /* Clear any error information */
1253     INTERNET_SetLastError(0);
1254
1255     /* Ensure we can write to lpszNewfile by opening it */
1256     hFile = CreateFileW(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1257         CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1258     if (INVALID_HANDLE_VALUE == hFile)
1259         goto lend;
1260
1261     /* Set up socket to retrieve data */
1262     nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
1263
1264     if (nBytes > 0)
1265     {
1266         INT nDataSocket;
1267
1268         /* Get data socket to server */
1269         if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1270         {
1271             INT nResCode;
1272
1273             /* Receive data */
1274             FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
1275             nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
1276             if (nResCode)
1277             {
1278                 if (nResCode == 226)
1279                     bSuccess = TRUE;
1280                 else
1281                     FTP_SetResponseError(nResCode);
1282             }
1283             closesocket(nDataSocket);
1284         }
1285     }
1286
1287 lend:
1288     if (lpwfs->lstnSocket != -1)
1289         closesocket(lpwfs->lstnSocket);
1290
1291     if (hFile)
1292         CloseHandle(hFile);
1293
1294     hIC = lpwfs->lpAppInfo;
1295     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1296     {
1297         INTERNET_ASYNC_RESULT iar;
1298
1299         iar.dwResult = (DWORD)bSuccess;
1300         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1301         SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1302             &iar, sizeof(INTERNET_ASYNC_RESULT));
1303     }
1304
1305     return bSuccess;
1306 }
1307
1308 /***********************************************************************
1309  *           FtpGetFileSize  (WININET.@)
1310  */
1311 DWORD WINAPI FtpGetFileSize( HINTERNET hFile, LPDWORD lpdwFileSizeHigh )
1312 {
1313     FIXME("(%p, %p)\n", hFile, lpdwFileSizeHigh);
1314
1315     if (lpdwFileSizeHigh)
1316         *lpdwFileSizeHigh = 0;
1317
1318     return 0;
1319 }
1320
1321 /***********************************************************************
1322  *           FtpDeleteFileA  (WININET.@)
1323  *
1324  * Delete a file on the ftp server
1325  *
1326  * RETURNS
1327  *    TRUE on success
1328  *    FALSE on failure
1329  *
1330  */
1331 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1332 {
1333     LPWSTR lpwzFileName;
1334     BOOL ret;
1335     
1336     lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1337     ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1338     HeapFree(GetProcessHeap(), 0, lpwzFileName);
1339     return ret;
1340 }
1341
1342 /***********************************************************************
1343  *           FtpDeleteFileW  (WININET.@)
1344  *
1345  * Delete a file on the ftp server
1346  *
1347  * RETURNS
1348  *    TRUE on success
1349  *    FALSE on failure
1350  *
1351  */
1352 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1353 {
1354     LPWININETFTPSESSIONW lpwfs;
1355     LPWININETAPPINFOW hIC = NULL;
1356     BOOL r = FALSE;
1357
1358     lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1359     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1360     {
1361         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1362         goto lend;
1363     }
1364
1365     hIC = lpwfs->lpAppInfo;
1366     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1367     {
1368         WORKREQUEST workRequest;
1369         struct WORKREQ_FTPDELETEFILEW *req;
1370
1371         workRequest.asyncall = FTPDELETEFILEW;
1372         workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1373         req = &workRequest.u.FtpDeleteFileW;
1374         req->lpszFilename = WININET_strdupW(lpszFileName);
1375
1376         r = INTERNET_AsyncCall(&workRequest);
1377     }
1378     else
1379     {
1380         r = FTP_FtpDeleteFileW(lpwfs, lpszFileName);
1381     }
1382
1383 lend:
1384     if( lpwfs )
1385         WININET_Release( &lpwfs->hdr );
1386
1387     return r;
1388 }
1389
1390 /***********************************************************************
1391  *           FTP_FtpDeleteFileW  (Internal)
1392  *
1393  * Delete a file on the ftp server
1394  *
1395  * RETURNS
1396  *    TRUE on success
1397  *    FALSE on failure
1398  *
1399  */
1400 BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName)
1401 {
1402     INT nResCode;
1403     BOOL bSuccess = FALSE;
1404     LPWININETAPPINFOW hIC = NULL;
1405
1406     TRACE("%p\n", lpwfs);
1407
1408     assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1409
1410     /* Clear any error information */
1411     INTERNET_SetLastError(0);
1412
1413     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1414         goto lend;
1415
1416     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1417     if (nResCode)
1418     {
1419         if (nResCode == 250)
1420             bSuccess = TRUE;
1421         else
1422             FTP_SetResponseError(nResCode);
1423     }
1424 lend:
1425     hIC = lpwfs->lpAppInfo;
1426     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1427     {
1428         INTERNET_ASYNC_RESULT iar;
1429
1430         iar.dwResult = (DWORD)bSuccess;
1431         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1432         SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1433             &iar, sizeof(INTERNET_ASYNC_RESULT));
1434     }
1435
1436     return bSuccess;
1437 }
1438
1439
1440 /***********************************************************************
1441  *           FtpRemoveDirectoryA  (WININET.@)
1442  *
1443  * Remove a directory on the ftp server
1444  *
1445  * RETURNS
1446  *    TRUE on success
1447  *    FALSE on failure
1448  *
1449  */
1450 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1451 {
1452     LPWSTR lpwzDirectory;
1453     BOOL ret;
1454     
1455     lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
1456     ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1457     HeapFree(GetProcessHeap(), 0, lpwzDirectory);
1458     return ret;
1459 }
1460
1461 /***********************************************************************
1462  *           FtpRemoveDirectoryW  (WININET.@)
1463  *
1464  * Remove a directory on the ftp server
1465  *
1466  * RETURNS
1467  *    TRUE on success
1468  *    FALSE on failure
1469  *
1470  */
1471 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1472 {
1473     LPWININETFTPSESSIONW lpwfs;
1474     LPWININETAPPINFOW hIC = NULL;
1475     BOOL r = FALSE;
1476
1477     lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1478     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1479     {
1480         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1481         goto lend;
1482     }
1483
1484     hIC = lpwfs->lpAppInfo;
1485     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1486     {
1487         WORKREQUEST workRequest;
1488         struct WORKREQ_FTPREMOVEDIRECTORYW *req;
1489
1490         workRequest.asyncall = FTPREMOVEDIRECTORYW;
1491         workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1492         req = &workRequest.u.FtpRemoveDirectoryW;
1493         req->lpszDirectory = WININET_strdupW(lpszDirectory);
1494
1495         r = INTERNET_AsyncCall(&workRequest);
1496     }
1497     else
1498     {
1499         r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory);
1500     }
1501
1502 lend:
1503     if( lpwfs )
1504         WININET_Release( &lpwfs->hdr );
1505
1506     return r;
1507 }
1508
1509 /***********************************************************************
1510  *           FTP_FtpRemoveDirectoryW  (Internal)
1511  *
1512  * Remove a directory on the ftp server
1513  *
1514  * RETURNS
1515  *    TRUE on success
1516  *    FALSE on failure
1517  *
1518  */
1519 BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
1520 {
1521     INT nResCode;
1522     BOOL bSuccess = FALSE;
1523     LPWININETAPPINFOW hIC = NULL;
1524
1525     TRACE("\n");
1526
1527     assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1528
1529     /* Clear any error information */
1530     INTERNET_SetLastError(0);
1531
1532     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1533         goto lend;
1534
1535     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1536     if (nResCode)
1537     {
1538         if (nResCode == 250)
1539             bSuccess = TRUE;
1540         else
1541             FTP_SetResponseError(nResCode);
1542     }
1543
1544 lend:
1545     hIC = lpwfs->lpAppInfo;
1546     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1547     {
1548         INTERNET_ASYNC_RESULT iar;
1549
1550         iar.dwResult = (DWORD)bSuccess;
1551         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1552         SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1553             &iar, sizeof(INTERNET_ASYNC_RESULT));
1554     }
1555
1556     return bSuccess;
1557 }
1558
1559
1560 /***********************************************************************
1561  *           FtpRenameFileA  (WININET.@)
1562  *
1563  * Rename a file on the ftp server
1564  *
1565  * RETURNS
1566  *    TRUE on success
1567  *    FALSE on failure
1568  *
1569  */
1570 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1571 {
1572     LPWSTR lpwzSrc;
1573     LPWSTR lpwzDest;
1574     BOOL ret;
1575     
1576     lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL;
1577     lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL;
1578     ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
1579     HeapFree(GetProcessHeap(), 0, lpwzSrc);
1580     HeapFree(GetProcessHeap(), 0, lpwzDest);
1581     return ret;
1582 }
1583
1584 /***********************************************************************
1585  *           FtpRenameFileW  (WININET.@)
1586  *
1587  * Rename a file on the ftp server
1588  *
1589  * RETURNS
1590  *    TRUE on success
1591  *    FALSE on failure
1592  *
1593  */
1594 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
1595 {
1596     LPWININETFTPSESSIONW lpwfs;
1597     LPWININETAPPINFOW hIC = NULL;
1598     BOOL r = FALSE;
1599
1600     lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1601     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1602     {
1603         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1604         goto lend;
1605     }
1606
1607     hIC = lpwfs->lpAppInfo;
1608     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1609     {
1610         WORKREQUEST workRequest;
1611         struct WORKREQ_FTPRENAMEFILEW *req;
1612
1613         workRequest.asyncall = FTPRENAMEFILEW;
1614         workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1615         req = &workRequest.u.FtpRenameFileW;
1616         req->lpszSrcFile = WININET_strdupW(lpszSrc);
1617         req->lpszDestFile = WININET_strdupW(lpszDest);
1618
1619         r = INTERNET_AsyncCall(&workRequest);
1620     }
1621     else
1622     {
1623         r = FTP_FtpRenameFileW(lpwfs, lpszSrc, lpszDest);
1624     }
1625
1626 lend:
1627     if( lpwfs )
1628         WININET_Release( &lpwfs->hdr );
1629
1630     return r;
1631 }
1632
1633 /***********************************************************************
1634  *           FTP_FtpRenameFileW  (Internal)
1635  *
1636  * Rename a file on the ftp server
1637  *
1638  * RETURNS
1639  *    TRUE on success
1640  *    FALSE on failure
1641  *
1642  */
1643 BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs,
1644                          LPCWSTR lpszSrc, LPCWSTR lpszDest)
1645 {
1646     INT nResCode;
1647     BOOL bSuccess = FALSE;
1648     LPWININETAPPINFOW hIC = NULL;
1649
1650     TRACE("\n");
1651
1652     assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1653
1654     /* Clear any error information */
1655     INTERNET_SetLastError(0);
1656
1657     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1658         goto lend;
1659
1660     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1661     if (nResCode == 350)
1662     {
1663         if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1664             goto lend;
1665
1666         nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1667     }
1668
1669     if (nResCode == 250)
1670         bSuccess = TRUE;
1671     else
1672         FTP_SetResponseError(nResCode);
1673
1674 lend:
1675     hIC = lpwfs->lpAppInfo;
1676     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1677     {
1678         INTERNET_ASYNC_RESULT iar;
1679
1680         iar.dwResult = (DWORD)bSuccess;
1681         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1682         SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1683             &iar, sizeof(INTERNET_ASYNC_RESULT));
1684     }
1685
1686     return bSuccess;
1687 }
1688
1689 /***********************************************************************
1690  *           FtpCommandA  (WININET.@)
1691  */
1692 BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1693                          LPCSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1694 {
1695     FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1696           debugstr_a(lpszCommand), dwContext, phFtpCommand);
1697
1698     return TRUE;
1699 }
1700
1701 /***********************************************************************
1702  *           FtpCommandW  (WININET.@)
1703  */
1704 BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1705                          LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1706 {
1707     FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1708           debugstr_w(lpszCommand), dwContext, phFtpCommand);
1709
1710     return TRUE;
1711 }
1712
1713 /***********************************************************************
1714  *           FTP_Connect (internal)
1715  *
1716  * Connect to a ftp server
1717  *
1718  * RETURNS
1719  *   HINTERNET a session handle on success
1720  *   NULL on failure
1721  *
1722  * NOTES:
1723  *
1724  * Windows uses 'anonymous' as the username, when given a NULL username
1725  * and a NULL password. The password is first looked up in:
1726  *
1727  * HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\EmailName
1728  *
1729  * If this entry is not present it uses the current username as the password.
1730  *
1731  */
1732
1733 HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
1734         INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1735         LPCWSTR lpszPassword, DWORD dwFlags, DWORD dwContext,
1736         DWORD dwInternalFlags)
1737 {
1738     static const WCHAR szKey[] = {'S','o','f','t','w','a','r','e','\\',
1739                                    'M','i','c','r','o','s','o','f','t','\\',
1740                                    'W','i','n','d','o','w','s','\\',
1741                                    'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1742                                    'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
1743     static const WCHAR szValue[] = {'E','m','a','i','l','N','a','m','e',0};
1744     static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'};
1745     static const WCHAR szEmpty[] = {'\0'};
1746     struct sockaddr_in socketAddr;
1747     INT nsocket = -1;
1748     UINT sock_namelen;
1749     BOOL bSuccess = FALSE;
1750     LPWININETFTPSESSIONW lpwfs = NULL;
1751     HINTERNET handle = NULL;
1752
1753     TRACE("%p  Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1754             hIC, debugstr_w(lpszServerName),
1755             nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
1756
1757     assert( hIC->hdr.htype == WH_HINIT );
1758
1759     if (NULL == lpszUserName && NULL != lpszPassword)
1760     {
1761         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1762         goto lerror;
1763     }
1764     
1765     lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
1766     if (NULL == lpwfs)
1767     {
1768         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1769         goto lerror;
1770     }
1771
1772     if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1773         nServerPort = INTERNET_DEFAULT_FTP_PORT;
1774
1775     lpwfs->hdr.htype = WH_HFTPSESSION;
1776     lpwfs->hdr.dwFlags = dwFlags;
1777     lpwfs->hdr.dwContext = dwContext;
1778     lpwfs->hdr.dwInternalFlags = dwInternalFlags;
1779     lpwfs->hdr.dwRefCount = 1;
1780     lpwfs->hdr.destroy = FTP_CloseSessionHandle;
1781     lpwfs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
1782     lpwfs->download_in_progress = NULL;
1783
1784     WININET_AddRef( &hIC->hdr );
1785     lpwfs->lpAppInfo = hIC;
1786
1787     handle = WININET_AllocHandle( &lpwfs->hdr );
1788     if( !handle )
1789     {
1790         ERR("Failed to alloc handle\n");
1791         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1792         goto lerror;
1793     }
1794
1795     if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1796         if(strchrW(hIC->lpszProxy, ' '))
1797             FIXME("Several proxies not implemented.\n");
1798         if(hIC->lpszProxyBypass)
1799             FIXME("Proxy bypass is ignored.\n");
1800     }
1801     if ( !lpszUserName) {
1802         HKEY key;
1803         WCHAR szPassword[MAX_PATH];
1804         DWORD len = sizeof(szPassword);
1805
1806         lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
1807
1808         RegOpenKeyW(HKEY_CURRENT_USER, szKey, &key);
1809         if (RegQueryValueExW(key, szValue, NULL, NULL, (LPBYTE)szPassword, &len)) {
1810             /* Nothing in the registry, get the username and use that as the password */
1811             if (!GetUserNameW(szPassword, &len)) {
1812                 /* Should never get here, but use an empty password as failsafe */
1813                 strcpyW(szPassword, szEmpty);
1814             }
1815         }
1816         RegCloseKey(key);
1817
1818         TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword));
1819         lpwfs->lpszPassword = WININET_strdupW(szPassword);
1820     }
1821     else {
1822         lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
1823
1824         if (lpszPassword)
1825             lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
1826         else
1827             lpwfs->lpszPassword = WININET_strdupW(szEmpty);
1828     }
1829     
1830     /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1831     if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
1832     {
1833         INTERNET_ASYNC_RESULT iar;
1834
1835         iar.dwResult = (DWORD)handle;
1836         iar.dwError = ERROR_SUCCESS;
1837
1838         SendAsyncCallback(&hIC->hdr, dwContext,
1839                       INTERNET_STATUS_HANDLE_CREATED, &iar,
1840                       sizeof(INTERNET_ASYNC_RESULT));
1841     }
1842         
1843     SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1844         (LPWSTR) lpszServerName, strlenW(lpszServerName));
1845
1846     if (!GetAddress(lpszServerName, nServerPort, &socketAddr))
1847     {
1848         INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1849         goto lerror;
1850     }
1851
1852     SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1853         (LPWSTR) lpszServerName, strlenW(lpszServerName));
1854
1855     nsocket = socket(AF_INET,SOCK_STREAM,0);
1856     if (nsocket == -1)
1857     {
1858         INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1859         goto lerror;
1860     }
1861
1862     SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1863         &socketAddr, sizeof(struct sockaddr_in));
1864
1865     if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1866     {
1867         ERR("Unable to connect (%s)\n", strerror(errno));
1868         INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1869     }
1870     else
1871     {
1872         TRACE("Connected to server\n");
1873         lpwfs->sndSocket = nsocket;
1874         SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1875             &socketAddr, sizeof(struct sockaddr_in));
1876
1877         sock_namelen = sizeof(lpwfs->socketAddress);
1878         getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1879
1880         if (FTP_ConnectToHost(lpwfs))
1881         {
1882             TRACE("Successfully logged into server\n");
1883             bSuccess = TRUE;
1884         }
1885     }
1886
1887 lerror:
1888     if (!bSuccess && nsocket == -1)
1889         closesocket(nsocket);
1890
1891     if (!bSuccess && lpwfs)
1892     {
1893         HeapFree(GetProcessHeap(), 0, lpwfs);
1894         WININET_FreeHandle( handle );
1895         handle = NULL;
1896         lpwfs = NULL;
1897     }
1898
1899     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1900     {
1901         INTERNET_ASYNC_RESULT iar;
1902
1903         iar.dwResult = (DWORD)lpwfs;
1904         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1905         SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1906             &iar, sizeof(INTERNET_ASYNC_RESULT));
1907     }
1908
1909     return handle;
1910 }
1911
1912
1913 /***********************************************************************
1914  *           FTP_ConnectToHost (internal)
1915  *
1916  * Connect to a ftp server
1917  *
1918  * RETURNS
1919  *   TRUE on success
1920  *   NULL on failure
1921  *
1922  */
1923 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
1924 {
1925     INT nResCode;
1926     BOOL bSuccess = FALSE;
1927
1928     TRACE("\n");
1929     FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1930
1931     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1932         goto lend;
1933
1934     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1935     if (nResCode)
1936     {
1937         /* Login successful... */
1938         if (nResCode == 230)
1939             bSuccess = TRUE;
1940         /* User name okay, need password... */
1941         else if (nResCode == 331)
1942             bSuccess = FTP_SendPassword(lpwfs);
1943         /* Need account for login... */
1944         else if (nResCode == 332)
1945             bSuccess = FTP_SendAccount(lpwfs);
1946         else
1947             FTP_SetResponseError(nResCode);
1948     }
1949
1950     TRACE("Returning %d\n", bSuccess);
1951 lend:
1952     return bSuccess;
1953 }
1954
1955
1956 /***********************************************************************
1957  *           FTP_SendCommandA (internal)
1958  *
1959  * Send command to server
1960  *
1961  * RETURNS
1962  *   TRUE on success
1963  *   NULL on failure
1964  *
1965  */
1966 static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1967         INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
1968 {
1969         DWORD len;
1970         CHAR *buf;
1971         DWORD nBytesSent = 0;
1972         int nRC = 0;
1973         DWORD dwParamLen;
1974
1975         TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1976
1977         if (lpfnStatusCB)
1978         {
1979             lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1980         }
1981
1982         dwParamLen = lpszParam?strlen(lpszParam)+1:0;
1983         len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
1984         if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1985         {
1986             INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1987             return FALSE;
1988         }
1989         sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
1990                 dwParamLen ? lpszParam : "", szCRLF);
1991
1992         TRACE("Sending (%s) len(%d)\n", buf, len);
1993         while((nBytesSent < len) && (nRC != -1))
1994         {
1995                 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1996                 nBytesSent += nRC;
1997         }
1998
1999         HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
2000
2001         if (lpfnStatusCB)
2002         {
2003             lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_REQUEST_SENT,
2004                          &nBytesSent, sizeof(DWORD));
2005         }
2006
2007         TRACE("Sent %d bytes\n", nBytesSent);
2008         return (nRC != -1);
2009 }
2010
2011 /***********************************************************************
2012  *           FTP_SendCommand (internal)
2013  *
2014  * Send command to server
2015  *
2016  * RETURNS
2017  *   TRUE on success
2018  *   NULL on failure
2019  *
2020  */
2021 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
2022         INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
2023 {
2024     BOOL ret;
2025     LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
2026     ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
2027     HeapFree(GetProcessHeap(), 0, lpszParamA);
2028     return ret;
2029 }
2030
2031 /***********************************************************************
2032  *           FTP_ReceiveResponse (internal)
2033  *
2034  * Receive response from server
2035  *
2036  * RETURNS
2037  *   Reply code on success
2038  *   0 on failure
2039  *
2040  */
2041 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext)
2042 {
2043     LPSTR lpszResponse = INTERNET_GetResponseBuffer();
2044     DWORD nRecv;
2045     INT rc = 0;
2046     char firstprefix[5];
2047     BOOL multiline = FALSE;
2048     LPWININETAPPINFOW hIC = NULL;
2049
2050     TRACE("socket(%d)\n", lpwfs->sndSocket);
2051
2052     hIC = lpwfs->lpAppInfo;
2053     SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2054
2055     while(1)
2056     {
2057         if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
2058             goto lerror;
2059
2060         if (nRecv >= 3)
2061         {
2062             if(!multiline)
2063             {
2064                 if(lpszResponse[3] != '-')
2065                     break;
2066                 else
2067                 {  /* Start of multiline repsonse.  Loop until we get "nnn " */
2068                     multiline = TRUE;
2069                     memcpy(firstprefix, lpszResponse, 3);
2070                     firstprefix[3] = ' ';
2071                     firstprefix[4] = '\0';
2072                 }
2073             }
2074             else
2075             {
2076                 if(!memcmp(firstprefix, lpszResponse, 4))
2077                     break;
2078             }
2079         }
2080     }
2081
2082     if (nRecv >= 3)
2083     {
2084         rc = atoi(lpszResponse);
2085
2086         SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2087                     &nRecv, sizeof(DWORD));
2088     }
2089
2090 lerror:
2091     TRACE("return %d\n", rc);
2092     return rc;
2093 }
2094
2095
2096 /***********************************************************************
2097  *           FTP_SendPassword (internal)
2098  *
2099  * Send password to ftp server
2100  *
2101  * RETURNS
2102  *   TRUE on success
2103  *   NULL on failure
2104  *
2105  */
2106 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
2107 {
2108     INT nResCode;
2109     BOOL bSuccess = FALSE;
2110
2111     TRACE("\n");
2112     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
2113         goto lend;
2114
2115     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2116     if (nResCode)
2117     {
2118         TRACE("Received reply code %d\n", nResCode);
2119         /* Login successful... */
2120         if (nResCode == 230)
2121             bSuccess = TRUE;
2122         /* Command not implemented, superfluous at the server site... */
2123         /* Need account for login... */
2124         else if (nResCode == 332)
2125             bSuccess = FTP_SendAccount(lpwfs);
2126         else
2127             FTP_SetResponseError(nResCode);
2128     }
2129
2130 lend:
2131     TRACE("Returning %d\n", bSuccess);
2132     return bSuccess;
2133 }
2134
2135
2136 /***********************************************************************
2137  *           FTP_SendAccount (internal)
2138  *
2139  *
2140  *
2141  * RETURNS
2142  *   TRUE on success
2143  *   FALSE on failure
2144  *
2145  */
2146 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
2147 {
2148     INT nResCode;
2149     BOOL bSuccess = FALSE;
2150
2151     TRACE("\n");
2152     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
2153         goto lend;
2154
2155     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2156     if (nResCode)
2157         bSuccess = TRUE;
2158     else
2159         FTP_SetResponseError(nResCode);
2160
2161 lend:
2162     return bSuccess;
2163 }
2164
2165
2166 /***********************************************************************
2167  *           FTP_SendStore (internal)
2168  *
2169  * Send request to upload file to ftp server
2170  *
2171  * RETURNS
2172  *   TRUE on success
2173  *   FALSE on failure
2174  *
2175  */
2176 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2177 {
2178     INT nResCode;
2179     BOOL bSuccess = FALSE;
2180
2181     TRACE("\n");
2182     if (!FTP_InitListenSocket(lpwfs))
2183         goto lend;
2184
2185     if (!FTP_SendType(lpwfs, dwType))
2186         goto lend;
2187
2188     if (!FTP_SendPortOrPasv(lpwfs))
2189         goto lend;
2190
2191     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2192             goto lend;
2193     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2194     if (nResCode)
2195     {
2196         if (nResCode == 150 || nResCode == 125)
2197             bSuccess = TRUE;
2198         else
2199             FTP_SetResponseError(nResCode);
2200     }
2201
2202 lend:
2203     if (!bSuccess && lpwfs->lstnSocket != -1)
2204     {
2205         closesocket(lpwfs->lstnSocket);
2206         lpwfs->lstnSocket = -1;
2207     }
2208
2209     return bSuccess;
2210 }
2211
2212
2213 /***********************************************************************
2214  *           FTP_InitListenSocket (internal)
2215  *
2216  * Create a socket to listen for server response
2217  *
2218  * RETURNS
2219  *   TRUE on success
2220  *   FALSE on failure
2221  *
2222  */
2223 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
2224 {
2225     BOOL bSuccess = FALSE;
2226     size_t namelen = sizeof(struct sockaddr_in);
2227
2228     TRACE("\n");
2229
2230     lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2231     if (lpwfs->lstnSocket == -1)
2232     {
2233         TRACE("Unable to create listening socket\n");
2234             goto lend;
2235     }
2236
2237     /* We obtain our ip addr from the name of the command channel socket */
2238     lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2239
2240     /* and get the system to assign us a port */
2241     lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
2242
2243     if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
2244     {
2245         TRACE("Unable to bind socket\n");
2246         goto lend;
2247     }
2248
2249     if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2250     {
2251         TRACE("listen failed\n");
2252         goto lend;
2253     }
2254
2255     if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2256         bSuccess = TRUE;
2257
2258 lend:
2259     if (!bSuccess && lpwfs->lstnSocket == -1)
2260     {
2261         closesocket(lpwfs->lstnSocket);
2262         lpwfs->lstnSocket = -1;
2263     }
2264
2265     return bSuccess;
2266 }
2267
2268
2269 /***********************************************************************
2270  *           FTP_SendType (internal)
2271  *
2272  * Tell server type of data being transferred
2273  *
2274  * RETURNS
2275  *   TRUE on success
2276  *   FALSE on failure
2277  *
2278  * W98SE doesn't cache the type that's currently set
2279  * (i.e. it sends it always),
2280  * so we probably don't want to do that either.
2281  */
2282 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
2283 {
2284     INT nResCode;
2285     WCHAR type[] = { 'I','\0' };
2286     BOOL bSuccess = FALSE;
2287
2288     TRACE("\n");
2289     if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2290         type[0] = 'A';
2291
2292     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2293         goto lend;
2294
2295     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2296     if (nResCode)
2297     {
2298         if (nResCode == 2)
2299             bSuccess = TRUE;
2300         else
2301             FTP_SetResponseError(nResCode);
2302     }
2303
2304 lend:
2305     return bSuccess;
2306 }
2307
2308 /***********************************************************************
2309  *           FTP_GetFileSize (internal)
2310  *
2311  * Retrieves from the server the size of the given file
2312  *
2313  * RETURNS
2314  *   TRUE on success
2315  *   FALSE on failure
2316  *
2317  */
2318 static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
2319 {
2320     INT nResCode;
2321     BOOL bSuccess = FALSE;
2322
2323     TRACE("\n");
2324
2325     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2326         goto lend;
2327
2328     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2329     if (nResCode)
2330     {
2331         if (nResCode == 213) {
2332             /* Now parses the output to get the actual file size */
2333             int i;
2334             LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2335
2336             for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2337             if (lpszResponseBuffer[i] == '\0') return FALSE;
2338             *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2339             
2340             bSuccess = TRUE;
2341         } else {
2342             FTP_SetResponseError(nResCode);
2343         }
2344     }
2345
2346 lend:
2347     return bSuccess;
2348 }
2349
2350
2351 /***********************************************************************
2352  *           FTP_SendPort (internal)
2353  *
2354  * Tell server which port to use
2355  *
2356  * RETURNS
2357  *   TRUE on success
2358  *   FALSE on failure
2359  *
2360  */
2361 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
2362 {
2363     static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2364     INT nResCode;
2365     WCHAR szIPAddress[64];
2366     BOOL bSuccess = FALSE;
2367     TRACE("\n");
2368
2369     sprintfW(szIPAddress, szIPFormat,
2370          lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2371         (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2372         (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2373         (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2374         lpwfs->lstnSocketAddress.sin_port & 0xFF,
2375         (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2376
2377     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2378         goto lend;
2379
2380     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2381     if (nResCode)
2382     {
2383         if (nResCode == 200)
2384             bSuccess = TRUE;
2385         else
2386             FTP_SetResponseError(nResCode);
2387     }
2388
2389 lend:
2390     return bSuccess;
2391 }
2392
2393
2394 /***********************************************************************
2395  *           FTP_DoPassive (internal)
2396  *
2397  * Tell server that we want to do passive transfers
2398  * and connect data socket
2399  *
2400  * RETURNS
2401  *   TRUE on success
2402  *   FALSE on failure
2403  *
2404  */
2405 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
2406 {
2407     INT nResCode;
2408     BOOL bSuccess = FALSE;
2409
2410     TRACE("\n");
2411     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2412         goto lend;
2413
2414     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2415     if (nResCode)
2416     {
2417         if (nResCode == 227)
2418         {
2419             LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2420             LPSTR p;
2421             int f[6];
2422             int i;
2423             char *pAddr, *pPort;
2424             INT nsocket = -1;
2425             struct sockaddr_in dataSocketAddress;
2426
2427             p = lpszResponseBuffer+4; /* skip status code */
2428
2429             /* do a very strict check; we can improve that later. */
2430
2431             if (strncmp(p, "Entering Passive Mode", 21))
2432             {
2433                 ERR("unknown response '%.*s', aborting\n", 21, p);
2434                 goto lend;
2435             }
2436             p += 21; /* skip string */
2437             if ((*p++ != ' ') || (*p++ != '('))
2438             {
2439                 ERR("unknown response format, aborting\n");
2440                 goto lend;
2441             }
2442
2443             if (sscanf(p, "%d,%d,%d,%d,%d,%d",  &f[0], &f[1], &f[2], &f[3],
2444                                                 &f[4], &f[5]) != 6)
2445             {
2446                 ERR("unknown response address format '%s', aborting\n", p);
2447                 goto lend;
2448             }
2449             for (i=0; i < 6; i++)
2450                 f[i] = f[i] & 0xff;
2451
2452             dataSocketAddress = lpwfs->socketAddress;
2453             pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2454             pPort = (char *)&(dataSocketAddress.sin_port);
2455             pAddr[0] = f[0];
2456             pAddr[1] = f[1];
2457             pAddr[2] = f[2];
2458             pAddr[3] = f[3];
2459             pPort[0] = f[4];
2460             pPort[1] = f[5];
2461
2462             nsocket = socket(AF_INET,SOCK_STREAM,0);
2463             if (nsocket == -1)
2464                 goto lend;
2465
2466             if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2467             {
2468                 ERR("can't connect passive FTP data port.\n");
2469                 closesocket(nsocket);
2470                 goto lend;
2471             }
2472             lpwfs->pasvSocket = nsocket;
2473             bSuccess = TRUE;
2474         }
2475         else
2476             FTP_SetResponseError(nResCode);
2477     }
2478
2479 lend:
2480     return bSuccess;
2481 }
2482
2483
2484 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
2485 {
2486     if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2487     {
2488         if (!FTP_DoPassive(lpwfs))
2489             return FALSE;
2490     }
2491     else
2492     {
2493         if (!FTP_SendPort(lpwfs))
2494             return FALSE;
2495     }
2496     return TRUE;
2497 }
2498
2499
2500 /***********************************************************************
2501  *           FTP_GetDataSocket (internal)
2502  *
2503  * Either accepts an incoming data socket connection from the server
2504  * or just returns the already opened socket after a PASV command
2505  * in case of passive FTP.
2506  *
2507  *
2508  * RETURNS
2509  *   TRUE on success
2510  *   FALSE on failure
2511  *
2512  */
2513 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
2514 {
2515     struct sockaddr_in saddr;
2516     size_t addrlen = sizeof(struct sockaddr);
2517
2518     TRACE("\n");
2519     if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2520     {
2521         *nDataSocket = lpwfs->pasvSocket;
2522     }
2523     else
2524     {
2525         *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2526         closesocket(lpwfs->lstnSocket);
2527         lpwfs->lstnSocket = -1;
2528     }
2529     return *nDataSocket != -1;
2530 }
2531
2532
2533 /***********************************************************************
2534  *           FTP_SendData (internal)
2535  *
2536  * Send data to the server
2537  *
2538  * RETURNS
2539  *   TRUE on success
2540  *   FALSE on failure
2541  *
2542  */
2543 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2544 {
2545     BY_HANDLE_FILE_INFORMATION fi;
2546     DWORD nBytesRead = 0;
2547     DWORD nBytesSent = 0;
2548     DWORD nTotalSent = 0;
2549     DWORD nBytesToSend, nLen;
2550     int nRC = 1;
2551     time_t s_long_time, e_long_time;
2552     LONG nSeconds;
2553     CHAR *lpszBuffer;
2554
2555     TRACE("\n");
2556     lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2557     memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2558
2559     /* Get the size of the file. */
2560     GetFileInformationByHandle(hFile, &fi);
2561     time(&s_long_time);
2562
2563     do
2564     {
2565         nBytesToSend = nBytesRead - nBytesSent;
2566
2567         if (nBytesToSend <= 0)
2568         {
2569             /* Read data from file. */
2570             nBytesSent = 0;
2571             if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2572             ERR("Failed reading from file\n");
2573
2574             if (nBytesRead > 0)
2575                 nBytesToSend = nBytesRead;
2576             else
2577                 break;
2578         }
2579
2580         nLen = DATA_PACKET_SIZE < nBytesToSend ?
2581             DATA_PACKET_SIZE : nBytesToSend;
2582         nRC  = send(nDataSocket, lpszBuffer, nLen, 0);
2583
2584         if (nRC != -1)
2585         {
2586             nBytesSent += nRC;
2587             nTotalSent += nRC;
2588         }
2589
2590         /* Do some computation to display the status. */
2591         time(&e_long_time);
2592         nSeconds = e_long_time - s_long_time;
2593         if( nSeconds / 60 > 0 )
2594         {
2595             TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n",
2596             nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2597             nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2598         }
2599         else
2600         {
2601             TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n",
2602             nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2603             (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2604         }
2605     } while (nRC != -1);
2606
2607     TRACE("file transfer complete!\n");
2608
2609     HeapFree(GetProcessHeap(), 0, lpszBuffer);
2610
2611     return nTotalSent;
2612 }
2613
2614
2615 /***********************************************************************
2616  *           FTP_SendRetrieve (internal)
2617  *
2618  * Send request to retrieve a file
2619  *
2620  * RETURNS
2621  *   Number of bytes to be received on success
2622  *   0 on failure
2623  *
2624  */
2625 static DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2626 {
2627     INT nResCode;
2628     DWORD nResult = 0;
2629
2630     TRACE("\n");
2631     if (!FTP_InitListenSocket(lpwfs))
2632         goto lend;
2633
2634     if (!FTP_SendType(lpwfs, dwType))
2635         goto lend;
2636
2637     if (!FTP_SendPortOrPasv(lpwfs))
2638         goto lend;
2639
2640     if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2641         goto lend;
2642
2643     TRACE("Waiting to receive %d bytes\n", nResult);
2644     
2645     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2646         goto lend;
2647
2648     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2649     if ((nResCode != 125) && (nResCode != 150)) {
2650         /* That means that we got an error getting the file. */
2651         nResult = 0;
2652     }
2653
2654 lend:
2655     if (0 == nResult && lpwfs->lstnSocket != -1)
2656     {
2657         closesocket(lpwfs->lstnSocket);
2658         lpwfs->lstnSocket = -1;
2659     }
2660
2661     return nResult;
2662 }
2663
2664
2665 /***********************************************************************
2666  *           FTP_RetrieveData  (internal)
2667  *
2668  * Retrieve data from server
2669  *
2670  * RETURNS
2671  *   TRUE on success
2672  *   FALSE on failure
2673  *
2674  */
2675 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2676 {
2677     DWORD nBytesWritten;
2678     DWORD nBytesReceived = 0;
2679     INT nRC = 0;
2680     CHAR *lpszBuffer;
2681
2682     TRACE("\n");
2683
2684     if (INVALID_HANDLE_VALUE == hFile)
2685         return FALSE;
2686
2687     lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2688     if (NULL == lpszBuffer)
2689     {
2690         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2691         return FALSE;
2692     }
2693
2694     while (nBytesReceived < nBytes && nRC != -1)
2695     {
2696         nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2697         if (nRC != -1)
2698         {
2699             /* other side closed socket. */
2700             if (nRC == 0)
2701                 goto recv_end;
2702             WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2703             nBytesReceived += nRC;
2704         }
2705
2706         TRACE("%d bytes of %d (%d%%)\r", nBytesReceived, nBytes,
2707            nBytesReceived * 100 / nBytes);
2708     }
2709
2710     TRACE("Data transfer complete\n");
2711     HeapFree(GetProcessHeap(), 0, lpszBuffer);
2712
2713 recv_end:
2714     return  (nRC != -1);
2715 }
2716
2717
2718 /***********************************************************************
2719  *           FTP_CloseSessionHandle (internal)
2720  *
2721  * Deallocate session handle
2722  *
2723  * RETURNS
2724  *   TRUE on success
2725  *   FALSE on failure
2726  *
2727  */
2728 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr)
2729 {
2730     LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2731
2732     TRACE("\n");
2733
2734     WININET_Release(&lpwfs->lpAppInfo->hdr);
2735
2736     if (lpwfs->download_in_progress != NULL)
2737         lpwfs->download_in_progress->session_deleted = TRUE;
2738     
2739     if (lpwfs->sndSocket != -1)
2740         closesocket(lpwfs->sndSocket);
2741
2742     if (lpwfs->lstnSocket != -1)
2743         closesocket(lpwfs->lstnSocket);
2744
2745     HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2746     HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2747     HeapFree(GetProcessHeap(), 0, lpwfs);
2748 }
2749
2750
2751 /***********************************************************************
2752  *           FTP_FindNextFileW (Internal)
2753  *
2754  * Continues a file search from a previous call to FindFirstFile
2755  *
2756  * RETURNS
2757  *    TRUE on success
2758  *    FALSE on failure
2759  *
2760  */
2761 BOOL WINAPI FTP_FindNextFileW(LPWININETFTPFINDNEXTW lpwh, LPVOID lpvFindData)
2762 {
2763     BOOL bSuccess = TRUE;
2764     LPWIN32_FIND_DATAW lpFindFileData;
2765
2766     TRACE("index(%d) size(%d)\n", lpwh->index, lpwh->size);
2767
2768     assert (lpwh->hdr.htype == WH_HFTPFINDNEXT);
2769
2770     /* Clear any error information */
2771     INTERNET_SetLastError(0);
2772
2773     lpFindFileData = (LPWIN32_FIND_DATAW) lpvFindData;
2774     ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2775
2776     if (lpwh->index >= lpwh->size)
2777     {
2778         INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2779         bSuccess = FALSE;
2780         goto lend;
2781     }
2782
2783     FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
2784     lpwh->index++;
2785
2786     TRACE("\nName: %s\nSize: %d\n", debugstr_w(lpFindFileData->cFileName), lpFindFileData->nFileSizeLow);
2787
2788 lend:
2789
2790     if (lpwh->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2791     {
2792         INTERNET_ASYNC_RESULT iar;
2793
2794         iar.dwResult = (DWORD)bSuccess;
2795         iar.dwError = iar.dwError = bSuccess ? ERROR_SUCCESS :
2796                                                INTERNET_GetLastError();
2797
2798         INTERNET_SendCallback(&lpwh->hdr, lpwh->hdr.dwContext,
2799                               INTERNET_STATUS_REQUEST_COMPLETE, &iar,
2800                               sizeof(INTERNET_ASYNC_RESULT));
2801     }
2802
2803     return bSuccess;
2804 }
2805
2806
2807 /***********************************************************************
2808  *           FTP_CloseFindNextHandle (internal)
2809  *
2810  * Deallocate session handle
2811  *
2812  * RETURNS
2813  *   TRUE on success
2814  *   FALSE on failure
2815  *
2816  */
2817 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr)
2818 {
2819     LPWININETFTPFINDNEXTW lpwfn = (LPWININETFTPFINDNEXTW) hdr;
2820     DWORD i;
2821
2822     TRACE("\n");
2823
2824     WININET_Release(&lpwfn->lpFtpSession->hdr);
2825
2826     for (i = 0; i < lpwfn->size; i++)
2827     {
2828         HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2829     }
2830
2831     HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2832     HeapFree(GetProcessHeap(), 0, lpwfn);
2833 }
2834
2835 /***********************************************************************
2836  *           FTP_CloseFileTransferHandle (internal)
2837  *
2838  * Closes the file transfer handle. This also 'cleans' the data queue of
2839  * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2840  *
2841  */
2842 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr)
2843 {
2844     LPWININETFTPFILE lpwh = (LPWININETFTPFILE) hdr;
2845     LPWININETFTPSESSIONW lpwfs = lpwh->lpFtpSession;
2846     INT nResCode;
2847
2848     TRACE("\n");
2849
2850     WININET_Release(&lpwh->lpFtpSession->hdr);
2851
2852     if (!lpwh->session_deleted)
2853         lpwfs->download_in_progress = NULL;
2854
2855     /* This just serves to flush the control socket of any spurrious lines written
2856        to it (like '226 Transfer complete.').
2857
2858        Wonder what to do if the server sends us an error code though...
2859     */
2860     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2861     
2862     if (lpwh->nDataSocket != -1)
2863         closesocket(lpwh->nDataSocket);
2864
2865     HeapFree(GetProcessHeap(), 0, lpwh);
2866 }
2867
2868 /***********************************************************************
2869  *           FTP_ReceiveFileList (internal)
2870  *
2871  * Read file list from server
2872  *
2873  * RETURNS
2874  *   Handle to file list on success
2875  *   NULL on failure
2876  *
2877  */
2878 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2879         LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext)
2880 {
2881     DWORD dwSize = 0;
2882     LPFILEPROPERTIESW lpafp = NULL;
2883     LPWININETFTPFINDNEXTW lpwfn = NULL;
2884     HINTERNET handle = 0;
2885
2886     TRACE("(%p,%d,%s,%p,%d)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
2887
2888     if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
2889     {
2890         if(lpFindFileData)
2891             FTP_ConvertFileProp(lpafp, lpFindFileData);
2892
2893         lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFTPFINDNEXTW));
2894         if (lpwfn)
2895         {
2896             lpwfn->hdr.htype = WH_HFTPFINDNEXT;
2897             lpwfn->hdr.dwContext = dwContext;
2898             lpwfn->hdr.dwRefCount = 1;
2899             lpwfn->hdr.destroy = FTP_CloseFindNextHandle;
2900             lpwfn->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
2901             lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2902             lpwfn->size = dwSize;
2903             lpwfn->lpafp = lpafp;
2904
2905             WININET_AddRef( &lpwfs->hdr );
2906             lpwfn->lpFtpSession = lpwfs;
2907
2908             handle = WININET_AllocHandle( &lpwfn->hdr );
2909         }
2910     }
2911
2912     if( lpwfn )
2913         WININET_Release( &lpwfn->hdr );
2914
2915     TRACE("Matched %d files\n", dwSize);
2916     return handle;
2917 }
2918
2919
2920 /***********************************************************************
2921  *           FTP_ConvertFileProp (internal)
2922  *
2923  * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
2924  *
2925  * RETURNS
2926  *   TRUE on success
2927  *   FALSE on failure
2928  *
2929  */
2930 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
2931 {
2932     BOOL bSuccess = FALSE;
2933
2934     ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
2935
2936     if (lpafp)
2937     {
2938         /* Convert 'Unix' time to Windows time */
2939         RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
2940                                   (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
2941         lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime;
2942         lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime;
2943         
2944         /* Not all fields are filled in */
2945         lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2946         lpFindFileData->nFileSizeLow = lpafp->nSize;
2947
2948         if (lpafp->bIsDirectory)
2949             lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2950
2951         if (lpafp->lpszName)
2952             lstrcpynW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2953
2954         bSuccess = TRUE;
2955     }
2956
2957     return bSuccess;
2958 }
2959
2960 /***********************************************************************
2961  *           FTP_ParseNextFile (internal)
2962  *
2963  * Parse the next line in file listing
2964  *
2965  * RETURNS
2966  *   TRUE on success
2967  *   FALSE on failure
2968  */
2969 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
2970 {
2971     static const char szSpace[] = " \t";
2972     DWORD nBufLen;
2973     char *pszLine;
2974     char *pszToken;
2975     char *pszTmp;
2976     BOOL found = FALSE;
2977     int i;
2978     
2979     lpfp->lpszName = NULL;
2980     do {
2981         if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
2982             return FALSE;
2983     
2984         pszToken = strtok(pszLine, szSpace);
2985         /* ls format
2986          * <Permissions> <NoLinks> <owner>   <group> <size> <date>  <time or year> <filename>
2987          *
2988          * For instance:
2989          * drwx--s---     2         pcarrier  ens     512    Sep 28  1995           pcarrier
2990          */
2991         if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
2992             if(!FTP_ParsePermission(pszToken, lpfp))
2993                 lpfp->bIsDirectory = FALSE;
2994             for(i=0; i<=3; i++) {
2995               if(!(pszToken = strtok(NULL, szSpace)))
2996                   break;
2997             }
2998             if(!pszToken) continue;
2999             if(lpfp->bIsDirectory) {
3000                 TRACE("Is directory\n");
3001                 lpfp->nSize = 0;
3002             }
3003             else {
3004                 TRACE("Size: %s\n", pszToken);
3005                 lpfp->nSize = atol(pszToken);
3006             }
3007             
3008             lpfp->tmLastModified.tm_sec  = 0;
3009             lpfp->tmLastModified.tm_min  = 0;
3010             lpfp->tmLastModified.tm_hour = 0;
3011             lpfp->tmLastModified.tm_mday = 0;
3012             lpfp->tmLastModified.tm_mon  = 0;
3013             lpfp->tmLastModified.tm_year = 0;
3014             
3015             /* Determine month */
3016             pszToken = strtok(NULL, szSpace);
3017             if(!pszToken) continue;
3018             if(strlen(pszToken) >= 3) {
3019                 pszToken[3] = 0;
3020                 if((pszTmp = StrStrIA(szMonths, pszToken)))
3021                     lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
3022             }
3023             /* Determine day */
3024             pszToken = strtok(NULL, szSpace);
3025             if(!pszToken) continue;
3026             lpfp->tmLastModified.tm_mday = atoi(pszToken);
3027             /* Determine time or year */
3028             pszToken = strtok(NULL, szSpace);
3029             if(!pszToken) continue;
3030             if((pszTmp = strchr(pszToken, ':'))) {
3031                 struct tm* apTM;
3032                 time_t aTime;
3033                 *pszTmp = 0;
3034                 pszTmp++;
3035                 lpfp->tmLastModified.tm_min = atoi(pszTmp);
3036                 lpfp->tmLastModified.tm_hour = atoi(pszToken);
3037                 time(&aTime);
3038                 apTM = localtime(&aTime);
3039                 lpfp->tmLastModified.tm_year = apTM->tm_year;
3040             }
3041             else {
3042                 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
3043                 lpfp->tmLastModified.tm_hour = 12;
3044             }
3045             TRACE("Mod time: %02d:%02d:%02d  %02d/%02d/%02d\n",
3046                 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3047                 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3048                 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3049
3050             pszToken = strtok(NULL, szSpace);
3051             if(!pszToken) continue;
3052             lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3053             TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
3054         }
3055         /* NT way of parsing ... :
3056             
3057                 07-13-03  08:55PM       <DIR>          sakpatch
3058                 05-09-03  06:02PM             12656686 2003-04-21bgm_cmd_e.rgz
3059         */
3060         else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
3061             lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
3062             
3063             sscanf(pszToken, "%d-%d-%d",
3064                 &lpfp->tmLastModified.tm_mon,
3065                 &lpfp->tmLastModified.tm_mday,
3066                 &lpfp->tmLastModified.tm_year);
3067
3068             /* Hacky and bad Y2K protection :-) */
3069             if (lpfp->tmLastModified.tm_year < 70)
3070                 lpfp->tmLastModified.tm_year += 100;
3071             
3072             pszToken = strtok(NULL, szSpace);
3073             if(!pszToken) continue;
3074             sscanf(pszToken, "%d:%d",
3075                 &lpfp->tmLastModified.tm_hour,
3076                 &lpfp->tmLastModified.tm_min);
3077             if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
3078                 lpfp->tmLastModified.tm_hour += 12;
3079             }
3080             lpfp->tmLastModified.tm_sec = 0;
3081
3082             TRACE("Mod time: %02d:%02d:%02d  %02d/%02d/%02d\n",
3083                 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3084                 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3085                 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3086             
3087             pszToken = strtok(NULL, szSpace);
3088             if(!pszToken) continue;
3089             if(!strcasecmp(pszToken, "<DIR>")) {
3090                 lpfp->bIsDirectory = TRUE;
3091                 lpfp->nSize = 0;
3092                 TRACE("Is directory\n");
3093             }
3094             else {
3095                 lpfp->bIsDirectory = FALSE;
3096                 lpfp->nSize = atol(pszToken);
3097                 TRACE("Size: %d\n", lpfp->nSize);
3098             }
3099             
3100             pszToken = strtok(NULL, szSpace);
3101             if(!pszToken) continue;
3102             lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3103             TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
3104         }
3105         /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
3106         else if(pszToken[0] == '+') {
3107             FIXME("EPLF Format not implemented\n");
3108         }
3109         
3110         if(lpfp->lpszName) {
3111             if((lpszSearchFile == NULL) ||
3112                (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
3113                 found = TRUE;
3114                 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
3115             }
3116             else {
3117                 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
3118                 lpfp->lpszName = NULL;
3119             }
3120         }
3121     } while(!found);
3122     return TRUE;
3123 }
3124
3125 /***********************************************************************
3126  *           FTP_ParseDirectory (internal)
3127  *
3128  * Parse string of directory information
3129  *
3130  * RETURNS
3131  *   TRUE on success
3132  *   FALSE on failure
3133  */
3134 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3135     LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
3136 {
3137     BOOL bSuccess = TRUE;
3138     INT sizeFilePropArray = 500;/*20; */
3139     INT indexFilePropArray = -1;
3140
3141     TRACE("\n");
3142
3143     /* Allocate intial file properties array */
3144     *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
3145     if (!*lpafp)
3146         return FALSE;
3147
3148     do {
3149         if (indexFilePropArray+1 >= sizeFilePropArray)
3150         {
3151             LPFILEPROPERTIESW tmpafp;
3152             
3153             sizeFilePropArray *= 2;
3154             tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
3155                 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
3156             if (NULL == tmpafp)
3157             {
3158                 bSuccess = FALSE;
3159                 break;
3160             }
3161
3162             *lpafp = tmpafp;
3163         }
3164         indexFilePropArray++;
3165     } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
3166
3167     if (bSuccess && indexFilePropArray)
3168     {
3169         if (indexFilePropArray < sizeFilePropArray - 1)
3170         {
3171             LPFILEPROPERTIESW tmpafp;
3172
3173             tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
3174                 sizeof(FILEPROPERTIESW)*indexFilePropArray);
3175             if (NULL == tmpafp)
3176                 *lpafp = tmpafp;
3177         }
3178         *dwfp = indexFilePropArray;
3179     }
3180     else
3181     {
3182         HeapFree(GetProcessHeap(), 0, *lpafp);
3183         INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3184         bSuccess = FALSE;
3185     }
3186
3187     return bSuccess;
3188 }
3189
3190
3191 /***********************************************************************
3192  *           FTP_ParsePermission (internal)
3193  *
3194  * Parse permission string of directory information
3195  *
3196  * RETURNS
3197  *   TRUE on success
3198  *   FALSE on failure
3199  *
3200  */
3201 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3202 {
3203     BOOL bSuccess = TRUE;
3204     unsigned short nPermission = 0;
3205     INT nPos = 1;
3206     INT nLast  = 9;
3207
3208     TRACE("\n");
3209     if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3210     {
3211         bSuccess = FALSE;
3212         return bSuccess;
3213     }
3214
3215     lpfp->bIsDirectory = (*lpszPermission == 'd');
3216     do
3217     {
3218         switch (nPos)
3219         {
3220             case 1:
3221                 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3222                 break;
3223             case 2:
3224                 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3225                 break;
3226             case 3:
3227                 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3228                 break;
3229             case 4:
3230                 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3231                 break;
3232             case 5:
3233                 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3234                 break;
3235             case 6:
3236                 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3237                 break;
3238             case 7:
3239                 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3240                 break;
3241             case 8:
3242                 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3243                 break;
3244             case 9:
3245                 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3246                 break;
3247         }
3248         nPos++;
3249     }while (nPos <= nLast);
3250
3251     lpfp->permissions = nPermission;
3252     return bSuccess;
3253 }
3254
3255
3256 /***********************************************************************
3257  *           FTP_SetResponseError (internal)
3258  *
3259  * Set the appropriate error code for a given response from the server
3260  *
3261  * RETURNS
3262  *
3263  */
3264 static DWORD FTP_SetResponseError(DWORD dwResponse)
3265 {
3266     DWORD dwCode = 0;
3267
3268     switch(dwResponse)
3269     {
3270         case 421: /* Service not available - Server may be shutting down. */
3271             dwCode = ERROR_INTERNET_TIMEOUT;
3272             break;
3273
3274         case 425: /* Cannot open data connection. */
3275             dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3276             break;
3277
3278         case 426: /* Connection closed, transer aborted. */
3279             dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3280             break;
3281
3282         case 500: /* Syntax error. Command unrecognized. */
3283         case 501: /* Syntax error. Error in parameters or arguments. */
3284             dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
3285             break;
3286
3287         case 530: /* Not logged in. Login incorrect. */
3288             dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3289             break;
3290
3291         case 550: /* File action not taken. File not found or no access. */
3292             dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
3293             break;
3294
3295         case 450: /* File action not taken. File may be busy. */
3296         case 451: /* Action aborted. Server error. */
3297         case 452: /* Action not taken. Insufficient storage space on server. */
3298         case 502: /* Command not implemented. */
3299         case 503: /* Bad sequence of command. */
3300         case 504: /* Command not implemented for that parameter. */
3301         case 532: /* Need account for storing files */
3302         case 551: /* Requested action aborted. Page type unknown */
3303         case 552: /* Action aborted. Exceeded storage allocation */
3304         case 553: /* Action not taken. File name not allowed. */
3305
3306         default:
3307             dwCode = ERROR_INTERNET_INTERNAL_ERROR;
3308             break;
3309     }
3310
3311     INTERNET_SetLastError(dwCode);
3312     return dwCode;
3313 }