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