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