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