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 struct tm 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)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)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 FTPFILE_WriteFile,
1271 NULL,
1272 NULL
1273 };
1274
1275 /***********************************************************************
1276 * FTP_FtpOpenFileW (Internal)
1277 *
1278 * Open a remote file for writing or reading
1279 *
1280 * RETURNS
1281 * HINTERNET handle on success
1282 * NULL on failure
1283 *
1284 */
1285 HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs,
1286 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1287 DWORD_PTR dwContext)
1288 {
1289 INT nDataSocket;
1290 BOOL bSuccess = FALSE;
1291 LPWININETFTPFILE lpwh = NULL;
1292 LPWININETAPPINFOW hIC = NULL;
1293 HINTERNET handle = NULL;
1294
1295 TRACE("\n");
1296
1297 /* Clear any error information */
1298 INTERNET_SetLastError(0);
1299
1300 if (GENERIC_READ == fdwAccess)
1301 {
1302 /* Set up socket to retrieve data */
1303 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
1304 }
1305 else if (GENERIC_WRITE == fdwAccess)
1306 {
1307 /* Set up socket to send data */
1308 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
1309 }
1310
1311 /* Get data socket to server */
1312 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
1313 {
1314 lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPFILE));
1315 lpwh->hdr.htype = WH_HFILE;
1316 lpwh->hdr.vtbl = &FTPFILEVtbl;
1317 lpwh->hdr.dwFlags = dwFlags;
1318 lpwh->hdr.dwContext = dwContext;
1319 lpwh->hdr.refs = 1;
1320 lpwh->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
1321 lpwh->nDataSocket = nDataSocket;
1322 lpwh->session_deleted = FALSE;
1323
1324 WININET_AddRef( &lpwfs->hdr );
1325 lpwh->lpFtpSession = lpwfs;
1326 list_add_head( &lpwfs->hdr.children, &lpwh->hdr.entry );
1327
1328 handle = WININET_AllocHandle( &lpwh->hdr );
1329 if( !handle )
1330 goto lend;
1331
1332 /* Indicate that a download is currently in progress */
1333 lpwfs->download_in_progress = lpwh;
1334 }
1335
1336 if (lpwfs->lstnSocket != -1)
1337 closesocket(lpwfs->lstnSocket);
1338
1339 hIC = lpwfs->lpAppInfo;
1340 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1341 {
1342 INTERNET_ASYNC_RESULT iar;
1343
1344 if (lpwh)
1345 {
1346 iar.dwResult = (DWORD)handle;
1347 iar.dwError = ERROR_SUCCESS;
1348 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
1349 &iar, sizeof(INTERNET_ASYNC_RESULT));
1350 }
1351
1352 iar.dwResult = (DWORD)bSuccess;
1353 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1354 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1355 &iar, sizeof(INTERNET_ASYNC_RESULT));
1356 }
1357
1358 lend:
1359 if( lpwh )
1360 WININET_Release( &lpwh->hdr );
1361
1362 return handle;
1363 }
1364
1365
1366 /***********************************************************************
1367 * FtpGetFileA (WININET.@)
1368 *
1369 * Retrieve file from the FTP server
1370 *
1371 * RETURNS
1372 * TRUE on success
1373 * FALSE on failure
1374 *
1375 */
1376 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1377 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1378 DWORD_PTR dwContext)
1379 {
1380 LPWSTR lpwzRemoteFile;
1381 LPWSTR lpwzNewFile;
1382 BOOL ret;
1383
1384 lpwzRemoteFile = lpszRemoteFile?WININET_strdup_AtoW(lpszRemoteFile):NULL;
1385 lpwzNewFile = lpszNewFile?WININET_strdup_AtoW(lpszNewFile):NULL;
1386 ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists,
1387 dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1388 HeapFree(GetProcessHeap(), 0, lpwzRemoteFile);
1389 HeapFree(GetProcessHeap(), 0, lpwzNewFile);
1390 return ret;
1391 }
1392
1393
1394 static void AsyncFtpGetFileProc(WORKREQUEST *workRequest)
1395 {
1396 struct WORKREQ_FTPGETFILEW const *req = &workRequest->u.FtpGetFileW;
1397 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1398
1399 TRACE("%p\n", lpwfs);
1400
1401 FTP_FtpGetFileW(lpwfs, req->lpszRemoteFile,
1402 req->lpszNewFile, req->fFailIfExists,
1403 req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext);
1404 HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile);
1405 HeapFree(GetProcessHeap(), 0, req->lpszNewFile);
1406 }
1407
1408
1409 /***********************************************************************
1410 * FtpGetFileW (WININET.@)
1411 *
1412 * Retrieve file from the FTP server
1413 *
1414 * RETURNS
1415 * TRUE on success
1416 * FALSE on failure
1417 *
1418 */
1419 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1420 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1421 DWORD_PTR dwContext)
1422 {
1423 LPWININETFTPSESSIONW lpwfs;
1424 LPWININETAPPINFOW hIC = NULL;
1425 BOOL r = FALSE;
1426
1427 if (!lpszRemoteFile || !lpszNewFile)
1428 {
1429 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1430 return FALSE;
1431 }
1432
1433 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet );
1434 if (!lpwfs)
1435 {
1436 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1437 return FALSE;
1438 }
1439
1440 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1441 {
1442 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1443 goto lend;
1444 }
1445
1446 if ((dwInternetFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY)
1447 {
1448 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1449 goto lend;
1450 }
1451
1452 if (lpwfs->download_in_progress != NULL)
1453 {
1454 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1455 goto lend;
1456 }
1457
1458 hIC = lpwfs->lpAppInfo;
1459 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1460 {
1461 WORKREQUEST workRequest;
1462 struct WORKREQ_FTPGETFILEW *req;
1463
1464 workRequest.asyncproc = AsyncFtpGetFileProc;
1465 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1466 req = &workRequest.u.FtpGetFileW;
1467 req->lpszRemoteFile = WININET_strdupW(lpszRemoteFile);
1468 req->lpszNewFile = WININET_strdupW(lpszNewFile);
1469 req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1470 req->fFailIfExists = fFailIfExists;
1471 req->dwFlags = dwInternetFlags;
1472 req->dwContext = dwContext;
1473
1474 r = INTERNET_AsyncCall(&workRequest);
1475 }
1476 else
1477 {
1478 r = FTP_FtpGetFileW(lpwfs, lpszRemoteFile, lpszNewFile,
1479 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1480 }
1481
1482 lend:
1483 WININET_Release( &lpwfs->hdr );
1484
1485 return r;
1486 }
1487
1488
1489 /***********************************************************************
1490 * FTP_FtpGetFileW (Internal)
1491 *
1492 * Retrieve file from the FTP server
1493 *
1494 * RETURNS
1495 * TRUE on success
1496 * FALSE on failure
1497 *
1498 */
1499 static BOOL FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1500 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1501 DWORD_PTR dwContext)
1502 {
1503 BOOL bSuccess = FALSE;
1504 HANDLE hFile;
1505 LPWININETAPPINFOW hIC = NULL;
1506
1507 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile));
1508
1509 /* Clear any error information */
1510 INTERNET_SetLastError(0);
1511
1512 /* Ensure we can write to lpszNewfile by opening it */
1513 hFile = CreateFileW(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1514 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1515 if (INVALID_HANDLE_VALUE == hFile)
1516 return FALSE;
1517
1518 /* Set up socket to retrieve data */
1519 if (FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags))
1520 {
1521 INT nDataSocket;
1522
1523 /* Get data socket to server */
1524 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1525 {
1526 INT nResCode;
1527
1528 /* Receive data */
1529 FTP_RetrieveFileData(lpwfs, nDataSocket, hFile);
1530 closesocket(nDataSocket);
1531
1532 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
1533 if (nResCode)
1534 {
1535 if (nResCode == 226)
1536 bSuccess = TRUE;
1537 else
1538 FTP_SetResponseError(nResCode);
1539 }
1540 }
1541 }
1542
1543 if (lpwfs->lstnSocket != -1)
1544 closesocket(lpwfs->lstnSocket);
1545
1546 CloseHandle(hFile);
1547
1548 hIC = lpwfs->lpAppInfo;
1549 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1550 {
1551 INTERNET_ASYNC_RESULT iar;
1552
1553 iar.dwResult = (DWORD)bSuccess;
1554 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1555 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1556 &iar, sizeof(INTERNET_ASYNC_RESULT));
1557 }
1558
1559 if (!bSuccess) DeleteFileW(lpszNewFile);
1560 return bSuccess;
1561 }
1562
1563 /***********************************************************************
1564 * FtpGetFileSize (WININET.@)
1565 */
1566 DWORD WINAPI FtpGetFileSize( HINTERNET hFile, LPDWORD lpdwFileSizeHigh )
1567 {
1568 FIXME("(%p, %p)\n", hFile, lpdwFileSizeHigh);
1569
1570 if (lpdwFileSizeHigh)
1571 *lpdwFileSizeHigh = 0;
1572
1573 return 0;
1574 }
1575
1576 /***********************************************************************
1577 * FtpDeleteFileA (WININET.@)
1578 *
1579 * Delete a file on the ftp server
1580 *
1581 * RETURNS
1582 * TRUE on success
1583 * FALSE on failure
1584 *
1585 */
1586 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1587 {
1588 LPWSTR lpwzFileName;
1589 BOOL ret;
1590
1591 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1592 ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1593 HeapFree(GetProcessHeap(), 0, lpwzFileName);
1594 return ret;
1595 }
1596
1597 static void AsyncFtpDeleteFileProc(WORKREQUEST *workRequest)
1598 {
1599 struct WORKREQ_FTPDELETEFILEW const *req = &workRequest->u.FtpDeleteFileW;
1600 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1601
1602 TRACE("%p\n", lpwfs);
1603
1604 FTP_FtpDeleteFileW(lpwfs, req->lpszFilename);
1605 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1606 }
1607
1608 /***********************************************************************
1609 * FtpDeleteFileW (WININET.@)
1610 *
1611 * Delete a file on the ftp server
1612 *
1613 * RETURNS
1614 * TRUE on success
1615 * FALSE on failure
1616 *
1617 */
1618 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1619 {
1620 LPWININETFTPSESSIONW lpwfs;
1621 LPWININETAPPINFOW hIC = NULL;
1622 BOOL r = FALSE;
1623
1624 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1625 if (!lpwfs)
1626 {
1627 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1628 return FALSE;
1629 }
1630
1631 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1632 {
1633 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1634 goto lend;
1635 }
1636
1637 if (lpwfs->download_in_progress != NULL)
1638 {
1639 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1640 goto lend;
1641 }
1642
1643 if (!lpszFileName)
1644 {
1645 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1646 goto lend;
1647 }
1648
1649 hIC = lpwfs->lpAppInfo;
1650 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1651 {
1652 WORKREQUEST workRequest;
1653 struct WORKREQ_FTPDELETEFILEW *req;
1654
1655 workRequest.asyncproc = AsyncFtpDeleteFileProc;
1656 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1657 req = &workRequest.u.FtpDeleteFileW;
1658 req->lpszFilename = WININET_strdupW(lpszFileName);
1659
1660 r = INTERNET_AsyncCall(&workRequest);
1661 }
1662 else
1663 {
1664 r = FTP_FtpDeleteFileW(lpwfs, lpszFileName);
1665 }
1666
1667 lend:
1668 WININET_Release( &lpwfs->hdr );
1669
1670 return r;
1671 }
1672
1673 /***********************************************************************
1674 * FTP_FtpDeleteFileW (Internal)
1675 *
1676 * Delete a file on the ftp server
1677 *
1678 * RETURNS
1679 * TRUE on success
1680 * FALSE on failure
1681 *
1682 */
1683 BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName)
1684 {
1685 INT nResCode;
1686 BOOL bSuccess = FALSE;
1687 LPWININETAPPINFOW hIC = NULL;
1688
1689 TRACE("%p\n", lpwfs);
1690
1691 /* Clear any error information */
1692 INTERNET_SetLastError(0);
1693
1694 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1695 goto lend;
1696
1697 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1698 if (nResCode)
1699 {
1700 if (nResCode == 250)
1701 bSuccess = TRUE;
1702 else
1703 FTP_SetResponseError(nResCode);
1704 }
1705 lend:
1706 hIC = lpwfs->lpAppInfo;
1707 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1708 {
1709 INTERNET_ASYNC_RESULT iar;
1710
1711 iar.dwResult = (DWORD)bSuccess;
1712 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1713 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1714 &iar, sizeof(INTERNET_ASYNC_RESULT));
1715 }
1716
1717 return bSuccess;
1718 }
1719
1720
1721 /***********************************************************************
1722 * FtpRemoveDirectoryA (WININET.@)
1723 *
1724 * Remove a directory on the ftp server
1725 *
1726 * RETURNS
1727 * TRUE on success
1728 * FALSE on failure
1729 *
1730 */
1731 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1732 {
1733 LPWSTR lpwzDirectory;
1734 BOOL ret;
1735
1736 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
1737 ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1738 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
1739 return ret;
1740 }
1741
1742 static void AsyncFtpRemoveDirectoryProc(WORKREQUEST *workRequest)
1743 {
1744 struct WORKREQ_FTPREMOVEDIRECTORYW const *req = &workRequest->u.FtpRemoveDirectoryW;
1745 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1746
1747 TRACE("%p\n", lpwfs);
1748
1749 FTP_FtpRemoveDirectoryW(lpwfs, req->lpszDirectory);
1750 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
1751 }
1752
1753 /***********************************************************************
1754 * FtpRemoveDirectoryW (WININET.@)
1755 *
1756 * Remove a directory on the ftp server
1757 *
1758 * RETURNS
1759 * TRUE on success
1760 * FALSE on failure
1761 *
1762 */
1763 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1764 {
1765 LPWININETFTPSESSIONW lpwfs;
1766 LPWININETAPPINFOW hIC = NULL;
1767 BOOL r = FALSE;
1768
1769 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1770 if (!lpwfs)
1771 {
1772 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1773 return FALSE;
1774 }
1775
1776 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1777 {
1778 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1779 goto lend;
1780 }
1781
1782 if (lpwfs->download_in_progress != NULL)
1783 {
1784 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1785 goto lend;
1786 }
1787
1788 if (!lpszDirectory)
1789 {
1790 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1791 goto lend;
1792 }
1793
1794 hIC = lpwfs->lpAppInfo;
1795 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1796 {
1797 WORKREQUEST workRequest;
1798 struct WORKREQ_FTPREMOVEDIRECTORYW *req;
1799
1800 workRequest.asyncproc = AsyncFtpRemoveDirectoryProc;
1801 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1802 req = &workRequest.u.FtpRemoveDirectoryW;
1803 req->lpszDirectory = WININET_strdupW(lpszDirectory);
1804
1805 r = INTERNET_AsyncCall(&workRequest);
1806 }
1807 else
1808 {
1809 r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory);
1810 }
1811
1812 lend:
1813 WININET_Release( &lpwfs->hdr );
1814
1815 return r;
1816 }
1817
1818 /***********************************************************************
1819 * FTP_FtpRemoveDirectoryW (Internal)
1820 *
1821 * Remove a directory on the ftp server
1822 *
1823 * RETURNS
1824 * TRUE on success
1825 * FALSE on failure
1826 *
1827 */
1828 BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
1829 {
1830 INT nResCode;
1831 BOOL bSuccess = FALSE;
1832 LPWININETAPPINFOW hIC = NULL;
1833
1834 TRACE("\n");
1835
1836 /* Clear any error information */
1837 INTERNET_SetLastError(0);
1838
1839 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1840 goto lend;
1841
1842 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1843 if (nResCode)
1844 {
1845 if (nResCode == 250)
1846 bSuccess = TRUE;
1847 else
1848 FTP_SetResponseError(nResCode);
1849 }
1850
1851 lend:
1852 hIC = lpwfs->lpAppInfo;
1853 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1854 {
1855 INTERNET_ASYNC_RESULT iar;
1856
1857 iar.dwResult = (DWORD)bSuccess;
1858 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1859 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1860 &iar, sizeof(INTERNET_ASYNC_RESULT));
1861 }
1862
1863 return bSuccess;
1864 }
1865
1866
1867 /***********************************************************************
1868 * FtpRenameFileA (WININET.@)
1869 *
1870 * Rename a file on the ftp server
1871 *
1872 * RETURNS
1873 * TRUE on success
1874 * FALSE on failure
1875 *
1876 */
1877 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1878 {
1879 LPWSTR lpwzSrc;
1880 LPWSTR lpwzDest;
1881 BOOL ret;
1882
1883 lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL;
1884 lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL;
1885 ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
1886 HeapFree(GetProcessHeap(), 0, lpwzSrc);
1887 HeapFree(GetProcessHeap(), 0, lpwzDest);
1888 return ret;
1889 }
1890
1891 static void AsyncFtpRenameFileProc(WORKREQUEST *workRequest)
1892 {
1893 struct WORKREQ_FTPRENAMEFILEW const *req = &workRequest->u.FtpRenameFileW;
1894 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1895
1896 TRACE("%p\n", lpwfs);
1897
1898 FTP_FtpRenameFileW(lpwfs, req->lpszSrcFile, req->lpszDestFile);
1899 HeapFree(GetProcessHeap(), 0, req->lpszSrcFile);
1900 HeapFree(GetProcessHeap(), 0, req->lpszDestFile);
1901 }
1902
1903 /***********************************************************************
1904 * FtpRenameFileW (WININET.@)
1905 *
1906 * Rename a file on the ftp server
1907 *
1908 * RETURNS
1909 * TRUE on success
1910 * FALSE on failure
1911 *
1912 */
1913 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
1914 {
1915 LPWININETFTPSESSIONW lpwfs;
1916 LPWININETAPPINFOW hIC = NULL;
1917 BOOL r = FALSE;
1918
1919 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1920 if (!lpwfs)
1921 {
1922 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1923 return FALSE;
1924 }
1925
1926 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1927 {
1928 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1929 goto lend;
1930 }
1931
1932 if (lpwfs->download_in_progress != NULL)
1933 {
1934 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1935 goto lend;
1936 }
1937
1938 if (!lpszSrc || !lpszDest)
1939 {
1940 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1941 goto lend;
1942 }
1943
1944 hIC = lpwfs->lpAppInfo;
1945 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1946 {
1947 WORKREQUEST workRequest;
1948 struct WORKREQ_FTPRENAMEFILEW *req;
1949
1950 workRequest.asyncproc = AsyncFtpRenameFileProc;
1951 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1952 req = &workRequest.u.FtpRenameFileW;
1953 req->lpszSrcFile = WININET_strdupW(lpszSrc);
1954 req->lpszDestFile = WININET_strdupW(lpszDest);
1955
1956 r = INTERNET_AsyncCall(&workRequest);
1957 }
1958 else
1959 {
1960 r = FTP_FtpRenameFileW(lpwfs, lpszSrc, lpszDest);
1961 }
1962
1963 lend:
1964 WININET_Release( &lpwfs->hdr );
1965
1966 return r;
1967 }
1968
1969 /***********************************************************************
1970 * FTP_FtpRenameFileW (Internal)
1971 *
1972 * Rename a file on the ftp server
1973 *
1974 * RETURNS
1975 * TRUE on success
1976 * FALSE on failure
1977 *
1978 */
1979 BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs,
1980 LPCWSTR lpszSrc, LPCWSTR lpszDest)
1981 {
1982 INT nResCode;
1983 BOOL bSuccess = FALSE;
1984 LPWININETAPPINFOW hIC = NULL;
1985
1986 TRACE("\n");
1987
1988 /* Clear any error information */
1989 INTERNET_SetLastError(0);
1990
1991 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1992 goto lend;
1993
1994 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1995 if (nResCode == 350)
1996 {
1997 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1998 goto lend;
1999
2000 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2001 }
2002
2003 if (nResCode == 250)
2004 bSuccess = TRUE;
2005 else
2006 FTP_SetResponseError(nResCode);
2007
2008 lend:
2009 hIC = lpwfs->lpAppInfo;
2010 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2011 {
2012 INTERNET_ASYNC_RESULT iar;
2013
2014 iar.dwResult = (DWORD)bSuccess;
2015 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
2016 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
2017 &iar, sizeof(INTERNET_ASYNC_RESULT));
2018 }
2019
2020 return bSuccess;
2021 }
2022
2023 /***********************************************************************
2024 * FtpCommandA (WININET.@)
2025 */
2026 BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
2027 LPCSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
2028 {
2029 BOOL r;
2030 WCHAR *cmdW;
2031
2032 TRACE("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
2033 debugstr_a(lpszCommand), dwContext, phFtpCommand);
2034
2035 if (fExpectResponse)
2036 {
2037 FIXME("data connection not supported\n");
2038 return FALSE;
2039 }
2040
2041 if (!lpszCommand || !lpszCommand[0])
2042 {
2043 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2044 return FALSE;
2045 }
2046
2047 if (!(cmdW = WININET_strdup_AtoW(lpszCommand)))
2048 {
2049 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2050 return FALSE;
2051 }
2052
2053 r = FtpCommandW(hConnect, fExpectResponse, dwFlags, cmdW, dwContext, phFtpCommand);
2054
2055 HeapFree(GetProcessHeap(), 0, cmdW);
2056 return r;
2057 }
2058
2059 /***********************************************************************
2060 * FtpCommandW (WININET.@)
2061 */
2062 BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
2063 LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
2064 {
2065 BOOL r = FALSE;
2066 LPWININETFTPSESSIONW lpwfs;
2067 LPSTR cmd = NULL;
2068 DWORD len, nBytesSent= 0;
2069 INT nResCode, nRC = 0;
2070
2071 TRACE("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
2072 debugstr_w(lpszCommand), dwContext, phFtpCommand);
2073
2074 if (!lpszCommand || !lpszCommand[0])
2075 {
2076 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2077 return FALSE;
2078 }
2079
2080 if (fExpectResponse)
2081 {
2082 FIXME("data connection not supported\n");
2083 return FALSE;
2084 }
2085
2086 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
2087 if (!lpwfs)
2088 {
2089 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2090 return FALSE;
2091 }
2092
2093 if (WH_HFTPSESSION != lpwfs->hdr.htype)
2094 {
2095 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2096 goto lend;
2097 }
2098
2099 if (lpwfs->download_in_progress != NULL)
2100 {
2101 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
2102 goto lend;
2103 }
2104
2105 len = WideCharToMultiByte(CP_ACP, 0, lpszCommand, -1, NULL, 0, NULL, NULL) + strlen(szCRLF);
2106 if ((cmd = HeapAlloc(GetProcessHeap(), 0, len )))
2107 WideCharToMultiByte(CP_ACP, 0, lpszCommand, -1, cmd, len, NULL, NULL);
2108 else
2109 {
2110 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2111 goto lend;
2112 }
2113
2114 strcat(cmd, szCRLF);
2115 len--;
2116
2117 TRACE("Sending (%s) len(%d)\n", cmd, len);
2118 while ((nBytesSent < len) && (nRC != -1))
2119 {
2120 nRC = send(lpwfs->sndSocket, cmd + nBytesSent, len - nBytesSent, 0);
2121 if (nRC != -1)
2122 {
2123 nBytesSent += nRC;
2124 TRACE("Sent %d bytes\n", nRC);
2125 }
2126 }
2127
2128 if (nBytesSent)
2129 {
2130 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2131 if (nResCode > 0 && nResCode < 400)
2132 r = TRUE;
2133 else
2134 FTP_SetResponseError(nResCode);
2135 }
2136
2137 lend:
2138 WININET_Release( &lpwfs->hdr );
2139 HeapFree(GetProcessHeap(), 0, cmd);
2140 return r;
2141 }
2142
2143
2144 /***********************************************************************
2145 * FTPSESSION_Destroy (internal)
2146 *
2147 * Deallocate session handle
2148 */
2149 static void FTPSESSION_Destroy(WININETHANDLEHEADER *hdr)
2150 {
2151 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2152
2153 TRACE("\n");
2154
2155 WININET_Release(&lpwfs->lpAppInfo->hdr);
2156
2157 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2158 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2159 HeapFree(GetProcessHeap(), 0, lpwfs);
2160 }
2161
2162 static void FTPSESSION_CloseConnection(WININETHANDLEHEADER *hdr)
2163 {
2164 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2165
2166 TRACE("\n");
2167
2168 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext,
2169 INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
2170
2171 if (lpwfs->download_in_progress != NULL)
2172 lpwfs->download_in_progress->session_deleted = TRUE;
2173
2174 if (lpwfs->sndSocket != -1)
2175 closesocket(lpwfs->sndSocket);
2176
2177 if (lpwfs->lstnSocket != -1)
2178 closesocket(lpwfs->lstnSocket);
2179
2180 if (lpwfs->pasvSocket != -1)
2181 closesocket(lpwfs->pasvSocket);
2182
2183 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext,
2184 INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
2185 }
2186
2187 static DWORD FTPSESSION_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
2188 {
2189 switch(option) {
2190 case INTERNET_OPTION_HANDLE_TYPE:
2191 TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
2192
2193 if (*size < sizeof(ULONG))
2194 return ERROR_INSUFFICIENT_BUFFER;
2195
2196 *size = sizeof(DWORD);
2197 *(DWORD*)buffer = INTERNET_HANDLE_TYPE_CONNECT_FTP;
2198 return ERROR_SUCCESS;
2199 }
2200
2201 return INET_QueryOption(option, buffer, size, unicode);
2202 }
2203
2204 static const HANDLEHEADERVtbl FTPSESSIONVtbl = {
2205 FTPSESSION_Destroy,
2206 FTPSESSION_CloseConnection,
2207 FTPSESSION_QueryOption,
2208 NULL,
2209 NULL,
2210 NULL,
2211 NULL,
2212 NULL,
2213 NULL
2214 };
2215
2216
2217 /***********************************************************************
2218 * FTP_Connect (internal)
2219 *
2220 * Connect to a ftp server
2221 *
2222 * RETURNS
2223 * HINTERNET a session handle on success
2224 * NULL on failure
2225 *
2226 * NOTES:
2227 *
2228 * Windows uses 'anonymous' as the username, when given a NULL username
2229 * and a NULL password. The password is first looked up in:
2230 *
2231 * HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\EmailName
2232 *
2233 * If this entry is not present it uses the current username as the password.
2234 *
2235 */
2236
2237 HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
2238 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
2239 LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext,
2240 DWORD dwInternalFlags)
2241 {
2242 static const WCHAR szKey[] = {'S','o','f','t','w','a','r','e','\\',
2243 'M','i','c','r','o','s','o','f','t','\\',
2244 'W','i','n','d','o','w','s','\\',
2245 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2246 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
2247 static const WCHAR szValue[] = {'E','m','a','i','l','N','a','m','e',0};
2248 static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'};
2249 static const WCHAR szEmpty[] = {'\0'};
2250 struct sockaddr_in socketAddr;
2251 INT nsocket = -1;
2252 UINT sock_namelen;
2253 BOOL bSuccess = FALSE;
2254 LPWININETFTPSESSIONW lpwfs = NULL;
2255 HINTERNET handle = NULL;
2256
2257 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
2258 hIC, debugstr_w(lpszServerName),
2259 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
2260
2261 assert( hIC->hdr.htype == WH_HINIT );
2262
2263 if ((!lpszUserName || !strlenW(lpszUserName)) && lpszPassword)
2264 {
2265 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2266 goto lerror;
2267 }
2268
2269 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
2270 if (NULL == lpwfs)
2271 {
2272 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2273 goto lerror;
2274 }
2275
2276 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
2277 nServerPort = INTERNET_DEFAULT_FTP_PORT;
2278
2279 lpwfs->hdr.htype = WH_HFTPSESSION;
2280 lpwfs->hdr.vtbl = &FTPSESSIONVtbl;
2281 lpwfs->hdr.dwFlags = dwFlags;
2282 lpwfs->hdr.dwContext = dwContext;
2283 lpwfs->hdr.dwInternalFlags = dwInternalFlags;
2284 lpwfs->hdr.refs = 1;
2285 lpwfs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
2286 lpwfs->download_in_progress = NULL;
2287 lpwfs->sndSocket = -1;
2288 lpwfs->lstnSocket = -1;
2289 lpwfs->pasvSocket = -1;
2290
2291 WININET_AddRef( &hIC->hdr );
2292 lpwfs->lpAppInfo = hIC;
2293 list_add_head( &hIC->hdr.children, &lpwfs->hdr.entry );
2294
2295 handle = WININET_AllocHandle( &lpwfs->hdr );
2296 if( !handle )
2297 {
2298 ERR("Failed to alloc handle\n");
2299 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2300 goto lerror;
2301 }
2302
2303 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
2304 if(strchrW(hIC->lpszProxy, ' '))
2305 FIXME("Several proxies not implemented.\n");
2306 if(hIC->lpszProxyBypass)
2307 FIXME("Proxy bypass is ignored.\n");
2308 }
2309 if (!lpszUserName || !strlenW(lpszUserName)) {
2310 HKEY key;
2311 WCHAR szPassword[MAX_PATH];
2312 DWORD len = sizeof(szPassword);
2313
2314 lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
2315
2316 RegOpenKeyW(HKEY_CURRENT_USER, szKey, &key);
2317 if (RegQueryValueExW(key, szValue, NULL, NULL, (LPBYTE)szPassword, &len)) {
2318 /* Nothing in the registry, get the username and use that as the password */
2319 if (!GetUserNameW(szPassword, &len)) {
2320 /* Should never get here, but use an empty password as failsafe */
2321 strcpyW(szPassword, szEmpty);
2322 }
2323 }
2324 RegCloseKey(key);
2325
2326 TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword));
2327 lpwfs->lpszPassword = WININET_strdupW(szPassword);
2328 }
2329 else {
2330 lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
2331
2332 if (lpszPassword)
2333 lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
2334 else
2335 lpwfs->lpszPassword = WININET_strdupW(szEmpty);
2336 }
2337
2338 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
2339 if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
2340 {
2341 INTERNET_ASYNC_RESULT iar;
2342
2343 iar.dwResult = (DWORD)handle;
2344 iar.dwError = ERROR_SUCCESS;
2345
2346 SendAsyncCallback(&hIC->hdr, dwContext,
2347 INTERNET_STATUS_HANDLE_CREATED, &iar,
2348 sizeof(INTERNET_ASYNC_RESULT));
2349 }
2350
2351 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
2352 (LPWSTR) lpszServerName, strlenW(lpszServerName));
2353
2354 if (!GetAddress(lpszServerName, nServerPort, &socketAddr))
2355 {
2356 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
2357 goto lerror;
2358 }
2359
2360 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
2361 (LPWSTR) lpszServerName, strlenW(lpszServerName));
2362
2363 nsocket = socket(AF_INET,SOCK_STREAM,0);
2364 if (nsocket == -1)
2365 {
2366 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
2367 goto lerror;
2368 }
2369
2370 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
2371 &socketAddr, sizeof(struct sockaddr_in));
2372
2373 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
2374 {
2375 ERR("Unable to connect (%s)\n", strerror(errno));
2376 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
2377 }
2378 else
2379 {
2380 TRACE("Connected to server\n");
2381 lpwfs->sndSocket = nsocket;
2382 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
2383 &socketAddr, sizeof(struct sockaddr_in));
2384
2385 sock_namelen = sizeof(lpwfs->socketAddress);
2386 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
2387
2388 if (FTP_ConnectToHost(lpwfs))
2389 {
2390 TRACE("Successfully logged into server\n");
2391 bSuccess = TRUE;
2392 }
2393 }
2394
2395 lerror:
2396 if (lpwfs) WININET_Release( &lpwfs->hdr );
2397
2398 if (!bSuccess && handle)
2399 {
2400 WININET_FreeHandle( handle );
2401 handle = NULL;
2402 }
2403
2404 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2405 {
2406 INTERNET_ASYNC_RESULT iar;
2407
2408 iar.dwResult = bSuccess ? (DWORD_PTR)lpwfs : 0;
2409 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
2410 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
2411 &iar, sizeof(INTERNET_ASYNC_RESULT));
2412 }
2413
2414 return handle;
2415 }
2416
2417
2418 /***********************************************************************
2419 * FTP_ConnectToHost (internal)
2420 *
2421 * Connect to a ftp server
2422 *
2423 * RETURNS
2424 * TRUE on success
2425 * NULL on failure
2426 *
2427 */
2428 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
2429 {
2430 INT nResCode;
2431 BOOL bSuccess = FALSE;
2432
2433 TRACE("\n");
2434 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2435
2436 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
2437 goto lend;
2438
2439 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2440 if (nResCode)
2441 {
2442 /* Login successful... */
2443 if (nResCode == 230)
2444 bSuccess = TRUE;
2445 /* User name okay, need password... */
2446 else if (nResCode == 331)
2447 bSuccess = FTP_SendPassword(lpwfs);
2448 /* Need account for login... */
2449 else if (nResCode == 332)
2450 bSuccess = FTP_SendAccount(lpwfs);
2451 else
2452 FTP_SetResponseError(nResCode);
2453 }
2454
2455 TRACE("Returning %d\n", bSuccess);
2456 lend:
2457 return bSuccess;
2458 }
2459
2460
2461 /***********************************************************************
2462 * FTP_SendCommandA (internal)
2463 *
2464 * Send command to server
2465 *
2466 * RETURNS
2467 * TRUE on success
2468 * NULL on failure
2469 *
2470 */
2471 static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
2472 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext)
2473 {
2474 DWORD len;
2475 CHAR *buf;
2476 DWORD nBytesSent = 0;
2477 int nRC = 0;
2478 DWORD dwParamLen;
2479
2480 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
2481
2482 if (lpfnStatusCB)
2483 {
2484 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
2485 }
2486
2487 dwParamLen = lpszParam?strlen(lpszParam)+1:0;
2488 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
2489 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
2490 {
2491 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2492 return FALSE;
2493 }
2494 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
2495 dwParamLen ? lpszParam : "", szCRLF);
2496
2497 TRACE("Sending (%s) len(%d)\n", buf, len);
2498 while((nBytesSent < len) && (nRC != -1))
2499 {
2500 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
2501 nBytesSent += nRC;
2502 }
2503
2504 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
2505
2506 if (lpfnStatusCB)
2507 {
2508 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_REQUEST_SENT,
2509 &nBytesSent, sizeof(DWORD));
2510 }
2511
2512 TRACE("Sent %d bytes\n", nBytesSent);
2513 return (nRC != -1);
2514 }
2515
2516 /***********************************************************************
2517 * FTP_SendCommand (internal)
2518 *
2519 * Send command to server
2520 *
2521 * RETURNS
2522 * TRUE on success
2523 * NULL on failure
2524 *
2525 */
2526 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
2527 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext)
2528 {
2529 BOOL ret;
2530 LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
2531 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
2532 HeapFree(GetProcessHeap(), 0, lpszParamA);
2533 return ret;
2534 }
2535
2536 /***********************************************************************
2537 * FTP_ReceiveResponse (internal)
2538 *
2539 * Receive response from server
2540 *
2541 * RETURNS
2542 * Reply code on success
2543 * 0 on failure
2544 *
2545 */
2546 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD_PTR dwContext)
2547 {
2548 LPSTR lpszResponse = INTERNET_GetResponseBuffer();
2549 DWORD nRecv;
2550 INT rc = 0;
2551 char firstprefix[5];
2552 BOOL multiline = FALSE;
2553
2554 TRACE("socket(%d)\n", lpwfs->sndSocket);
2555
2556 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2557
2558 while(1)
2559 {
2560 if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
2561 goto lerror;
2562
2563 if (nRecv >= 3)
2564 {
2565 if(!multiline)
2566 {
2567 if(lpszResponse[3] != '-')
2568 break;
2569 else
2570 { /* Start of multiline response. Loop until we get "nnn " */
2571 multiline = TRUE;
2572 memcpy(firstprefix, lpszResponse, 3);
2573 firstprefix[3] = ' ';
2574 firstprefix[4] = '\0';
2575 }
2576 }
2577 else
2578 {
2579 if(!memcmp(firstprefix, lpszResponse, 4))
2580 break;
2581 }
2582 }
2583 }
2584
2585 if (nRecv >= 3)
2586 {
2587 rc = atoi(lpszResponse);
2588
2589 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2590 &nRecv, sizeof(DWORD));
2591 }
2592
2593 lerror:
2594 TRACE("return %d\n", rc);
2595 return rc;
2596 }
2597
2598
2599 /***********************************************************************
2600 * FTP_SendPassword (internal)
2601 *
2602 * Send password to ftp server
2603 *
2604 * RETURNS
2605 * TRUE on success
2606 * NULL on failure
2607 *
2608 */
2609 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
2610 {
2611 INT nResCode;
2612 BOOL bSuccess = FALSE;
2613
2614 TRACE("\n");
2615 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
2616 goto lend;
2617
2618 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2619 if (nResCode)
2620 {
2621 TRACE("Received reply code %d\n", nResCode);
2622 /* Login successful... */
2623 if (nResCode == 230)
2624 bSuccess = TRUE;
2625 /* Command not implemented, superfluous at the server site... */
2626 /* Need account for login... */
2627 else if (nResCode == 332)
2628 bSuccess = FTP_SendAccount(lpwfs);
2629 else
2630 FTP_SetResponseError(nResCode);
2631 }
2632
2633 lend:
2634 TRACE("Returning %d\n", bSuccess);
2635 return bSuccess;
2636 }
2637
2638
2639 /***********************************************************************
2640 * FTP_SendAccount (internal)
2641 *
2642 *
2643 *
2644 * RETURNS
2645 * TRUE on success
2646 * FALSE on failure
2647 *
2648 */
2649 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
2650 {
2651 INT nResCode;
2652 BOOL bSuccess = FALSE;
2653
2654 TRACE("\n");
2655 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
2656 goto lend;
2657
2658 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2659 if (nResCode)
2660 bSuccess = TRUE;
2661 else
2662 FTP_SetResponseError(nResCode);
2663
2664 lend:
2665 return bSuccess;
2666 }
2667
2668
2669 /***********************************************************************
2670 * FTP_SendStore (internal)
2671 *
2672 * Send request to upload file to ftp server
2673 *
2674 * RETURNS
2675 * TRUE on success
2676 * FALSE on failure
2677 *
2678 */
2679 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2680 {
2681 INT nResCode;
2682 BOOL bSuccess = FALSE;
2683
2684 TRACE("\n");
2685 if (!FTP_InitListenSocket(lpwfs))
2686 goto lend;
2687
2688 if (!FTP_SendType(lpwfs, dwType))
2689 goto lend;
2690
2691 if (!FTP_SendPortOrPasv(lpwfs))
2692 goto lend;
2693
2694 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2695 goto lend;
2696 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2697 if (nResCode)
2698 {
2699 if (nResCode == 150 || nResCode == 125)
2700 bSuccess = TRUE;
2701 else
2702 FTP_SetResponseError(nResCode);
2703 }
2704
2705 lend:
2706 if (!bSuccess && lpwfs->lstnSocket != -1)
2707 {
2708 closesocket(lpwfs->lstnSocket);
2709 lpwfs->lstnSocket = -1;
2710 }
2711
2712 return bSuccess;
2713 }
2714
2715
2716 /***********************************************************************
2717 * FTP_InitListenSocket (internal)
2718 *
2719 * Create a socket to listen for server response
2720 *
2721 * RETURNS
2722 * TRUE on success
2723 * FALSE on failure
2724 *
2725 */
2726 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
2727 {
2728 BOOL bSuccess = FALSE;
2729 socklen_t namelen = sizeof(struct sockaddr_in);
2730
2731 TRACE("\n");
2732
2733 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2734 if (lpwfs->lstnSocket == -1)
2735 {
2736 TRACE("Unable to create listening socket\n");
2737 goto lend;
2738 }
2739
2740 /* We obtain our ip addr from the name of the command channel socket */
2741 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2742
2743 /* and get the system to assign us a port */
2744 lpwfs->lstnSocketAddress.sin_port = htons(0);
2745
2746 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
2747 {
2748 TRACE("Unable to bind socket\n");
2749 goto lend;
2750 }
2751
2752 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2753 {
2754 TRACE("listen failed\n");
2755 goto lend;
2756 }
2757
2758 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2759 bSuccess = TRUE;
2760
2761 lend:
2762 if (!bSuccess && lpwfs->lstnSocket != -1)
2763 {
2764 closesocket(lpwfs->lstnSocket);
2765 lpwfs->lstnSocket = -1;
2766 }
2767
2768 return bSuccess;
2769 }
2770
2771
2772 /***********************************************************************
2773 * FTP_SendType (internal)
2774 *
2775 * Tell server type of data being transferred
2776 *
2777 * RETURNS
2778 * TRUE on success
2779 * FALSE on failure
2780 *
2781 * W98SE doesn't cache the type that's currently set
2782 * (i.e. it sends it always),
2783 * so we probably don't want to do that either.
2784 */
2785 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
2786 {
2787 INT nResCode;
2788 WCHAR type[] = { 'I','\0' };
2789 BOOL bSuccess = FALSE;
2790
2791 TRACE("\n");
2792 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2793 type[0] = 'A';
2794
2795 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2796 goto lend;
2797
2798 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2799 if (nResCode)
2800 {
2801 if (nResCode == 2)
2802 bSuccess = TRUE;
2803 else
2804 FTP_SetResponseError(nResCode);
2805 }
2806
2807 lend:
2808 return bSuccess;
2809 }
2810
2811
2812 #if 0 /* FIXME: should probably be used for FtpGetFileSize */
2813 /***********************************************************************
2814 * FTP_GetFileSize (internal)
2815 *
2816 * Retrieves from the server the size of the given file
2817 *
2818 * RETURNS
2819 * TRUE on success
2820 * FALSE on failure
2821 *
2822 */
2823 static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
2824 {
2825 INT nResCode;
2826 BOOL bSuccess = FALSE;
2827
2828 TRACE("\n");
2829
2830 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2831 goto lend;
2832
2833 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2834 if (nResCode)
2835 {
2836 if (nResCode == 213) {
2837 /* Now parses the output to get the actual file size */
2838 int i;
2839 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2840
2841 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2842 if (lpszResponseBuffer[i] == '\0') return FALSE;
2843 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2844
2845 bSuccess = TRUE;
2846 } else {
2847 FTP_SetResponseError(nResCode);
2848 }
2849 }
2850
2851 lend:
2852 return bSuccess;
2853 }
2854 #endif
2855
2856
2857 /***********************************************************************
2858 * FTP_SendPort (internal)
2859 *
2860 * Tell server which port to use
2861 *
2862 * RETURNS
2863 * TRUE on success
2864 * FALSE on failure
2865 *
2866 */
2867 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
2868 {
2869 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2870 INT nResCode;
2871 WCHAR szIPAddress[64];
2872 BOOL bSuccess = FALSE;
2873 TRACE("\n");
2874
2875 sprintfW(szIPAddress, szIPFormat,
2876 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2877 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2878 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2879 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2880 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2881 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2882
2883 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2884 goto lend;
2885
2886 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2887 if (nResCode)
2888 {
2889 if (nResCode == 200)
2890 bSuccess = TRUE;
2891 else
2892 FTP_SetResponseError(nResCode);
2893 }
2894
2895 lend:
2896 return bSuccess;
2897 }
2898
2899
2900 /***********************************************************************
2901 * FTP_DoPassive (internal)
2902 *
2903 * Tell server that we want to do passive transfers
2904 * and connect data socket
2905 *
2906 * RETURNS
2907 * TRUE on success
2908 * FALSE on failure
2909 *
2910 */
2911 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
2912 {
2913 INT nResCode;
2914 BOOL bSuccess = FALSE;
2915
2916 TRACE("\n");
2917 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2918 goto lend;
2919
2920 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2921 if (nResCode)
2922 {
2923 if (nResCode == 227)
2924 {
2925 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2926 LPSTR p;
2927 int f[6];
2928 int i;
2929 char *pAddr, *pPort;
2930 INT nsocket = -1;
2931 struct sockaddr_in dataSocketAddress;
2932
2933 p = lpszResponseBuffer+4; /* skip status code */
2934 while (*p != '\0' && (*p < '' || *p > '9')) p++;
2935
2936 if (*p == '\0')
2937 {
2938 ERR("no address found in response, aborting\n");
2939 goto lend;
2940 }
2941
2942 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2943 &f[4], &f[5]) != 6)
2944 {
2945 ERR("unknown response address format '%s', aborting\n", p);
2946 goto lend;
2947 }
2948 for (i=0; i < 6; i++)
2949 f[i] = f[i] & 0xff;
2950
2951 dataSocketAddress = lpwfs->socketAddress;
2952 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2953 pPort = (char *)&(dataSocketAddress.sin_port);
2954 pAddr[0] = f[0];
2955 pAddr[1] = f[1];
2956 pAddr[2] = f[2];
2957 pAddr[3] = f[3];
2958 pPort[0] = f[4];
2959 pPort[1] = f[5];
2960
2961 nsocket = socket(AF_INET,SOCK_STREAM,0);
2962 if (nsocket == -1)
2963 goto lend;
2964
2965 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2966 {
2967 ERR("can't connect passive FTP data port.\n");
2968 closesocket(nsocket);
2969 goto lend;
2970 }
2971 lpwfs->pasvSocket = nsocket;
2972 bSuccess = TRUE;
2973 }
2974 else
2975 FTP_SetResponseError(nResCode);
2976 }
2977
2978 lend:
2979 return bSuccess;
2980 }
2981
2982
2983 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
2984 {
2985 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2986 {
2987 if (!FTP_DoPassive(lpwfs))
2988 return FALSE;
2989 }
2990 else
2991 {
2992 if (!FTP_SendPort(lpwfs))
2993 return FALSE;
2994 }
2995 return TRUE;
2996 }
2997
2998
2999 /***********************************************************************
3000 * FTP_GetDataSocket (internal)
3001 *
3002 * Either accepts an incoming data socket connection from the server
3003 * or just returns the already opened socket after a PASV command
3004 * in case of passive FTP.
3005 *
3006 *
3007 * RETURNS
3008 * TRUE on success
3009 * FALSE on failure
3010 *
3011 */
3012 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
3013 {
3014 struct sockaddr_in saddr;
3015 socklen_t addrlen = sizeof(struct sockaddr);
3016
3017 TRACE("\n");
3018 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
3019 {
3020 *nDataSocket = lpwfs->pasvSocket;
3021 }
3022 else
3023 {
3024 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
3025 closesocket(lpwfs->lstnSocket);
3026 lpwfs->lstnSocket = -1;
3027 }
3028 return *nDataSocket != -1;
3029 }
3030
3031
3032 /***********************************************************************
3033 * FTP_SendData (internal)
3034 *
3035 * Send data to the server
3036 *
3037 * RETURNS
3038 * TRUE on success
3039 * FALSE on failure
3040 *
3041 */
3042 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
3043 {
3044 BY_HANDLE_FILE_INFORMATION fi;
3045 DWORD nBytesRead = 0;
3046 DWORD nBytesSent = 0;
3047 DWORD nTotalSent = 0;
3048 DWORD nBytesToSend, nLen;
3049 int nRC = 1;
3050 time_t s_long_time, e_long_time;
3051 LONG nSeconds;
3052 CHAR *lpszBuffer;
3053
3054 TRACE("\n");
3055 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
3056
3057 /* Get the size of the file. */
3058 GetFileInformationByHandle(hFile, &fi);
3059 time(&s_long_time);
3060
3061 do
3062 {
3063 nBytesToSend = nBytesRead - nBytesSent;
3064
3065 if (nBytesToSend <= 0)
3066 {
3067 /* Read data from file. */
3068 nBytesSent = 0;
3069 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
3070 ERR("Failed reading from file\n");
3071
3072 if (nBytesRead > 0)
3073 nBytesToSend = nBytesRead;
3074 else
3075 break;
3076 }
3077
3078 nLen = DATA_PACKET_SIZE < nBytesToSend ?
3079 DATA_PACKET_SIZE : nBytesToSend;
3080 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
3081
3082 if (nRC != -1)
3083 {
3084 nBytesSent += nRC;
3085 nTotalSent += nRC;
3086 }
3087
3088 /* Do some computation to display the status. */
3089 time(&e_long_time);
3090 nSeconds = e_long_time - s_long_time;
3091 if( nSeconds / 60 > 0 )
3092 {
3093 TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n",
3094 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
3095 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
3096 }
3097 else
3098 {
3099 TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n",
3100 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
3101 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
3102 }
3103 } while (nRC != -1);
3104
3105 TRACE("file transfer complete!\n");
3106
3107 HeapFree(GetProcessHeap(), 0, lpszBuffer);
3108
3109 return nTotalSent;
3110 }
3111
3112
3113 /***********************************************************************
3114 * FTP_SendRetrieve (internal)
3115 *
3116 * Send request to retrieve a file
3117 *
3118 * RETURNS
3119 * Number of bytes to be received on success
3120 * 0 on failure
3121 *
3122 */
3123 static BOOL FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
3124 {
3125 INT nResCode;
3126 BOOL ret;
3127
3128 TRACE("\n");
3129 if (!(ret = FTP_InitListenSocket(lpwfs)))
3130 goto lend;
3131
3132 if (!(ret = FTP_SendType(lpwfs, dwType)))
3133 goto lend;
3134
3135 if (!(ret = FTP_SendPortOrPasv(lpwfs)))
3136 goto lend;
3137
3138 if (!(ret = FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0)))
3139 goto lend;
3140
3141 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
3142 if ((nResCode != 125) && (nResCode != 150)) {
3143 /* That means that we got an error getting the file. */
3144 FTP_SetResponseError(nResCode);
3145 ret = FALSE;
3146 }
3147
3148 lend:
3149 if (!ret && lpwfs->lstnSocket != -1)
3150 {
3151 closesocket(lpwfs->lstnSocket);
3152 lpwfs->lstnSocket = -1;
3153 }
3154
3155 return ret;
3156 }
3157
3158
3159 /***********************************************************************
3160 * FTP_RetrieveData (internal)
3161 *
3162 * Retrieve data from server
3163 *
3164 * RETURNS
3165 * TRUE on success
3166 * FALSE on failure
3167 *
3168 */
3169 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
3170 {
3171 DWORD nBytesWritten;
3172 INT nRC = 0;
3173 CHAR *lpszBuffer;
3174
3175 TRACE("\n");
3176
3177 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
3178 if (NULL == lpszBuffer)
3179 {
3180 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
3181 return FALSE;
3182 }
3183
3184 while (nRC != -1)
3185 {
3186 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
3187 if (nRC != -1)
3188 {
3189 /* other side closed socket. */
3190 if (nRC == 0)
3191 goto recv_end;
3192 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
3193 }
3194 }
3195
3196 TRACE("Data transfer complete\n");
3197
3198 recv_end:
3199 HeapFree(GetProcessHeap(), 0, lpszBuffer);
3200
3201 return (nRC != -1);
3202 }
3203
3204 /***********************************************************************
3205 * FTPFINDNEXT_Destroy (internal)
3206 *
3207 * Deallocate session handle
3208 */
3209 static void FTPFINDNEXT_Destroy(WININETHANDLEHEADER *hdr)
3210 {
3211 LPWININETFTPFINDNEXTW lpwfn = (LPWININETFTPFINDNEXTW) hdr;
3212 DWORD i;
3213
3214 TRACE("\n");
3215
3216 WININET_Release(&lpwfn->lpFtpSession->hdr);
3217
3218 for (i = 0; i < lpwfn->size; i++)
3219 {
3220 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
3221 }
3222
3223 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
3224 HeapFree(GetProcessHeap(), 0, lpwfn);
3225 }
3226
3227 static DWORD FTPFINDNEXT_FindNextFileProc(WININETFTPFINDNEXTW *find, LPVOID data)
3228 {
3229 WIN32_FIND_DATAW *find_data = data;
3230 DWORD res = ERROR_SUCCESS;
3231
3232 TRACE("index(%d) size(%d)\n", find->index, find->size);
3233
3234 ZeroMemory(find_data, sizeof(WIN32_FIND_DATAW));
3235
3236 if (find->index < find->size) {
3237 FTP_ConvertFileProp(&find->lpafp[find->index], find_data);
3238 find->index++;
3239
3240 TRACE("Name: %s\nSize: %d\n", debugstr_w(find_data->cFileName), find_data->nFileSizeLow);
3241 }else {
3242 res = ERROR_NO_MORE_FILES;
3243 }
3244
3245 if (find->hdr.dwFlags & INTERNET_FLAG_ASYNC)
3246 {
3247 INTERNET_ASYNC_RESULT iar;
3248
3249 iar.dwResult = (res == ERROR_SUCCESS);
3250 iar.dwError = res;
3251
3252 INTERNET_SendCallback(&find->hdr, find->hdr.dwContext,
3253 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
3254 sizeof(INTERNET_ASYNC_RESULT));
3255 }
3256
3257 return res;
3258 }
3259
3260 static void FTPFINDNEXT_AsyncFindNextFileProc(WORKREQUEST *workRequest)
3261 {
3262 struct WORKREQ_FTPFINDNEXTW *req = &workRequest->u.FtpFindNextW;
3263
3264 FTPFINDNEXT_FindNextFileProc((WININETFTPFINDNEXTW*)workRequest->hdr, req->lpFindFileData);
3265 }
3266
3267 static DWORD FTPFINDNEXT_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
3268 {
3269 switch(option) {
3270 case INTERNET_OPTION_HANDLE_TYPE:
3271 TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
3272
3273 if (*size < sizeof(ULONG))
3274 return ERROR_INSUFFICIENT_BUFFER;
3275
3276 *size = sizeof(DWORD);
3277 *(DWORD*)buffer = INTERNET_HANDLE_TYPE_FTP_FIND;
3278 return ERROR_SUCCESS;
3279 }
3280
3281 return INET_QueryOption(option, buffer, size, unicode);
3282 }
3283
3284 static DWORD FTPFINDNEXT_FindNextFileW(WININETHANDLEHEADER *hdr, void *data)
3285 {
3286 WININETFTPFINDNEXTW *find = (WININETFTPFINDNEXTW*)hdr;
3287
3288 if (find->lpFtpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
3289 {
3290 WORKREQUEST workRequest;
3291 struct WORKREQ_FTPFINDNEXTW *req;
3292
3293 workRequest.asyncproc = FTPFINDNEXT_AsyncFindNextFileProc;
3294 workRequest.hdr = WININET_AddRef( &find->hdr );
3295 req = &workRequest.u.FtpFindNextW;
3296 req->lpFindFileData = data;
3297
3298 INTERNET_AsyncCall(&workRequest);
3299
3300 return ERROR_SUCCESS;
3301 }
3302
3303 return FTPFINDNEXT_FindNextFileProc(find, data);
3304 }
3305
3306 static const HANDLEHEADERVtbl FTPFINDNEXTVtbl = {
3307 FTPFINDNEXT_Destroy,
3308 NULL,
3309 FTPFINDNEXT_QueryOption,
3310 NULL,
3311 NULL,
3312 NULL,
3313 NULL,
3314 NULL,
3315 FTPFINDNEXT_FindNextFileW
3316 };
3317
3318 /***********************************************************************
3319 * FTP_ReceiveFileList (internal)
3320 *
3321 * Read file list from server
3322 *
3323 * RETURNS
3324 * Handle to file list on success
3325 * NULL on failure
3326 *
3327 */
3328 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3329 LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext)
3330 {
3331 DWORD dwSize = 0;
3332 LPFILEPROPERTIESW lpafp = NULL;
3333 LPWININETFTPFINDNEXTW lpwfn = NULL;
3334 HINTERNET handle = 0;
3335
3336 TRACE("(%p,%d,%s,%p,%08lx)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
3337
3338 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
3339 {
3340 if(lpFindFileData)
3341 FTP_ConvertFileProp(lpafp, lpFindFileData);
3342
3343 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFTPFINDNEXTW));
3344 if (lpwfn)
3345 {
3346 lpwfn->hdr.htype = WH_HFTPFINDNEXT;
3347 lpwfn->hdr.vtbl = &FTPFINDNEXTVtbl;
3348 lpwfn->hdr.dwContext = dwContext;
3349 lpwfn->hdr.refs = 1;
3350 lpwfn->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
3351 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
3352 lpwfn->size = dwSize;
3353 lpwfn->lpafp = lpafp;
3354
3355 WININET_AddRef( &lpwfs->hdr );
3356 lpwfn->lpFtpSession = lpwfs;
3357 list_add_head( &lpwfs->hdr.children, &lpwfn->hdr.entry );
3358
3359 handle = WININET_AllocHandle( &lpwfn->hdr );
3360 }
3361 }
3362
3363 if( lpwfn )
3364 WININET_Release( &lpwfn->hdr );
3365
3366 TRACE("Matched %d files\n", dwSize);
3367 return handle;
3368 }
3369
3370
3371 /***********************************************************************
3372 * FTP_ConvertFileProp (internal)
3373 *
3374 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
3375 *
3376 * RETURNS
3377 * TRUE on success
3378 * FALSE on failure
3379 *
3380 */
3381 static BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
3382 {
3383 BOOL bSuccess = FALSE;
3384
3385 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
3386
3387 if (lpafp)
3388 {
3389 /* Convert 'Unix' time to Windows time */
3390 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
3391 (LARGE_INTEGER *) &(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.tm_sec = 0;
3460 lpfp->tmLastModified.tm_min = 0;
3461 lpfp->tmLastModified.tm_hour = 0;
3462 lpfp->tmLastModified.tm_mday = 0;
3463 lpfp->tmLastModified.tm_mon = 0;
3464 lpfp->tmLastModified.tm_year = 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.tm_mon = ((pszTmp - szMonths) / 3)+1;
3473 }
3474 /* Determine day */
3475 pszToken = strtok(NULL, szSpace);
3476 if(!pszToken) continue;
3477 lpfp->tmLastModified.tm_mday = atoi(pszToken);
3478 /* Determine time or year */
3479 pszToken = strtok(NULL, szSpace);
3480 if(!pszToken) continue;
3481 if((pszTmp = strchr(pszToken, ':'))) {
3482 struct tm* apTM;
3483 time_t aTime;
3484 *pszTmp = 0;
3485 pszTmp++;
3486 lpfp->tmLastModified.tm_min = atoi(pszTmp);
3487 lpfp->tmLastModified.tm_hour = atoi(pszToken);
3488 time(&aTime);
3489 apTM = localtime(&aTime);
3490 lpfp->tmLastModified.tm_year = apTM->tm_year;
3491 }
3492 else {
3493 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
3494 lpfp->tmLastModified.tm_hour = 12;
3495 }
3496 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3497 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3498 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3499 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3500
3501 pszToken = strtok(NULL, szSpace);
3502 if(!pszToken) continue;
3503 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3504 TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
3505 }
3506 /* NT way of parsing ... :
3507
3508 07-13-03 08:55PM <DIR> sakpatch
3509 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
3510 */
3511 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
3512 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
3513
3514 sscanf(pszToken, "%d-%d-%d",
3515 &lpfp->tmLastModified.tm_mon,
3516 &lpfp->tmLastModified.tm_mday,
3517 &lpfp->tmLastModified.tm_year);
3518
3519 /* Hacky and bad Y2K protection :-) */
3520 if (lpfp->tmLastModified.tm_year < 70)
3521 lpfp->tmLastModified.tm_year += 100;
3522
3523 pszToken = strtok(NULL, szSpace);
3524 if(!pszToken) continue;
3525 sscanf(pszToken, "%d:%d",
3526 &lpfp->tmLastModified.tm_hour,
3527 &lpfp->tmLastModified.tm_min);
3528 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
3529 lpfp->tmLastModified.tm_hour += 12;
3530 }
3531 lpfp->tmLastModified.tm_sec = 0;
3532
3533 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3534 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3535 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3536 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3537
3538 pszToken = strtok(NULL, szSpace);
3539 if(!pszToken) continue;
3540 if(!strcasecmp(pszToken, "<DIR>")) {
3541 lpfp->bIsDirectory = TRUE;
3542 lpfp->nSize = 0;
3543 TRACE("Is directory\n");
3544 }
3545 else {
3546 lpfp->bIsDirectory = FALSE;
3547 lpfp->nSize = atol(pszToken);
3548 TRACE("Size: %d\n", lpfp->nSize);
3549 }
3550
3551 pszToken = strtok(NULL, szSpace);
3552 if(!pszToken) continue;
3553 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3554 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
3555 }
3556 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
3557 else if(pszToken[0] == '+') {
3558 FIXME("EPLF Format not implemented\n");
3559 }
3560
3561 if(lpfp->lpszName) {
3562 if((lpszSearchFile == NULL) ||
3563 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
3564 found = TRUE;
3565 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
3566 }
3567 else {
3568 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
3569 lpfp->lpszName = NULL;
3570 }
3571 }
3572 } while(!found);
3573 return TRUE;
3574 }
3575
3576 /***********************************************************************
3577 * FTP_ParseDirectory (internal)
3578 *
3579 * Parse string of directory information
3580 *
3581 * RETURNS
3582 * TRUE on success
3583 * FALSE on failure
3584 */
3585 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3586 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
3587 {
3588 BOOL bSuccess = TRUE;
3589 INT sizeFilePropArray = 500;/*20; */
3590 INT indexFilePropArray = -1;
3591
3592 TRACE("\n");
3593
3594 /* Allocate initial file properties array */
3595 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
3596 if (!*lpafp)
3597 return FALSE;
3598
3599 do {
3600 if (indexFilePropArray+1 >= sizeFilePropArray)
3601 {
3602 LPFILEPROPERTIESW tmpafp;
3603
3604 sizeFilePropArray *= 2;
3605 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
3606 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
3607 if (NULL == tmpafp)
3608 {
3609 bSuccess = FALSE;
3610 break;
3611 }
3612
3613 *lpafp = tmpafp;
3614 }
3615 indexFilePropArray++;
3616 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
3617
3618 if (bSuccess && indexFilePropArray)
3619 {
3620 if (indexFilePropArray < sizeFilePropArray - 1)
3621 {
3622 LPFILEPROPERTIESW tmpafp;
3623
3624 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
3625 sizeof(FILEPROPERTIESW)*indexFilePropArray);
3626 if (NULL != tmpafp)
3627 *lpafp = tmpafp;
3628 }
3629 *dwfp = indexFilePropArray;
3630 }
3631 else
3632 {
3633 HeapFree(GetProcessHeap(), 0, *lpafp);
3634 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3635 bSuccess = FALSE;
3636 }
3637
3638 return bSuccess;
3639 }
3640
3641
3642 /***********************************************************************
3643 * FTP_ParsePermission (internal)
3644 *
3645 * Parse permission string of directory information
3646 *
3647 * RETURNS
3648 * TRUE on success
3649 * FALSE on failure
3650 *
3651 */
3652 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3653 {
3654 BOOL bSuccess = TRUE;
3655 unsigned short nPermission = 0;
3656 INT nPos = 1;
3657 INT nLast = 9;
3658
3659 TRACE("\n");
3660 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3661 {
3662 bSuccess = FALSE;
3663 return bSuccess;
3664 }
3665
3666 lpfp->bIsDirectory = (*lpszPermission == 'd');
3667 do
3668 {
3669 switch (nPos)
3670 {
3671 case 1:
3672 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3673 break;
3674 case 2:
3675 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3676 break;
3677 case 3:
3678 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3679 break;
3680 case 4:
3681 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3682 break;
3683 case 5:
3684 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3685 break;
3686 case 6:
3687 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3688 break;
3689 case 7:
3690 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3691 break;
3692 case 8:
3693 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3694 break;
3695 case 9:
3696 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3697 break;
3698 }
3699 nPos++;
3700 }while (nPos <= nLast);
3701
3702 lpfp->permissions = nPermission;
3703 return bSuccess;
3704 }
3705
3706
3707 /***********************************************************************
3708 * FTP_SetResponseError (internal)
3709 *
3710 * Set the appropriate error code for a given response from the server
3711 *
3712 * RETURNS
3713 *
3714 */
3715 static DWORD FTP_SetResponseError(DWORD dwResponse)
3716 {
3717 DWORD dwCode = 0;
3718
3719 switch(dwResponse)
3720 {
3721 case 425: /* Cannot open data connection. */
3722 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3723 break;
3724
3725 case 426: /* Connection closed, transer aborted. */
3726 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3727 break;
3728
3729 case 530: /* Not logged in. Login incorrect. */
3730 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3731 break;
3732
3733 case 421: /* Service not available - Server may be shutting down. */
3734 case 450: /* File action not taken. File may be busy. */
3735 case 451: /* Action aborted. Server error. */
3736 case 452: /* Action not taken. Insufficient storage space on server. */
3737 case 500: /* Syntax error. Command unrecognized. */
3738 case 501: /* Syntax error. Error in parameters or arguments. */
3739 case 502: /* Command not implemented. */
3740 case 503: /* Bad sequence of commands. */
3741 case 504: /* Command not implemented for that parameter. */
3742 case 532: /* Need account for storing files */
3743 case 550: /* File action not taken. File not found or no access. */
3744 case 551: /* Requested action aborted. Page type unknown */
3745 case 552: /* Action aborted. Exceeded storage allocation */
3746 case 553: /* Action not taken. File name not allowed. */
3747
3748 default:
3749 dwCode = ERROR_INTERNET_EXTENDED_ERROR;
3750 break;
3751 }
3752
3753 INTERNET_SetLastError(dwCode);
3754 return dwCode;
3755 }
3756
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.