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