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

~ [ 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.