wininet: Add a test for status callbacks on ftp connections.
[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,
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,
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         ok ( bRet == FALSE, "Expected FtpGetFileA to fail\n");
456         ok ( GetLastError() == ERROR_FTP_TRANSFER_IN_PROGRESS,
457             "Expected ERROR_FTP_TRANSFER_IN_PROGRESS, got %d\n", GetLastError());
458         DeleteFileA("should_be_non_existing_deadbeef"); /* Just in case */
459
460         SetLastError(0xdeadbeef);
461         hOpenFile2 = FtpOpenFileA(hFtp, "welcome.msg", GENERIC_READ, FTP_TRANSFER_TYPE_ASCII, 0);
462         ok ( bRet == FALSE, "Expected FtpOpenFileA to fail\n");
463         ok ( GetLastError() == ERROR_FTP_TRANSFER_IN_PROGRESS,
464             "Expected ERROR_FTP_TRANSFER_IN_PROGRESS, got %d\n", GetLastError());
465         InternetCloseHandle(hOpenFile2); /* Just in case */
466
467         /* Create a temporary local file */
468         SetLastError(0xdeadbeef);
469         hFile = CreateFileA("now_existing_local", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
470         ok ( hFile != NULL, "Error creating a local file : %d\n", GetLastError());
471         CloseHandle(hFile);
472         SetLastError(0xdeadbeef);
473         bRet = FtpPutFileA(hFtp, "now_existing_local", "non_existing_remote", FTP_TRANSFER_TYPE_UNKNOWN, 0);
474         ok ( bRet == FALSE, "Expected FtpPutFileA to fail\n");
475         ok ( GetLastError() == ERROR_FTP_TRANSFER_IN_PROGRESS,
476             "Expected ERROR_FTP_TRANSFER_IN_PROGRESS, got %d\n", GetLastError());
477         DeleteFileA("now_existing_local");
478
479         SetLastError(0xdeadbeef);
480         bRet = FtpRemoveDirectoryA(hFtp, "should_be_non_existing_deadbeef_dir");
481         ok ( bRet == FALSE, "Expected FtpRemoveDirectoryA to fail\n");
482         ok ( GetLastError() == ERROR_FTP_TRANSFER_IN_PROGRESS,
483             "Expected ERROR_FTP_TRANSFER_IN_PROGRESS, got %d\n", GetLastError());
484
485         SetLastError(0xdeadbeef);
486         bRet = FtpRenameFileA(hFtp , "should_be_non_existing_deadbeef", "new");
487         ok ( bRet == FALSE, "Expected FtpRenameFileA to fail\n");
488         ok ( GetLastError() == ERROR_FTP_TRANSFER_IN_PROGRESS,
489             "Expected ERROR_FTP_TRANSFER_IN_PROGRESS, got %d\n", GetLastError());
490     }
491
492     InternetCloseHandle(hOpenFile);
493
494     /* One small test to show that handle type is checked before parameters */
495     SetLastError(0xdeadbeef);
496     hOpenFile = FtpOpenFileA(hConnect, "welcome.msg", GENERIC_READ, 5, 0);
497     ok ( !hOpenFile, "Expected FtpOpenFileA to fail\n");
498     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
499         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got %d\n", GetLastError());
500     InternetCloseHandle(hOpenFile); /* Just in case */
501
502     SetLastError(0xdeadbeef);
503     hOpenFile = FtpOpenFileA(hConnect, "welcome.msg", GENERIC_READ, FTP_TRANSFER_TYPE_ASCII, 0);
504     ok ( hOpenFile == NULL, "Expected FtpOpenFileA to fail\n");
505     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
506         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got %d\n", GetLastError());
507
508     InternetCloseHandle(hOpenFile); /* Just in case */
509 }
510
511 static void test_putfile(HINTERNET hFtp, HINTERNET hConnect)
512 {
513     BOOL      bRet;
514     HANDLE    hFile;
515
516     /* The order of checking is:
517      *
518      *   All parameters except 'session handle' and 'condition flags'
519      *   Session handle
520      *   Session handle type
521      *   Condition flags
522      */
523
524     /* Test to show the parameter checking order depends on the Windows version */
525     SetLastError(0xdeadbeef);
526     bRet = FtpPutFileA(NULL, NULL, "non_existing_remote", FTP_TRANSFER_TYPE_UNKNOWN, 0);
527     ok ( bRet == FALSE, "Expected FtpPutFileA to fail\n");
528     ok ( GetLastError() == ERROR_INVALID_HANDLE ||
529          GetLastError() == ERROR_INVALID_PARAMETER,
530         "Expected ERROR_INVALID_HANDLE (win98) or ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
531
532     /* Test to show session handle is checked before 'condition flags' */
533     SetLastError(0xdeadbeef);
534     bRet = FtpPutFileA(NULL, "non_existing_local", "non_existing_remote", 5, 0);
535     ok ( bRet == FALSE, "Expected FtpPutFileA to fail\n");
536     ok ( GetLastError() == ERROR_INVALID_HANDLE,
537         "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
538
539     /* Start clean */
540     DeleteFileA("non_existing_local");
541
542     /* No local file given */
543     SetLastError(0xdeadbeef);
544     bRet = FtpPutFileA(hFtp, NULL, "non_existing_remote", FTP_TRANSFER_TYPE_UNKNOWN, 0);
545     ok ( bRet == FALSE, "Expected FtpPutFileA to fail\n");
546     ok ( GetLastError() == ERROR_INVALID_PARAMETER,
547         "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
548
549     /* No remote file given */
550     SetLastError(0xdeadbeef);
551     bRet = FtpPutFileA(hFtp, "non_existing_local", NULL, FTP_TRANSFER_TYPE_UNKNOWN, 0);
552     ok ( bRet == FALSE, "Expected FtpPutFileA to fail\n");
553     ok ( GetLastError() == ERROR_INVALID_PARAMETER,
554         "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
555
556     /* Illegal condition flags */
557     SetLastError(0xdeadbeef);
558     bRet = FtpPutFileA(hFtp, "non_existing_local", "non_existing_remote", 5, 0);
559     ok ( bRet == FALSE, "Expected FtpPutFileA to fail\n");
560     ok ( GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_INVALID_PARAMETER,
561         "Expected ERROR_FILE_NOT_FOUND or ERROR_INVALID_PARAMETER (win98), got %d\n", GetLastError());
562
563     /* Parameters are OK but local file doesn't exist */
564     SetLastError(0xdeadbeef);
565     bRet = FtpPutFileA(hFtp, "non_existing_local", "non_existing_remote", FTP_TRANSFER_TYPE_UNKNOWN, 0);
566     ok ( bRet == FALSE, "Expected FtpPutFileA to fail\n");
567     ok ( GetLastError() == ERROR_FILE_NOT_FOUND,
568         "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
569
570     /* Create a temporary local file */
571     SetLastError(0xdeadbeef);
572     hFile = CreateFileA("now_existing_local", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
573     ok ( hFile != NULL, "Error creating a local file : %d\n", GetLastError());
574     CloseHandle(hFile);
575
576     /* Local file exists but we shouldn't be allowed to 'put' the file */
577     SetLastError(0xdeadbeef);
578     bRet = FtpPutFileA(hFtp, "now_existing_local", "non_existing_remote", FTP_TRANSFER_TYPE_UNKNOWN, 0);
579     ok ( bRet == FALSE, "Expected FtpPutFileA to fail\n");
580     ok ( GetLastError() == ERROR_INTERNET_EXTENDED_ERROR,
581         "Expected ERROR_INTERNET_EXTENDED_ERROR, got %d\n", GetLastError());
582
583     DeleteFileA("now_existing_local");
584
585     /* Test to show the parameter checking order depends on the Windows version */
586     SetLastError(0xdeadbeef);
587     bRet = FtpPutFileA(hConnect, NULL, "non_existing_remote", FTP_TRANSFER_TYPE_UNKNOWN, 0);
588     ok ( bRet == FALSE, "Expected FtpPutFileA to fail\n");
589     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE ||
590          GetLastError() == ERROR_INVALID_PARAMETER,
591         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE (win98) or ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
592
593     /* Test to show that 'session handle type' is checked before 'condition flags' */
594     SetLastError(0xdeadbeef);
595     bRet = FtpPutFileA(hConnect, "non_existing_local", "non_existing_remote", 5, 0);
596     ok ( bRet == FALSE, "Expected FtpPutFileA to fail\n");
597     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
598         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got %d\n", GetLastError());
599
600     SetLastError(0xdeadbeef);
601     bRet = FtpPutFileA(hConnect, "non_existing_local", "non_existing_remote", FTP_TRANSFER_TYPE_UNKNOWN, 0);
602     ok ( bRet == FALSE, "Expected FtpPutFileA to fail\n");
603     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
604         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got %d\n", GetLastError());
605 }
606
607 static void test_removedir(HINTERNET hFtp, HINTERNET hConnect)
608 {
609     BOOL      bRet;
610
611     /* Invalid internet handle, the other is a valid parameter */
612     SetLastError(0xdeadbeef);
613     bRet = FtpRemoveDirectoryA(NULL, "should_be_non_existing_deadbeef_dir");
614     ok ( bRet == FALSE, "Expected FtpRemoveDirectoryA to fail\n");
615     ok ( GetLastError() == ERROR_INVALID_HANDLE,
616         "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
617
618     /* No remote directory given */
619     SetLastError(0xdeadbeef);
620     bRet = FtpRemoveDirectoryA(hFtp, NULL);
621     ok ( bRet == FALSE, "Expected FtpRemoveDirectoryA to fail\n");
622     ok ( GetLastError() == ERROR_INVALID_PARAMETER,
623         "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
624
625     /* Remote directory doesn't exist */
626     SetLastError(0xdeadbeef);
627     bRet = FtpRemoveDirectoryA(hFtp, "should_be_non_existing_deadbeef_dir");
628     ok ( bRet == FALSE, "Expected FtpRemoveDirectoryA to fail\n");
629     ok ( GetLastError() == ERROR_INTERNET_EXTENDED_ERROR,
630         "Expected ERROR_INTERNET_EXTENDED_ERROR, got %d\n", GetLastError());
631
632     /* We shouldn't be allowed to remove that directory */
633     SetLastError(0xdeadbeef);
634     bRet = FtpRemoveDirectoryA(hFtp, "pub");
635     ok ( bRet == FALSE, "Expected FtpRemoveDirectoryA to fail\n");
636     ok ( GetLastError() == ERROR_INTERNET_EXTENDED_ERROR,
637         "Expected ERROR_INTERNET_EXTENDED_ERROR, got %d\n", GetLastError());
638
639     /* One small test to show that handle type is checked before parameters */
640     SetLastError(0xdeadbeef);
641     bRet = FtpRemoveDirectoryA(hConnect, NULL);
642     ok ( bRet == FALSE, "Expected FtpRemoveDirectoryA to fail\n");
643     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
644         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got %d\n", GetLastError());
645
646     SetLastError(0xdeadbeef);
647     bRet = FtpRemoveDirectoryA(hConnect, "should_be_non_existing_deadbeef_dir");
648     ok ( bRet == FALSE, "Expected FtpRemoveDirectoryA to fail\n");
649     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
650         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got %d\n", GetLastError());
651 }
652
653 static void test_renamefile(HINTERNET hFtp, HINTERNET hConnect)
654 {
655     BOOL      bRet;
656
657     /* Invalid internet handle, the rest are valid parameters */
658     SetLastError(0xdeadbeef);
659     bRet = FtpRenameFileA(NULL , "should_be_non_existing_deadbeef", "new");
660     ok ( bRet == FALSE, "Expected FtpRenameFileA to fail\n");
661     ok ( GetLastError() == ERROR_INVALID_HANDLE,
662         "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
663
664     /* No 'existing' file */
665     SetLastError(0xdeadbeef);
666     bRet = FtpRenameFileA(hFtp , NULL, "new");
667     ok ( bRet == FALSE, "Expected FtpRenameFileA to fail\n");
668     ok ( GetLastError() == ERROR_INVALID_PARAMETER,
669         "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
670
671     /* No new file */
672     SetLastError(0xdeadbeef);
673     bRet = FtpRenameFileA(hFtp , "should_be_non_existing_deadbeef", NULL);
674     ok ( bRet == FALSE, "Expected FtpRenameFileA to fail\n");
675     ok ( GetLastError() == ERROR_INVALID_PARAMETER,
676         "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
677
678     /* Existing file shouldn't be there */
679     SetLastError(0xdeadbeef);
680     bRet = FtpRenameFileA(hFtp , "should_be_non_existing_deadbeef", "new");
681     ok ( bRet == FALSE, "Expected FtpRenameFileA to fail\n");
682     ok ( GetLastError() == ERROR_INTERNET_EXTENDED_ERROR,
683         "Expected ERROR_INTERNET_EXTENDED_ERROR, got %d\n", GetLastError());
684
685     /* One small test to show that handle type is checked before parameters */
686     SetLastError(0xdeadbeef);
687     bRet = FtpRenameFileA(hConnect , "should_be_non_existing_deadbeef", NULL);
688     ok ( bRet == FALSE, "Expected FtpRenameFileA to fail\n");
689     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
690         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got %d\n", GetLastError());
691
692     SetLastError(0xdeadbeef);
693     bRet = FtpRenameFileA(hConnect , "should_be_non_existing_deadbeef", "new");
694     ok ( bRet == FALSE, "Expected FtpRenameFileA to fail\n");
695     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
696         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got %d\n", GetLastError());
697 }
698
699 static void test_command(HINTERNET hFtp, HINTERNET hConnect)
700 {
701     BOOL ret;
702     DWORD error;
703     unsigned int i;
704     static const struct
705     {
706         BOOL  ret;
707         DWORD error;
708         const char *cmd;
709     }
710     command_test[] =
711     {
712         { FALSE, ERROR_INVALID_PARAMETER,       NULL },
713         { FALSE, ERROR_INVALID_PARAMETER,       "" },
714         { FALSE, ERROR_INTERNET_EXTENDED_ERROR, "HELO" },
715         { FALSE, ERROR_INTERNET_EXTENDED_ERROR, "SIZE " },
716         { FALSE, ERROR_INTERNET_EXTENDED_ERROR, " SIZE" },
717         { FALSE, ERROR_INTERNET_EXTENDED_ERROR, "SIZE " },
718         { FALSE, ERROR_INTERNET_EXTENDED_ERROR, "SIZE /welcome.msg /welcome.msg" },
719         { FALSE, ERROR_INTERNET_EXTENDED_ERROR, "SIZE  /welcome.msg" },
720         { FALSE, ERROR_INTERNET_EXTENDED_ERROR, "SIZE /welcome.msg " },
721         { TRUE,  ERROR_SUCCESS,                 "SIZE\t/welcome.msg" },
722         { TRUE,  ERROR_SUCCESS,                 "SIZE /welcome.msg" },
723         { FALSE, ERROR_INTERNET_EXTENDED_ERROR, "PWD /welcome.msg" },
724         { TRUE,  ERROR_SUCCESS,                 "PWD" },
725         { TRUE,  ERROR_SUCCESS,                 "PWD\r\n" }
726     };
727
728     if (!pFtpCommandA)
729     {
730         win_skip("FtpCommandA() is not available. Skipping the Ftp command tests\n");
731         return;
732     }
733
734     for (i = 0; i < sizeof(command_test) / sizeof(command_test[0]); i++)
735     {
736         SetLastError(0xdeadbeef);
737         ret = pFtpCommandA(hFtp, FALSE, FTP_TRANSFER_TYPE_ASCII, command_test[i].cmd, 0, NULL);
738         error = GetLastError();
739
740         ok(ret == command_test[i].ret, "%d: expected FtpCommandA to %s\n", i, command_test[i].ret ? "succeed" : "fail");
741         ok(error == command_test[i].error, "%d: expected error %u, got %u\n", i, command_test[i].error, error);
742     }
743 }
744
745 static void test_find_first_file(HINTERNET hFtp, HINTERNET hConnect)
746 {
747     WIN32_FIND_DATA findData;
748     HINTERNET hSearch;
749     HINTERNET hSearch2;
750     HINTERNET hOpenFile;
751
752     /* NULL as the search file ought to return the first file in the directory */
753     SetLastError(0xdeadbeef);
754     hSearch = FtpFindFirstFileA(hFtp, NULL, &findData, 0, 0);
755     ok ( hSearch != NULL, "Expected FtpFindFirstFileA to pass\n" );
756
757     /* This should fail as the previous handle wasn't closed */
758     SetLastError(0xdeadbeef);
759     hSearch2 = FtpFindFirstFileA(hFtp, "welcome.msg", &findData, 0, 0);
760     todo_wine ok ( hSearch2 == NULL, "Expected FtpFindFirstFileA to fail\n" );
761     todo_wine ok ( GetLastError() == ERROR_FTP_TRANSFER_IN_PROGRESS,
762         "Expected ERROR_FTP_TRANSFER_IN_PROGRESS, got %d\n", GetLastError() );
763     InternetCloseHandle(hSearch2); /* Just in case */
764
765     InternetCloseHandle(hSearch);
766
767     /* Try a valid filename in a subdirectory search */
768     SetLastError(0xdeadbeef);
769     hSearch = FtpFindFirstFileA(hFtp, "pub/wine", &findData, 0, 0);
770     todo_wine ok ( hSearch != NULL, "Expected FtpFindFirstFileA to pass\n" );
771     InternetCloseHandle(hSearch);
772
773     /* Try a valid filename in a subdirectory wildcard search */
774     SetLastError(0xdeadbeef);
775     hSearch = FtpFindFirstFileA(hFtp, "pub/w*", &findData, 0, 0);
776     todo_wine ok ( hSearch != NULL, "Expected FtpFindFirstFileA to pass\n" );
777     InternetCloseHandle(hSearch);
778
779     /* Try an invalid wildcard search */
780     SetLastError(0xdeadbeef);
781     hSearch = FtpFindFirstFileA(hFtp, "*/w*", &findData, 0, 0);
782     ok ( hSearch == NULL, "Expected FtpFindFirstFileA to fail\n" );
783     InternetCloseHandle(hSearch); /* Just in case */
784
785     /* Try FindFirstFile between FtpOpenFile and InternetCloseHandle */
786     SetLastError(0xdeadbeef);
787     hOpenFile = FtpOpenFileA(hFtp, "welcome.msg", GENERIC_READ, FTP_TRANSFER_TYPE_ASCII, 0);
788     ok ( hOpenFile != NULL, "Expected FtpOpenFileA to succeed\n" );
789     ok ( GetLastError() == ERROR_SUCCESS ||
790         broken(GetLastError() == ERROR_FILE_NOT_FOUND), /* Win98 */
791         "Expected ERROR_SUCCESS, got %u\n", GetLastError() );
792
793     /* This should fail as the OpenFile handle wasn't closed */
794     SetLastError(0xdeadbeef);
795     hSearch = FtpFindFirstFileA(hFtp, "welcome.msg", &findData, 0, 0);
796     ok ( hSearch == NULL, "Expected FtpFindFirstFileA to fail\n" );
797     ok ( GetLastError() == ERROR_FTP_TRANSFER_IN_PROGRESS,
798         "Expected ERROR_FTP_TRANSFER_IN_PROGRESS, got %d\n", GetLastError() );
799     InternetCloseHandle(hSearch); /* Just in case */
800
801     InternetCloseHandle(hOpenFile);
802
803     /* Test using a nonexistent filename */
804     SetLastError(0xdeadbeef);
805     hSearch = FtpFindFirstFileA(hFtp, "this_file_should_not_exist", &findData, 0, 0);
806     ok ( hSearch == NULL, "Expected FtpFindFirstFileA to fail\n" );
807     todo_wine ok ( GetLastError() == ERROR_INTERNET_EXTENDED_ERROR,
808         "Expected ERROR_INTERNET_EXTENDED_ERROR, got %d\n", GetLastError() );
809     InternetCloseHandle(hSearch); /* Just in case */
810
811     /* Test using a nonexistent filename and a wildcard */
812     SetLastError(0xdeadbeef);
813     hSearch = FtpFindFirstFileA(hFtp, "this_file_should_not_exist*", &findData, 0, 0);
814     ok ( hSearch == NULL, "Expected FtpFindFirstFileA to fail\n" );
815     todo_wine ok ( GetLastError() == ERROR_NO_MORE_FILES,
816         "Expected ERROR_NO_MORE_FILES, got %d\n", GetLastError() );
817     InternetCloseHandle(hSearch); /* Just in case */
818
819     /* Test using an invalid handle type */
820     SetLastError(0xdeadbeef);
821     hSearch = FtpFindFirstFileA(hConnect, "welcome.msg", &findData, 0, 0);
822     ok ( hSearch == NULL, "Expected FtpFindFirstFileA to fail\n" );
823     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
824         "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got %d\n", GetLastError() );
825     InternetCloseHandle(hSearch); /* Just in case */
826 }
827
828 static void test_get_current_dir(HINTERNET hFtp, HINTERNET hConnect)
829 {
830     BOOL    bRet;
831     DWORD   dwCurrentDirectoryLen = MAX_PATH;
832     CHAR    lpszCurrentDirectory[MAX_PATH];
833
834     if (!pFtpCommandA)
835     {
836         win_skip("FtpCommandA() is not available. Skipping the Ftp get_current_dir tests\n");
837         return;
838     }
839
840     /* change directories to get a more interesting pwd */
841     bRet = pFtpCommandA(hFtp, FALSE, FTP_TRANSFER_TYPE_ASCII, "CWD pub/", 0, NULL);
842     if(bRet == FALSE)
843     {
844         skip("Failed to change directories in test_get_current_dir(HINTERNET hFtp).\n");
845         return;
846     }
847
848     /* test with all NULL arguments */
849     SetLastError(0xdeadbeef);
850     bRet = FtpGetCurrentDirectoryA( NULL, NULL, 0 );
851     ok ( bRet == FALSE, "Expected FtpGetCurrentDirectoryA to fail\n" );
852     ok ( GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got: %d\n", GetLastError());
853
854     /* test with NULL parameters instead of expected LPSTR/LPDWORD */
855     SetLastError(0xdeadbeef);
856     bRet = FtpGetCurrentDirectoryA( hFtp, NULL, 0 );
857     ok ( bRet == FALSE, "Expected FtpGetCurrentDirectoryA to fail\n" );
858     ok ( GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got: %d\n", GetLastError());
859
860     /* test with no valid handle and valid parameters */
861     SetLastError(0xdeadbeef);
862     bRet = FtpGetCurrentDirectoryA( NULL, lpszCurrentDirectory, &dwCurrentDirectoryLen );
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 invalid dwCurrentDirectory and all other parameters correct */
867     SetLastError(0xdeadbeef);
868     bRet = FtpGetCurrentDirectoryA( hFtp, lpszCurrentDirectory, 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 invalid lpszCurrentDirectory and all other parameters correct */
873     SetLastError(0xdeadbeef);
874     bRet = FtpGetCurrentDirectoryA( hFtp, NULL, &dwCurrentDirectoryLen );
875     ok ( bRet == FALSE, "Expected FtpGetCurrentDirectoryA to fail\n" );
876     ok ( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INSUFFICIENT_BUFFER, got: %d\n", GetLastError());
877
878     /* test to show it checks the handle type */
879     SetLastError(0xdeadbeef);
880     bRet = FtpGetCurrentDirectoryA( hConnect, lpszCurrentDirectory, &dwCurrentDirectoryLen );
881     ok ( bRet == FALSE, "Expected FtpGetCurrentDirectoryA to fail\n" );
882     ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
883     "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got: %d\n", GetLastError());
884
885     /* test for the current directory with legitimate values */
886     SetLastError(0xdeadbeef);
887     bRet = FtpGetCurrentDirectoryA( hFtp, lpszCurrentDirectory, &dwCurrentDirectoryLen );
888     ok ( bRet == TRUE, "Expected FtpGetCurrentDirectoryA to pass\n" );
889     ok ( !strcmp(lpszCurrentDirectory, "/pub"), "Expected returned value \"%s\" to match \"/pub\"\n", lpszCurrentDirectory);
890     ok ( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got: %d\n", GetLastError());
891
892     /* test for the current directory with a size only large enough to
893      * fit the string and not the null terminating character */
894     SetLastError(0xdeadbeef);
895     dwCurrentDirectoryLen = 4;
896     lpszCurrentDirectory[4] = 'a'; /* set position 4 of the array to something else to make sure a leftover \0 isn't fooling the test */
897     bRet = FtpGetCurrentDirectoryA( hFtp, lpszCurrentDirectory, &dwCurrentDirectoryLen );
898     ok ( bRet == FALSE, "Expected FtpGetCurrentDirectoryA to fail\n");
899     ok ( strcmp(lpszCurrentDirectory, "/pub"), "Expected returned value \"%s\" to not match \"/pub\"\n", lpszCurrentDirectory);
900     ok ( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INSUFFICIENT_BUFFER, got: %d\n", GetLastError());
901
902     /* test for the current directory with a size large enough to store
903      * the expected string as well as the null terminating character */
904     SetLastError(0xdeadbeef);
905     dwCurrentDirectoryLen = 5;
906     bRet = FtpGetCurrentDirectoryA( hFtp, lpszCurrentDirectory, &dwCurrentDirectoryLen );
907     ok ( bRet == TRUE, "Expected FtpGetCurrentDirectoryA to pass\n");
908     ok ( !strcmp(lpszCurrentDirectory, "/pub"), "Expected returned value \"%s\" to match \"/pub\"\n", lpszCurrentDirectory);
909     ok ( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got: %d\n", GetLastError());
910 }
911
912 static void WINAPI status_callback(HINTERNET handle, DWORD_PTR ctx, DWORD status, LPVOID info, DWORD info_len)
913 {
914     switch (status)
915     {
916     case INTERNET_STATUS_RESOLVING_NAME:
917     case INTERNET_STATUS_NAME_RESOLVED:
918     case INTERNET_STATUS_CONNECTING_TO_SERVER:
919     case INTERNET_STATUS_CONNECTED_TO_SERVER:
920         trace("%p %lx %u %s %u\n", handle, ctx, status, (char *)info, info_len);
921         break;
922     default:
923         break;
924     }
925 }
926
927 static void test_status_callbacks(HINTERNET hInternet)
928 {
929     INTERNET_STATUS_CALLBACK cb;
930     HINTERNET hFtp;
931     BOOL ret;
932
933     if (!pInternetSetStatusCallbackA)
934     {
935         win_skip("InternetSetStatusCallbackA() is not available, skipping test\n");
936         return;
937     }
938
939     cb = pInternetSetStatusCallbackA(hInternet, status_callback);
940     ok(cb == NULL, "expected NULL got %p\n", cb);
941
942     hFtp = InternetConnect(hInternet, "ftp.winehq.org", INTERNET_DEFAULT_FTP_PORT, "anonymous", NULL,
943                            INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 1);
944     if (!hFtp)
945     {
946         skip("No ftp connection could be made to ftp.winehq.org %u\n", GetLastError());
947         return;
948     }
949
950     ret = InternetCloseHandle(hFtp);
951     ok(ret, "InternetCloseHandle failed %u\n", GetLastError());
952
953     cb = pInternetSetStatusCallbackA(hInternet, NULL);
954     ok(cb == status_callback, "expected check_status got %p\n", cb);
955 }
956
957 START_TEST(ftp)
958 {
959     HMODULE hWininet;
960     HANDLE hInternet, hFtp, hHttp;
961
962     hWininet = GetModuleHandleA("wininet.dll");
963     pFtpCommandA = (void*)GetProcAddress(hWininet, "FtpCommandA");
964     pInternetSetStatusCallbackA = (void*)GetProcAddress(hWininet, "InternetSetStatusCallbackA");
965
966     SetLastError(0xdeadbeef);
967     hInternet = InternetOpen("winetest", 0, NULL, NULL, 0);
968     ok(hInternet != NULL, "InternetOpen failed: %u\n", GetLastError());
969
970     hFtp = InternetConnect(hInternet, "ftp.winehq.org", INTERNET_DEFAULT_FTP_PORT, "anonymous", NULL, INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0);
971     if (!hFtp)
972     {
973         InternetCloseHandle(hInternet);
974         skip("No ftp connection could be made to ftp.winehq.org\n");
975         return;
976     }
977     hHttp = InternetConnect(hInternet, "www.winehq.org", INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
978     if (!hHttp)
979     {
980         InternetCloseHandle(hFtp);
981         InternetCloseHandle(hInternet);
982         skip("No http connection could be made to www.winehq.org\n");
983         return;
984     }
985
986     /* The first call should always be a proper InternetOpen, if not
987      * several calls will return ERROR_INTERNET_NOT_INITIALIZED when
988      * all parameters are correct but no session handle is given. Whereas
989      * the same call will return ERROR_INVALID_HANDLE if an InternetOpen
990      * is done before.
991      * The following test will show that behaviour, where the tests inside
992      * the other sub-tests will show the other situation.
993      */
994     test_getfile_no_open();
995     test_connect(hInternet);
996     test_createdir(hFtp, hHttp);
997     test_deletefile(hFtp, hHttp);
998     test_getfile(hFtp, hHttp);
999     test_openfile(hFtp, hHttp);
1000     test_putfile(hFtp, hHttp);
1001     test_removedir(hFtp, hHttp);
1002     test_renamefile(hFtp, hHttp);
1003     test_command(hFtp, hHttp);
1004     test_find_first_file(hFtp, hHttp);
1005     test_get_current_dir(hFtp, hHttp);
1006     test_status_callbacks(hInternet);
1007
1008     InternetCloseHandle(hHttp);
1009     InternetCloseHandle(hFtp);
1010     InternetCloseHandle(hInternet);
1011 }