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