~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/wininet/ftp.c

Version: ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main