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