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