~ [ 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 _ftp_session_t ftp_session_t;
 72 
 73 typedef struct
 74 {
 75     object_header_t hdr;
 76     ftp_session_t *lpFtpSession;
 77     BOOL session_deleted;
 78     int nDataSocket;
 79 } ftp_file_t;
 80 
 81 struct _ftp_session_t
 82 {
 83     object_header_t hdr;
 84     appinfo_t *lpAppInfo;
 85     int sndSocket;
 86     int lstnSocket;
 87     int pasvSocket; /* data socket connected by us in case of passive FTP */
 88     ftp_file_t *download_in_progress;
 89     struct sockaddr_in socketAddress;
 90     struct sockaddr_in lstnSocketAddress;
 91     LPWSTR  lpszPassword;
 92     LPWSTR  lpszUserName;
 93 };
 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     object_header_t hdr;
107     ftp_session_t *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, object_header_t *hdr, DWORD_PTR dwContext);
176 static BOOL FTP_SendStore(ftp_session_t*, LPCWSTR lpszRemoteFile, DWORD dwType);
177 static BOOL FTP_GetDataSocket(ftp_session_t*, LPINT nDataSocket);
178 static BOOL FTP_SendData(ftp_session_t*, INT nDataSocket, HANDLE hFile);
179 static INT FTP_ReceiveResponse(ftp_session_t*, DWORD_PTR dwContext);
180 static BOOL FTP_SendRetrieve(ftp_session_t*, LPCWSTR lpszRemoteFile, DWORD dwType);
181 static BOOL FTP_RetrieveFileData(ftp_session_t*, INT nDataSocket, HANDLE hFile);
182 static BOOL FTP_InitListenSocket(ftp_session_t*);
183 static BOOL FTP_ConnectToHost(ftp_session_t*);
184 static BOOL FTP_SendPassword(ftp_session_t*);
185 static BOOL FTP_SendAccount(ftp_session_t*);
186 static BOOL FTP_SendType(ftp_session_t*, DWORD dwType);
187 static BOOL FTP_SendPort(ftp_session_t*);
188 static BOOL FTP_DoPassive(ftp_session_t*);
189 static BOOL FTP_SendPortOrPasv(ftp_session_t*);
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(ftp_session_t*, INT nSocket, LPCWSTR lpszSearchFile,
193         LPFILEPROPERTIESW *lpafp, LPDWORD dwfp);
194 static HINTERNET FTP_ReceiveFileList(ftp_session_t*, 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(ftp_session_t*, LPCWSTR lpszLocalFile,
199         LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext);
200 static BOOL FTP_FtpSetCurrentDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory);
201 static BOOL FTP_FtpCreateDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory);
202 static HINTERNET FTP_FtpFindFirstFileW(ftp_session_t*,
203         LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext);
204 static BOOL FTP_FtpGetCurrentDirectoryW(ftp_session_t*, LPWSTR lpszCurrentDirectory,
205         LPDWORD lpdwCurrentDirectory);
206 static BOOL FTP_FtpRenameFileW(ftp_session_t*, LPCWSTR lpszSrc, LPCWSTR lpszDest);
207 static BOOL FTP_FtpRemoveDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory);
208 static BOOL FTP_FtpDeleteFileW(ftp_session_t*, LPCWSTR lpszFileName);
209 static BOOL FTP_FtpGetFileW(ftp_session_t*, 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 = heap_strdupAtoW(lpszLocalFile);
232     lpwzNewRemoteFile = heap_strdupAtoW(lpszNewRemoteFile);
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     ftp_session_t *lpwfs = (ftp_session_t*) 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     ftp_session_t *lpwfs;
268     appinfo_t *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 = (ftp_session_t*) 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 = heap_strdupW(lpszLocalFile);
311         req->lpszNewRemoteFile = heap_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(ftp_session_t *lpwfs, LPCWSTR lpszLocalFile,
340     LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext)
341 {
342     HANDLE hFile;
343     BOOL bSuccess = FALSE;
344     appinfo_t *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 = heap_strdupAtoW(lpszDirectory);
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     ftp_session_t *lpwfs = (ftp_session_t*) 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     ftp_session_t *lpwfs = NULL;
447     appinfo_t *hIC = NULL;
448     BOOL r = FALSE;
449 
450     if (!lpszDirectory)
451     {
452         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
453         goto lend;
454     }
455 
456     lpwfs = (ftp_session_t*) 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 = heap_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(ftp_session_t *lpwfs, LPCWSTR lpszDirectory)
508 {
509     INT nResCode;
510     appinfo_t *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 = heap_strdupAtoW(lpszDirectory);
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     ftp_session_t *lpwfs = (ftp_session_t*) 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     ftp_session_t *lpwfs;
593     appinfo_t *hIC = NULL;
594     BOOL r = FALSE;
595 
596     lpwfs = (ftp_session_t*) 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 = heap_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(ftp_session_t *lpwfs, LPCWSTR lpszDirectory)
656 {
657     INT nResCode;
658     BOOL bSuccess = FALSE;
659     appinfo_t *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 = heap_strdupAtoW(lpszSearchFile);
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     ftp_session_t *lpwfs = (ftp_session_t*) 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     ftp_session_t *lpwfs;
749     appinfo_t *hIC = NULL;
750     HINTERNET r = NULL;
751 
752     lpwfs = (ftp_session_t*) 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 : heap_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(ftp_session_t *lpwfs,
806     LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext)
807 {
808     INT nResCode;
809     appinfo_t *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     ftp_session_t *lpwfs = (ftp_session_t*) 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     ftp_session_t *lpwfs;
942     appinfo_t *hIC = NULL;
943     BOOL r = FALSE;
944 
945     TRACE("%p %p %p\n", hFtpSession, lpszCurrentDirectory, lpdwCurrentDirectory);
946 
947     lpwfs = (ftp_session_t*) 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(ftp_session_t *lpwfs, LPWSTR lpszCurrentDirectory,
1017         LPDWORD lpdwCurrentDirectory)
1018 {
1019     INT nResCode;
1020     appinfo_t *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 = heap_strdupAtoW(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(object_header_t *hdr)
1088 {
1089     ftp_file_t *lpwh = (ftp_file_t*) hdr;
1090     ftp_session_t *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(object_header_t *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(object_header_t *hdr, void *buffer, DWORD size, DWORD *read)
1127 {
1128     ftp_file_t *file = (ftp_file_t*)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 DWORD FTPFILE_ReadFileExA(object_header_t *hdr, INTERNET_BUFFERSA *buffers,
1142     DWORD flags, DWORD_PTR context)
1143 {
1144     return FTPFILE_ReadFile(hdr, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength);
1145 }
1146 
1147 static DWORD FTPFILE_ReadFileExW(object_header_t *hdr, INTERNET_BUFFERSW *buffers,
1148     DWORD flags, DWORD_PTR context)
1149 {
1150     return FTPFILE_ReadFile(hdr, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength);
1151 }
1152 
1153 static BOOL FTPFILE_WriteFile(object_header_t *hdr, const void *buffer, DWORD size, DWORD *written)
1154 {
1155     ftp_file_t *lpwh = (ftp_file_t*) hdr;
1156     int res;
1157 
1158     res = send(lpwh->nDataSocket, buffer, size, 0);
1159 
1160     *written = res>0 ? res : 0;
1161     return res >= 0;
1162 }
1163 
1164 static void FTP_ReceiveRequestData(ftp_file_t *file, BOOL first_notif)
1165 {
1166     INTERNET_ASYNC_RESULT iar;
1167     BYTE buffer[4096];
1168     int available;
1169 
1170     TRACE("%p\n", file);
1171 
1172     available = recv(file->nDataSocket, buffer, sizeof(buffer), MSG_PEEK);
1173 
1174     if(available != -1) {
1175         iar.dwResult = (DWORD_PTR)file->hdr.hInternet;
1176         iar.dwError = first_notif ? 0 : available;
1177     }else {
1178         iar.dwResult = 0;
1179         iar.dwError = INTERNET_GetLastError();
1180     }
1181 
1182     INTERNET_SendCallback(&file->hdr, file->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar,
1183                           sizeof(INTERNET_ASYNC_RESULT));
1184 }
1185 
1186 static void FTPFILE_AsyncQueryDataAvailableProc(WORKREQUEST *workRequest)
1187 {
1188     ftp_file_t *file = (ftp_file_t*)workRequest->hdr;
1189 
1190     FTP_ReceiveRequestData(file, FALSE);
1191 }
1192 
1193 static DWORD FTPFILE_QueryDataAvailable(object_header_t *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx)
1194 {
1195     ftp_file_t *file = (ftp_file_t*) hdr;
1196     int retval, unread = 0;
1197 
1198     TRACE("(%p %p %x %lx)\n", file, available, flags, ctx);
1199 
1200 #ifdef FIONREAD
1201     retval = ioctlsocket(file->nDataSocket, FIONREAD, &unread);
1202     if (!retval)
1203         TRACE("%d bytes of queued, but unread data\n", unread);
1204 #else
1205     FIXME("FIONREAD not available\n");
1206 #endif
1207 
1208     *available = unread;
1209 
1210     if(!unread) {
1211         BYTE byte;
1212 
1213         *available = 0;
1214 
1215         retval = recv(file->nDataSocket, &byte, 1, MSG_PEEK);
1216         if(retval > 0) {
1217             WORKREQUEST workRequest;
1218 
1219             *available = 0;
1220             workRequest.asyncproc = FTPFILE_AsyncQueryDataAvailableProc;
1221             workRequest.hdr = WININET_AddRef( &file->hdr );
1222 
1223             INTERNET_AsyncCall(&workRequest);
1224 
1225             return ERROR_IO_PENDING;
1226         }
1227     }
1228 
1229     return ERROR_SUCCESS;
1230 }
1231 
1232 
1233 static const object_vtbl_t FTPFILEVtbl = {
1234     FTPFILE_Destroy,
1235     NULL,
1236     FTPFILE_QueryOption,
1237     NULL,
1238     FTPFILE_ReadFile,
1239     FTPFILE_ReadFileExA,
1240     FTPFILE_ReadFileExW,
1241     FTPFILE_WriteFile,
1242     FTPFILE_QueryDataAvailable,
1243     NULL
1244 };
1245 
1246 /***********************************************************************
1247  *           FTP_FtpOpenFileW (Internal)
1248  *
1249  * Open a remote file for writing or reading
1250  *
1251  * RETURNS
1252  *    HINTERNET handle on success
1253  *    NULL on failure
1254  *
1255  */
1256 HINTERNET FTP_FtpOpenFileW(ftp_session_t *lpwfs,
1257         LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1258         DWORD_PTR dwContext)
1259 {
1260     INT nDataSocket;
1261     BOOL bSuccess = FALSE;
1262     ftp_file_t *lpwh = NULL;
1263     appinfo_t *hIC = NULL;
1264     HINTERNET handle = NULL;
1265 
1266     TRACE("\n");
1267 
1268     /* Clear any error information */
1269     INTERNET_SetLastError(0);
1270 
1271     if (GENERIC_READ == fdwAccess)
1272     {
1273         /* Set up socket to retrieve data */
1274         bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
1275     }
1276     else if (GENERIC_WRITE == fdwAccess)
1277     {
1278         /* Set up socket to send data */
1279         bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
1280     }
1281 
1282     /* Get data socket to server */
1283     if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
1284     {
1285         lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(ftp_file_t));
1286         lpwh->hdr.htype = WH_HFILE;
1287         lpwh->hdr.vtbl = &FTPFILEVtbl;
1288         lpwh->hdr.dwFlags = dwFlags;
1289         lpwh->hdr.dwContext = dwContext;
1290         lpwh->hdr.refs = 1;
1291         lpwh->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
1292         lpwh->nDataSocket = nDataSocket;
1293         lpwh->session_deleted = FALSE;
1294 
1295         WININET_AddRef( &lpwfs->hdr );
1296         lpwh->lpFtpSession = lpwfs;
1297         list_add_head( &lpwfs->hdr.children, &lpwh->hdr.entry );
1298         
1299         handle = WININET_AllocHandle( &lpwh->hdr );
1300         if( !handle )
1301             goto lend;
1302 
1303         /* Indicate that a download is currently in progress */
1304         lpwfs->download_in_progress = lpwh;
1305     }
1306 
1307     if (lpwfs->lstnSocket != -1)
1308         closesocket(lpwfs->lstnSocket);
1309 
1310     hIC = lpwfs->lpAppInfo;
1311     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1312     {
1313         INTERNET_ASYNC_RESULT iar;
1314 
1315         if (lpwh)
1316         {
1317             iar.dwResult = (DWORD_PTR)handle;
1318             iar.dwError = ERROR_SUCCESS;
1319             SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
1320                 &iar, sizeof(INTERNET_ASYNC_RESULT));
1321         }
1322 
1323         if(bSuccess) {
1324             FTP_ReceiveRequestData(lpwh, TRUE);
1325         }else {
1326             iar.dwResult = 0;
1327             iar.dwError = INTERNET_GetLastError();
1328             SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1329                     &iar, sizeof(INTERNET_ASYNC_RESULT));
1330         }
1331     }
1332 
1333 lend:
1334     if( lpwh )
1335         WININET_Release( &lpwh->hdr );
1336 
1337     return handle;
1338 }
1339 
1340 
1341 /***********************************************************************
1342  *           FtpOpenFileA (WININET.@)
1343  *
1344  * Open a remote file for writing or reading
1345  *
1346  * RETURNS
1347  *    HINTERNET handle on success
1348  *    NULL on failure
1349  *
1350  */
1351 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
1352     LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1353     DWORD_PTR dwContext)
1354 {
1355     LPWSTR lpwzFileName;
1356     HINTERNET ret;
1357 
1358     lpwzFileName = heap_strdupAtoW(lpszFileName);
1359     ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext);
1360     HeapFree(GetProcessHeap(), 0, lpwzFileName);
1361     return ret;
1362 }
1363 
1364 
1365 static void AsyncFtpOpenFileProc(WORKREQUEST *workRequest)
1366 {
1367     struct WORKREQ_FTPOPENFILEW const *req = &workRequest->u.FtpOpenFileW;
1368     ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr;
1369 
1370     TRACE("%p\n", lpwfs);
1371 
1372     FTP_FtpOpenFileW(lpwfs, req->lpszFilename,
1373         req->dwAccess, req->dwFlags, req->dwContext);
1374     HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1375 }
1376 
1377 /***********************************************************************
1378  *           FtpOpenFileW (WININET.@)
1379  *
1380  * Open a remote file for writing or reading
1381  *
1382  * RETURNS
1383  *    HINTERNET handle on success
1384  *    NULL on failure
1385  *
1386  */
1387 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
1388     LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1389     DWORD_PTR dwContext)
1390 {
1391     ftp_session_t *lpwfs;
1392     appinfo_t *hIC = NULL;
1393     HINTERNET r = NULL;
1394 
1395     TRACE("(%p,%s,0x%08x,0x%08x,0x%08lx)\n", hFtpSession,
1396         debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext);
1397 
1398     lpwfs = (ftp_session_t*) WININET_GetObject( hFtpSession );
1399     if (!lpwfs)
1400     {
1401         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1402         return FALSE;
1403     }
1404 
1405     if (WH_HFTPSESSION != lpwfs->hdr.htype)
1406     {
1407         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1408         goto lend;
1409     }
1410 
1411     if ((!lpszFileName) ||
1412         ((fdwAccess != GENERIC_READ) && (fdwAccess != GENERIC_WRITE)) ||
1413         ((dwFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY))
1414     {
1415         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1416         goto lend;
1417     }
1418 
1419     if (lpwfs->download_in_progress != NULL)
1420     {
1421         INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1422         goto lend;
1423     }
1424 
1425     hIC = lpwfs->lpAppInfo;
1426     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1427     {
1428         WORKREQUEST workRequest;
1429         struct WORKREQ_FTPOPENFILEW *req;
1430 
1431         workRequest.asyncproc = AsyncFtpOpenFileProc;
1432         workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1433         req = &workRequest.u.FtpOpenFileW;
1434         req->lpszFilename = heap_strdupW(lpszFileName);
1435         req->dwAccess = fdwAccess;
1436         req->dwFlags = dwFlags;
1437         req->dwContext = dwContext;
1438 
1439         INTERNET_AsyncCall(&workRequest);
1440         r = NULL;
1441     }
1442     else
1443     {
1444         r = FTP_FtpOpenFileW(lpwfs, lpszFileName, fdwAccess, dwFlags, dwContext);
1445     }
1446 
1447 lend:
1448     WININET_Release( &lpwfs->hdr );
1449 
1450     return r;
1451 }
1452 
1453 
1454 /***********************************************************************
1455  *           FtpGetFileA (WININET.@)
1456  *
1457  * Retrieve file from the FTP server
1458  *
1459  * RETURNS
1460  *    TRUE on success
1461  *    FALSE on failure
1462  *
1463  */
1464 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1465     BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1466     DWORD_PTR dwContext)
1467 {
1468     LPWSTR lpwzRemoteFile;
1469     LPWSTR lpwzNewFile;
1470     BOOL ret;
1471     
1472     lpwzRemoteFile = heap_strdupAtoW(lpszRemoteFile);
1473     lpwzNewFile = heap_strdupAtoW(lpszNewFile);
1474     ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists,
1475         dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1476     HeapFree(GetProcessHeap(), 0, lpwzRemoteFile);
1477     HeapFree(GetProcessHeap(), 0, lpwzNewFile);
1478     return ret;
1479 }
1480 
1481 
1482 static void AsyncFtpGetFileProc(WORKREQUEST *workRequest)
1483 {
1484     struct WORKREQ_FTPGETFILEW const *req = &workRequest->u.FtpGetFileW;
1485     ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr;
1486 
1487     TRACE("%p\n", lpwfs);
1488 
1489     FTP_FtpGetFileW(lpwfs, req->lpszRemoteFile,
1490              req->lpszNewFile, req->fFailIfExists,
1491              req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext);
1492     HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile);
1493     HeapFree(GetProcessHeap(), 0, req->lpszNewFile);
1494 }
1495 
1496 
1497 /***********************************************************************
1498  *           FtpGetFileW (WININET.@)
1499  *
1500  * Retrieve file from the FTP server
1501  *
1502  * RETURNS
1503  *    TRUE on success
1504  *    FALSE on failure
1505  *
1506  */
1507 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1508     BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1509     DWORD_PTR dwContext)
1510 {
1511     ftp_session_t *lpwfs;
1512     appinfo_t *hIC = NULL;
1513     BOOL r = FALSE;
1514 
1515     if (!lpszRemoteFile || !lpszNewFile)
1516     {
1517         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1518         return FALSE;
1519     }
1520 
1521     lpwfs = (ftp_session_t*) WININET_GetObject( hInternet );
1522     if (!lpwfs)
1523     {
1524         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1525         return FALSE;
1526     }
1527 
1528     if (WH_HFTPSESSION != lpwfs->hdr.htype)
1529     {
1530         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1531         goto lend;
1532     }
1533 
1534     if ((dwInternetFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY)
1535     {
1536         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1537         goto lend;
1538     }
1539 
1540     if (lpwfs->download_in_progress != NULL)
1541     {
1542         INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1543         goto lend;
1544     }
1545     
1546     hIC = lpwfs->lpAppInfo;
1547     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1548     {
1549         WORKREQUEST workRequest;
1550         struct WORKREQ_FTPGETFILEW *req;
1551 
1552         workRequest.asyncproc = AsyncFtpGetFileProc;
1553         workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1554         req = &workRequest.u.FtpGetFileW;
1555         req->lpszRemoteFile = heap_strdupW(lpszRemoteFile);
1556         req->lpszNewFile = heap_strdupW(lpszNewFile);
1557         req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1558         req->fFailIfExists = fFailIfExists;
1559         req->dwFlags = dwInternetFlags;
1560         req->dwContext = dwContext;
1561 
1562         r = INTERNET_AsyncCall(&workRequest);
1563     }
1564     else
1565     {
1566         r = FTP_FtpGetFileW(lpwfs, lpszRemoteFile, lpszNewFile,
1567            fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1568     }
1569 
1570 lend:
1571     WININET_Release( &lpwfs->hdr );
1572 
1573     return r;
1574 }
1575 
1576 
1577 /***********************************************************************
1578  *           FTP_FtpGetFileW (Internal)
1579  *
1580  * Retrieve file from the FTP server
1581  *
1582  * RETURNS
1583  *    TRUE on success
1584  *    FALSE on failure
1585  *
1586  */
1587 static BOOL FTP_FtpGetFileW(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1588         BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1589         DWORD_PTR dwContext)
1590 {
1591     BOOL bSuccess = FALSE;
1592     HANDLE hFile;
1593     appinfo_t *hIC = NULL;
1594 
1595     TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile));
1596 
1597     /* Clear any error information */
1598     INTERNET_SetLastError(0);
1599 
1600     /* Ensure we can write to lpszNewfile by opening it */
1601     hFile = CreateFileW(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1602         CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1603     if (INVALID_HANDLE_VALUE == hFile)
1604         return FALSE;
1605 
1606     /* Set up socket to retrieve data */
1607     if (FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags))
1608     {
1609         INT nDataSocket;
1610 
1611         /* Get data socket to server */
1612         if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1613         {
1614             INT nResCode;
1615 
1616             /* Receive data */
1617             FTP_RetrieveFileData(lpwfs, nDataSocket, hFile);
1618             closesocket(nDataSocket);
1619 
1620             nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
1621             if (nResCode)
1622             {
1623                 if (nResCode == 226)
1624                     bSuccess = TRUE;
1625                 else
1626                     FTP_SetResponseError(nResCode);
1627             }
1628         }
1629     }
1630 
1631     if (lpwfs->lstnSocket != -1)
1632         closesocket(lpwfs->lstnSocket);
1633 
1634     CloseHandle(hFile);
1635 
1636     hIC = lpwfs->lpAppInfo;
1637     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1638     {
1639         INTERNET_ASYNC_RESULT iar;
1640 
1641         iar.dwResult = (DWORD)bSuccess;
1642         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1643         SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1644             &iar, sizeof(INTERNET_ASYNC_RESULT));
1645     }
1646 
1647     if (!bSuccess) DeleteFileW(lpszNewFile);
1648     return bSuccess;
1649 }
1650 
1651 /***********************************************************************
1652  *           FtpGetFileSize  (WININET.@)
1653  */
1654 DWORD WINAPI FtpGetFileSize( HINTERNET hFile, LPDWORD lpdwFileSizeHigh )
1655 {
1656     FIXME("(%p, %p)\n", hFile, lpdwFileSizeHigh);
1657 
1658     if (lpdwFileSizeHigh)
1659         *lpdwFileSizeHigh = 0;
1660 
1661     return 0;
1662 }
1663 
1664 /***********************************************************************
1665  *           FtpDeleteFileA  (WININET.@)
1666  *
1667  * Delete a file on the ftp server
1668  *
1669  * RETURNS
1670  *    TRUE on success
1671  *    FALSE on failure
1672  *
1673  */
1674 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1675 {
1676     LPWSTR lpwzFileName;
1677     BOOL ret;
1678     
1679     lpwzFileName = heap_strdupAtoW(lpszFileName);
1680     ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1681     HeapFree(GetProcessHeap(), 0, lpwzFileName);
1682     return ret;
1683 }
1684 
1685 static void AsyncFtpDeleteFileProc(WORKREQUEST *workRequest)
1686 {
1687     struct WORKREQ_FTPDELETEFILEW const *req = &workRequest->u.FtpDeleteFileW;
1688     ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr;
1689 
1690     TRACE("%p\n", lpwfs);
1691 
1692     FTP_FtpDeleteFileW(lpwfs, req->lpszFilename);
1693     HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1694 }
1695 
1696 /***********************************************************************
1697  *           FtpDeleteFileW  (WININET.@)
1698  *
1699  * Delete a file on the ftp server
1700  *
1701  * RETURNS
1702  *    TRUE on success
1703  *    FALSE on failure
1704  *
1705  */
1706 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1707 {
1708     ftp_session_t *lpwfs;
1709     appinfo_t *hIC = NULL;
1710     BOOL r = FALSE;
1711 
1712     lpwfs = (ftp_session_t*) WININET_GetObject( hFtpSession );
1713     if (!lpwfs)
1714     {
1715         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1716         return FALSE;
1717     }
1718 
1719     if (WH_HFTPSESSION != lpwfs->hdr.htype)
1720     {
1721         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1722         goto lend;
1723     }
1724 
1725     if (lpwfs->download_in_progress != NULL)
1726     {
1727         INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1728         goto lend;
1729     }
1730 
1731     if (!lpszFileName)
1732     {
1733         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1734         goto lend;
1735     }
1736 
1737     hIC = lpwfs->lpAppInfo;
1738     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1739     {
1740         WORKREQUEST workRequest;
1741         struct WORKREQ_FTPDELETEFILEW *req;
1742 
1743         workRequest.asyncproc = AsyncFtpDeleteFileProc;
1744         workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1745         req = &workRequest.u.FtpDeleteFileW;
1746         req->lpszFilename = heap_strdupW(lpszFileName);
1747 
1748         r = INTERNET_AsyncCall(&workRequest);
1749     }
1750     else
1751     {
1752         r = FTP_FtpDeleteFileW(lpwfs, lpszFileName);
1753     }
1754 
1755 lend:
1756     WININET_Release( &lpwfs->hdr );
1757 
1758     return r;
1759 }
1760 
1761 /***********************************************************************
1762  *           FTP_FtpDeleteFileW  (Internal)
1763  *
1764  * Delete a file on the ftp server
1765  *
1766  * RETURNS
1767  *    TRUE on success
1768  *    FALSE on failure
1769  *
1770  */
1771 BOOL FTP_FtpDeleteFileW(ftp_session_t *lpwfs, LPCWSTR lpszFileName)
1772 {
1773     INT nResCode;
1774     BOOL bSuccess = FALSE;
1775     appinfo_t *hIC = NULL;
1776 
1777     TRACE("%p\n", lpwfs);
1778 
1779     /* Clear any error information */
1780     INTERNET_SetLastError(0);
1781 
1782     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1783         goto lend;
1784 
1785     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1786     if (nResCode)
1787     {
1788         if (nResCode == 250)
1789             bSuccess = TRUE;
1790         else
1791             FTP_SetResponseError(nResCode);
1792     }
1793 lend:
1794     hIC = lpwfs->lpAppInfo;
1795     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1796     {
1797         INTERNET_ASYNC_RESULT iar;
1798 
1799         iar.dwResult = (DWORD)bSuccess;
1800         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1801         SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1802             &iar, sizeof(INTERNET_ASYNC_RESULT));
1803     }
1804 
1805     return bSuccess;
1806 }
1807 
1808 
1809 /***********************************************************************
1810  *           FtpRemoveDirectoryA  (WININET.@)
1811  *
1812  * Remove a directory on the ftp server
1813  *
1814  * RETURNS
1815  *    TRUE on success
1816  *    FALSE on failure
1817  *
1818  */
1819 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1820 {
1821     LPWSTR lpwzDirectory;
1822     BOOL ret;
1823     
1824     lpwzDirectory = heap_strdupAtoW(lpszDirectory);
1825     ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1826     HeapFree(GetProcessHeap(), 0, lpwzDirectory);
1827     return ret;
1828 }
1829 
1830 static void AsyncFtpRemoveDirectoryProc(WORKREQUEST *workRequest)
1831 {
1832     struct WORKREQ_FTPREMOVEDIRECTORYW const *req = &workRequest->u.FtpRemoveDirectoryW;
1833     ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr;
1834 
1835     TRACE("%p\n", lpwfs);
1836 
1837     FTP_FtpRemoveDirectoryW(lpwfs, req->lpszDirectory);
1838     HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
1839 }
1840 
1841 /***********************************************************************
1842  *           FtpRemoveDirectoryW  (WININET.@)
1843  *
1844  * Remove a directory on the ftp server
1845  *
1846  * RETURNS
1847  *    TRUE on success
1848  *    FALSE on failure
1849  *
1850  */
1851 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1852 {
1853     ftp_session_t *lpwfs;
1854     appinfo_t *hIC = NULL;
1855     BOOL r = FALSE;
1856 
1857     lpwfs = (ftp_session_t*) WININET_GetObject( hFtpSession );
1858     if (!lpwfs)
1859     {
1860         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1861         return FALSE;
1862     }
1863 
1864     if (WH_HFTPSESSION != lpwfs->hdr.htype)
1865     {
1866         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1867         goto lend;
1868     }
1869 
1870     if (lpwfs->download_in_progress != NULL)
1871     {
1872         INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1873         goto lend;
1874     }
1875 
1876     if (!lpszDirectory)
1877     {
1878         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1879         goto lend;
1880     }
1881 
1882     hIC = lpwfs->lpAppInfo;
1883     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1884     {
1885         WORKREQUEST workRequest;
1886         struct WORKREQ_FTPREMOVEDIRECTORYW *req;
1887 
1888         workRequest.asyncproc = AsyncFtpRemoveDirectoryProc;
1889         workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1890         req = &workRequest.u.FtpRemoveDirectoryW;
1891         req->lpszDirectory = heap_strdupW(lpszDirectory);
1892 
1893         r = INTERNET_AsyncCall(&workRequest);
1894     }
1895     else
1896     {
1897         r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory);
1898     }
1899 
1900 lend:
1901     WININET_Release( &lpwfs->hdr );
1902 
1903     return r;
1904 }
1905 
1906 /***********************************************************************
1907  *           FTP_FtpRemoveDirectoryW  (Internal)
1908  *
1909  * Remove a directory on the ftp server
1910  *
1911  * RETURNS
1912  *    TRUE on success
1913  *    FALSE on failure
1914  *
1915  */
1916 BOOL FTP_FtpRemoveDirectoryW(ftp_session_t *lpwfs, LPCWSTR lpszDirectory)
1917 {
1918     INT nResCode;
1919     BOOL bSuccess = FALSE;
1920     appinfo_t *hIC = NULL;
1921 
1922     TRACE("\n");
1923 
1924     /* Clear any error information */
1925     INTERNET_SetLastError(0);
1926 
1927     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1928         goto lend;
1929 
1930     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1931     if (nResCode)
1932     {
1933         if (nResCode == 250)
1934             bSuccess = TRUE;
1935         else
1936             FTP_SetResponseError(nResCode);
1937     }
1938 
1939 lend:
1940     hIC = lpwfs->lpAppInfo;
1941     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1942     {
1943         INTERNET_ASYNC_RESULT iar;
1944 
1945         iar.dwResult = (DWORD)bSuccess;
1946         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1947         SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1948             &iar, sizeof(INTERNET_ASYNC_RESULT));
1949     }
1950 
1951     return bSuccess;
1952 }
1953 
1954 
1955 /***********************************************************************
1956  *           FtpRenameFileA  (WININET.@)
1957  *
1958  * Rename a file on the ftp server
1959  *
1960  * RETURNS
1961  *    TRUE on success
1962  *    FALSE on failure
1963  *
1964  */
1965 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1966 {
1967     LPWSTR lpwzSrc;
1968     LPWSTR lpwzDest;
1969     BOOL ret;
1970     
1971     lpwzSrc = heap_strdupAtoW(lpszSrc);
1972     lpwzDest = heap_strdupAtoW(lpszDest);
1973     ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
1974     HeapFree(GetProcessHeap(), 0, lpwzSrc);
1975     HeapFree(GetProcessHeap(), 0, lpwzDest);
1976     return ret;
1977 }
1978 
1979 static void AsyncFtpRenameFileProc(WORKREQUEST *workRequest)
1980 {
1981     struct WORKREQ_FTPRENAMEFILEW const *req = &workRequest->u.FtpRenameFileW;
1982     ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr;
1983 
1984     TRACE("%p\n", lpwfs);
1985 
1986     FTP_FtpRenameFileW(lpwfs, req->lpszSrcFile, req->lpszDestFile);
1987     HeapFree(GetProcessHeap(), 0, req->lpszSrcFile);
1988     HeapFree(GetProcessHeap(), 0, req->lpszDestFile);
1989 }
1990 
1991 /***********************************************************************
1992  *           FtpRenameFileW  (WININET.@)
1993  *
1994  * Rename a file on the ftp server
1995  *
1996  * RETURNS
1997  *    TRUE on success
1998  *    FALSE on failure
1999  *
2000  */
2001 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
2002 {
2003     ftp_session_t *lpwfs;
2004     appinfo_t *hIC = NULL;
2005     BOOL r = FALSE;
2006 
2007     lpwfs = (ftp_session_t*) WININET_GetObject( hFtpSession );
2008     if (!lpwfs)
2009     {
2010         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2011         return FALSE;
2012     }
2013 
2014     if (WH_HFTPSESSION != lpwfs->hdr.htype)
2015     {
2016         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2017         goto lend;
2018     }
2019 
2020     if (lpwfs->download_in_progress != NULL)
2021     {
2022         INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
2023         goto lend;
2024     }
2025 
2026     if (!lpszSrc || !lpszDest)
2027     {
2028         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2029         goto lend;
2030     }
2031 
2032     hIC = lpwfs->lpAppInfo;
2033     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2034     {
2035         WORKREQUEST workRequest;
2036         struct WORKREQ_FTPRENAMEFILEW *req;
2037 
2038         workRequest.asyncproc = AsyncFtpRenameFileProc;
2039         workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
2040         req = &workRequest.u.FtpRenameFileW;
2041         req->lpszSrcFile = heap_strdupW(lpszSrc);
2042         req->lpszDestFile = heap_strdupW(lpszDest);
2043 
2044         r = INTERNET_AsyncCall(&workRequest);
2045     }
2046     else
2047     {
2048         r = FTP_FtpRenameFileW(lpwfs, lpszSrc, lpszDest);
2049     }
2050 
2051 lend:
2052     WININET_Release( &lpwfs->hdr );
2053 
2054     return r;
2055 }
2056 
2057 /***********************************************************************
2058  *           FTP_FtpRenameFileW  (Internal)
2059  *
2060  * Rename a file on the ftp server
2061  *
2062  * RETURNS
2063  *    TRUE on success
2064  *    FALSE on failure
2065  *
2066  */
2067 BOOL FTP_FtpRenameFileW(ftp_session_t *lpwfs, LPCWSTR lpszSrc, LPCWSTR lpszDest)
2068 {
2069     INT nResCode;
2070     BOOL bSuccess = FALSE;
2071     appinfo_t *hIC = NULL;
2072 
2073     TRACE("\n");
2074 
2075     /* Clear any error information */
2076     INTERNET_SetLastError(0);
2077 
2078     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
2079         goto lend;
2080 
2081     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2082     if (nResCode == 350)
2083     {
2084         if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
2085             goto lend;
2086 
2087         nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2088     }
2089 
2090     if (nResCode == 250)
2091         bSuccess = TRUE;
2092     else
2093         FTP_SetResponseError(nResCode);
2094 
2095 lend:
2096     hIC = lpwfs->lpAppInfo;
2097     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2098     {
2099         INTERNET_ASYNC_RESULT iar;
2100 
2101         iar.dwResult = (DWORD)bSuccess;
2102         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
2103         SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
2104             &iar, sizeof(INTERNET_ASYNC_RESULT));
2105     }
2106 
2107     return bSuccess;
2108 }
2109 
2110 /***********************************************************************
2111  *           FtpCommandA  (WININET.@)
2112  */
2113 BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
2114                          LPCSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
2115 {
2116     BOOL r;
2117     WCHAR *cmdW;
2118 
2119     TRACE("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
2120           debugstr_a(lpszCommand), dwContext, phFtpCommand);
2121 
2122     if (fExpectResponse)
2123     {
2124         FIXME("data connection not supported\n");
2125         return FALSE;
2126     }
2127 
2128     if (!lpszCommand || !lpszCommand[0])
2129     {
2130         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2131         return FALSE;
2132     }
2133 
2134     if (!(cmdW = heap_strdupAtoW(lpszCommand)))
2135     {
2136         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2137         return FALSE;
2138     }
2139 
2140     r = FtpCommandW(hConnect, fExpectResponse, dwFlags, cmdW, dwContext, phFtpCommand);
2141 
2142     HeapFree(GetProcessHeap(), 0, cmdW);
2143     return r;
2144 }
2145 
2146 /***********************************************************************
2147  *           FtpCommandW  (WININET.@)
2148  */
2149 BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
2150                          LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
2151 {
2152     BOOL r = FALSE;
2153     ftp_session_t *lpwfs;
2154     LPSTR cmd = NULL;
2155     DWORD len, nBytesSent= 0;
2156     INT nResCode, nRC = 0;
2157 
2158     TRACE("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
2159            debugstr_w(lpszCommand), dwContext, phFtpCommand);
2160 
2161     if (!lpszCommand || !lpszCommand[0])
2162     {
2163         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2164         return FALSE;
2165     }
2166 
2167     if (fExpectResponse)
2168     {
2169         FIXME("data connection not supported\n");
2170         return FALSE;
2171     }
2172 
2173     lpwfs = (ftp_session_t*) WININET_GetObject( hConnect );
2174     if (!lpwfs)
2175     {
2176         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2177         return FALSE;
2178     }
2179 
2180     if (WH_HFTPSESSION != lpwfs->hdr.htype)
2181     {
2182         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2183         goto lend;
2184     }
2185 
2186     if (lpwfs->download_in_progress != NULL)
2187     {
2188         INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
2189         goto lend;
2190     }
2191 
2192     len = WideCharToMultiByte(CP_ACP, 0, lpszCommand, -1, NULL, 0, NULL, NULL) + strlen(szCRLF);
2193     if ((cmd = HeapAlloc(GetProcessHeap(), 0, len )))
2194         WideCharToMultiByte(CP_ACP, 0, lpszCommand, -1, cmd, len, NULL, NULL);
2195     else
2196     {
2197         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2198         goto lend;
2199     }
2200 
2201     strcat(cmd, szCRLF);
2202     len--;
2203 
2204     TRACE("Sending (%s) len(%d)\n", cmd, len);
2205     while ((nBytesSent < len) && (nRC != -1))
2206     {
2207         nRC = send(lpwfs->sndSocket, cmd + nBytesSent, len - nBytesSent, 0);
2208         if (nRC != -1)
2209         {
2210             nBytesSent += nRC;
2211             TRACE("Sent %d bytes\n", nRC);
2212         }
2213     }
2214 
2215     if (nBytesSent)
2216     {
2217         nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2218         if (nResCode > 0 && nResCode < 400)
2219             r = TRUE;
2220         else
2221             FTP_SetResponseError(nResCode);
2222     }
2223 
2224 lend:
2225     WININET_Release( &lpwfs->hdr );
2226     HeapFree(GetProcessHeap(), 0, cmd);
2227     return r;
2228 }
2229 
2230 
2231 /***********************************************************************
2232  *           FTPSESSION_Destroy (internal)
2233  *
2234  * Deallocate session handle
2235  */
2236 static void FTPSESSION_Destroy(object_header_t *hdr)
2237 {
2238     ftp_session_t *lpwfs = (ftp_session_t*) hdr;
2239 
2240     TRACE("\n");
2241 
2242     WININET_Release(&lpwfs->lpAppInfo->hdr);
2243 
2244     HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2245     HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2246     HeapFree(GetProcessHeap(), 0, lpwfs);
2247 }
2248 
2249 static void FTPSESSION_CloseConnection(object_header_t *hdr)
2250 {
2251     ftp_session_t *lpwfs = (ftp_session_t*) hdr;
2252 
2253     TRACE("\n");
2254 
2255     SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext,
2256                       INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
2257 
2258     if (lpwfs->download_in_progress != NULL)
2259         lpwfs->download_in_progress->session_deleted = TRUE;
2260 
2261      if (lpwfs->sndSocket != -1)
2262          closesocket(lpwfs->sndSocket);
2263 
2264      if (lpwfs->lstnSocket != -1)
2265          closesocket(lpwfs->lstnSocket);
2266 
2267     if (lpwfs->pasvSocket != -1)
2268         closesocket(lpwfs->pasvSocket);
2269 
2270     SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext,
2271                       INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
2272 }
2273 
2274 static DWORD FTPSESSION_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
2275 {
2276     switch(option) {
2277     case INTERNET_OPTION_HANDLE_TYPE:
2278         TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
2279 
2280         if (*size < sizeof(ULONG))
2281             return ERROR_INSUFFICIENT_BUFFER;
2282 
2283         *size = sizeof(DWORD);
2284         *(DWORD*)buffer = INTERNET_HANDLE_TYPE_CONNECT_FTP;
2285         return ERROR_SUCCESS;
2286     }
2287 
2288     return INET_QueryOption(option, buffer, size, unicode);
2289 }
2290 
2291 static const object_vtbl_t FTPSESSIONVtbl = {
2292     FTPSESSION_Destroy,
2293     FTPSESSION_CloseConnection,
2294     FTPSESSION_QueryOption,
2295     NULL,
2296     NULL,
2297     NULL,
2298     NULL,
2299     NULL,
2300     NULL
2301 };
2302 
2303 
2304 /***********************************************************************
2305  *           FTP_Connect (internal)
2306  *
2307  * Connect to a ftp server
2308  *
2309  * RETURNS
2310  *   HINTERNET a session handle on success
2311  *   NULL on failure
2312  *
2313  * NOTES:
2314  *
2315  * Windows uses 'anonymous' as the username, when given a NULL username
2316  * and a NULL password. The password is first looked up in:
2317  *
2318  * HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\EmailName
2319  *
2320  * If this entry is not present it uses the current username as the password.
2321  *
2322  */
2323 
2324 HINTERNET FTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName,
2325         INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
2326         LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext,
2327         DWORD dwInternalFlags)
2328 {
2329     static const WCHAR szKey[] = {'S','o','f','t','w','a','r','e','\\',
2330                                    'M','i','c','r','o','s','o','f','t','\\',
2331                                    'W','i','n','d','o','w','s','\\',
2332                                    'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2333                                    'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
2334     static const WCHAR szValue[] = {'E','m','a','i','l','N','a','m','e',0};
2335     static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'};
2336     static const WCHAR szEmpty[] = {'\0'};
2337     struct sockaddr_in socketAddr;
2338     INT nsocket = -1;
2339     UINT sock_namelen;
2340     BOOL bSuccess = FALSE;
2341     ftp_session_t *lpwfs = NULL;
2342     HINTERNET handle = NULL;
2343 
2344     TRACE("%p  Server(%s) Port(%d) User(%s) Paswd(%s)\n",
2345             hIC, debugstr_w(lpszServerName),
2346             nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
2347 
2348     assert( hIC->hdr.htype == WH_HINIT );
2349 
2350     if ((!lpszUserName || !*lpszUserName) && lpszPassword && *lpszPassword)
2351     {
2352         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2353         goto lerror;
2354     }
2355     
2356     lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(ftp_session_t));
2357     if (NULL == lpwfs)
2358     {
2359         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2360         goto lerror;
2361     }
2362 
2363     if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
2364         nServerPort = INTERNET_DEFAULT_FTP_PORT;
2365 
2366     lpwfs->hdr.htype = WH_HFTPSESSION;
2367     lpwfs->hdr.vtbl = &FTPSESSIONVtbl;
2368     lpwfs->hdr.dwFlags = dwFlags;
2369     lpwfs->hdr.dwContext = dwContext;
2370     lpwfs->hdr.dwInternalFlags = dwInternalFlags;
2371     lpwfs->hdr.refs = 1;
2372     lpwfs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
2373     lpwfs->download_in_progress = NULL;
2374     lpwfs->sndSocket = -1;
2375     lpwfs->lstnSocket = -1;
2376     lpwfs->pasvSocket = -1;
2377 
2378     WININET_AddRef( &hIC->hdr );
2379     lpwfs->lpAppInfo = hIC;
2380     list_add_head( &hIC->hdr.children, &lpwfs->hdr.entry );
2381 
2382     handle = WININET_AllocHandle( &lpwfs->hdr );
2383     if( !handle )
2384     {
2385         ERR("Failed to alloc handle\n");
2386         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2387         goto lerror;
2388     }
2389 
2390     if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
2391         if(strchrW(hIC->lpszProxy, ' '))
2392             FIXME("Several proxies not implemented.\n");
2393         if(hIC->lpszProxyBypass)
2394             FIXME("Proxy bypass is ignored.\n");
2395     }
2396     if (!lpszUserName || !strlenW(lpszUserName)) {
2397         HKEY key;
2398         WCHAR szPassword[MAX_PATH];
2399         DWORD len = sizeof(szPassword);
2400 
2401         lpwfs->lpszUserName = heap_strdupW(szDefaultUsername);
2402 
2403         RegOpenKeyW(HKEY_CURRENT_USER, szKey, &key);
2404         if (RegQueryValueExW(key, szValue, NULL, NULL, (LPBYTE)szPassword, &len)) {
2405             /* Nothing in the registry, get the username and use that as the password */
2406             if (!GetUserNameW(szPassword, &len)) {
2407                 /* Should never get here, but use an empty password as failsafe */
2408                 strcpyW(szPassword, szEmpty);
2409             }
2410         }
2411         RegCloseKey(key);
2412 
2413         TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword));
2414         lpwfs->lpszPassword = heap_strdupW(szPassword);
2415     }
2416     else {
2417         lpwfs->lpszUserName = heap_strdupW(lpszUserName);
2418         lpwfs->lpszPassword = heap_strdupW(lpszPassword ? lpszPassword : szEmpty);
2419     }
2420     
2421     /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
2422     if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
2423     {
2424         INTERNET_ASYNC_RESULT iar;
2425 
2426         iar.dwResult = (DWORD_PTR)handle;
2427         iar.dwError = ERROR_SUCCESS;
2428 
2429         SendAsyncCallback(&hIC->hdr, dwContext,
2430                       INTERNET_STATUS_HANDLE_CREATED, &iar,
2431                       sizeof(INTERNET_ASYNC_RESULT));
2432     }
2433         
2434     SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
2435         (LPWSTR) lpszServerName, strlenW(lpszServerName));
2436 
2437     sock_namelen = sizeof(socketAddr);
2438     if (!GetAddress(lpszServerName, nServerPort,
2439         (struct sockaddr *)&socketAddr, &sock_namelen))
2440     {
2441         INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
2442         goto lerror;
2443     }
2444 
2445     SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
2446         (LPWSTR) lpszServerName, strlenW(lpszServerName));
2447 
2448     if (socketAddr.sin_family != AF_INET)
2449     {
2450         WARN("unsupported address family %d\n", socketAddr.sin_family);
2451         INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
2452         goto lerror;
2453     }
2454     nsocket = socket(AF_INET,SOCK_STREAM,0);
2455     if (nsocket == -1)
2456     {
2457         INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
2458         goto lerror;
2459     }
2460 
2461     SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
2462         &socketAddr, sock_namelen);
2463 
2464     if (connect(nsocket, (struct sockaddr *)&socketAddr, sock_namelen) < 0)
2465     {
2466         ERR("Unable to connect (%s)\n", strerror(errno));
2467         INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
2468         closesocket(nsocket);
2469     }
2470     else
2471     {
2472         TRACE("Connected to server\n");
2473         lpwfs->sndSocket = nsocket;
2474         SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
2475             &socketAddr, sock_namelen);
2476 
2477         sock_namelen = sizeof(lpwfs->socketAddress);
2478         getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
2479 
2480         if (FTP_ConnectToHost(lpwfs))
2481         {
2482             TRACE("Successfully logged into server\n");
2483             bSuccess = TRUE;
2484         }
2485     }
2486 
2487 lerror:
2488     if (lpwfs) WININET_Release( &lpwfs->hdr );
2489 
2490     if (!bSuccess && handle)
2491     {
2492         WININET_FreeHandle( handle );
2493         handle = NULL;
2494     }
2495 
2496     return handle;
2497 }
2498 
2499 
2500 /***********************************************************************
2501  *           FTP_ConnectToHost (internal)
2502  *
2503  * Connect to a ftp server
2504  *
2505  * RETURNS
2506  *   TRUE on success
2507  *   NULL on failure
2508  *
2509  */
2510 static BOOL FTP_ConnectToHost(ftp_session_t *lpwfs)
2511 {
2512     INT nResCode;
2513     BOOL bSuccess = FALSE;
2514 
2515     TRACE("\n");
2516     FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2517 
2518     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
2519         goto lend;
2520 
2521     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2522     if (nResCode)
2523     {
2524         /* Login successful... */
2525         if (nResCode == 230)
2526             bSuccess = TRUE;
2527         /* User name okay, need password... */
2528         else if (nResCode == 331)
2529             bSuccess = FTP_SendPassword(lpwfs);
2530         /* Need account for login... */
2531         else if (nResCode == 332)
2532             bSuccess = FTP_SendAccount(lpwfs);
2533         else
2534             FTP_SetResponseError(nResCode);
2535     }
2536 
2537     TRACE("Returning %d\n", bSuccess);
2538 lend:
2539     return bSuccess;
2540 }
2541 
2542 
2543 /***********************************************************************
2544  *           FTP_SendCommandA (internal)
2545  *
2546  * Send command to server
2547  *
2548  * RETURNS
2549  *   TRUE on success
2550  *   NULL on failure
2551  *
2552  */
2553 static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
2554         INTERNET_STATUS_CALLBACK lpfnStatusCB, object_header_t *hdr, DWORD_PTR dwContext)
2555 {
2556         DWORD len;
2557         CHAR *buf;
2558         DWORD nBytesSent = 0;
2559         int nRC = 0;
2560         DWORD dwParamLen;
2561 
2562         TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
2563 
2564         if (lpfnStatusCB)
2565         {
2566             lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
2567         }
2568 
2569         dwParamLen = lpszParam?strlen(lpszParam)+1:0;
2570         len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
2571         if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
2572         {
2573             INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2574             return FALSE;
2575         }
2576         sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
2577                 dwParamLen ? lpszParam : "", szCRLF);
2578 
2579         TRACE("Sending (%s) len(%d)\n", buf, len);
2580         while((nBytesSent < len) && (nRC != -1))
2581         {
2582                 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
2583                 nBytesSent += nRC;
2584         }
2585 
2586         HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
2587 
2588         if (lpfnStatusCB)
2589         {
2590             lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_REQUEST_SENT,
2591                          &nBytesSent, sizeof(DWORD));
2592         }
2593 
2594         TRACE("Sent %d bytes\n", nBytesSent);
2595         return (nRC != -1);
2596 }
2597 
2598 /***********************************************************************
2599  *           FTP_SendCommand (internal)
2600  *
2601  * Send command to server
2602  *
2603  * RETURNS
2604  *   TRUE on success
2605  *   NULL on failure
2606  *
2607  */
2608 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
2609         INTERNET_STATUS_CALLBACK lpfnStatusCB, object_header_t *hdr, DWORD_PTR dwContext)
2610 {
2611     BOOL ret;
2612     LPSTR lpszParamA = heap_strdupWtoA(lpszParam);
2613     ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
2614     HeapFree(GetProcessHeap(), 0, lpszParamA);
2615     return ret;
2616 }
2617 
2618 /***********************************************************************
2619  *           FTP_ReceiveResponse (internal)
2620  *
2621  * Receive response from server
2622  *
2623  * RETURNS
2624  *   Reply code on success
2625  *   0 on failure
2626  *
2627  */
2628 INT FTP_ReceiveResponse(ftp_session_t *lpwfs, DWORD_PTR dwContext)
2629 {
2630     LPSTR lpszResponse = INTERNET_GetResponseBuffer();
2631     DWORD nRecv;
2632     INT rc = 0;
2633     char firstprefix[5];
2634     BOOL multiline = FALSE;
2635 
2636     TRACE("socket(%d)\n", lpwfs->sndSocket);
2637 
2638     SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2639 
2640     while(1)
2641     {
2642         if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
2643             goto lerror;
2644 
2645         if (nRecv >= 3)
2646         {
2647             if(!multiline)
2648             {
2649                 if(lpszResponse[3] != '-')
2650                     break;
2651                 else
2652                 {  /* Start of multiline response.  Loop until we get "nnn " */
2653                     multiline = TRUE;
2654                     memcpy(firstprefix, lpszResponse, 3);
2655                     firstprefix[3] = ' ';
2656                     firstprefix[4] = '\0';
2657                 }
2658             }
2659             else
2660             {
2661                 if(!memcmp(firstprefix, lpszResponse, 4))
2662                     break;
2663             }
2664         }
2665     }
2666 
2667     if (nRecv >= 3)
2668     {
2669         rc = atoi(lpszResponse);
2670 
2671         SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2672                     &nRecv, sizeof(DWORD));
2673     }
2674 
2675 lerror:
2676     TRACE("return %d\n", rc);
2677     return rc;
2678 }
2679 
2680 
2681 /***********************************************************************
2682  *           FTP_SendPassword (internal)
2683  *
2684  * Send password to ftp server
2685  *
2686  * RETURNS
2687  *   TRUE on success
2688  *   NULL on failure
2689  *
2690  */
2691 static BOOL FTP_SendPassword(ftp_session_t *lpwfs)
2692 {
2693     INT nResCode;
2694     BOOL bSuccess = FALSE;
2695 
2696     TRACE("\n");
2697     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
2698         goto lend;
2699 
2700     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2701     if (nResCode)
2702     {
2703         TRACE("Received reply code %d\n", nResCode);
2704         /* Login successful... */
2705         if (nResCode == 230)
2706             bSuccess = TRUE;
2707         /* Command not implemented, superfluous at the server site... */
2708         /* Need account for login... */
2709         else if (nResCode == 332)
2710             bSuccess = FTP_SendAccount(lpwfs);
2711         else
2712             FTP_SetResponseError(nResCode);
2713     }
2714 
2715 lend:
2716     TRACE("Returning %d\n", bSuccess);
2717     return bSuccess;
2718 }
2719 
2720 
2721 /***********************************************************************
2722  *           FTP_SendAccount (internal)
2723  *
2724  *
2725  *
2726  * RETURNS
2727  *   TRUE on success
2728  *   FALSE on failure
2729  *
2730  */
2731 static BOOL FTP_SendAccount(ftp_session_t *lpwfs)
2732 {
2733     INT nResCode;
2734     BOOL bSuccess = FALSE;
2735 
2736     TRACE("\n");
2737     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
2738         goto lend;
2739 
2740     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2741     if (nResCode)
2742         bSuccess = TRUE;
2743     else
2744         FTP_SetResponseError(nResCode);
2745 
2746 lend:
2747     return bSuccess;
2748 }
2749 
2750 
2751 /***********************************************************************
2752  *           FTP_SendStore (internal)
2753  *
2754  * Send request to upload file to ftp server
2755  *
2756  * RETURNS
2757  *   TRUE on success
2758  *   FALSE on failure
2759  *
2760  */
2761 static BOOL FTP_SendStore(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2762 {
2763     INT nResCode;
2764     BOOL bSuccess = FALSE;
2765 
2766     TRACE("\n");
2767     if (!FTP_InitListenSocket(lpwfs))
2768         goto lend;
2769 
2770     if (!FTP_SendType(lpwfs, dwType))
2771         goto lend;
2772 
2773     if (!FTP_SendPortOrPasv(lpwfs))
2774         goto lend;
2775 
2776     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2777             goto lend;
2778     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2779     if (nResCode)
2780     {
2781         if (nResCode == 150 || nResCode == 125)
2782             bSuccess = TRUE;
2783         else
2784             FTP_SetResponseError(nResCode);
2785     }
2786 
2787 lend:
2788     if (!bSuccess && lpwfs->lstnSocket != -1)
2789     {
2790         closesocket(lpwfs->lstnSocket);
2791         lpwfs->lstnSocket = -1;
2792     }
2793 
2794     return bSuccess;
2795 }
2796 
2797 
2798 /***********************************************************************
2799  *           FTP_InitListenSocket (internal)
2800  *
2801  * Create a socket to listen for server response
2802  *
2803  * RETURNS
2804  *   TRUE on success
2805  *   FALSE on failure
2806  *
2807  */
2808 static BOOL FTP_InitListenSocket(ftp_session_t *lpwfs)
2809 {
2810     BOOL bSuccess = FALSE;
2811     socklen_t namelen = sizeof(lpwfs->lstnSocketAddress);
2812 
2813     TRACE("\n");
2814 
2815     lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2816     if (lpwfs->lstnSocket == -1)
2817     {
2818         TRACE("Unable to create listening socket\n");
2819             goto lend;
2820     }
2821 
2822     /* We obtain our ip addr from the name of the command channel socket */
2823     lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2824 
2825     /* and get the system to assign us a port */
2826     lpwfs->lstnSocketAddress.sin_port = htons(0);
2827 
2828     if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(lpwfs->lstnSocketAddress)) == -1)
2829     {
2830         TRACE("Unable to bind socket\n");
2831         goto lend;
2832     }
2833 
2834     if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2835     {
2836         TRACE("listen failed\n");
2837         goto lend;
2838     }
2839 
2840     if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2841         bSuccess = TRUE;
2842 
2843 lend:
2844     if (!bSuccess && lpwfs->lstnSocket != -1)
2845     {
2846         closesocket(lpwfs->lstnSocket);
2847         lpwfs->lstnSocket = -1;
2848     }
2849 
2850     return bSuccess;
2851 }
2852 
2853 
2854 /***********************************************************************
2855  *           FTP_SendType (internal)
2856  *
2857  * Tell server type of data being transferred
2858  *
2859  * RETURNS
2860  *   TRUE on success
2861  *   FALSE on failure
2862  *
2863  * W98SE doesn't cache the type that's currently set
2864  * (i.e. it sends it always),
2865  * so we probably don't want to do that either.
2866  */
2867 static BOOL FTP_SendType(ftp_session_t *lpwfs, DWORD dwType)
2868 {
2869     INT nResCode;
2870     WCHAR type[] = { 'I','\0' };
2871     BOOL bSuccess = FALSE;
2872 
2873     TRACE("\n");
2874     if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2875         type[0] = 'A';
2876 
2877     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2878         goto lend;
2879 
2880     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2881     if (nResCode)
2882     {
2883         if (nResCode == 2)
2884             bSuccess = TRUE;
2885         else
2886             FTP_SetResponseError(nResCode);
2887     }
2888 
2889 lend:
2890     return bSuccess;
2891 }
2892 
2893 
2894 #if 0  /* FIXME: should probably be used for FtpGetFileSize */
2895 /***********************************************************************
2896  *           FTP_GetFileSize (internal)
2897  *
2898  * Retrieves from the server the size of the given file
2899  *
2900  * RETURNS
2901  *   TRUE on success
2902  *   FALSE on failure
2903  *
2904  */
2905 static BOOL FTP_GetFileSize(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
2906 {
2907     INT nResCode;
2908     BOOL bSuccess = FALSE;
2909 
2910     TRACE("\n");
2911 
2912     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2913         goto lend;
2914 
2915     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2916     if (nResCode)
2917     {
2918         if (nResCode == 213) {
2919             /* Now parses the output to get the actual file size */
2920             int i;
2921             LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2922 
2923             for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2924             if (lpszResponseBuffer[i] == '\0') return FALSE;
2925             *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2926             
2927             bSuccess = TRUE;
2928         } else {
2929             FTP_SetResponseError(nResCode);
2930         }
2931     }
2932 
2933 lend:
2934     return bSuccess;
2935 }
2936 #endif
2937 
2938 
2939 /***********************************************************************
2940  *           FTP_SendPort (internal)
2941  *
2942  * Tell server which port to use
2943  *
2944  * RETURNS
2945  *   TRUE on success
2946  *   FALSE on failure
2947  *
2948  */
2949 static BOOL FTP_SendPort(ftp_session_t *lpwfs)
2950 {
2951     static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2952     INT nResCode;
2953     WCHAR szIPAddress[64];
2954     BOOL bSuccess = FALSE;
2955     TRACE("\n");
2956 
2957     sprintfW(szIPAddress, szIPFormat,
2958          lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2959         (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2960         (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2961         (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2962         lpwfs->lstnSocketAddress.sin_port & 0xFF,
2963         (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2964 
2965     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2966         goto lend;
2967 
2968     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2969     if (nResCode)
2970     {
2971         if (nResCode == 200)
2972             bSuccess = TRUE;
2973         else
2974             FTP_SetResponseError(nResCode);
2975     }
2976 
2977 lend:
2978     return bSuccess;
2979 }
2980 
2981 
2982 /***********************************************************************
2983  *           FTP_DoPassive (internal)
2984  *
2985  * Tell server that we want to do passive transfers
2986  * and connect data socket
2987  *
2988  * RETURNS
2989  *   TRUE on success
2990  *   FALSE on failure
2991  *
2992  */
2993 static BOOL FTP_DoPassive(ftp_session_t *lpwfs)
2994 {
2995     INT nResCode;
2996     BOOL bSuccess = FALSE;
2997 
2998     TRACE("\n");
2999     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
3000         goto lend;
3001 
3002     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
3003     if (nResCode)
3004     {
3005         if (nResCode == 227)
3006         {
3007             LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
3008             LPSTR p;
3009             int f[6];
3010             int i;
3011             char *pAddr, *pPort;
3012             INT nsocket = -1;
3013             struct sockaddr_in dataSocketAddress;
3014 
3015             p = lpszResponseBuffer+4; /* skip status code */
3016             while (*p != '\0' && (*p < '' || *p > '9')) p++;
3017 
3018             if (*p == '\0')
3019             {
3020                 ERR("no address found in response, aborting\n");
3021                 goto lend;
3022             }
3023 
3024             if (sscanf(p, "%d,%d,%d,%d,%d,%d",  &f[0], &f[1], &f[2], &f[3],
3025                                                 &f[4], &f[5]) != 6)
3026             {
3027                 ERR("unknown response address format '%s', aborting\n", p);
3028                 goto lend;
3029             }
3030             for (i=0; i < 6; i++)
3031                 f[i] = f[i] & 0xff;
3032 
3033             dataSocketAddress = lpwfs->socketAddress;
3034             pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
3035             pPort = (char *)&(dataSocketAddress.sin_port);
3036             pAddr[0] = f[0];
3037             pAddr[1] = f[1];
3038             pAddr[2] = f[2];
3039             pAddr[3] = f[3];
3040             pPort[0] = f[4];
3041             pPort[1] = f[5];
3042 
3043             nsocket = socket(AF_INET,SOCK_STREAM,0);
3044             if (nsocket == -1)
3045                 goto lend;
3046 
3047             if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
3048             {
3049                 ERR("can't connect passive FTP data port.\n");
3050                 closesocket(nsocket);
3051                 goto lend;
3052             }
3053             lpwfs->pasvSocket = nsocket;
3054             bSuccess = TRUE;
3055         }
3056         else
3057             FTP_SetResponseError(nResCode);
3058     }
3059 
3060 lend:
3061     return bSuccess;
3062 }
3063 
3064 
3065 static BOOL FTP_SendPortOrPasv(ftp_session_t *lpwfs)
3066 {
3067     if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
3068     {
3069         if (!FTP_DoPassive(lpwfs))
3070             return FALSE;
3071     }
3072     else
3073     {
3074         if (!FTP_SendPort(lpwfs))
3075             return FALSE;
3076     }
3077     return TRUE;
3078 }
3079 
3080 
3081 /***********************************************************************
3082  *           FTP_GetDataSocket (internal)
3083  *
3084  * Either accepts an incoming data socket connection from the server
3085  * or just returns the already opened socket after a PASV command
3086  * in case of passive FTP.
3087  *
3088  *
3089  * RETURNS
3090  *   TRUE on success
3091  *   FALSE on failure
3092  *
3093  */
3094 static BOOL FTP_GetDataSocket(ftp_session_t *lpwfs, LPINT nDataSocket)
3095 {
3096     struct sockaddr_in saddr;
3097     socklen_t addrlen = sizeof(struct sockaddr);
3098 
3099     TRACE("\n");
3100     if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
3101     {
3102         *nDataSocket = lpwfs->pasvSocket;
3103     }
3104     else
3105     {
3106         *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
3107         closesocket(lpwfs->lstnSocket);
3108         lpwfs->lstnSocket = -1;
3109     }
3110     return *nDataSocket != -1;
3111 }
3112 
3113 
3114 /***********************************************************************
3115  *           FTP_SendData (internal)
3116  *
3117  * Send data to the server
3118  *
3119  * RETURNS
3120  *   TRUE on success
3121  *   FALSE on failure
3122  *
3123  */
3124 static BOOL FTP_SendData(ftp_session_t *lpwfs, INT nDataSocket, HANDLE hFile)
3125 {
3126     BY_HANDLE_FILE_INFORMATION fi;
3127     DWORD nBytesRead = 0;
3128     DWORD nBytesSent = 0;
3129     DWORD nTotalSent = 0;
3130     DWORD nBytesToSend, nLen;
3131     int nRC = 1;
3132     time_t s_long_time, e_long_time;
3133     LONG nSeconds;
3134     CHAR *lpszBuffer;
3135 
3136     TRACE("\n");
3137     lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
3138 
3139     /* Get the size of the file. */
3140     GetFileInformationByHandle(hFile, &fi);
3141     time(&s_long_time);
3142 
3143     do
3144     {
3145         nBytesToSend = nBytesRead - nBytesSent;
3146 
3147         if (nBytesToSend <= 0)
3148         {
3149             /* Read data from file. */
3150             nBytesSent = 0;
3151             if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
3152             ERR("Failed reading from file\n");
3153 
3154             if (nBytesRead > 0)
3155                 nBytesToSend = nBytesRead;
3156             else
3157                 break;
3158         }
3159 
3160         nLen = DATA_PACKET_SIZE < nBytesToSend ?
3161             DATA_PACKET_SIZE : nBytesToSend;
3162         nRC  = send(nDataSocket, lpszBuffer, nLen, 0);
3163 
3164         if (nRC != -1)
3165         {
3166             nBytesSent += nRC;
3167             nTotalSent += nRC;
3168         }
3169 
3170         /* Do some computation to display the status. */
3171         time(&e_long_time);
3172         nSeconds = e_long_time - s_long_time;
3173         if( nSeconds / 60 > 0 )
3174         {
3175             TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n",
3176             nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
3177             nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
3178         }
3179         else
3180         {
3181             TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n",
3182             nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
3183             (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
3184         }
3185     } while (nRC != -1);
3186 
3187     TRACE("file transfer complete!\n");
3188 
3189     HeapFree(GetProcessHeap(), 0, lpszBuffer);
3190 
3191     return nTotalSent;
3192 }
3193 
3194 
3195 /***********************************************************************
3196  *           FTP_SendRetrieve (internal)
3197  *
3198  * Send request to retrieve a file
3199  *
3200  * RETURNS
3201  *   Number of bytes to be received on success
3202  *   0 on failure
3203  *
3204  */
3205 static BOOL FTP_SendRetrieve(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
3206 {
3207     INT nResCode;
3208     BOOL ret;
3209 
3210     TRACE("\n");
3211     if (!(ret = FTP_InitListenSocket(lpwfs)))
3212         goto lend;
3213 
3214     if (!(ret = FTP_SendType(lpwfs, dwType)))
3215         goto lend;
3216 
3217     if (!(ret = FTP_SendPortOrPasv(lpwfs)))
3218         goto lend;
3219 
3220     if (!(ret = FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0)))
3221         goto lend;
3222 
3223     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
3224     if ((nResCode != 125) && (nResCode != 150)) {
3225         /* That means that we got an error getting the file. */
3226         FTP_SetResponseError(nResCode);
3227         ret = FALSE;
3228     }
3229 
3230 lend:
3231     if (!ret && lpwfs->lstnSocket != -1)
3232     {
3233         closesocket(lpwfs->lstnSocket);
3234         lpwfs->lstnSocket = -1;
3235     }
3236 
3237     return ret;
3238 }
3239 
3240 
3241 /***********************************************************************
3242  *           FTP_RetrieveData  (internal)
3243  *
3244  * Retrieve data from server
3245  *
3246  * RETURNS
3247  *   TRUE on success
3248  *   FALSE on failure
3249  *
3250  */
3251 static BOOL FTP_RetrieveFileData(ftp_session_t *lpwfs, INT nDataSocket, HANDLE hFile)
3252 {
3253     DWORD nBytesWritten;
3254     INT nRC = 0;
3255     CHAR *lpszBuffer;
3256 
3257     TRACE("\n");
3258 
3259     lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
3260     if (NULL == lpszBuffer)
3261     {
3262         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
3263         return FALSE;
3264     }
3265 
3266     while (nRC != -1)
3267     {
3268         nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
3269         if (nRC != -1)
3270         {
3271             /* other side closed socket. */
3272             if (nRC == 0)
3273                 goto recv_end;
3274             WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
3275         }
3276     }
3277 
3278     TRACE("Data transfer complete\n");
3279 
3280 recv_end:
3281     HeapFree(GetProcessHeap(), 0, lpszBuffer);
3282 
3283     return  (nRC != -1);
3284 }
3285 
3286 /***********************************************************************
3287  *           FTPFINDNEXT_Destroy (internal)
3288  *
3289  * Deallocate session handle
3290  */
3291 static void FTPFINDNEXT_Destroy(object_header_t *hdr)
3292 {
3293     LPWININETFTPFINDNEXTW lpwfn = (LPWININETFTPFINDNEXTW) hdr;
3294     DWORD i;
3295 
3296     TRACE("\n");
3297 
3298     WININET_Release(&lpwfn->lpFtpSession->hdr);
3299 
3300     for (i = 0; i < lpwfn->size; i++)
3301     {
3302         HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
3303     }
3304 
3305     HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
3306     HeapFree(GetProcessHeap(), 0, lpwfn);
3307 }
3308 
3309 static DWORD FTPFINDNEXT_FindNextFileProc(WININETFTPFINDNEXTW *find, LPVOID data)
3310 {
3311     WIN32_FIND_DATAW *find_data = data;
3312     DWORD res = ERROR_SUCCESS;
3313 
3314     TRACE("index(%d) size(%d)\n", find->index, find->size);
3315 
3316     ZeroMemory(find_data, sizeof(WIN32_FIND_DATAW));
3317 
3318     if (find->index < find->size) {
3319         FTP_ConvertFileProp(&find->lpafp[find->index], find_data);
3320         find->index++;
3321 
3322         TRACE("Name: %s\nSize: %d\n", debugstr_w(find_data->cFileName), find_data->nFileSizeLow);
3323     }else {
3324         res = ERROR_NO_MORE_FILES;
3325     }
3326 
3327     if (find->hdr.dwFlags & INTERNET_FLAG_ASYNC)
3328     {
3329         INTERNET_ASYNC_RESULT iar;
3330 
3331         iar.dwResult = (res == ERROR_SUCCESS);
3332         iar.dwError = res;
3333 
3334         INTERNET_SendCallback(&find->hdr, find->hdr.dwContext,
3335                               INTERNET_STATUS_REQUEST_COMPLETE, &iar,
3336                               sizeof(INTERNET_ASYNC_RESULT));
3337     }
3338 
3339     return res;
3340 }
3341 
3342 static void FTPFINDNEXT_AsyncFindNextFileProc(WORKREQUEST *workRequest)
3343 {
3344     struct WORKREQ_FTPFINDNEXTW *req = &workRequest->u.FtpFindNextW;
3345 
3346     FTPFINDNEXT_FindNextFileProc((WININETFTPFINDNEXTW*)workRequest->hdr, req->lpFindFileData);
3347 }
3348 
3349 static DWORD FTPFINDNEXT_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
3350 {
3351     switch(option) {
3352     case INTERNET_OPTION_HANDLE_TYPE:
3353         TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
3354 
3355         if (*size < sizeof(ULONG))
3356             return ERROR_INSUFFICIENT_BUFFER;
3357 
3358         *size = sizeof(DWORD);
3359         *(DWORD*)buffer = INTERNET_HANDLE_TYPE_FTP_FIND;
3360         return ERROR_SUCCESS;
3361     }
3362 
3363     return INET_QueryOption(option, buffer, size, unicode);
3364 }
3365 
3366 static DWORD FTPFINDNEXT_FindNextFileW(object_header_t *hdr, void *data)
3367 {
3368     WININETFTPFINDNEXTW *find = (WININETFTPFINDNEXTW*)hdr;
3369 
3370     if (find->lpFtpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
3371     {
3372         WORKREQUEST workRequest;
3373         struct WORKREQ_FTPFINDNEXTW *req;
3374 
3375         workRequest.asyncproc = FTPFINDNEXT_AsyncFindNextFileProc;
3376         workRequest.hdr = WININET_AddRef( &find->hdr );
3377         req = &workRequest.u.FtpFindNextW;
3378         req->lpFindFileData = data;
3379 
3380         INTERNET_AsyncCall(&workRequest);
3381 
3382         return ERROR_SUCCESS;
3383     }
3384 
3385     return FTPFINDNEXT_FindNextFileProc(find, data);
3386 }
3387 
3388 static const object_vtbl_t FTPFINDNEXTVtbl = {
3389     FTPFINDNEXT_Destroy,
3390     NULL,
3391     FTPFINDNEXT_QueryOption,
3392     NULL,
3393     NULL,
3394     NULL,
3395     NULL,
3396     NULL,
3397     NULL,
3398     FTPFINDNEXT_FindNextFileW
3399 };
3400 
3401 /***********************************************************************
3402  *           FTP_ReceiveFileList (internal)
3403  *
3404  * Read file list from server
3405  *
3406  * RETURNS
3407  *   Handle to file list on success
3408  *   NULL on failure
3409  *
3410  */
3411 static HINTERNET FTP_ReceiveFileList(ftp_session_t *lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3412         LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext)
3413 {
3414     DWORD dwSize = 0;
3415     LPFILEPROPERTIESW lpafp = NULL;
3416     LPWININETFTPFINDNEXTW lpwfn = NULL;
3417     HINTERNET handle = 0;
3418 
3419     TRACE("(%p,%d,%s,%p,%08lx)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
3420 
3421     if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
3422     {
3423         if(lpFindFileData)
3424             FTP_ConvertFileProp(lpafp, lpFindFileData);
3425 
3426         lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFTPFINDNEXTW));
3427         if (lpwfn)
3428         {
3429             lpwfn->hdr.htype = WH_HFTPFINDNEXT;
3430             lpwfn->hdr.vtbl = &FTPFINDNEXTVtbl;
3431             lpwfn->hdr.dwContext = dwContext;
3432             lpwfn->hdr.refs = 1;
3433             lpwfn->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
3434             lpwfn->index = 1; /* Next index is 1 since we return index 0 */
3435             lpwfn->size = dwSize;
3436             lpwfn->lpafp = lpafp;
3437 
3438             WININET_AddRef( &lpwfs->hdr );
3439             lpwfn->lpFtpSession = lpwfs;
3440             list_add_head( &lpwfs->hdr.children, &lpwfn->hdr.entry );
3441 
3442             handle = WININET_AllocHandle( &lpwfn->hdr );
3443         }
3444     }
3445 
3446     if( lpwfn )
3447         WININET_Release( &lpwfn->hdr );
3448 
3449     TRACE("Matched %d files\n", dwSize);
3450     return handle;
3451 }
3452 
3453 
3454 /***********************************************************************
3455  *           FTP_ConvertFileProp (internal)
3456  *
3457  * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
3458  *
3459  * RETURNS
3460  *   TRUE on success
3461  *   FALSE on failure
3462  *
3463  */
3464 static BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
3465 {
3466     BOOL bSuccess = FALSE;
3467 
3468     ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
3469 
3470     if (lpafp)
3471     {
3472         SystemTimeToFileTime( &lpafp->tmLastModified, &lpFindFileData->ftLastAccessTime );
3473         lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime;
3474         lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime;
3475         
3476         /* Not all fields are filled in */
3477         lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
3478         lpFindFileData->nFileSizeLow = lpafp->nSize;
3479 
3480         if (lpafp->bIsDirectory)
3481             lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
3482 
3483         if (lpafp->lpszName)
3484             lstrcpynW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
3485 
3486         bSuccess = TRUE;
3487     }
3488 
3489     return bSuccess;
3490 }
3491 
3492 /***********************************************************************
3493  *           FTP_ParseNextFile (internal)
3494  *
3495  * Parse the next line in file listing
3496  *
3497  * RETURNS
3498  *   TRUE on success
3499  *   FALSE on failure
3500  */
3501 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
3502 {
3503     static const char szSpace[] = " \t";
3504     DWORD nBufLen;
3505     char *pszLine;
3506     char *pszToken;
3507     char *pszTmp;
3508     BOOL found = FALSE;
3509     int i;
3510     
3511     lpfp->lpszName = NULL;
3512     do {
3513         if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
3514             return FALSE;
3515     
3516         pszToken = strtok(pszLine, szSpace);
3517         /* ls format
3518          * <Permissions> <NoLinks> <owner>   <group> <size> <date>  <time or year> <filename>
3519          *
3520          * For instance:
3521          * drwx--s---     2         pcarrier  ens     512    Sep 28  1995           pcarrier
3522          */
3523         if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
3524             if(!FTP_ParsePermission(pszToken, lpfp))
3525                 lpfp->bIsDirectory = FALSE;
3526             for(i=0; i<=3; i++) {
3527               if(!(pszToken = strtok(NULL, szSpace)))
3528                   break;
3529             }
3530             if(!pszToken) continue;
3531             if(lpfp->bIsDirectory) {
3532                 TRACE("Is directory\n");
3533                 lpfp->nSize = 0;
3534             }
3535             else {
3536                 TRACE("Size: %s\n", pszToken);
3537                 lpfp->nSize = atol(pszToken);
3538             }
3539             
3540             lpfp->tmLastModified.wSecond = 0;
3541             lpfp->tmLastModified.wMinute = 0;
3542             lpfp->tmLastModified.wHour   = 0;
3543             lpfp->tmLastModified.wDay    = 0;
3544             lpfp->tmLastModified.wMonth  = 0;
3545             lpfp->tmLastModified.wYear   = 0;
3546             
3547             /* Determine month */
3548             pszToken = strtok(NULL, szSpace);
3549             if(!pszToken) continue;
3550             if(strlen(pszToken) >= 3) {
3551                 pszToken[3] = 0;
3552                 if((pszTmp = StrStrIA(szMonths, pszToken)))
3553                     lpfp->tmLastModified.wMonth = ((pszTmp - szMonths) / 3)+1;
3554             }
3555             /* Determine day */
3556             pszToken = strtok(NULL, szSpace);
3557             if(!pszToken) continue;
3558             lpfp->tmLastModified.wDay = atoi(pszToken);
3559             /* Determine time or year */
3560             pszToken = strtok(NULL, szSpace);
3561             if(!pszToken) continue;
3562             if((pszTmp = strchr(pszToken, ':'))) {
3563                 SYSTEMTIME curr_time;
3564                 *pszTmp = 0;
3565                 pszTmp++;
3566                 lpfp->tmLastModified.wMinute = atoi(pszTmp);
3567                 lpfp->tmLastModified.wHour = atoi(pszToken);
3568                 GetLocalTime( &curr_time );
3569                 lpfp->tmLastModified.wYear = curr_time.wYear;
3570             }
3571             else {
3572                 lpfp->tmLastModified.wYear = atoi(pszToken);
3573                 lpfp->tmLastModified.wHour = 12;
3574             }
3575             TRACE("Mod time: %02d:%02d:%02d  %04d/%02d/%02d\n",
3576                   lpfp->tmLastModified.wHour, lpfp->tmLastModified.wMinute, lpfp->tmLastModified.wSecond,
3577                   lpfp->tmLastModified.wYear, lpfp->tmLastModified.wMonth, lpfp->tmLastModified.wDay);
3578 
3579             pszToken = strtok(NULL, szSpace);
3580             if(!pszToken) continue;
3581             lpfp->lpszName = heap_strdupAtoW(pszToken);
3582             TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
3583         }
3584         /* NT way of parsing ... :
3585             
3586                 07-13-03  08:55PM       <DIR>          sakpatch
3587                 05-09-03  06:02PM             12656686 2003-04-21bgm_cmd_e.rgz
3588         */
3589         else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
3590             int mon, mday, year, hour, min;
3591             lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
3592             
3593             sscanf(pszToken, "%d-%d-%d", &mon, &mday, &year);
3594             lpfp->tmLastModified.wDay   = mday;
3595             lpfp->tmLastModified.wMonth = mon;
3596             lpfp->tmLastModified.wYear  = year;
3597 
3598             /* Hacky and bad Y2K protection :-) */
3599             if (lpfp->tmLastModified.wYear < 70) lpfp->tmLastModified.wYear += 2000;
3600 
3601             pszToken = strtok(NULL, szSpace);
3602             if(!pszToken) continue;
3603             sscanf(pszToken, "%d:%d", &hour, &min);
3604             lpfp->tmLastModified.wHour   = hour;
3605             lpfp->tmLastModified.wMinute = min;
3606             if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
3607                 lpfp->tmLastModified.wHour += 12;
3608             }
3609             lpfp->tmLastModified.wSecond = 0;
3610 
3611             TRACE("Mod time: %02d:%02d:%02d  %04d/%02d/%02d\n",
3612                   lpfp->tmLastModified.wHour, lpfp->tmLastModified.wMinute, lpfp->tmLastModified.wSecond,
3613                   lpfp->tmLastModified.wYear, lpfp->tmLastModified.wMonth, lpfp->tmLastModified.wDay);
3614 
3615             pszToken = strtok(NULL, szSpace);
3616             if(!pszToken) continue;
3617             if(!strcasecmp(pszToken, "<DIR>")) {
3618                 lpfp->bIsDirectory = TRUE;
3619                 lpfp->nSize = 0;
3620                 TRACE("Is directory\n");
3621             }
3622             else {
3623                 lpfp->bIsDirectory = FALSE;
3624                 lpfp->nSize = atol(pszToken);
3625                 TRACE("Size: %d\n", lpfp->nSize);
3626             }
3627             
3628             pszToken = strtok(NULL, szSpace);
3629             if(!pszToken) continue;
3630             lpfp->lpszName = heap_strdupAtoW(pszToken);
3631             TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
3632         }
3633         /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
3634         else if(pszToken[0] == '+') {
3635             FIXME("EPLF Format not implemented\n");
3636         }
3637         
3638         if(lpfp->lpszName) {
3639             if((lpszSearchFile == NULL) ||
3640                (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
3641                 found = TRUE;
3642                 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
3643             }
3644             else {
3645                 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
3646                 lpfp->lpszName = NULL;
3647             }
3648         }
3649     } while(!found);
3650     return TRUE;
3651 }
3652 
3653 /***********************************************************************
3654  *           FTP_ParseDirectory (internal)
3655  *
3656  * Parse string of directory information
3657  *
3658  * RETURNS
3659  *   TRUE on success
3660  *   FALSE on failure
3661  */
3662 static BOOL FTP_ParseDirectory(ftp_session_t *lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3663     LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
3664 {
3665     BOOL bSuccess = TRUE;
3666     INT sizeFilePropArray = 500;/*20; */
3667     INT indexFilePropArray = -1;
3668 
3669     TRACE("\n");
3670 
3671     /* Allocate initial file properties array */
3672     *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
3673     if (!*lpafp)
3674         return FALSE;
3675 
3676     do {
3677         if (indexFilePropArray+1 >= sizeFilePropArray)
3678         {
3679             LPFILEPROPERTIESW tmpafp;
3680             
3681             sizeFilePropArray *= 2;
3682             tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
3683                 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
3684             if (NULL == tmpafp)
3685             {
3686                 bSuccess = FALSE;
3687                 break;
3688             }
3689 
3690             *lpafp = tmpafp;
3691         }
3692         indexFilePropArray++;
3693     } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
3694 
3695     if (bSuccess && indexFilePropArray)
3696     {
3697         if (indexFilePropArray < sizeFilePropArray - 1)
3698         {
3699             LPFILEPROPERTIESW tmpafp;
3700 
3701             tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
3702                 sizeof(FILEPROPERTIESW)*indexFilePropArray);
3703             if (NULL != tmpafp)
3704                 *lpafp = tmpafp;
3705         }
3706         *dwfp = indexFilePropArray;
3707     }
3708     else
3709     {
3710         HeapFree(GetProcessHeap(), 0, *lpafp);
3711         INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3712         bSuccess = FALSE;
3713     }
3714 
3715     return bSuccess;
3716 }
3717 
3718 
3719 /***********************************************************************
3720  *           FTP_ParsePermission (internal)
3721  *
3722  * Parse permission string of directory information
3723  *
3724  * RETURNS
3725  *   TRUE on success
3726  *   FALSE on failure
3727  *
3728  */
3729 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3730 {
3731     BOOL bSuccess = TRUE;
3732     unsigned short nPermission = 0;
3733     INT nPos = 1;
3734     INT nLast  = 9;
3735 
3736     TRACE("\n");
3737     if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3738     {
3739         bSuccess = FALSE;
3740         return bSuccess;
3741     }
3742 
3743     lpfp->bIsDirectory = (*lpszPermission == 'd');
3744     do
3745     {
3746         switch (nPos)
3747         {
3748             case 1:
3749                 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3750                 break;
3751             case 2:
3752                 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3753                 break;
3754             case 3:
3755                 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3756                 break;
3757             case 4:
3758                 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3759                 break;
3760             case 5:
3761                 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3762                 break;
3763             case 6:
3764                 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3765                 break;
3766             case 7:
3767                 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3768                 break;
3769             case 8:
3770                 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3771                 break;
3772             case 9:
3773                 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3774                 break;
3775         }
3776         nPos++;
3777     }while (nPos <= nLast);
3778 
3779     lpfp->permissions = nPermission;
3780     return bSuccess;
3781 }
3782 
3783 
3784 /***********************************************************************
3785  *           FTP_SetResponseError (internal)
3786  *
3787  * Set the appropriate error code for a given response from the server
3788  *
3789  * RETURNS
3790  *
3791  */
3792 static DWORD FTP_SetResponseError(DWORD dwResponse)
3793 {
3794     DWORD dwCode = 0;
3795 
3796     switch(dwResponse)
3797     {
3798     case 425: /* Cannot open data connection. */
3799         dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3800         break;
3801 
3802     case 426: /* Connection closed, transer aborted. */
3803         dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3804         break;
3805 
3806     case 530: /* Not logged in. Login incorrect. */
3807         dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3808         break;
3809 
3810     case 421: /* Service not available - Server may be shutting down. */
3811     case 450: /* File action not taken. File may be busy. */
3812     case 451: /* Action aborted. Server error. */
3813     case 452: /* Action not taken. Insufficient storage space on server. */
3814     case 500: /* Syntax error. Command unrecognized. */
3815     case 501: /* Syntax error. Error in parameters or arguments. */
3816     case 502: /* Command not implemented. */
3817     case 503: /* Bad sequence of commands. */
3818     case 504: /* Command not implemented for that parameter. */
3819     case 532: /* Need account for storing files */
3820     case 550: /* File action not taken. File not found or no access. */
3821     case 551: /* Requested action aborted. Page type unknown */
3822     case 552: /* Action aborted. Exceeded storage allocation */
3823     case 553: /* Action not taken. File name not allowed. */
3824 
3825     default:
3826         dwCode = ERROR_INTERNET_EXTENDED_ERROR;
3827         break;
3828     }
3829 
3830     INTERNET_SetLastError(dwCode);
3831     return dwCode;
3832 }
3833 

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

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.