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