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