1 /*
2  * Wininet - ftp tests
3  *
4  * Copyright 2007 Paul Vriens
5  * Copyright 2007 Hans Leidekker
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 /*
23  * FIXME:
24  *     Use InternetGetLastResponseInfo when the last error is set to ERROR_INTERNET_EXTENDED_ERROR.
25  * TODO:
26  *     Add W-function tests.
27  *     Add missing function tests:
28  *         FtpGetFileSize
29  *         FtpSetCurrentDirectory
30  */
31 
32 #include <stdarg.h>
33 //#include <stdio.h>
34 //#include <stdlib.h>
35 
36 #define WIN32_NO_STATUS
37 #define _INC_WINDOWS
38 
39 #include <windef.h>
40 #include <winbase.h>
41 #include <wininet.h>
42 //#include "winsock.h"
43 
44 #include <wine/test.h>
45 
46 
47 static BOOL (WINAPI *pFtpCommandA)(HINTERNET,BOOL,DWORD,LPCSTR,DWORD_PTR,HINTERNET*);
48 static INTERNET_STATUS_CALLBACK (WINAPI *pInternetSetStatusCallbackA)(HINTERNET,INTERNET_STATUS_CALLBACK);
49 
50 
51 static void test_getfile_no_open(void)
52 {
53     BOOL      bRet;
54 
55     /* Invalid internet handle, the others are valid parameters */
56     SetLastError(0xdeadbeef);
57     bRet = FtpGetFileA(NULL, "welcome.msg", "should_be_non_existing_deadbeef", FALSE, FILE_ATTRIBUTE_NORMAL, FTP_TRANSFER_TYPE_UNKNOWN, 0);
58     ok ( bRet == FALSE, "Expected FtpGetFileA to fail\n");
59     ok ( GetLastError() == ERROR_INTERNET_NOT_INITIALIZED ||
60          GetLastError() == ERROR_INVALID_HANDLE,
61         "Expected ERROR_INTERNET_NOT_INITIALIZED or ERROR_INVALID_HANDLE (win98), got %d\n", GetLastError());
62 }
63 
64 static void test_connect(HINTERNET hInternet)
65 {
66     HINTERNET hFtp;
67 
68     /* Try a few username/password combinations:
69      * anonymous : NULL
70      * NULL      : IEUser@
71      * NULL      : NULL
72      * ""        : IEUser@
73      * ""        : NULL
74      */
75 
76     SetLastError(0xdeadbeef);
77     hFtp = InternetConnectA(hInternet, "ftp.winehq.org", INTERNET_DEFAULT_FTP_PORT, "anonymous", NULL, INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0);
78     if (hFtp)  /* some servers accept an empty password */
79     {
80         ok ( GetLastError() == ERROR_SUCCESS, "ERROR_SUCCESS, got %d\n", GetLastError());
81         InternetCloseHandle(hFtp);
82     }
83     else
84         ok ( GetLastError() == ERROR_INTERNET_LOGIN_FAILURE,
85              "Expected ERROR_INTERNET_LOGIN_FAILURE, got %d\n", GetLastError());
86 
87     SetLastError(0xdeadbeef);
88     hFtp = InternetConnectA(hInternet, "ftp.winehq.org", INTERNET_DEFAULT_FTP_PORT, NULL, "IEUser@", INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0);
89     ok ( hFtp == NULL, "Expected InternetConnect to fail\n");
90     ok ( GetLastError() == ERROR_INVALID_PARAMETER,
91         "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
92 
93     SetLastError(0xdeadbeef);
94     hFtp = InternetConnectA(hInternet, "ftp.winehq.org", INTERNET_DEFAULT_FTP_PORT, "", "IEUser@",
95             INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0);
96     ok(!hFtp, "Expected InternetConnect to fail\n");
97     ok(GetLastError() == ERROR_INVALID_PARAMETER,
98         "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
99 
100     /* Using a NULL username and password will be interpreted as anonymous ftp. The username will be 'anonymous' the password
101      * is created via some simple heuristics (see dlls/wininet/ftp.c).
102      * On Wine this registry key is not set by default so (NULL, NULL) will result in anonymous ftp with an (most likely) not
103      * accepted password (the username).
104      * If the first call fails because we get an ERROR_INTERNET_LOGIN_FAILURE, we try again with a (more) correct password.
105      */
106 
107     SetLastError(0xdeadbeef);
108     hFtp = InternetConnectA(hInternet, "ftp.winehq.org", INTERNET_DEFAULT_FTP_PORT, NULL, NULL, INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0);
109     if (!hFtp && (GetLastError() == ERROR_INTERNET_LOGIN_FAILURE))
110     {
111         /* We are most likely running on a clean Wine install or a Windows install where the registry key is removed */
112         SetLastError(0xdeadbeef);
113         hFtp = InternetConnectA(hInternet, "ftp.winehq.org", INTERNET_DEFAULT_FTP_PORT, "anonymous", "IEUser@", INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0);
114     }
115     ok ( hFtp != NULL, "InternetConnect failed : %d\n", GetLastError());
116     ok ( GetLastError() == ERROR_SUCCESS,
117         "ERROR_SUCCESS, got %d\n", GetLastError());
118     InternetCloseHandle(hFtp);
119 
120     SetLastError(0xdeadbeef);
121     hFtp = InternetConnectA(hInternet, "ftp.winehq.org", INTERNET_DEFAULT_FTP_PORT, "", NULL,
122             INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0);
123     if (!hFtp)
124     {
125         ok(GetLastError() == ERROR_INTERNET_LOGIN_FAILURE,
126                 "Expected ERROR_INTERNET_LOGIN_FAILURE, got %d\n", GetLastError());
127     }
128     else
129     {
130         ok(GetLastError() == ERROR_SUCCESS,
131                 "Expected ERROR_SUCCESS, got %d\n", GetLastError());
132         InternetCloseHandle(hFtp);
133     }
134 }
135 
136 static void test_createdir(HINTERNET hFtp, HINTERNET hConnect)
137 {
138     BOOL      bRet;
139 
140     /* Invalid internet handle, the other is a valid parameter */
141     SetLastError(0xdeadbeef);
142     bRet = FtpCreateDirectoryA(NULL, "new_directory_deadbeef");
143     ok ( bRet == FALSE, "Expected FtpCreateDirectoryA to fail\n");
144     ok ( GetLastError() == ERROR_INVALID_HANDLE,
145         "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
146 
147     /* No directory-name */
148     SetLastError(0xdeadbeef);
149     bRet = FtpCreateDirectoryA(hFtp, NULL);
150     ok ( bRet == FALSE, "Expected FtpCreateDirectoryA to fail\n");
151     ok ( GetLastError() == ERROR_INVALID_PARAMETER,
152         "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
153 
154     /* Parameters are OK, but we shouldn't be allowed to create the directory */
155     SetLastError(0xdeadbeef);
156     bRet = FtpCreateDirectoryA(hFtp, "new_directory_deadbeef");
157     ok ( bRet == FALSE, "Expected FtpCreateDirectoryA to fail\n");
158     ok ( GetLastError() == ERROR_INTERNET_EXTENDED_ERROR,
159         "Expected ERROR_INTERNET_EXTENDED_ERROR, got %d\n", GetLastError());
160 
161     /* One small test to show that handle type is checked before parameters */
162     SetLastError(0xdeadbeef);
163     bRet = FtpCreateDirectoryA(hConnect, NULL);
164     ok ( bRet == FALSE, "Expected FtpCreateDirectoryA to fail\n");
165     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
166         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got %d\n", GetLastError());
167 
168     SetLastError(0xdeadbeef);
169     bRet = FtpCreateDirectoryA(hConnect, "new_directory_deadbeef");
170     ok ( bRet == FALSE, "Expected FtpCreateDirectoryA to fail\n");
171     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
172         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got %d\n", GetLastError());
173 }
174 
175 static void test_deletefile(HINTERNET hFtp, HINTERNET hConnect)
176 {
177     BOOL      bRet;
178 
179     /* Invalid internet handle, the other is a valid parameter */
180     SetLastError(0xdeadbeef);
181     bRet = FtpDeleteFileA(NULL, "non_existent_file_deadbeef");
182     ok ( bRet == FALSE, "Expected FtpDeleteFileA to fail\n");
183     ok ( GetLastError() == ERROR_INVALID_HANDLE,
184         "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
185 
186     /* No filename */
187     SetLastError(0xdeadbeef);
188     bRet = FtpDeleteFileA(hFtp, NULL);
189     ok ( bRet == FALSE, "Expected FtpDeleteFileA to fail\n");
190     ok ( GetLastError() == ERROR_INVALID_PARAMETER,
191         "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
192 
193     /* Parameters are OK but remote file should not be there */
194     SetLastError(0xdeadbeef);
195     bRet = FtpDeleteFileA(hFtp, "non_existent_file_deadbeef");
196     ok ( bRet == FALSE, "Expected FtpDeleteFileA to fail\n");
197     ok ( GetLastError() == ERROR_INTERNET_EXTENDED_ERROR,
198         "Expected ERROR_INTERNET_EXTENDED_ERROR, got %d\n", GetLastError());
199 
200     /* One small test to show that handle type is checked before parameters */
201     SetLastError(0xdeadbeef);
202     bRet = FtpDeleteFileA(hConnect, NULL);
203     ok ( bRet == FALSE, "Expected FtpDeleteFileA to fail\n");
204     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
205         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got %d\n", GetLastError());
206 
207     SetLastError(0xdeadbeef);
208     bRet = FtpDeleteFileA(hConnect, "non_existent_file_deadbeef");
209     ok ( bRet == FALSE, "Expected FtpCreateDirectoryA to fail\n");
210     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
211         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got %d\n", GetLastError());
212 }
213 
214 static void test_getfile(HINTERNET hFtp, HINTERNET hConnect)
215 {
216     BOOL      bRet;
217     HANDLE    hFile;
218 
219     /* The order of checking is:
220      *
221      *   All parameters except 'session handle' and 'condition flags'
222      *   Session handle
223      *   Session handle type
224      *   Condition flags
225      */
226 
227     /* Test to show the parameter checking order depends on the Windows version */
228     SetLastError(0xdeadbeef);
229     bRet = FtpGetFileA(NULL, NULL, "should_be_non_existing_deadbeef", FALSE, FILE_ATTRIBUTE_NORMAL, FTP_TRANSFER_TYPE_UNKNOWN, 0);
230     ok ( bRet == FALSE, "Expected FtpGetFileA to fail\n");
231     ok ( GetLastError() == ERROR_INVALID_HANDLE ||
232          GetLastError() == ERROR_INVALID_PARAMETER,
233         "Expected ERROR_INVALID_HANDLE (win98) or ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
234 
235     /* Test to show session handle is checked before 'condition flags' */
236     SetLastError(0xdeadbeef);
237     bRet = FtpGetFileA(NULL, "welcome.msg", "should_be_non_existing_deadbeef", FALSE, FILE_ATTRIBUTE_NORMAL, 5, 0);
238     ok ( bRet == FALSE, "Expected FtpGetFileA to fail\n");
239     ok ( GetLastError() == ERROR_INVALID_HANDLE,
240         "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
241 
242     /* Make sure we start clean */
243 
244     DeleteFileA("should_be_non_existing_deadbeef");
245     DeleteFileA("should_also_be_non_existing_deadbeef");
246 
247     /* No remote file */
248     SetLastError(0xdeadbeef);
249     bRet = FtpGetFileA(hFtp, NULL, "should_be_non_existing_deadbeef", FALSE, FILE_ATTRIBUTE_NORMAL, FTP_TRANSFER_TYPE_UNKNOWN, 0);
250     ok ( bRet == FALSE, "Expected FtpGetFileA to fail\n");
251     ok ( GetLastError() == ERROR_INVALID_PARAMETER,
252         "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
253     ok (GetFileAttributesA("should_be_non_existing_deadbeef") == INVALID_FILE_ATTRIBUTES,
254         "Local file should not have been created\n");
255     DeleteFileA("should_be_non_existing_deadbeef");
256 
257     /* No local file */
258     SetLastError(0xdeadbeef);
259     bRet = FtpGetFileA(hFtp, "welcome.msg", NULL, FALSE, FILE_ATTRIBUTE_NORMAL, FTP_TRANSFER_TYPE_UNKNOWN, 0);
260     ok ( bRet == FALSE, "Expected FtpGetFileA to fail\n");
261     ok ( GetLastError() == ERROR_INVALID_PARAMETER,
262         "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
263 
264     /* Zero attributes */
265     bRet = FtpGetFileA(hFtp, "welcome.msg", "should_be_existing_non_deadbeef", FALSE, 0, FTP_TRANSFER_TYPE_UNKNOWN, 0);
266     ok ( bRet == TRUE, "Expected FtpGetFileA to succeed\n");
267     ok (GetFileAttributesA("should_be_existing_non_deadbeef") != INVALID_FILE_ATTRIBUTES,
268         "Local file should have been created\n");
269     DeleteFileA("should_be_existing_non_deadbeef");
270 
271     /* Illegal condition flags */
272     SetLastError(0xdeadbeef);
273     bRet = FtpGetFileA(hFtp, "welcome.msg", "should_be_non_existing_deadbeef", FALSE, FILE_ATTRIBUTE_NORMAL, 0xffffffff, 0);
274     ok ( bRet == FALSE, "Expected FtpGetFileA to fail\n");
275     ok ( GetLastError() == ERROR_INTERNET_EXTENDED_ERROR || GetLastError() == ERROR_INVALID_PARAMETER,
276         "Expected ERROR_INTERNET_EXTENDED_ERROR or ERROR_INVALID_PARAMETER (win98), got %d\n", GetLastError());
277     ok (GetFileAttributesA("should_be_non_existing_deadbeef") == INVALID_FILE_ATTRIBUTES,
278         "Local file should not have been created\n");
279     DeleteFileA("should_be_non_existing_deadbeef");
280 
281     /* Remote file doesn't exist (and local doesn't exist as well) */
282     SetLastError(0xdeadbeef);
283     bRet = FtpGetFileA(hFtp, "should_be_non_existing_deadbeef", "should_also_be_non_existing_deadbeef", FALSE, FILE_ATTRIBUTE_NORMAL, FTP_TRANSFER_TYPE_UNKNOWN, 0);
284     ok ( bRet == FALSE, "Expected FtpGetFileA to fail\n");
285     ok ( GetLastError() == ERROR_INTERNET_EXTENDED_ERROR,
286         "Expected ERROR_INTERNET_EXTENDED_ERROR, got %d\n", GetLastError());
287     /* Currently Wine always creates the local file (even on failure) which is not correct, hence the test */
288     ok (GetFileAttributesA("should_also_be_non_existing_deadbeef") == INVALID_FILE_ATTRIBUTES,
289         "Local file should not have been created\n");
290 
291     DeleteFileA("should_also_be_non_existing_deadbeef");
292 
293     /* Same call as the previous but now the local file does exists. Windows just removes the file if the call fails
294      * even if the local existed before!
295      */
296 
297     /* Create a temporary local file */
298     SetLastError(0xdeadbeef);
299     hFile = CreateFileA("should_also_be_non_existing_deadbeef", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
300     ok ( hFile != NULL, "Error creating a local file : %d\n", GetLastError());
301     CloseHandle(hFile);
302     SetLastError(0xdeadbeef);
303     bRet = FtpGetFileA(hFtp, "should_be_non_existing_deadbeef", "should_also_be_non_existing_deadbeef", FALSE, FILE_ATTRIBUTE_NORMAL, FTP_TRANSFER_TYPE_UNKNOWN, 0);
304     ok ( bRet == FALSE, "Expected FtpGetFileA to fail\n");
305     ok ( GetLastError() == ERROR_INTERNET_EXTENDED_ERROR,
306         "Expected ERROR_INTERNET_EXTENDED_ERROR, got %d\n", GetLastError());
307     /* Currently Wine always creates the local file (even on failure) which is not correct, hence the test */
308     ok (GetFileAttributesA("should_also_be_non_existing_deadbeef") == INVALID_FILE_ATTRIBUTES,
309         "Local file should not have been created\n");
310 
311     DeleteFileA("should_also_be_non_existing_deadbeef");
312 
313     /* This one should succeed */
314     SetLastError(0xdeadbeef);
315     bRet = FtpGetFileA(hFtp, "welcome.msg", "should_be_existing_non_deadbeef", FALSE, FILE_ATTRIBUTE_NORMAL, FTP_TRANSFER_TYPE_UNKNOWN, 0);
316     ok ( bRet == TRUE, "Expected FtpGetFileA to fail\n");
317     ok ( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", GetLastError());
318 
319     if (GetFileAttributesA("should_be_existing_non_deadbeef") != INVALID_FILE_ATTRIBUTES)
320     {
321         /* Should succeed as fFailIfExists is set to FALSE (meaning don't fail if local file exists) */
322         SetLastError(0xdeadbeef);
323         bRet = FtpGetFileA(hFtp, "welcome.msg", "should_be_non_existing_deadbeef", FALSE, FILE_ATTRIBUTE_NORMAL, FTP_TRANSFER_TYPE_UNKNOWN, 0);
324         ok ( bRet == TRUE, "Expected FtpGetFileA to succeed\n");
325         ok ( GetLastError() == ERROR_SUCCESS,
326             "Expected ERROR_SUCCESS, got %d\n", GetLastError());
327 
328         /* Should fail as fFailIfExists is set to TRUE */
329         SetLastError(0xdeadbeef);
330         bRet = FtpGetFileA(hFtp, "welcome.msg", "should_be_non_existing_deadbeef", TRUE, FILE_ATTRIBUTE_NORMAL, FTP_TRANSFER_TYPE_UNKNOWN, 0);
331         ok ( bRet == FALSE, "Expected FtpGetFileA to fail\n");
332         ok ( GetLastError() == ERROR_FILE_EXISTS,
333             "Expected ERROR_FILE_EXISTS, got %d\n", GetLastError());
334 
335         /* Prove that the existence of the local file is checked first (or at least reported last) */
336         SetLastError(0xdeadbeef);
337         bRet = FtpGetFileA(hFtp, "should_be_non_existing_deadbeef", "should_be_non_existing_deadbeef", TRUE, FILE_ATTRIBUTE_NORMAL, FTP_TRANSFER_TYPE_UNKNOWN, 0);
338         ok ( bRet == FALSE, "Expected FtpGetFileA to fail\n");
339         ok ( GetLastError() == ERROR_FILE_EXISTS,
340             "Expected ERROR_FILE_EXISTS, got %d\n", GetLastError());
341 
342         DeleteFileA("should_be_existing_non_deadbeef");
343     }
344 
345     /* Test to show the parameter checking order depends on the Windows version */
346     SetLastError(0xdeadbeef);
347     bRet = FtpGetFileA(hConnect, NULL, "should_be_non_existing_deadbeef", FALSE, FILE_ATTRIBUTE_NORMAL, FTP_TRANSFER_TYPE_UNKNOWN, 0);
348     ok ( bRet == FALSE, "Expected FtpGetFileA to fail\n");
349     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE ||
350          GetLastError() == ERROR_INVALID_PARAMETER,
351         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE (win98) or ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
352 
353     /* Test to show that 'session handle type' is checked before 'condition flags' */
354     SetLastError(0xdeadbeef);
355     bRet = FtpGetFileA(hConnect, "welcome.msg", "should_be_non_existing_deadbeef", FALSE, FILE_ATTRIBUTE_NORMAL, 5, 0);
356     ok ( bRet == FALSE, "Expected FtpGetFileA to fail\n");
357     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
358         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got %d\n", GetLastError());
359 
360     SetLastError(0xdeadbeef);
361     bRet = FtpGetFileA(hConnect, "should_be_non_existing_deadbeef", "should_be_non_existing_deadbeef", TRUE, FILE_ATTRIBUTE_NORMAL, FTP_TRANSFER_TYPE_UNKNOWN, 0);
362     ok ( bRet == FALSE, "Expected FtpGetFileA to fail\n");
363     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
364         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got %d\n", GetLastError());
365 }
366 
367 static void trace_extended_error(DWORD error)
368 {
369     DWORD code, buflen = 0;
370 
371     if (error != ERROR_INTERNET_EXTENDED_ERROR) return;
372     if (!InternetGetLastResponseInfoA(&code, NULL, &buflen) && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
373     {
374         char *text = HeapAlloc(GetProcessHeap(), 0, ++buflen);
375         InternetGetLastResponseInfoA(&code, text, &buflen);
376         trace("%u %s\n", code, text);
377         HeapFree(GetProcessHeap(), 0, text);
378     }
379 }
380 
381 static void test_openfile(HINTERNET hFtp, HINTERNET hConnect)
382 {
383     HINTERNET hOpenFile;
384 
385     /* Invalid internet handle, the rest are valid parameters */
386     SetLastError(0xdeadbeef);
387     hOpenFile = FtpOpenFileA(NULL, "welcome.msg", GENERIC_READ, FTP_TRANSFER_TYPE_ASCII, 0);
388     ok ( !hOpenFile, "Expected FtpOpenFileA to fail\n");
389     ok ( GetLastError() == ERROR_INVALID_HANDLE,
390         "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
391     InternetCloseHandle(hOpenFile); /* Just in case */
392 
393     /* No filename */
394     SetLastError(0xdeadbeef);
395     hOpenFile = FtpOpenFileA(hFtp, NULL, GENERIC_READ, FTP_TRANSFER_TYPE_ASCII, 0);
396     ok ( !hOpenFile, "Expected FtpOpenFileA to fail\n");
397     ok ( GetLastError() == ERROR_INVALID_PARAMETER,
398         "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
399     InternetCloseHandle(hOpenFile); /* Just in case */
400 
401     /* Illegal access flags */
402     SetLastError(0xdeadbeef);
403     hOpenFile = FtpOpenFileA(hFtp, "welcome.msg", 0, FTP_TRANSFER_TYPE_ASCII, 0);
404     ok ( !hOpenFile, "Expected FtpOpenFileA to fail\n");
405     ok ( GetLastError() == ERROR_INVALID_PARAMETER,
406         "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
407     InternetCloseHandle(hOpenFile); /* Just in case */
408 
409     /* Illegal combination of access flags */
410     SetLastError(0xdeadbeef);
411     hOpenFile = FtpOpenFileA(hFtp, "welcome.msg", GENERIC_READ|GENERIC_WRITE, FTP_TRANSFER_TYPE_ASCII, 0);
412     ok ( !hOpenFile, "Expected FtpOpenFileA to fail\n");
413     ok ( GetLastError() == ERROR_INVALID_PARAMETER,
414         "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
415     InternetCloseHandle(hOpenFile); /* Just in case */
416 
417     /* Illegal condition flags */
418     SetLastError(0xdeadbeef);
419     hOpenFile = FtpOpenFileA(hFtp, "welcome.msg", GENERIC_READ, 0xffffffff, 0);
420     ok ( !hOpenFile, "Expected FtpOpenFileA to fail\n");
421     ok ( GetLastError() == ERROR_INTERNET_EXTENDED_ERROR || GetLastError() == ERROR_INVALID_PARAMETER,
422         "Expected ERROR_INTERNET_EXTENDED_ERROR or ERROR_INVALID_PARAMETER (win98), got %d\n", GetLastError());
423     InternetCloseHandle(hOpenFile); /* Just in case */
424 
425     SetLastError(0xdeadbeef);
426     hOpenFile = FtpOpenFileA(hFtp, "welcome.msg", GENERIC_READ, FTP_TRANSFER_TYPE_ASCII, 0);
427     ok ( hOpenFile != NULL, "Expected FtpOpenFileA to succeed\n");
428     ok ( GetLastError() == ERROR_SUCCESS ||
429         broken(GetLastError() == ERROR_FILE_NOT_FOUND), /* Win98 */
430         "Expected ERROR_SUCCESS, got %u\n", GetLastError());
431 
432     if (hOpenFile)
433     {
434         BOOL bRet;
435         DWORD error;
436         HINTERNET hOpenFile2;
437         HANDLE    hFile;
438 
439         /* We have a handle so all ftp calls should fail (TODO: Put all ftp-calls in here) */
440         SetLastError(0xdeadbeef);
441         bRet = FtpCreateDirectoryA(hFtp, "new_directory_deadbeef");
442         error = GetLastError();
443         ok ( bRet == FALSE, "Expected FtpCreateDirectoryA to fail\n");
444         ok ( error == ERROR_FTP_TRANSFER_IN_PROGRESS || broken(error == ERROR_INTERNET_EXTENDED_ERROR),
445             "Expected ERROR_FTP_TRANSFER_IN_PROGRESS, got %d\n", error);
446         trace_extended_error(error);
447 
448         SetLastError(0xdeadbeef);
449         bRet = FtpDeleteFileA(hFtp, "non_existent_file_deadbeef");
450         error = GetLastError();
451         ok ( bRet == FALSE, "Expected FtpDeleteFileA to fail\n");
452         ok ( error == ERROR_FTP_TRANSFER_IN_PROGRESS || broken(error == ERROR_INTERNET_EXTENDED_ERROR),
453             "Expected ERROR_FTP_TRANSFER_IN_PROGRESS, got %d\n", error);
454         trace_extended_error(error);
455 
456         SetLastError(0xdeadbeef);
457         bRet = FtpGetFileA(hFtp, "welcome.msg", "should_be_non_existing_deadbeef", FALSE, FILE_ATTRIBUTE_NORMAL, FTP_TRANSFER_TYPE_UNKNOWN, 0);
458         error = GetLastError();
459         ok ( bRet == FALSE || broken(bRet == TRUE), "Expected FtpGetFileA to fail\n");
460         ok ( error == ERROR_FTP_TRANSFER_IN_PROGRESS || broken(error == ERROR_SUCCESS),
461             "Expected ERROR_FTP_TRANSFER_IN_PROGRESS, got %d\n", error);
462         DeleteFileA("should_be_non_existing_deadbeef"); /* Just in case */
463 
464         SetLastError(0xdeadbeef);
465         hOpenFile2 = FtpOpenFileA(hFtp, "welcome.msg", GENERIC_READ, FTP_TRANSFER_TYPE_ASCII, 0);
466         error = GetLastError();
467         ok ( bRet == FALSE || broken(bRet == TRUE), "Expected FtpOpenFileA to fail\n");
468         ok ( error == ERROR_FTP_TRANSFER_IN_PROGRESS || broken(error == ERROR_SUCCESS),
469             "Expected ERROR_FTP_TRANSFER_IN_PROGRESS, got %d\n", error);
470         InternetCloseHandle(hOpenFile2); /* Just in case */
471 
472         /* Create a temporary local file */
473         SetLastError(0xdeadbeef);
474         hFile = CreateFileA("now_existing_local", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
475         ok ( hFile != NULL, "Error creating a local file : %d\n", GetLastError());
476         CloseHandle(hFile);
477         SetLastError(0xdeadbeef);
478         bRet = FtpPutFileA(hFtp, "now_existing_local", "non_existing_remote", FTP_TRANSFER_TYPE_UNKNOWN, 0);
479         error = GetLastError();
480         ok ( bRet == FALSE, "Expected FtpPutFileA to fail\n");
481         ok ( error == ERROR_FTP_TRANSFER_IN_PROGRESS || broken(error == ERROR_INTERNET_EXTENDED_ERROR),
482             "Expected ERROR_FTP_TRANSFER_IN_PROGRESS, got %d\n", error);
483         DeleteFileA("now_existing_local");
484 
485         SetLastError(0xdeadbeef);
486         bRet = FtpRemoveDirectoryA(hFtp, "should_be_non_existing_deadbeef_dir");
487         error = GetLastError();
488         ok ( bRet == FALSE, "Expected FtpRemoveDirectoryA to fail\n");
489         ok ( error == ERROR_FTP_TRANSFER_IN_PROGRESS || broken(error == ERROR_INTERNET_EXTENDED_ERROR),
490             "Expected ERROR_FTP_TRANSFER_IN_PROGRESS, got %d\n", error);
491 
492         SetLastError(0xdeadbeef);
493         bRet = FtpRenameFileA(hFtp , "should_be_non_existing_deadbeef", "new");
494         error = GetLastError();
495         ok ( bRet == FALSE, "Expected FtpRenameFileA to fail\n");
496         ok ( error == ERROR_FTP_TRANSFER_IN_PROGRESS || broken(error == ERROR_INTERNET_EXTENDED_ERROR),
497             "Expected ERROR_FTP_TRANSFER_IN_PROGRESS, got %d\n", error);
498     }
499 
500     InternetCloseHandle(hOpenFile);
501 
502     /* One small test to show that handle type is checked before parameters */
503     SetLastError(0xdeadbeef);
504     hOpenFile = FtpOpenFileA(hConnect, "welcome.msg", GENERIC_READ, 5, 0);
505     ok ( !hOpenFile, "Expected FtpOpenFileA to fail\n");
506     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
507         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got %d\n", GetLastError());
508     InternetCloseHandle(hOpenFile); /* Just in case */
509 
510     SetLastError(0xdeadbeef);
511     hOpenFile = FtpOpenFileA(hConnect, "welcome.msg", GENERIC_READ, FTP_TRANSFER_TYPE_ASCII, 0);
512     ok ( hOpenFile == NULL, "Expected FtpOpenFileA to fail\n");
513     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
514         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got %d\n", GetLastError());
515 
516     InternetCloseHandle(hOpenFile); /* Just in case */
517 }
518 
519 static void test_putfile(HINTERNET hFtp, HINTERNET hConnect)
520 {
521     BOOL      bRet;
522     HANDLE    hFile;
523 
524     /* The order of checking is:
525      *
526      *   All parameters except 'session handle' and 'condition flags'
527      *   Session handle
528      *   Session handle type
529      *   Condition flags
530      */
531 
532     /* Test to show the parameter checking order depends on the Windows version */
533     SetLastError(0xdeadbeef);
534     bRet = FtpPutFileA(NULL, NULL, "non_existing_remote", FTP_TRANSFER_TYPE_UNKNOWN, 0);
535     ok ( bRet == FALSE, "Expected FtpPutFileA to fail\n");
536     ok ( GetLastError() == ERROR_INVALID_HANDLE ||
537          GetLastError() == ERROR_INVALID_PARAMETER,
538         "Expected ERROR_INVALID_HANDLE (win98) or ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
539 
540     /* Test to show session handle is checked before 'condition flags' */
541     SetLastError(0xdeadbeef);
542     bRet = FtpPutFileA(NULL, "non_existing_local", "non_existing_remote", 5, 0);
543     ok ( bRet == FALSE, "Expected FtpPutFileA to fail\n");
544     ok ( GetLastError() == ERROR_INVALID_HANDLE,
545         "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
546 
547     /* Start clean */
548     DeleteFileA("non_existing_local");
549 
550     /* No local file given */
551     SetLastError(0xdeadbeef);
552     bRet = FtpPutFileA(hFtp, NULL, "non_existing_remote", FTP_TRANSFER_TYPE_UNKNOWN, 0);
553     ok ( bRet == FALSE, "Expected FtpPutFileA to fail\n");
554     ok ( GetLastError() == ERROR_INVALID_PARAMETER,
555         "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
556 
557     /* No remote file given */
558     SetLastError(0xdeadbeef);
559     bRet = FtpPutFileA(hFtp, "non_existing_local", NULL, FTP_TRANSFER_TYPE_UNKNOWN, 0);
560     ok ( bRet == FALSE, "Expected FtpPutFileA to fail\n");
561     ok ( GetLastError() == ERROR_INVALID_PARAMETER,
562         "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
563 
564     /* Illegal condition flags */
565     SetLastError(0xdeadbeef);
566     bRet = FtpPutFileA(hFtp, "non_existing_local", "non_existing_remote", 5, 0);
567     ok ( bRet == FALSE, "Expected FtpPutFileA to fail\n");
568     ok ( GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_INVALID_PARAMETER,
569         "Expected ERROR_FILE_NOT_FOUND or ERROR_INVALID_PARAMETER (win98), got %d\n", GetLastError());
570 
571     /* Parameters are OK but local file doesn't exist */
572     SetLastError(0xdeadbeef);
573     bRet = FtpPutFileA(hFtp, "non_existing_local", "non_existing_remote", FTP_TRANSFER_TYPE_UNKNOWN, 0);
574     ok ( bRet == FALSE, "Expected FtpPutFileA to fail\n");
575     ok ( GetLastError() == ERROR_FILE_NOT_FOUND,
576         "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
577 
578     /* Create a temporary local file */
579     SetLastError(0xdeadbeef);
580     hFile = CreateFileA("now_existing_local", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
581     ok ( hFile != NULL, "Error creating a local file : %d\n", GetLastError());
582     CloseHandle(hFile);
583 
584     /* Local file exists but we shouldn't be allowed to 'put' the file */
585     SetLastError(0xdeadbeef);
586     bRet = FtpPutFileA(hFtp, "now_existing_local", "non_existing_remote", FTP_TRANSFER_TYPE_UNKNOWN, 0);
587     ok ( bRet == FALSE, "Expected FtpPutFileA to fail\n");
588     ok ( GetLastError() == ERROR_INTERNET_EXTENDED_ERROR,
589         "Expected ERROR_INTERNET_EXTENDED_ERROR, got %d\n", GetLastError());
590 
591     DeleteFileA("now_existing_local");
592 
593     /* Test to show the parameter checking order depends on the Windows version */
594     SetLastError(0xdeadbeef);
595     bRet = FtpPutFileA(hConnect, NULL, "non_existing_remote", FTP_TRANSFER_TYPE_UNKNOWN, 0);
596     ok ( bRet == FALSE, "Expected FtpPutFileA to fail\n");
597     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE ||
598          GetLastError() == ERROR_INVALID_PARAMETER,
599         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE (win98) or ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
600 
601     /* Test to show that 'session handle type' is checked before 'condition flags' */
602     SetLastError(0xdeadbeef);
603     bRet = FtpPutFileA(hConnect, "non_existing_local", "non_existing_remote", 5, 0);
604     ok ( bRet == FALSE, "Expected FtpPutFileA to fail\n");
605     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
606         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got %d\n", GetLastError());
607 
608     SetLastError(0xdeadbeef);
609     bRet = FtpPutFileA(hConnect, "non_existing_local", "non_existing_remote", FTP_TRANSFER_TYPE_UNKNOWN, 0);
610     ok ( bRet == FALSE, "Expected FtpPutFileA to fail\n");
611     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
612         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got %d\n", GetLastError());
613 }
614 
615 static void test_removedir(HINTERNET hFtp, HINTERNET hConnect)
616 {
617     BOOL      bRet;
618 
619     /* Invalid internet handle, the other is a valid parameter */
620     SetLastError(0xdeadbeef);
621     bRet = FtpRemoveDirectoryA(NULL, "should_be_non_existing_deadbeef_dir");
622     ok ( bRet == FALSE, "Expected FtpRemoveDirectoryA to fail\n");
623     ok ( GetLastError() == ERROR_INVALID_HANDLE,
624         "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
625 
626     /* No remote directory given */
627     SetLastError(0xdeadbeef);
628     bRet = FtpRemoveDirectoryA(hFtp, NULL);
629     ok ( bRet == FALSE, "Expected FtpRemoveDirectoryA to fail\n");
630     ok ( GetLastError() == ERROR_INVALID_PARAMETER,
631         "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
632 
633     /* Remote directory doesn't exist */
634     SetLastError(0xdeadbeef);
635     bRet = FtpRemoveDirectoryA(hFtp, "should_be_non_existing_deadbeef_dir");
636     ok ( bRet == FALSE, "Expected FtpRemoveDirectoryA to fail\n");
637     ok ( GetLastError() == ERROR_INTERNET_EXTENDED_ERROR,
638         "Expected ERROR_INTERNET_EXTENDED_ERROR, got %d\n", GetLastError());
639 
640     /* We shouldn't be allowed to remove that directory */
641     SetLastError(0xdeadbeef);
642     bRet = FtpRemoveDirectoryA(hFtp, "pub");
643     ok ( bRet == FALSE, "Expected FtpRemoveDirectoryA to fail\n");
644     ok ( GetLastError() == ERROR_INTERNET_EXTENDED_ERROR,
645         "Expected ERROR_INTERNET_EXTENDED_ERROR, got %d\n", GetLastError());
646 
647     /* One small test to show that handle type is checked before parameters */
648     SetLastError(0xdeadbeef);
649     bRet = FtpRemoveDirectoryA(hConnect, NULL);
650     ok ( bRet == FALSE, "Expected FtpRemoveDirectoryA to fail\n");
651     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
652         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got %d\n", GetLastError());
653 
654     SetLastError(0xdeadbeef);
655     bRet = FtpRemoveDirectoryA(hConnect, "should_be_non_existing_deadbeef_dir");
656     ok ( bRet == FALSE, "Expected FtpRemoveDirectoryA to fail\n");
657     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
658         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got %d\n", GetLastError());
659 }
660 
661 static void test_renamefile(HINTERNET hFtp, HINTERNET hConnect)
662 {
663     BOOL      bRet;
664 
665     /* Invalid internet handle, the rest are valid parameters */
666     SetLastError(0xdeadbeef);
667     bRet = FtpRenameFileA(NULL , "should_be_non_existing_deadbeef", "new");
668     ok ( bRet == FALSE, "Expected FtpRenameFileA to fail\n");
669     ok ( GetLastError() == ERROR_INVALID_HANDLE,
670         "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
671 
672     /* No 'existing' file */
673     SetLastError(0xdeadbeef);
674     bRet = FtpRenameFileA(hFtp , NULL, "new");
675     ok ( bRet == FALSE, "Expected FtpRenameFileA to fail\n");
676     ok ( GetLastError() == ERROR_INVALID_PARAMETER,
677         "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
678 
679     /* No new file */
680     SetLastError(0xdeadbeef);
681     bRet = FtpRenameFileA(hFtp , "should_be_non_existing_deadbeef", NULL);
682     ok ( bRet == FALSE, "Expected FtpRenameFileA to fail\n");
683     ok ( GetLastError() == ERROR_INVALID_PARAMETER,
684         "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
685 
686     /* Existing file shouldn't be there */
687     SetLastError(0xdeadbeef);
688     bRet = FtpRenameFileA(hFtp , "should_be_non_existing_deadbeef", "new");
689     ok ( bRet == FALSE, "Expected FtpRenameFileA to fail\n");
690     ok ( GetLastError() == ERROR_INTERNET_EXTENDED_ERROR,
691         "Expected ERROR_INTERNET_EXTENDED_ERROR, got %d\n", GetLastError());
692 
693     /* One small test to show that handle type is checked before parameters */
694     SetLastError(0xdeadbeef);
695     bRet = FtpRenameFileA(hConnect , "should_be_non_existing_deadbeef", NULL);
696     ok ( bRet == FALSE, "Expected FtpRenameFileA to fail\n");
697     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
698         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got %d\n", GetLastError());
699 
700     SetLastError(0xdeadbeef);
701     bRet = FtpRenameFileA(hConnect , "should_be_non_existing_deadbeef", "new");
702     ok ( bRet == FALSE, "Expected FtpRenameFileA to fail\n");
703     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
704         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got %d\n", GetLastError());
705 }
706 
707 static void test_command(HINTERNET hFtp, HINTERNET hConnect)
708 {
709     BOOL ret;
710     DWORD error;
711     unsigned int i;
712     static const struct
713     {
714         BOOL  ret;
715         DWORD error;
716         const char *cmd;
717     }
718     command_test[] =
719     {
720         { FALSE, ERROR_INVALID_PARAMETER,       NULL },
721         { FALSE, ERROR_INVALID_PARAMETER,       "" },
722         { FALSE, ERROR_INTERNET_EXTENDED_ERROR, "HELO" },
723         { FALSE, ERROR_INTERNET_EXTENDED_ERROR, "SIZE " },
724         { FALSE, ERROR_INTERNET_EXTENDED_ERROR, " SIZE" },
725         { FALSE, ERROR_INTERNET_EXTENDED_ERROR, "SIZE " },
726         { FALSE, ERROR_INTERNET_EXTENDED_ERROR, "SIZE /welcome.msg /welcome.msg" },
727         { FALSE, ERROR_INTERNET_EXTENDED_ERROR, "SIZE  /welcome.msg" },
728         { FALSE, ERROR_INTERNET_EXTENDED_ERROR, "SIZE /welcome.msg " },
729         { TRUE,  ERROR_SUCCESS,                 "SIZE\t/welcome.msg" },
730         { TRUE,  ERROR_SUCCESS,                 "SIZE /welcome.msg" },
731         { FALSE, ERROR_INTERNET_EXTENDED_ERROR, "PWD /welcome.msg" },
732         { TRUE,  ERROR_SUCCESS,                 "PWD" }
733     };
734 
735     if (!pFtpCommandA)
736     {
737         win_skip("FtpCommandA() is not available. Skipping the Ftp command tests\n");
738         return;
739     }
740 
741     for (i = 0; i < sizeof(command_test) / sizeof(command_test[0]); i++)
742     {
743         SetLastError(0xdeadbeef);
744         ret = pFtpCommandA(hFtp, FALSE, FTP_TRANSFER_TYPE_ASCII, command_test[i].cmd, 0, NULL);
745         error = GetLastError();
746 
747         ok(ret == command_test[i].ret, "%d: expected FtpCommandA to %s\n", i, command_test[i].ret ? "succeed" : "fail");
748         ok(error == command_test[i].error, "%d: expected error %u, got %u\n", i, command_test[i].error, error);
749     }
750 }
751 
752 static void test_find_first_file(HINTERNET hFtp, HINTERNET hConnect)
753 {
754     WIN32_FIND_DATAA findData;
755     HINTERNET hSearch;
756     HINTERNET hSearch2;
757     HINTERNET hOpenFile;
758     DWORD error;
759     BOOL success;
760 
761     /* NULL as the search file ought to return the first file in the directory */
762     SetLastError(0xdeadbeef);
763     hSearch = FtpFindFirstFileA(hFtp, NULL, &findData, 0, 0);
764     ok ( hSearch != NULL, "Expected FtpFindFirstFileA to pass\n" );
765 
766     /* This should fail as the previous handle wasn't closed */
767     SetLastError(0xdeadbeef);
768     hSearch2 = FtpFindFirstFileA(hFtp, "welcome.msg", &findData, 0, 0);
769     todo_wine ok ( hSearch2 == NULL, "Expected FtpFindFirstFileA to fail\n" );
770     todo_wine ok ( GetLastError() == ERROR_FTP_TRANSFER_IN_PROGRESS,
771         "Expected ERROR_FTP_TRANSFER_IN_PROGRESS, got %d\n", GetLastError() );
772     InternetCloseHandle(hSearch2); /* Just in case */
773 
774     InternetCloseHandle(hSearch);
775 
776     /* Try a valid filename in a subdirectory search */
777     SetLastError(0xdeadbeef);
778     hSearch = FtpFindFirstFileA(hFtp, "pub/wine", &findData, 0, 0);
779     ok( hSearch != NULL, "Expected FtpFindFirstFileA to pass\n" );
780     InternetCloseHandle(hSearch);
781 
782     /* Try a valid filename in a subdirectory wildcard search */
783     SetLastError(0xdeadbeef);
784     hSearch = FtpFindFirstFileA(hFtp, "pub/w*", &findData, 0, 0);
785     ok( hSearch != NULL, "Expected FtpFindFirstFileA to pass\n" );
786     InternetCloseHandle(hSearch);
787 
788     /* Try an invalid wildcard search */
789     SetLastError(0xdeadbeef);
790     hSearch = FtpFindFirstFileA(hFtp, "*/w*", &findData, 0, 0);
791     ok ( hSearch == NULL, "Expected FtpFindFirstFileA to fail\n" );
792     InternetCloseHandle(hSearch); /* Just in case */
793 
794     /* change current directory, and repeat those tests - this shows
795      * that the search string is interpreted as relative directory. */
796     success = FtpSetCurrentDirectoryA(hFtp, "pub");
797     ok( success, "Expected FtpSetCurrentDirectory to succeed\n" );
798 
799     SetLastError(0xdeadbeef);
800     hSearch = FtpFindFirstFileA(hFtp, "wine", &findData, 0, 0);
801     ok( hSearch != NULL, "Expected FtpFindFirstFileA to pass\n" );
802     InternetCloseHandle(hSearch);
803 
804     SetLastError(0xdeadbeef);
805     hSearch = FtpFindFirstFileA(hFtp, "w*", &findData, 0, 0);
806     ok( hSearch != NULL, "Expected FtpFindFirstFileA to pass\n" );
807     InternetCloseHandle(hSearch);
808 
809     success = FtpSetCurrentDirectoryA(hFtp, "..");
810     ok( success, "Expected FtpSetCurrentDirectory to succeed\n" );
811 
812     /* Try FindFirstFile between FtpOpenFile and InternetCloseHandle */
813     SetLastError(0xdeadbeef);
814     hOpenFile = FtpOpenFileA(hFtp, "welcome.msg", GENERIC_READ, FTP_TRANSFER_TYPE_ASCII, 0);
815     ok ( hOpenFile != NULL, "Expected FtpOpenFileA to succeed\n" );
816     ok ( GetLastError() == ERROR_SUCCESS ||
817         broken(GetLastError() == ERROR_FILE_NOT_FOUND), /* Win98 */
818         "Expected ERROR_SUCCESS, got %u\n", GetLastError() );
819 
820     /* This should fail as the OpenFile handle wasn't closed */
821     SetLastError(0xdeadbeef);
822     hSearch = FtpFindFirstFileA(hFtp, "welcome.msg", &findData, 0, 0);
823     error = GetLastError();
824     ok ( hSearch == NULL || broken(hSearch != NULL), /* win2k */
825          "Expected FtpFindFirstFileA to fail\n" );
826     if (!hSearch)
827         ok ( error == ERROR_FTP_TRANSFER_IN_PROGRESS || broken(error == ERROR_INTERNET_EXTENDED_ERROR),
828              "Expected ERROR_FTP_TRANSFER_IN_PROGRESS, got %d\n", error );
829     else
830     {
831         ok( error == ERROR_SUCCESS, "wrong error %u on success\n", GetLastError() );
832         InternetCloseHandle(hSearch);
833     }
834 
835     InternetCloseHandle(hOpenFile);
836 
837     /* Test using a nonexistent filename */
838     SetLastError(0xdeadbeef);
839     hSearch = FtpFindFirstFileA(hFtp, "this_file_should_not_exist", &findData, 0, 0);
840     ok ( hSearch == NULL, "Expected FtpFindFirstFileA to fail\n" );
841     todo_wine ok ( GetLastError() == ERROR_INTERNET_EXTENDED_ERROR,
842         "Expected ERROR_INTERNET_EXTENDED_ERROR, got %d\n", GetLastError() );
843     InternetCloseHandle(hSearch); /* Just in case */
844 
845     /* Test using a nonexistent filename and a wildcard */
846     SetLastError(0xdeadbeef);
847     hSearch = FtpFindFirstFileA(hFtp, "this_file_should_not_exist*", &findData, 0, 0);
848     ok ( hSearch == NULL, "Expected FtpFindFirstFileA to fail\n" );
849     todo_wine ok ( GetLastError() == ERROR_NO_MORE_FILES,
850         "Expected ERROR_NO_MORE_FILES, got %d\n", GetLastError() );
851     InternetCloseHandle(hSearch); /* Just in case */
852 
853     /* Test using an invalid handle type */
854     SetLastError(0xdeadbeef);
855     hSearch = FtpFindFirstFileA(hConnect, "welcome.msg", &findData, 0, 0);
856     ok ( hSearch == NULL, "Expected FtpFindFirstFileA to fail\n" );
857     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
858         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got %d\n", GetLastError() );
859     InternetCloseHandle(hSearch); /* Just in case */
860 }
861 
862 static void test_get_current_dir(HINTERNET hFtp, HINTERNET hConnect)
863 {
864     BOOL    bRet;
865     DWORD   dwCurrentDirectoryLen = MAX_PATH;
866     CHAR    lpszCurrentDirectory[MAX_PATH];
867 
868     if (!pFtpCommandA)
869     {
870         win_skip("FtpCommandA() is not available. Skipping the Ftp get_current_dir tests\n");
871         return;
872     }
873 
874     /* change directories to get a more interesting pwd */
875     bRet = pFtpCommandA(hFtp, FALSE, FTP_TRANSFER_TYPE_ASCII, "CWD pub/", 0, NULL);
876     if(bRet == FALSE)
877     {
878         skip("Failed to change directories in test_get_current_dir(HINTERNET hFtp).\n");
879         return;
880     }
881 
882     /* test with all NULL arguments */
883     SetLastError(0xdeadbeef);
884     bRet = FtpGetCurrentDirectoryA( NULL, NULL, 0 );
885     ok ( bRet == FALSE, "Expected FtpGetCurrentDirectoryA to fail\n" );
886     ok ( GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got: %d\n", GetLastError());
887 
888     /* test with NULL parameters instead of expected LPSTR/LPDWORD */
889     SetLastError(0xdeadbeef);
890     bRet = FtpGetCurrentDirectoryA( hFtp, NULL, 0 );
891     ok ( bRet == FALSE, "Expected FtpGetCurrentDirectoryA to fail\n" );
892     ok ( GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got: %d\n", GetLastError());
893 
894     /* test with no valid handle and valid parameters */
895     SetLastError(0xdeadbeef);
896     bRet = FtpGetCurrentDirectoryA( NULL, lpszCurrentDirectory, &dwCurrentDirectoryLen );
897     ok ( bRet == FALSE, "Expected FtpGetCurrentDirectoryA to fail\n" );
898     ok ( GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got: %d\n", GetLastError());
899 
900     /* test with invalid dwCurrentDirectory and all other parameters correct */
901     SetLastError(0xdeadbeef);
902     bRet = FtpGetCurrentDirectoryA( hFtp, lpszCurrentDirectory, 0 );
903     ok ( bRet == FALSE, "Expected FtpGetCurrentDirectoryA to fail\n" );
904     ok ( GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got: %d\n", GetLastError());
905 
906     /* test with invalid lpszCurrentDirectory and all other parameters correct */
907     SetLastError(0xdeadbeef);
908     bRet = FtpGetCurrentDirectoryA( hFtp, NULL, &dwCurrentDirectoryLen );
909     ok ( bRet == FALSE, "Expected FtpGetCurrentDirectoryA to fail\n" );
910     ok ( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INSUFFICIENT_BUFFER, got: %d\n", GetLastError());
911 
912     /* test to show it checks the handle type */
913     SetLastError(0xdeadbeef);
914     bRet = FtpGetCurrentDirectoryA( hConnect, lpszCurrentDirectory, &dwCurrentDirectoryLen );
915     ok ( bRet == FALSE, "Expected FtpGetCurrentDirectoryA to fail\n" );
916     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
917     "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got: %d\n", GetLastError());
918 
919     /* test for the current directory with legitimate values */
920     SetLastError(0xdeadbeef);
921     bRet = FtpGetCurrentDirectoryA( hFtp, lpszCurrentDirectory, &dwCurrentDirectoryLen );
922     ok ( bRet == TRUE, "Expected FtpGetCurrentDirectoryA to pass\n" );
923     ok ( !strcmp(lpszCurrentDirectory, "/pub"), "Expected returned value \"%s\" to match \"/pub\"\n", lpszCurrentDirectory);
924     ok ( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got: %d\n", GetLastError());
925 
926     /* test for the current directory with a size only large enough to
927      * fit the string and not the null terminating character */
928     SetLastError(0xdeadbeef);
929     dwCurrentDirectoryLen = 4;
930     lpszCurrentDirectory[4] = 'a'; /* set position 4 of the array to something else to make sure a leftover \0 isn't fooling the test */
931     bRet = FtpGetCurrentDirectoryA( hFtp, lpszCurrentDirectory, &dwCurrentDirectoryLen );
932     ok ( bRet == FALSE, "Expected FtpGetCurrentDirectoryA to fail\n");
933     ok ( strcmp(lpszCurrentDirectory, "/pub"), "Expected returned value \"%s\" to not match \"/pub\"\n", lpszCurrentDirectory);
934     ok ( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INSUFFICIENT_BUFFER, got: %d\n", GetLastError());
935 
936     /* test for the current directory with a size large enough to store
937      * the expected string as well as the null terminating character */
938     SetLastError(0xdeadbeef);
939     dwCurrentDirectoryLen = 5;
940     bRet = FtpGetCurrentDirectoryA( hFtp, lpszCurrentDirectory, &dwCurrentDirectoryLen );
941     ok ( bRet == TRUE, "Expected FtpGetCurrentDirectoryA to pass\n");
942     ok ( !strcmp(lpszCurrentDirectory, "/pub"), "Expected returned value \"%s\" to match \"/pub\"\n", lpszCurrentDirectory);
943     ok ( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got: %d\n", GetLastError());
944 }
945 
946 static void WINAPI status_callback(HINTERNET handle, DWORD_PTR ctx, DWORD status, LPVOID info, DWORD info_len)
947 {
948     switch (status)
949     {
950     case INTERNET_STATUS_RESOLVING_NAME:
951     case INTERNET_STATUS_NAME_RESOLVED:
952     case INTERNET_STATUS_CONNECTING_TO_SERVER:
953     case INTERNET_STATUS_CONNECTED_TO_SERVER:
954         trace("%p %lx %u %s %u\n", handle, ctx, status, (char *)info, info_len);
955         break;
956     default:
957         break;
958     }
959 }
960 
961 static void test_status_callbacks(HINTERNET hInternet)
962 {
963     INTERNET_STATUS_CALLBACK cb;
964     HINTERNET hFtp;
965     BOOL ret;
966 
967     cb = pInternetSetStatusCallbackA(hInternet, status_callback);
968     ok(cb == NULL, "expected NULL got %p\n", cb);
969 
970     hFtp = InternetConnectA(hInternet, "ftp.winehq.org", INTERNET_DEFAULT_FTP_PORT, "anonymous", NULL,
971                            INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 1);
972     if (!hFtp)
973     {
974         skip("No ftp connection could be made to ftp.winehq.org %u\n", GetLastError());
975         return;
976     }
977 
978     ret = InternetCloseHandle(hFtp);
979     ok(ret, "InternetCloseHandle failed %u\n", GetLastError());
980 
981     cb = pInternetSetStatusCallbackA(hInternet, NULL);
982     ok(cb == status_callback, "expected check_status got %p\n", cb);
983 }
984 
985 START_TEST(ftp)
986 {
987     HMODULE hWininet;
988     HANDLE hInternet, hFtp, hHttp;
989 
990     hWininet = GetModuleHandleA("wininet.dll");
991 
992     if(!GetProcAddress(hWininet, "InternetGetCookieExW")) {
993         win_skip("Too old IE (older than 6.0)\n");
994         return;
995     }
996 
997     pFtpCommandA = (void*)GetProcAddress(hWininet, "FtpCommandA");
998     pInternetSetStatusCallbackA = (void*)GetProcAddress(hWininet, "InternetSetStatusCallbackA");
999 
1000     SetLastError(0xdeadbeef);
1001     hInternet = InternetOpenA("winetest", 0, NULL, NULL, 0);
1002     ok(hInternet != NULL, "InternetOpen failed: %u\n", GetLastError());
1003 
1004     hFtp = InternetConnectA(hInternet, "ftp.winehq.org", INTERNET_DEFAULT_FTP_PORT, "anonymous", NULL, INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0);
1005     if (!hFtp)
1006     {
1007         InternetCloseHandle(hInternet);
1008         skip("No ftp connection could be made to ftp.winehq.org\n");
1009         return;
1010     }
1011     hHttp = InternetConnectA(hInternet, "www.winehq.org", INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
1012     if (!hHttp)
1013     {
1014         InternetCloseHandle(hFtp);
1015         InternetCloseHandle(hInternet);
1016         skip("No http connection could be made to www.winehq.org\n");
1017         return;
1018     }
1019 
1020     /* The first call should always be a proper InternetOpen, if not
1021      * several calls will return ERROR_INTERNET_NOT_INITIALIZED when
1022      * all parameters are correct but no session handle is given. Whereas
1023      * the same call will return ERROR_INVALID_HANDLE if an InternetOpen
1024      * is done before.
1025      * The following test will show that behaviour, where the tests inside
1026      * the other sub-tests will show the other situation.
1027      */
1028     test_getfile_no_open();
1029     test_connect(hInternet);
1030     test_createdir(hFtp, hHttp);
1031     test_deletefile(hFtp, hHttp);
1032     test_getfile(hFtp, hHttp);
1033     test_openfile(hFtp, hHttp);
1034     test_putfile(hFtp, hHttp);
1035     test_removedir(hFtp, hHttp);
1036     test_renamefile(hFtp, hHttp);
1037     test_command(hFtp, hHttp);
1038     test_find_first_file(hFtp, hHttp);
1039     test_get_current_dir(hFtp, hHttp);
1040     test_status_callbacks(hInternet);
1041 
1042     InternetCloseHandle(hHttp);
1043     InternetCloseHandle(hFtp);
1044     InternetCloseHandle(hInternet);
1045 }
1046