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