INT21_GetFreeDiskSpace(): The drive parameter is found in the DL
[wine] / dlls / wininet / internet.c
1 /*
2  * Wininet
3  *
4  * Copyright 1999 Corel Corporation
5  * Copyright 2002 CodeWeavers Inc.
6  * Copyright 2002 Jaco Greeff
7  * Copyright 2002 TransGaming Technologies Inc.
8  *
9  * Ulrich Czekalla
10  * Aric Stewart
11  * David Hammerton
12  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Lesser General Public
15  * License as published by the Free Software Foundation; either
16  * version 2.1 of the License, or (at your option) any later version.
17  *
18  * This library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Lesser General Public License for more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public
24  * License along with this library; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  */
27
28 #include "config.h"
29
30 #define MAXHOSTNAME 100 /* from http.c */
31
32 #include <string.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <sys/types.h>
36 #ifdef HAVE_SYS_SOCKET_H
37 # include <sys/socket.h>
38 #endif
39 #ifdef HAVE_SYS_TIME_H
40 # include <sys/time.h>
41 #endif
42 #include <stdlib.h>
43 #include <ctype.h>
44 #ifdef HAVE_UNISTD_H
45 # include <unistd.h>
46 #endif
47
48 #include "ntstatus.h"
49 #include "windef.h"
50 #include "winbase.h"
51 #include "winreg.h"
52 #include "wininet.h"
53 #include "winnls.h"
54 #include "wine/debug.h"
55 #include "winerror.h"
56 #define NO_SHLWAPI_STREAM
57 #include "shlwapi.h"
58
59 #include "wine/exception.h"
60 #include "excpt.h"
61
62 #include "internet.h"
63
64 #include "wine/unicode.h"
65
66 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
67
68 #define MAX_IDLE_WORKER 1000*60*1
69 #define MAX_WORKER_THREADS 10
70 #define RESPONSE_TIMEOUT        30
71
72 #define GET_HWININET_FROM_LPWININETFINDNEXT(lpwh) \
73 (LPWININETAPPINFOA)(((LPWININETFTPSESSIONA)(lpwh->hdr.lpwhparent))->hdr.lpwhparent)
74
75 /* filter for page-fault exceptions */
76 static WINE_EXCEPTION_FILTER(page_fault)
77 {
78     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ||
79         GetExceptionCode() == EXCEPTION_PRIV_INSTRUCTION)
80         return EXCEPTION_EXECUTE_HANDLER;
81     return EXCEPTION_CONTINUE_SEARCH;
82 }
83
84 typedef struct
85 {
86     DWORD  dwError;
87     CHAR   response[MAX_REPLY_LEN];
88 } WITHREADERROR, *LPWITHREADERROR;
89
90 BOOL WINAPI INTERNET_FindNextFileA(HINTERNET hFind, LPVOID lpvFindData);
91 VOID INTERNET_ExecuteWork();
92
93 DWORD g_dwTlsErrIndex = TLS_OUT_OF_INDEXES;
94 DWORD dwNumThreads;
95 DWORD dwNumIdleThreads;
96 DWORD dwNumJobs;
97 HANDLE hEventArray[2];
98 #define hQuitEvent hEventArray[0]
99 #define hWorkEvent hEventArray[1]
100 CRITICAL_SECTION csQueue;
101 LPWORKREQUEST lpHeadWorkQueue;
102 LPWORKREQUEST lpWorkQueueTail;
103
104 /***********************************************************************
105  * DllMain [Internal] Initializes the internal 'WININET.DLL'.
106  *
107  * PARAMS
108  *     hinstDLL    [I] handle to the DLL's instance
109  *     fdwReason   [I]
110  *     lpvReserved [I] reserved, must be NULL
111  *
112  * RETURNS
113  *     Success: TRUE
114  *     Failure: FALSE
115  */
116
117 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
118 {
119     TRACE("%p,%lx,%p\n", hinstDLL, fdwReason, lpvReserved);
120
121     switch (fdwReason) {
122         case DLL_PROCESS_ATTACH:
123
124             g_dwTlsErrIndex = TlsAlloc();
125
126             if (g_dwTlsErrIndex == TLS_OUT_OF_INDEXES)
127                 return FALSE;
128
129             hQuitEvent = CreateEventA(0, TRUE, FALSE, NULL);
130             hWorkEvent = CreateEventA(0, FALSE, FALSE, NULL);
131             InitializeCriticalSection(&csQueue);
132
133             dwNumThreads = 0;
134             dwNumIdleThreads = 0;
135             dwNumJobs = 0;
136
137         case DLL_THREAD_ATTACH:
138             {
139                 LPWITHREADERROR lpwite = HeapAlloc(GetProcessHeap(), 0, sizeof(WITHREADERROR));
140                 if (NULL == lpwite)
141                     return FALSE;
142
143                 TlsSetValue(g_dwTlsErrIndex, (LPVOID)lpwite);
144             }
145             break;
146
147         case DLL_THREAD_DETACH:
148             if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
149                         {
150                                 LPVOID lpwite = TlsGetValue(g_dwTlsErrIndex);
151                                 if (lpwite)
152                    HeapFree(GetProcessHeap(), 0, lpwite);
153                         }
154             break;
155
156         case DLL_PROCESS_DETACH:
157
158             if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
159             {
160                 HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex));
161                 TlsFree(g_dwTlsErrIndex);
162             }
163
164             SetEvent(hQuitEvent);
165
166             CloseHandle(hQuitEvent);
167             CloseHandle(hWorkEvent);
168             DeleteCriticalSection(&csQueue);
169             break;
170     }
171
172     return TRUE;
173 }
174
175
176 /***********************************************************************
177  *           InternetInitializeAutoProxyDll   (WININET.@)
178  *
179  * Setup the internal proxy
180  *
181  * PARAMETERS
182  *     dwReserved
183  *
184  * RETURNS
185  *     FALSE on failure
186  *
187  */
188 BOOL WINAPI InternetInitializeAutoProxyDll(DWORD dwReserved)
189 {
190     FIXME("STUB\n");
191     INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
192     return FALSE;
193 }
194
195 /***********************************************************************
196  *           DetectAutoProxyUrl   (WININET.@)
197  *
198  * Auto detect the proxy url
199  *
200  * RETURNS
201  *     FALSE on failure
202  *
203  */
204 BOOL WINAPI DetectAutoProxyUrl(LPSTR lpszAutoProxyUrl,
205         DWORD dwAutoProxyUrlLength, DWORD dwDetectFlags)
206 {
207     FIXME("STUB\n");
208     INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
209     return FALSE;
210 }
211
212
213 /***********************************************************************
214  *           INTERNET_ConfigureProxyFromReg
215  *
216  * FIXME:
217  * The proxy may be specified in the form 'http=proxy.my.org'
218  * Presumably that means there can be ftp=ftpproxy.my.org too.
219  */
220 static BOOL INTERNET_ConfigureProxyFromReg( LPWININETAPPINFOA lpwai )
221 {
222     HKEY key;
223     DWORD r, keytype, len, enabled;
224     LPSTR lpszInternetSettings =
225         "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
226
227     r = RegOpenKeyA(HKEY_CURRENT_USER, lpszInternetSettings, &key);
228     if ( r != ERROR_SUCCESS )
229         return FALSE;
230
231     len = sizeof enabled;
232     r = RegQueryValueExA( key, "ProxyEnable", NULL, &keytype,
233                           (BYTE*)&enabled, &len);
234     if( (r == ERROR_SUCCESS) && enabled )
235     {
236         TRACE("Proxy is enabled.\n");
237
238         /* figure out how much memory the proxy setting takes */
239         r = RegQueryValueExA( key, "ProxyServer", NULL, &keytype, 
240                               NULL, &len);
241         if( (r == ERROR_SUCCESS) && len && (keytype == REG_SZ) )
242         {
243             LPSTR szProxy, p, szHttp = "http=";
244
245             szProxy=HeapAlloc( GetProcessHeap(), 0, len+1 );
246             RegQueryValueExA( key, "ProxyServer", NULL, &keytype,
247                               (BYTE*)szProxy, &len);
248
249             /* find the http proxy, and strip away everything else */
250             p = strstr( szProxy, szHttp );
251             if( p )
252             {
253                  p += strlen(szHttp);
254                  strcpy( szProxy, p );
255             }
256             p = strchr( szProxy, ' ' );
257             if( p )
258                 *p = 0;
259
260             lpwai->dwAccessType = INTERNET_OPEN_TYPE_PROXY;
261             lpwai->lpszProxy = szProxy;
262
263             TRACE("http proxy = %s\n", lpwai->lpszProxy);
264         }
265         else
266             ERR("Couldn't read proxy server settings.\n");
267     }
268     else
269         TRACE("Proxy is not enabled.\n");
270     RegCloseKey(key);
271
272     return enabled;
273 }
274
275 /***********************************************************************
276  *           InternetOpenA   (WININET.@)
277  *
278  * Per-application initialization of wininet
279  *
280  * RETURNS
281  *    HINTERNET on success
282  *    NULL on failure
283  *
284  */
285 HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType,
286     LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags)
287 {
288     LPWININETAPPINFOA lpwai = NULL;
289
290     TRACE("(%s, %li, %s, %s, %li)\n", debugstr_a(lpszAgent), dwAccessType,
291          debugstr_a(lpszProxy), debugstr_a(lpszProxyBypass), dwFlags);
292
293     /* Clear any error information */
294     INTERNET_SetLastError(0);
295
296     lpwai = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETAPPINFOA));
297     if (NULL == lpwai)
298     {
299         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
300         return NULL;
301     }
302  
303     memset(lpwai, 0, sizeof(WININETAPPINFOA));
304     lpwai->hdr.htype = WH_HINIT;
305     lpwai->hdr.lpwhparent = NULL;
306     lpwai->hdr.dwFlags = dwFlags;
307     lpwai->dwAccessType = dwAccessType;
308     lpwai->lpszProxyUsername = NULL;
309     lpwai->lpszProxyPassword = NULL;
310
311     if (NULL != lpszAgent)
312     {
313         lpwai->lpszAgent = HeapAlloc( GetProcessHeap(),0,
314                                       strlen(lpszAgent)+1);
315         if (lpwai->lpszAgent)
316             strcpy( lpwai->lpszAgent, lpszAgent );
317     }
318     if(dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG)
319         INTERNET_ConfigureProxyFromReg( lpwai );
320     else if (NULL != lpszProxy)
321     {
322         lpwai->lpszProxy = HeapAlloc( GetProcessHeap(), 0,
323                                       strlen(lpszProxy)+1);
324         if (lpwai->lpszProxy)
325             strcpy( lpwai->lpszProxy, lpszProxy );
326     }
327
328     if (NULL != lpszProxyBypass)
329     {
330         lpwai->lpszProxyBypass = HeapAlloc( GetProcessHeap(), 0,
331                                             strlen(lpszProxyBypass)+1);
332         if (lpwai->lpszProxyBypass)
333             strcpy( lpwai->lpszProxyBypass, lpszProxyBypass );
334     }
335
336     TRACE("returning %p\n", (HINTERNET)lpwai);
337     return (HINTERNET)lpwai;
338 }
339
340
341 /***********************************************************************
342  *           InternetOpenW   (WININET.@)
343  *
344  * Per-application initialization of wininet
345  *
346  * RETURNS
347  *    HINTERNET on success
348  *    NULL on failure
349  *
350  */
351 HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType,
352     LPCWSTR lpszProxy, LPCWSTR lpszProxyBypass, DWORD dwFlags)
353 {
354     HINTERNET rc = (HINTERNET)NULL;
355     INT lenAgent = WideCharToMultiByte(CP_ACP, 0, lpszAgent, -1, NULL, 0, NULL, NULL);
356     INT lenProxy = WideCharToMultiByte(CP_ACP, 0, lpszProxy, -1, NULL, 0, NULL, NULL);
357     INT lenBypass = WideCharToMultiByte(CP_ACP, 0, lpszProxyBypass, -1, NULL, 0, NULL, NULL);
358     CHAR *szAgent = (CHAR *)HeapAlloc(GetProcessHeap(), 0, lenAgent*sizeof(CHAR));
359     CHAR *szProxy = (CHAR *)HeapAlloc(GetProcessHeap(), 0, lenProxy*sizeof(CHAR));
360     CHAR *szBypass = (CHAR *)HeapAlloc(GetProcessHeap(), 0, lenBypass*sizeof(CHAR));
361
362     if (!szAgent || !szProxy || !szBypass)
363     {
364         if (szAgent)
365             HeapFree(GetProcessHeap(), 0, szAgent);
366         if (szProxy)
367             HeapFree(GetProcessHeap(), 0, szProxy);
368         if (szBypass)
369             HeapFree(GetProcessHeap(), 0, szBypass);
370         return (HINTERNET)NULL;
371     }
372
373     WideCharToMultiByte(CP_ACP, 0, lpszAgent, -1, szAgent, lenAgent,
374         NULL, NULL);
375     WideCharToMultiByte(CP_ACP, 0, lpszProxy, -1, szProxy, lenProxy,
376         NULL, NULL);
377     WideCharToMultiByte(CP_ACP, 0, lpszProxyBypass, -1, szBypass, lenBypass,
378         NULL, NULL);
379
380     rc = InternetOpenA(szAgent, dwAccessType, szProxy, szBypass, dwFlags);
381
382     HeapFree(GetProcessHeap(), 0, szAgent);
383     HeapFree(GetProcessHeap(), 0, szProxy);
384     HeapFree(GetProcessHeap(), 0, szBypass);
385
386     return rc;
387 }
388
389 /***********************************************************************
390  *           InternetGetLastResponseInfoA (WININET.@)
391  *
392  * Return last wininet error description on the calling thread
393  *
394  * RETURNS
395  *    TRUE on success of writing to buffer
396  *    FALSE on failure
397  *
398  */
399 BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError,
400     LPSTR lpszBuffer, LPDWORD lpdwBufferLength)
401 {
402     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
403
404     TRACE("\n");
405
406     *lpdwError = lpwite->dwError;
407     if (lpwite->dwError)
408     {
409         strncpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
410         *lpdwBufferLength = strlen(lpszBuffer);
411     }
412     else
413         *lpdwBufferLength = 0;
414
415     return TRUE;
416 }
417
418
419 /***********************************************************************
420  *           InternetGetConnectedState (WININET.@)
421  *
422  * Return connected state
423  *
424  * RETURNS
425  *    TRUE if connected
426  *    if lpdwStatus is not null, return the status (off line,
427  *    modem, lan...) in it.
428  *    FALSE if not connected
429  */
430 BOOL WINAPI InternetGetConnectedState(LPDWORD lpdwStatus, DWORD dwReserved)
431 {
432     if (lpdwStatus) {
433         FIXME("always returning LAN connection.\n");
434         *lpdwStatus = INTERNET_CONNECTION_LAN;
435     }
436     return TRUE;
437 }
438
439 /***********************************************************************
440  *           InternetGetConnectedStateEx (WININET.@)
441  *
442  * Return connected state
443  *
444  * RETURNS
445  *    TRUE if connected
446  *    if lpdwStatus is not null, return the status (off line,
447  *    modem, lan...) in it.
448  *    FALSE if not connected
449  */
450 BOOL WINAPI InternetGetConnectedStateExW(LPDWORD lpdwStatus, LPWSTR lpszConnectionName,
451                                          DWORD dwNameLen, DWORD dwReserved)
452 {
453     /* Must be zero */
454     if(dwReserved)
455         return FALSE;
456
457     if (lpdwStatus) {
458         FIXME("always returning LAN connection.\n");
459         *lpdwStatus = INTERNET_CONNECTION_LAN;
460     }
461     return TRUE;
462 }
463
464 /***********************************************************************
465  *           InternetConnectA (WININET.@)
466  *
467  * Open a ftp, gopher or http session
468  *
469  * RETURNS
470  *    HINTERNET a session handle on success
471  *    NULL on failure
472  *
473  */
474 HINTERNET WINAPI InternetConnectA(HINTERNET hInternet,
475     LPCSTR lpszServerName, INTERNET_PORT nServerPort,
476     LPCSTR lpszUserName, LPCSTR lpszPassword,
477     DWORD dwService, DWORD dwFlags, DWORD dwContext)
478 {
479     HINTERNET rc = (HINTERNET) NULL;
480
481     TRACE("(%p, %s, %i, %s, %s, %li, %li, %li)\n", hInternet, debugstr_a(lpszServerName),
482           nServerPort, debugstr_a(lpszUserName), debugstr_a(lpszPassword),
483           dwService, dwFlags, dwContext);
484
485     /* Clear any error information */
486     INTERNET_SetLastError(0);
487
488     switch (dwService)
489     {
490         case INTERNET_SERVICE_FTP:
491             rc = FTP_Connect(hInternet, lpszServerName, nServerPort,
492             lpszUserName, lpszPassword, dwFlags, dwContext);
493             break;
494
495         case INTERNET_SERVICE_HTTP:
496             rc = HTTP_Connect(hInternet, lpszServerName, nServerPort,
497             lpszUserName, lpszPassword, dwFlags, dwContext);
498             break;
499
500         case INTERNET_SERVICE_GOPHER:
501         default:
502             break;
503     }
504
505     TRACE("returning %p\n", rc);
506     return rc;
507 }
508
509
510 /***********************************************************************
511  *           InternetConnectW (WININET.@)
512  *
513  * Open a ftp, gopher or http session
514  *
515  * RETURNS
516  *    HINTERNET a session handle on success
517  *    NULL on failure
518  *
519  */
520 HINTERNET WINAPI InternetConnectW(HINTERNET hInternet,
521     LPCWSTR lpszServerName, INTERNET_PORT nServerPort,
522     LPCWSTR lpszUserName, LPCWSTR lpszPassword,
523     DWORD dwService, DWORD dwFlags, DWORD dwContext)
524 {
525     HINTERNET rc = (HINTERNET)NULL;
526     INT lenServer = 0;
527     INT lenUser = 0;
528     INT lenPass = 0;
529     CHAR *szServerName = NULL;
530     CHAR *szUserName = NULL;
531     CHAR *szPassword = NULL;
532
533     if (lpszServerName)
534     {
535         lenServer = WideCharToMultiByte(CP_ACP, 0, lpszServerName, -1, NULL, 0,
536                             NULL, NULL);
537         szServerName = (CHAR *)HeapAlloc(GetProcessHeap(), 0, lenServer*sizeof(CHAR));
538         WideCharToMultiByte(CP_ACP, 0, lpszServerName, -1, szServerName, lenServer,
539                             NULL, NULL);
540     }
541     if (lpszUserName)
542     {
543         lenUser = WideCharToMultiByte(CP_ACP, 0, lpszUserName, -1, NULL, 0,
544                             NULL, NULL);
545         szUserName = (CHAR *)HeapAlloc(GetProcessHeap(), 0, lenUser*sizeof(CHAR));
546         WideCharToMultiByte(CP_ACP, 0, lpszUserName, -1, szUserName, lenUser,
547                             NULL, NULL);
548     }
549     if (lpszPassword)
550     {
551         lenPass = WideCharToMultiByte(CP_ACP, 0, lpszPassword, -1, NULL, 0,
552                             NULL, NULL);
553         szPassword = (CHAR *)HeapAlloc(GetProcessHeap(), 0, lenPass*sizeof(CHAR));
554         WideCharToMultiByte(CP_ACP, 0, lpszPassword, -1, szPassword, lenPass,
555                             NULL, NULL);
556     }
557
558
559     rc = InternetConnectA(hInternet, szServerName, nServerPort,
560         szUserName, szPassword, dwService, dwFlags, dwContext);
561
562     if (szServerName) HeapFree(GetProcessHeap(), 0, szServerName);
563     if (szUserName) HeapFree(GetProcessHeap(), 0, szUserName);
564     if (szPassword) HeapFree(GetProcessHeap(), 0, szPassword);
565     return rc;
566 }
567
568
569 /***********************************************************************
570  *           InternetFindNextFileA (WININET.@)
571  *
572  * Continues a file search from a previous call to FindFirstFile
573  *
574  * RETURNS
575  *    TRUE on success
576  *    FALSE on failure
577  *
578  */
579 BOOL WINAPI InternetFindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
580 {
581     LPWININETAPPINFOA hIC = NULL;
582     LPWININETFINDNEXTA lpwh = (LPWININETFINDNEXTA) hFind;
583
584     TRACE("\n");
585
586     if (NULL == lpwh || lpwh->hdr.htype != WH_HFINDNEXT)
587     {
588         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
589         return FALSE;
590     }
591
592     hIC = GET_HWININET_FROM_LPWININETFINDNEXT(lpwh);
593     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
594     {
595         WORKREQUEST workRequest;
596         struct WORKREQ_INTERNETFINDNEXTA *req;
597
598         workRequest.asyncall = INTERNETFINDNEXTA;
599         workRequest.handle = hFind;
600         req = &workRequest.u.InternetFindNextA;
601         req->lpFindFileData = lpvFindData;
602
603         return INTERNET_AsyncCall(&workRequest);
604     }
605     else
606     {
607         return INTERNET_FindNextFileA(hFind, lpvFindData);
608     }
609 }
610
611 /***********************************************************************
612  *           INTERNET_FindNextFileA (Internal)
613  *
614  * Continues a file search from a previous call to FindFirstFile
615  *
616  * RETURNS
617  *    TRUE on success
618  *    FALSE on failure
619  *
620  */
621 BOOL WINAPI INTERNET_FindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
622 {
623     BOOL bSuccess = TRUE;
624     LPWININETAPPINFOA hIC = NULL;
625     LPWIN32_FIND_DATAA lpFindFileData;
626     LPWININETFINDNEXTA lpwh = (LPWININETFINDNEXTA) hFind;
627
628     TRACE("\n");
629
630     if (NULL == lpwh || lpwh->hdr.htype != WH_HFINDNEXT)
631     {
632         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
633         return FALSE;
634     }
635
636     /* Clear any error information */
637     INTERNET_SetLastError(0);
638
639     if (lpwh->hdr.lpwhparent->htype != WH_HFTPSESSION)
640     {
641         FIXME("Only FTP find next supported\n");
642         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
643         return FALSE;
644     }
645
646     TRACE("index(%d) size(%ld)\n", lpwh->index, lpwh->size);
647
648     lpFindFileData = (LPWIN32_FIND_DATAA) lpvFindData;
649     ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
650
651     if (lpwh->index >= lpwh->size)
652     {
653         INTERNET_SetLastError(ERROR_NO_MORE_FILES);
654         bSuccess = FALSE;
655         goto lend;
656     }
657
658     FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
659     lpwh->index++;
660
661     TRACE("\nName: %s\nSize: %ld\n", lpFindFileData->cFileName, lpFindFileData->nFileSizeLow);
662
663 lend:
664
665     hIC = GET_HWININET_FROM_LPWININETFINDNEXT(lpwh);
666     if (hIC->lpfnStatusCB)
667     {
668         INTERNET_ASYNC_RESULT iar;
669
670         iar.dwResult = (DWORD)bSuccess;
671         iar.dwError = iar.dwError = bSuccess ? ERROR_SUCCESS :
672                                                INTERNET_GetLastError();
673
674         SendAsyncCallback(hIC, hFind, lpwh->hdr.dwContext,
675                       INTERNET_STATUS_REQUEST_COMPLETE, &iar,
676                        sizeof(INTERNET_ASYNC_RESULT));
677     }
678
679     return bSuccess;
680 }
681
682
683 /***********************************************************************
684  *           INTERNET_CloseHandle (internal)
685  *
686  * Close internet handle
687  *
688  * RETURNS
689  *    Void
690  *
691  */
692 VOID INTERNET_CloseHandle(LPWININETAPPINFOA lpwai)
693 {
694     TRACE("%p\n",lpwai);
695
696     SendAsyncCallback(lpwai, lpwai, lpwai->hdr.dwContext,
697                       INTERNET_STATUS_HANDLE_CLOSING, lpwai,
698                       sizeof(HINTERNET));
699
700     if (lpwai->lpszAgent)
701         HeapFree(GetProcessHeap(), 0, lpwai->lpszAgent);
702
703     if (lpwai->lpszProxy)
704         HeapFree(GetProcessHeap(), 0, lpwai->lpszProxy);
705
706     if (lpwai->lpszProxyBypass)
707         HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyBypass);
708
709     if (lpwai->lpszProxyUsername)
710         HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyUsername);
711
712     if (lpwai->lpszProxyPassword)
713         HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyPassword);
714
715     HeapFree(GetProcessHeap(), 0, lpwai);
716 }
717
718
719 /***********************************************************************
720  *           InternetCloseHandle (WININET.@)
721  *
722  * Generic close handle function
723  *
724  * RETURNS
725  *    TRUE on success
726  *    FALSE on failure
727  *
728  */
729 BOOL WINAPI InternetCloseHandle(HINTERNET hInternet)
730 {
731     BOOL retval;
732     LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hInternet;
733
734     TRACE("%p\n",hInternet);
735     if (NULL == lpwh)
736         return FALSE;
737
738     __TRY {
739         /* Clear any error information */
740         INTERNET_SetLastError(0);
741         retval = FALSE;
742
743         switch (lpwh->htype)
744         {
745             case WH_HINIT:
746                 INTERNET_CloseHandle((LPWININETAPPINFOA) lpwh);
747                 retval = TRUE;
748                 break;
749
750             case WH_HHTTPSESSION:
751                 HTTP_CloseHTTPSessionHandle((LPWININETHTTPSESSIONA) lpwh);
752                 retval = TRUE;
753                 break;
754
755             case WH_HHTTPREQ:
756                 HTTP_CloseHTTPRequestHandle((LPWININETHTTPREQA) lpwh);
757                 retval = TRUE;
758                 break;
759
760             case WH_HFTPSESSION:
761                 retval = FTP_CloseSessionHandle((LPWININETFTPSESSIONA) lpwh);
762                 break;
763
764             case WH_HFINDNEXT:
765                 retval = FTP_CloseFindNextHandle((LPWININETFINDNEXTA) lpwh);
766                 break;
767
768             case WH_HFILE:
769                 retval = FTP_CloseFileTransferHandle((LPWININETFILE) lpwh);
770                 break;
771                 
772             default:
773                 break;
774         }
775     } __EXCEPT(page_fault) {
776         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
777         return FALSE;
778     }
779     __ENDTRY
780
781     return retval;
782 }
783
784
785 /***********************************************************************
786  *           ConvertUrlComponentValue (Internal)
787  *
788  * Helper function for InternetCrackUrlW
789  *
790  */
791 void ConvertUrlComponentValue(LPSTR* lppszComponent, LPDWORD dwComponentLen,
792                               LPWSTR lpwszComponent, DWORD dwwComponentLen,
793                               LPCSTR lpszStart,
794                               LPCWSTR lpwszStart)
795 {
796     if (*dwComponentLen != 0)
797     {
798         int nASCIILength=WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,NULL,0,NULL,NULL);
799         if (*lppszComponent == NULL)
800         {
801             int nASCIIOffset=WideCharToMultiByte(CP_ACP,0,lpwszStart,lpwszComponent-lpwszStart,NULL,0,NULL,NULL);
802             *lppszComponent = (LPSTR)lpszStart+nASCIIOffset;
803             *dwComponentLen = nASCIILength;
804         }
805         else
806         {
807             INT ncpylen = min((*dwComponentLen)-1, nASCIILength);
808             WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,*lppszComponent,ncpylen+1,NULL,NULL);
809             (*lppszComponent)[ncpylen]=0;
810             *dwComponentLen = ncpylen;
811         }
812     }
813 }
814
815
816 /***********************************************************************
817  *           InternetCrackUrlA (WININET.@)
818  *
819  * Break up URL into its components
820  *
821  * TODO: Handle dwFlags
822  *
823  * RETURNS
824  *    TRUE on success
825  *    FALSE on failure
826  *
827  */
828 BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
829     LPURL_COMPONENTSA lpUrlComponents)
830 {
831   DWORD nLength;
832   URL_COMPONENTSW UCW;
833   WCHAR* lpwszUrl;
834   if(dwUrlLength==0)
835       dwUrlLength=strlen(lpszUrl);
836   lpwszUrl=HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(dwUrlLength+1));
837   memset(lpwszUrl,0,sizeof(WCHAR)*(dwUrlLength+1));
838   nLength=MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,lpwszUrl,dwUrlLength+1);
839   memset(&UCW,0,sizeof(UCW));
840   if(lpUrlComponents->dwHostNameLength!=0)
841       UCW.dwHostNameLength=1;
842   if(lpUrlComponents->dwUserNameLength!=0)
843       UCW.dwUserNameLength=1;
844   if(lpUrlComponents->dwPasswordLength!=0)
845       UCW.dwPasswordLength=1;
846   if(lpUrlComponents->dwUrlPathLength!=0)
847       UCW.dwUrlPathLength=1;
848   if(lpUrlComponents->dwSchemeLength!=0)
849       UCW.dwSchemeLength=1;
850   if(lpUrlComponents->dwExtraInfoLength!=0)
851       UCW.dwExtraInfoLength=1;
852   if(!InternetCrackUrlW(lpwszUrl,nLength,dwFlags,&UCW))
853   {
854       HeapFree(GetProcessHeap(), 0, lpwszUrl);
855       return FALSE;
856   }
857   ConvertUrlComponentValue(&lpUrlComponents->lpszHostName, &lpUrlComponents->dwHostNameLength,
858                            UCW.lpszHostName, UCW.dwHostNameLength,
859                            lpszUrl, lpwszUrl);
860   ConvertUrlComponentValue(&lpUrlComponents->lpszUserName, &lpUrlComponents->dwUserNameLength,
861                            UCW.lpszUserName, UCW.dwUserNameLength,
862                            lpszUrl, lpwszUrl);
863   ConvertUrlComponentValue(&lpUrlComponents->lpszPassword, &lpUrlComponents->dwPasswordLength,
864                            UCW.lpszPassword, UCW.dwPasswordLength,
865                            lpszUrl, lpwszUrl);
866   ConvertUrlComponentValue(&lpUrlComponents->lpszUrlPath, &lpUrlComponents->dwUrlPathLength,
867                            UCW.lpszUrlPath, UCW.dwUrlPathLength,
868                            lpszUrl, lpwszUrl);
869   ConvertUrlComponentValue(&lpUrlComponents->lpszScheme, &lpUrlComponents->dwSchemeLength,
870                            UCW.lpszScheme, UCW.dwSchemeLength,
871                            lpszUrl, lpwszUrl);
872   ConvertUrlComponentValue(&lpUrlComponents->lpszExtraInfo, &lpUrlComponents->dwExtraInfoLength,
873                            UCW.lpszExtraInfo, UCW.dwExtraInfoLength,
874                            lpszUrl, lpwszUrl);
875   lpUrlComponents->nScheme=UCW.nScheme;
876   lpUrlComponents->nPort=UCW.nPort;
877   HeapFree(GetProcessHeap(), 0, lpwszUrl);
878   
879   TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", lpszUrl,
880           debugstr_an(lpUrlComponents->lpszScheme,lpUrlComponents->dwSchemeLength),
881           debugstr_an(lpUrlComponents->lpszHostName,lpUrlComponents->dwHostNameLength),
882           debugstr_an(lpUrlComponents->lpszUrlPath,lpUrlComponents->dwUrlPathLength),
883           debugstr_an(lpUrlComponents->lpszExtraInfo,lpUrlComponents->dwExtraInfoLength));
884
885   return TRUE;
886 }
887
888 /***********************************************************************
889  *           GetInternetSchemeW (internal)
890  *
891  * Get scheme of url
892  *
893  * RETURNS
894  *    scheme on success
895  *    INTERNET_SCHEME_UNKNOWN on failure
896  *
897  */
898 INTERNET_SCHEME GetInternetSchemeW(LPCWSTR lpszScheme, INT nMaxCmp)
899 {
900     INTERNET_SCHEME iScheme=INTERNET_SCHEME_UNKNOWN;
901     WCHAR lpszFtp[]={'f','t','p',0};
902     WCHAR lpszGopher[]={'g','o','p','h','e','r',0};
903     WCHAR lpszHttp[]={'h','t','t','p',0};
904     WCHAR lpszHttps[]={'h','t','t','p','s',0};
905     WCHAR lpszFile[]={'f','i','l','e',0};
906     WCHAR lpszNews[]={'n','e','w','s',0};
907     WCHAR lpszMailto[]={'m','a','i','l','t','o',0};
908     WCHAR lpszRes[]={'r','e','s',0};
909     WCHAR* tempBuffer=NULL;
910     TRACE("\n");
911     if(lpszScheme==NULL)
912         return INTERNET_SCHEME_UNKNOWN;
913
914     tempBuffer=HeapAlloc(GetProcessHeap(),0,(nMaxCmp+1)*sizeof(WCHAR));
915     strncpyW(tempBuffer,lpszScheme,nMaxCmp);
916     tempBuffer[nMaxCmp]=0;
917     strlwrW(tempBuffer);
918     if (nMaxCmp==strlenW(lpszFtp) && !strncmpW(lpszFtp, tempBuffer, nMaxCmp))
919         iScheme=INTERNET_SCHEME_FTP;
920     else if (nMaxCmp==strlenW(lpszGopher) && !strncmpW(lpszGopher, tempBuffer, nMaxCmp))
921         iScheme=INTERNET_SCHEME_GOPHER;
922     else if (nMaxCmp==strlenW(lpszHttp) && !strncmpW(lpszHttp, tempBuffer, nMaxCmp))
923         iScheme=INTERNET_SCHEME_HTTP;
924     else if (nMaxCmp==strlenW(lpszHttps) && !strncmpW(lpszHttps, tempBuffer, nMaxCmp))
925         iScheme=INTERNET_SCHEME_HTTPS;
926     else if (nMaxCmp==strlenW(lpszFile) && !strncmpW(lpszFile, tempBuffer, nMaxCmp))
927         iScheme=INTERNET_SCHEME_FILE;
928     else if (nMaxCmp==strlenW(lpszNews) && !strncmpW(lpszNews, tempBuffer, nMaxCmp))
929         iScheme=INTERNET_SCHEME_NEWS;
930     else if (nMaxCmp==strlenW(lpszMailto) && !strncmpW(lpszMailto, tempBuffer, nMaxCmp))
931         iScheme=INTERNET_SCHEME_MAILTO;
932     else if (nMaxCmp==strlenW(lpszRes) && !strncmpW(lpszRes, tempBuffer, nMaxCmp))
933         iScheme=INTERNET_SCHEME_RES;
934     HeapFree(GetProcessHeap(),0,tempBuffer);
935     return iScheme;
936 }
937
938 /***********************************************************************
939  *           SetUrlComponentValueW (Internal)
940  *
941  * Helper function for InternetCrackUrlW
942  *
943  * RETURNS
944  *    TRUE on success
945  *    FALSE on failure
946  *
947  */
948 BOOL SetUrlComponentValueW(LPWSTR* lppszComponent, LPDWORD dwComponentLen, LPCWSTR lpszStart, INT len)
949 {
950     TRACE("%s (%d)\n", debugstr_wn(lpszStart,len), len);
951
952     if (*dwComponentLen != 0 || *lppszComponent == NULL)
953     {
954         if (*lppszComponent == NULL)
955         {
956             *lppszComponent = (LPWSTR)lpszStart;
957             *dwComponentLen = len;
958         }
959         else
960         {
961             INT ncpylen = min((*dwComponentLen)-1, len);
962             strncpyW(*lppszComponent, lpszStart, ncpylen);
963             (*lppszComponent)[ncpylen] = '\0';
964             *dwComponentLen = ncpylen;
965         }
966     }
967
968     return TRUE;
969 }
970
971 /***********************************************************************
972  *           InternetCrackUrlW   (WININET.@)
973  */
974 BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
975                               LPURL_COMPONENTSW lpUC)
976 {
977   /*
978    * RFC 1808
979    * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
980    *
981    */
982     LPWSTR lpszParam    = NULL;
983     BOOL  bIsAbsolute = FALSE;
984     LPWSTR lpszap = (WCHAR*)lpszUrl;
985     LPWSTR lpszcp = NULL;
986     WCHAR lpszSeparators[3]={';','?',0};
987     WCHAR lpszSlash[2]={'/',0};
988     if(dwUrlLength==0)
989         dwUrlLength=strlenW(lpszUrl);
990
991     TRACE("\n");
992
993     /* Determine if the URI is absolute. */
994     while (*lpszap != '\0')
995     {
996         if (isalnumW(*lpszap))
997         {
998             lpszap++;
999             continue;
1000         }
1001         if ((*lpszap == ':') && (lpszap - lpszUrl >= 2))
1002         {
1003             bIsAbsolute = TRUE;
1004             lpszcp = lpszap;
1005         }
1006         else
1007         {
1008             lpszcp = (LPWSTR)lpszUrl; /* Relative url */
1009         }
1010
1011         break;
1012     }
1013
1014     /* Parse <params> */
1015     lpszParam = strpbrkW(lpszap, lpszSeparators);
1016     if (lpszParam != NULL)
1017     {
1018         if (!SetUrlComponentValueW(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength,
1019                                    lpszParam, dwUrlLength-(lpszParam-lpszUrl)))
1020         {
1021             return FALSE;
1022         }
1023     }
1024
1025     if (bIsAbsolute) /* Parse <protocol>:[//<net_loc>] */
1026     {
1027         LPWSTR lpszNetLoc;
1028         WCHAR wszAbout[]={'a','b','o','u','t',':',0};
1029
1030         /* Get scheme first. */
1031         lpUC->nScheme = GetInternetSchemeW(lpszUrl, lpszcp - lpszUrl);
1032         if (!SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength,
1033                                    lpszUrl, lpszcp - lpszUrl))
1034             return FALSE;
1035
1036         /* Eat ':' in protocol. */
1037         lpszcp++;
1038
1039         /* if the scheme is "about", there is no host */
1040         if(strncmpW(wszAbout,lpszUrl, lpszcp - lpszUrl)==0)
1041         {
1042             SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1043             SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1044             SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
1045             lpUC->nPort = 0;
1046         }
1047         else
1048         {
1049             /* Skip over slashes. */
1050             if (*lpszcp == '/')
1051             {
1052                 lpszcp++;
1053                 if (*lpszcp == '/')
1054                 {
1055                     lpszcp++;
1056                     if (*lpszcp == '/')
1057                         lpszcp++;
1058                 }
1059             }
1060
1061             lpszNetLoc = strpbrkW(lpszcp, lpszSlash);
1062             if (lpszParam)
1063             {
1064                 if (lpszNetLoc)
1065                     lpszNetLoc = min(lpszNetLoc, lpszParam);
1066                 else
1067                     lpszNetLoc = lpszParam;
1068             }
1069             else if (!lpszNetLoc)
1070                 lpszNetLoc = lpszcp + dwUrlLength-(lpszcp-lpszUrl);
1071
1072             /* Parse net-loc */
1073             if (lpszNetLoc)
1074             {
1075                 LPWSTR lpszHost;
1076                 LPWSTR lpszPort;
1077
1078                 /* [<user>[<:password>]@]<host>[:<port>] */
1079                 /* First find the user and password if they exist */
1080
1081                 lpszHost = strchrW(lpszcp, '@');
1082                 if (lpszHost == NULL || lpszHost > lpszNetLoc)
1083                 {
1084                     /* username and password not specified. */
1085                     SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1086                     SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1087                 }
1088                 else /* Parse out username and password */
1089                 {
1090                     LPWSTR lpszUser = lpszcp;
1091                     LPWSTR lpszPasswd = lpszHost;
1092
1093                     while (lpszcp < lpszHost)
1094                     {
1095                         if (*lpszcp == ':')
1096                             lpszPasswd = lpszcp;
1097
1098                         lpszcp++;
1099                     }
1100
1101                     SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength,
1102                                           lpszUser, lpszPasswd - lpszUser);
1103
1104                     if (lpszPasswd != lpszHost)
1105                         lpszPasswd++;
1106                     SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength,
1107                                           lpszPasswd == lpszHost ? NULL : lpszPasswd,
1108                                           lpszHost - lpszPasswd);
1109
1110                     lpszcp++; /* Advance to beginning of host */
1111                 }
1112
1113                 /* Parse <host><:port> */
1114
1115                 lpszHost = lpszcp;
1116                 lpszPort = lpszNetLoc;
1117
1118                 /* special case for res:// URLs: there is no port here, so the host is the
1119                    entire string up to the first '/' */
1120                 if(lpUC->nScheme==INTERNET_SCHEME_RES)
1121                 {
1122                     SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1123                                           lpszHost, lpszPort - lpszHost);
1124                     lpUC->nPort = 0;
1125                     lpszcp=lpszNetLoc;
1126                 }
1127                 else
1128                 {
1129                     while (lpszcp < lpszNetLoc)
1130                     {
1131                         if (*lpszcp == ':')
1132                             lpszPort = lpszcp;
1133
1134                         lpszcp++;
1135                     }
1136
1137                     /* If the scheme is "file" and the host is just one letter, it's not a host */
1138                     if(lpUC->nScheme==INTERNET_SCHEME_FILE && (lpszPort-lpszHost)==1)
1139                     {
1140                         lpszcp=lpszHost;
1141                         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1142                                               NULL, 0);
1143                         lpUC->nPort = 0;
1144                     }
1145                     else
1146                     {
1147                         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1148                                               lpszHost, lpszPort - lpszHost);
1149                         if (lpszPort != lpszNetLoc)
1150                             lpUC->nPort = atoiW(++lpszPort);
1151                         else
1152                             lpUC->nPort = 0;
1153                     }
1154                 }
1155             }
1156         }
1157     }
1158
1159     /* Here lpszcp points to:
1160      *
1161      * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1162      *                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1163      */
1164     if (lpszcp != 0 && *lpszcp != '\0' && (!lpszParam || lpszcp < lpszParam))
1165     {
1166         INT len;
1167
1168         /* Only truncate the parameter list if it's already been saved
1169          * in lpUC->lpszExtraInfo.
1170          */
1171         if (lpszParam && lpUC->dwExtraInfoLength)
1172             len = lpszParam - lpszcp;
1173         else
1174         {
1175             /* Leave the parameter list in lpszUrlPath.  Strip off any trailing
1176              * newlines if necessary.
1177              */
1178             LPWSTR lpsznewline = strchrW(lpszcp, '\n');
1179             if (lpsznewline != NULL)
1180                 len = lpsznewline - lpszcp;
1181             else
1182                 len = dwUrlLength-(lpszcp-lpszUrl);
1183         }
1184
1185         if (!SetUrlComponentValueW(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength,
1186                                    lpszcp, len))
1187             return FALSE;
1188     }
1189     else
1190     {
1191         lpUC->dwUrlPathLength = 0;
1192     }
1193
1194     TRACE("%s: host(%s) path(%s) extra(%s)\n", debugstr_wn(lpszUrl,dwUrlLength),
1195              debugstr_wn(lpUC->lpszHostName,lpUC->dwHostNameLength),
1196              debugstr_wn(lpUC->lpszUrlPath,lpUC->dwUrlPathLength),
1197              debugstr_wn(lpUC->lpszExtraInfo,lpUC->dwExtraInfoLength));
1198
1199     return TRUE;
1200 }
1201
1202 /***********************************************************************
1203  *           InternetAttemptConnect (WININET.@)
1204  *
1205  * Attempt to make a connection to the internet
1206  *
1207  * RETURNS
1208  *    ERROR_SUCCESS on success
1209  *    Error value   on failure
1210  *
1211  */
1212 DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
1213 {
1214     FIXME("Stub\n");
1215     return ERROR_SUCCESS;
1216 }
1217
1218
1219 /***********************************************************************
1220  *           InternetCanonicalizeUrlA (WININET.@)
1221  *
1222  * Escape unsafe characters and spaces
1223  *
1224  * RETURNS
1225  *    TRUE on success
1226  *    FALSE on failure
1227  *
1228  */
1229 BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
1230         LPDWORD lpdwBufferLength, DWORD dwFlags)
1231 {
1232     HRESULT hr;
1233     TRACE("%s %p %p %08lx\n",debugstr_a(lpszUrl), lpszBuffer,
1234           lpdwBufferLength, dwFlags);
1235
1236     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1237     dwFlags ^= ICU_NO_ENCODE;
1238
1239     dwFlags |= 0x80000000; /* Don't know what this means */
1240
1241     hr = UrlCanonicalizeA(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
1242
1243     return (hr == S_OK) ? TRUE : FALSE;
1244 }
1245
1246 /***********************************************************************
1247  *           InternetCanonicalizeUrlW (WININET.@)
1248  *
1249  * Escape unsafe characters and spaces
1250  *
1251  * RETURNS
1252  *    TRUE on success
1253  *    FALSE on failure
1254  *
1255  */
1256 BOOL WINAPI InternetCanonicalizeUrlW(LPCWSTR lpszUrl, LPWSTR lpszBuffer,
1257     LPDWORD lpdwBufferLength, DWORD dwFlags)
1258 {
1259     HRESULT hr;
1260     TRACE("%s %p %p %08lx\n", debugstr_w(lpszUrl), lpszBuffer,
1261         lpdwBufferLength, dwFlags);
1262
1263     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1264     dwFlags ^= ICU_NO_ENCODE;
1265
1266     dwFlags |= 0x80000000; /* Don't know what this means */
1267
1268     hr = UrlCanonicalizeW(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
1269
1270     return (hr == S_OK) ? TRUE : FALSE;
1271 }
1272
1273
1274 /***********************************************************************
1275  *           InternetSetStatusCallbackA (WININET.@)
1276  *
1277  * Sets up a callback function which is called as progress is made
1278  * during an operation.
1279  *
1280  * RETURNS
1281  *    Previous callback or NULL         on success
1282  *    INTERNET_INVALID_STATUS_CALLBACK  on failure
1283  *
1284  */
1285 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackA(
1286         HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
1287 {
1288     INTERNET_STATUS_CALLBACK retVal;
1289     LPWININETAPPINFOA lpwai = (LPWININETAPPINFOA)hInternet;
1290
1291     TRACE("0x%08lx\n", (ULONG)hInternet);
1292     if (lpwai->hdr.htype != WH_HINIT)
1293         return INTERNET_INVALID_STATUS_CALLBACK;
1294
1295     retVal = lpwai->lpfnStatusCB;
1296     lpwai->lpfnStatusCB = lpfnIntCB;
1297
1298     return retVal;
1299 }
1300
1301 /***********************************************************************
1302  *           InternetSetFilePointer (WININET.@)
1303  */
1304 DWORD WINAPI InternetSetFilePointer(HINTERNET f1, LONG f2, PVOID f3, DWORD f4, DWORD f5)
1305 {
1306     FIXME("stub\n");
1307     return FALSE;
1308 }
1309
1310 /***********************************************************************
1311  *           InternetWriteFile (WININET.@)
1312  *
1313  * Write data to an open internet file
1314  *
1315  * RETURNS
1316  *    TRUE  on success
1317  *    FALSE on failure
1318  *
1319  */
1320 BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer ,
1321         DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
1322 {
1323     BOOL retval = FALSE;
1324     int nSocket = -1;
1325     LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hFile;
1326
1327     TRACE("\n");
1328     if (NULL == lpwh)
1329         return FALSE;
1330
1331     switch (lpwh->htype)
1332     {
1333         case WH_HHTTPREQ:
1334             FIXME("This shouldn't be here! We don't support this kind"
1335                   " of connection anymore. Must use NETCON functions,"
1336                   " especially if using SSL\n");
1337             nSocket = ((LPWININETHTTPREQA)hFile)->netConnection.socketFD;
1338             break;
1339
1340         case WH_HFILE:
1341             nSocket = ((LPWININETFILE)hFile)->nDataSocket;
1342             break;
1343
1344         default:
1345             break;
1346     }
1347
1348     if (nSocket != -1)
1349     {
1350         int res = send(nSocket, lpBuffer, dwNumOfBytesToWrite, 0);
1351         retval = (res >= 0);
1352         *lpdwNumOfBytesWritten = retval ? res : 0;
1353     }
1354
1355     return retval;
1356 }
1357
1358
1359 /***********************************************************************
1360  *           InternetReadFile (WININET.@)
1361  *
1362  * Read data from an open internet file
1363  *
1364  * RETURNS
1365  *    TRUE  on success
1366  *    FALSE on failure
1367  *
1368  */
1369 BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
1370         DWORD dwNumOfBytesToRead, LPDWORD dwNumOfBytesRead)
1371 {
1372     BOOL retval = FALSE;
1373     int nSocket = -1;
1374     LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hFile;
1375
1376     TRACE("\n");
1377
1378     if (NULL == lpwh)
1379         return FALSE;
1380
1381     /* FIXME: this should use NETCON functions! */
1382     switch (lpwh->htype)
1383     {
1384         case WH_HHTTPREQ:
1385             if (!NETCON_recv(&((LPWININETHTTPREQA)hFile)->netConnection, lpBuffer,
1386                              dwNumOfBytesToRead, 0, (int *)dwNumOfBytesRead))
1387             {
1388                 *dwNumOfBytesRead = 0;
1389                 retval = TRUE; /* Under windows, it seems to return 0 even if nothing was read... */
1390             }
1391             else
1392                 retval = TRUE;
1393             break;
1394
1395         case WH_HFILE:
1396             /* FIXME: FTP should use NETCON_ stuff */
1397             nSocket = ((LPWININETFILE)hFile)->nDataSocket;
1398             if (nSocket != -1)
1399             {
1400                 int res = recv(nSocket, lpBuffer, dwNumOfBytesToRead, 0);
1401                 retval = (res >= 0);
1402                 *dwNumOfBytesRead = retval ? res : 0;
1403             }
1404             break;
1405
1406         default:
1407             break;
1408     }
1409
1410     return retval;
1411 }
1412
1413 /***********************************************************************
1414  *           InternetReadFileExA (WININET.@)
1415  *
1416  * Read data from an open internet file
1417  *
1418  * RETURNS
1419  *    TRUE  on success
1420  *    FALSE on failure
1421  *
1422  */
1423 BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffer,
1424         DWORD dwFlags, DWORD dwContext)
1425 {
1426   FIXME("stub\n");
1427   return FALSE;
1428 }
1429
1430 /***********************************************************************
1431  *           InternetReadFileExW (WININET.@)
1432  *
1433  * Read data from an open internet file
1434  *
1435  * RETURNS
1436  *    TRUE  on success
1437  *    FALSE on failure
1438  *
1439  */
1440 BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer,
1441         DWORD dwFlags, DWORD dwContext)
1442 {
1443   FIXME("stub\n");
1444
1445   INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1446   return FALSE;
1447 }
1448
1449 /***********************************************************************
1450  *           INET_QueryOptionHelper (internal)
1451  */
1452 static BOOL INET_QueryOptionHelper(BOOL bIsUnicode, HINTERNET hInternet, DWORD dwOption,
1453                                    LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1454 {
1455     LPWININETHANDLEHEADER lpwhh;
1456     BOOL bSuccess = FALSE;
1457
1458     TRACE("(%p, 0x%08lx, %p, %p)\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
1459
1460     if (NULL == hInternet)
1461     {
1462         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1463         return FALSE;
1464     }
1465
1466     lpwhh = (LPWININETHANDLEHEADER) hInternet;
1467
1468     switch (dwOption)
1469     {
1470         case INTERNET_OPTION_HANDLE_TYPE:
1471         {
1472             ULONG type = lpwhh->htype;
1473             TRACE("INTERNET_OPTION_HANDLE_TYPE: %ld\n", type);
1474
1475             if (*lpdwBufferLength < sizeof(ULONG))
1476                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1477             else
1478             {
1479                 memcpy(lpBuffer, &type, sizeof(ULONG));
1480                     *lpdwBufferLength = sizeof(ULONG);
1481                 bSuccess = TRUE;
1482             }
1483             break;
1484         }
1485
1486         case INTERNET_OPTION_REQUEST_FLAGS:
1487         {
1488             ULONG flags = 4;
1489             TRACE("INTERNET_OPTION_REQUEST_FLAGS: %ld\n", flags);
1490             if (*lpdwBufferLength < sizeof(ULONG))
1491                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1492             else
1493             {
1494                 memcpy(lpBuffer, &flags, sizeof(ULONG));
1495                     *lpdwBufferLength = sizeof(ULONG);
1496                 bSuccess = TRUE;
1497             }
1498             break;
1499         }
1500
1501         case INTERNET_OPTION_URL:
1502         case INTERNET_OPTION_DATAFILE_NAME:
1503         {
1504             ULONG type = lpwhh->htype;
1505             if (type == WH_HHTTPREQ)
1506             {
1507                 LPWININETHTTPREQA lpreq = hInternet;
1508                 char url[1023];
1509
1510                 sprintf(url,"http://%s%s",lpreq->lpszHostName,lpreq->lpszPath);
1511                 TRACE("INTERNET_OPTION_URL: %s\n",url);
1512                 if (*lpdwBufferLength < strlen(url)+1)
1513                     INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1514                 else
1515                 {
1516                     if(bIsUnicode)
1517                     {
1518                         *lpdwBufferLength=MultiByteToWideChar(CP_ACP,0,url,-1,lpBuffer,*lpdwBufferLength);
1519                     }
1520                     else
1521                     {
1522                         memcpy(lpBuffer, url, strlen(url)+1);
1523                         *lpdwBufferLength = strlen(url)+1;
1524                     }
1525                     bSuccess = TRUE;
1526                 }
1527             }
1528             break;
1529         }
1530        case INTERNET_OPTION_HTTP_VERSION:
1531        {
1532             /*
1533              * Presently hardcoded to 1.1
1534              */
1535             ((HTTP_VERSION_INFO*)lpBuffer)->dwMajorVersion = 1;
1536             ((HTTP_VERSION_INFO*)lpBuffer)->dwMinorVersion = 1;
1537             bSuccess = TRUE;
1538         break;
1539        }
1540
1541        default:
1542          FIXME("Stub! %ld \n",dwOption);
1543          break;
1544     }
1545
1546     return bSuccess;
1547 }
1548
1549 /***********************************************************************
1550  *           InternetQueryOptionW (WININET.@)
1551  *
1552  * Queries an options on the specified handle
1553  *
1554  * RETURNS
1555  *    TRUE  on success
1556  *    FALSE on failure
1557  *
1558  */
1559 BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption,
1560                                  LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1561 {
1562     return INET_QueryOptionHelper(TRUE, hInternet, dwOption, lpBuffer, lpdwBufferLength);
1563 }
1564
1565 /***********************************************************************
1566  *           InternetQueryOptionA (WININET.@)
1567  *
1568  * Queries an options on the specified handle
1569  *
1570  * RETURNS
1571  *    TRUE  on success
1572  *    FALSE on failure
1573  *
1574  */
1575 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
1576                                  LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1577 {
1578     return INET_QueryOptionHelper(FALSE, hInternet, dwOption, lpBuffer, lpdwBufferLength);
1579 }
1580
1581
1582 /***********************************************************************
1583  *           InternetSetOptionW (WININET.@)
1584  *
1585  * Sets an options on the specified handle
1586  *
1587  * RETURNS
1588  *    TRUE  on success
1589  *    FALSE on failure
1590  *
1591  */
1592 BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
1593                            LPVOID lpBuffer, DWORD dwBufferLength)
1594 {
1595     LPWININETHANDLEHEADER lpwhh;
1596
1597     TRACE("0x%08lx\n", dwOption);
1598
1599     if (NULL == hInternet)
1600     {
1601         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1602         return FALSE;
1603     }
1604
1605     lpwhh = (LPWININETHANDLEHEADER) hInternet;
1606
1607     switch (dwOption)
1608     {
1609     case INTERNET_OPTION_HTTP_VERSION:
1610       {
1611         HTTP_VERSION_INFO* pVersion=(HTTP_VERSION_INFO*)lpBuffer;
1612         FIXME("Option INTERNET_OPTION_HTTP_VERSION(%ld,%ld): STUB\n",pVersion->dwMajorVersion,pVersion->dwMinorVersion);
1613       }
1614       break;
1615     case INTERNET_OPTION_ERROR_MASK:
1616       {
1617         unsigned long flags=*(unsigned long*)lpBuffer;
1618         FIXME("Option INTERNET_OPTION_ERROR_MASK(%ld): STUB\n",flags);
1619       }
1620       break;
1621     case INTERNET_OPTION_CODEPAGE:
1622       {
1623         unsigned long codepage=*(unsigned long*)lpBuffer;
1624         FIXME("Option INTERNET_OPTION_CODEPAGE (%ld): STUB\n",codepage);
1625       }
1626       break;
1627     case INTERNET_OPTION_REQUEST_PRIORITY:
1628       {
1629         unsigned long priority=*(unsigned long*)lpBuffer;
1630         FIXME("Option INTERNET_OPTION_REQUEST_PRIORITY (%ld): STUB\n",priority);
1631       }
1632       break;
1633     default:
1634         FIXME("Option %ld STUB\n",dwOption);
1635         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1636         return FALSE;
1637     }
1638
1639     return TRUE;
1640 }
1641
1642
1643 /***********************************************************************
1644  *           InternetSetOptionA (WININET.@)
1645  *
1646  * Sets an options on the specified handle.
1647  *
1648  * RETURNS
1649  *    TRUE  on success
1650  *    FALSE on failure
1651  *
1652  */
1653 BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
1654                            LPVOID lpBuffer, DWORD dwBufferLength)
1655 {
1656     LPVOID wbuffer;
1657     DWORD wlen;
1658     BOOL r;
1659
1660     switch( dwOption )
1661     {
1662     case INTERNET_OPTION_PROXY:
1663         {
1664         LPINTERNET_PROXY_INFOA pi = (LPINTERNET_PROXY_INFOA) lpBuffer;
1665         LPINTERNET_PROXY_INFOW piw;
1666         DWORD proxlen, prbylen;
1667         LPWSTR prox, prby;
1668
1669         proxlen = MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, NULL, 0);
1670         prbylen= MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, NULL, 0);
1671         wlen = sizeof(*piw) + proxlen + prbylen;
1672         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
1673         piw = (LPINTERNET_PROXY_INFOW) wbuffer;
1674         piw->dwAccessType = pi->dwAccessType;
1675         prox = (LPWSTR) &piw[1];
1676         prby = &prox[proxlen+1];
1677         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, prox, proxlen);
1678         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, prby, prbylen);
1679         piw->lpszProxy = prox;
1680         piw->lpszProxyBypass = prby;
1681         }
1682         break;
1683     case INTERNET_OPTION_USER_AGENT:
1684     case INTERNET_OPTION_USERNAME:
1685     case INTERNET_OPTION_PASSWORD:
1686         wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
1687                                    NULL, 0 );
1688         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
1689         MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
1690                                    wbuffer, wlen );
1691         break;
1692     default:
1693         wbuffer = lpBuffer;
1694         wlen = dwBufferLength;
1695     }
1696
1697     r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen);
1698
1699     if( lpBuffer != wbuffer )
1700         HeapFree( GetProcessHeap(), 0, wbuffer );
1701
1702     return r;
1703 }
1704
1705
1706 /***********************************************************************
1707  *           InternetSetOptionExA (WININET.@)
1708  */
1709 BOOL WINAPI InternetSetOptionExA(HINTERNET hInternet, DWORD dwOption,
1710                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
1711 {
1712     FIXME("Flags %08lx ignored\n", dwFlags);
1713     return InternetSetOptionA( hInternet, dwOption, lpBuffer, dwBufferLength );
1714 }
1715
1716 /***********************************************************************
1717  *           InternetSetOptionExW (WININET.@)
1718  */
1719 BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption,
1720                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
1721 {
1722     FIXME("Flags %08lx ignored\n", dwFlags);
1723     if( dwFlags & ~ISO_VALID_FLAGS )
1724     {
1725         SetLastError( ERROR_INVALID_PARAMETER );
1726         return FALSE;
1727     }
1728     return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength );
1729 }
1730
1731
1732 /***********************************************************************
1733  *      InternetCheckConnectionA (WININET.@)
1734  *
1735  * Pings a requested host to check internet connection
1736  *
1737  * RETURNS
1738  *   TRUE on success and FALSE on failure. If a failure then
1739  *   ERROR_NOT_CONNECTED is placesd into GetLastError
1740  *
1741  */
1742 BOOL WINAPI InternetCheckConnectionA( LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
1743 {
1744 /*
1745  * this is a kludge which runs the resident ping program and reads the output.
1746  *
1747  * Anyone have a better idea?
1748  */
1749
1750   BOOL   rc = FALSE;
1751   char command[1024];
1752   char host[1024];
1753   int status = -1;
1754
1755   FIXME("\n");
1756
1757   /*
1758    * Crack or set the Address
1759    */
1760   if (lpszUrl == NULL)
1761   {
1762      /*
1763       * According to the doc we are supost to use the ip for the next
1764       * server in the WnInet internal server database. I have
1765       * no idea what that is or how to get it.
1766       *
1767       * So someone needs to implement this.
1768       */
1769      FIXME("Unimplemented with URL of NULL\n");
1770      return TRUE;
1771   }
1772   else
1773   {
1774      URL_COMPONENTSA componets;
1775
1776      ZeroMemory(&componets,sizeof(URL_COMPONENTSA));
1777      componets.lpszHostName = (LPSTR)&host;
1778      componets.dwHostNameLength = 1024;
1779
1780      if (!InternetCrackUrlA(lpszUrl,0,0,&componets))
1781        goto End;
1782
1783      TRACE("host name : %s\n",componets.lpszHostName);
1784   }
1785
1786   /*
1787    * Build our ping command
1788    */
1789   strcpy(command,"ping -w 1 ");
1790   strcat(command,host);
1791   strcat(command," >/dev/null 2>/dev/null");
1792
1793   TRACE("Ping command is : %s\n",command);
1794
1795   status = system(command);
1796
1797   TRACE("Ping returned a code of %i \n",status);
1798
1799   /* Ping return code of 0 indicates success */
1800   if (status == 0)
1801      rc = TRUE;
1802
1803 End:
1804
1805   if (rc == FALSE)
1806     SetLastError(ERROR_NOT_CONNECTED);
1807
1808   return rc;
1809 }
1810
1811
1812 /***********************************************************************
1813  *      InternetCheckConnectionW (WININET.@)
1814  *
1815  * Pings a requested host to check internet connection
1816  *
1817  * RETURNS
1818  *   TRUE on success and FALSE on failure. If a failure then
1819  *   ERROR_NOT_CONNECTED is placed into GetLastError
1820  *
1821  */
1822 BOOL WINAPI InternetCheckConnectionW(LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
1823 {
1824     CHAR *szUrl;
1825     INT len;
1826     BOOL rc;
1827
1828     len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
1829     if (!(szUrl = (CHAR *)HeapAlloc(GetProcessHeap(), 0, len*sizeof(CHAR))))
1830         return FALSE;
1831     WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, szUrl, len, NULL, NULL);
1832     rc = InternetCheckConnectionA((LPCSTR)szUrl, dwFlags, dwReserved);
1833     HeapFree(GetProcessHeap(), 0, szUrl);
1834     
1835     return rc;
1836 }
1837
1838
1839 /**********************************************************
1840  *      InternetOpenUrlA (WININET.@)
1841  *
1842  * Opens an URL
1843  *
1844  * RETURNS
1845  *   handle of connection or NULL on failure
1846  */
1847 HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
1848     LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
1849 {
1850   URL_COMPONENTSA urlComponents;
1851   char protocol[32], hostName[MAXHOSTNAME], userName[1024];
1852   char password[1024], path[2048], extra[1024];
1853   HINTERNET client = NULL, client1 = NULL;
1854
1855   TRACE("(%p, %s, %s, %08lx, %08lx, %08lx\n", hInternet, debugstr_a(lpszUrl), debugstr_a(lpszHeaders),
1856        dwHeadersLength, dwFlags, dwContext);
1857
1858   urlComponents.dwStructSize = sizeof(URL_COMPONENTSA);
1859   urlComponents.lpszScheme = protocol;
1860   urlComponents.dwSchemeLength = 32;
1861   urlComponents.lpszHostName = hostName;
1862   urlComponents.dwHostNameLength = MAXHOSTNAME;
1863   urlComponents.lpszUserName = userName;
1864   urlComponents.dwUserNameLength = 1024;
1865   urlComponents.lpszPassword = password;
1866   urlComponents.dwPasswordLength = 1024;
1867   urlComponents.lpszUrlPath = path;
1868   urlComponents.dwUrlPathLength = 2048;
1869   urlComponents.lpszExtraInfo = extra;
1870   urlComponents.dwExtraInfoLength = 1024;
1871   if(!InternetCrackUrlA(lpszUrl, strlen(lpszUrl), 0, &urlComponents))
1872     return NULL;
1873   switch(urlComponents.nScheme) {
1874   case INTERNET_SCHEME_FTP:
1875     if(urlComponents.nPort == 0)
1876       urlComponents.nPort = INTERNET_DEFAULT_FTP_PORT;
1877     client = InternetConnectA(hInternet, hostName, urlComponents.nPort,
1878         userName, password, INTERNET_SERVICE_FTP, dwFlags, dwContext);
1879     return FtpOpenFileA(client, path, GENERIC_READ, dwFlags, dwContext);
1880   case INTERNET_SCHEME_HTTP:
1881   case INTERNET_SCHEME_HTTPS:
1882   {
1883     LPCSTR accept[2] = { "*/*", NULL };
1884     if(urlComponents.nPort == 0) {
1885       if(urlComponents.nScheme == INTERNET_SCHEME_HTTP)
1886         urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
1887       else
1888         urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
1889     }
1890     client = InternetConnectA(hInternet, hostName, urlComponents.nPort, userName,
1891         password, INTERNET_SERVICE_HTTP, dwFlags, dwContext);
1892     if(client == NULL)
1893       return NULL;
1894     client1 = HttpOpenRequestA(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
1895     if(client1 == NULL) {
1896       InternetCloseHandle(client);
1897       return NULL;
1898     }
1899     HttpAddRequestHeadersA(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
1900     if(!HttpSendRequestA(client1, NULL, 0, NULL, 0)) {
1901       InternetCloseHandle(client1);
1902       InternetCloseHandle(client);
1903       return NULL;
1904     }
1905     return client1;
1906   }
1907   case INTERNET_SCHEME_GOPHER:
1908     /* gopher doesn't seem to be implemented in wine, but it's supposed
1909      * to be supported by InternetOpenUrlA. */
1910   default:
1911     return NULL;
1912   }
1913 }
1914
1915
1916 /**********************************************************
1917  *      InternetOpenUrlW (WININET.@)
1918  *
1919  * Opens an URL
1920  *
1921  * RETURNS
1922  *   handle of connection or NULL on failure
1923  */
1924 HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
1925     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
1926 {
1927     HINTERNET rc = (HINTERNET)NULL;
1928
1929     INT lenUrl = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
1930     INT lenHeaders = WideCharToMultiByte(CP_ACP, 0, lpszHeaders, -1, NULL, 0, NULL, NULL);
1931     CHAR *szUrl = (CHAR *)HeapAlloc(GetProcessHeap(), 0, lenUrl*sizeof(CHAR));
1932     CHAR *szHeaders = (CHAR *)HeapAlloc(GetProcessHeap(), 0, lenHeaders*sizeof(CHAR));
1933
1934     if (!szUrl || !szHeaders)
1935     {
1936         if (szUrl)
1937             HeapFree(GetProcessHeap(), 0, szUrl);
1938         if (szHeaders)
1939             HeapFree(GetProcessHeap(), 0, szHeaders);
1940         return (HINTERNET)NULL;
1941     }
1942
1943     WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, szUrl, lenUrl,
1944         NULL, NULL);
1945     WideCharToMultiByte(CP_ACP, 0, lpszHeaders, -1, szHeaders, lenHeaders,
1946         NULL, NULL);
1947
1948     rc = InternetOpenUrlA(hInternet, szUrl, szHeaders,
1949         dwHeadersLength, dwFlags, dwContext);
1950
1951     HeapFree(GetProcessHeap(), 0, szUrl);
1952     HeapFree(GetProcessHeap(), 0, szHeaders);
1953
1954     return rc;
1955 }
1956
1957
1958 /***********************************************************************
1959  *           INTERNET_SetLastError (internal)
1960  *
1961  * Set last thread specific error
1962  *
1963  * RETURNS
1964  *
1965  */
1966 void INTERNET_SetLastError(DWORD dwError)
1967 {
1968     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
1969
1970     SetLastError(dwError);
1971     if(lpwite)
1972         lpwite->dwError = dwError;
1973 }
1974
1975
1976 /***********************************************************************
1977  *           INTERNET_GetLastError (internal)
1978  *
1979  * Get last thread specific error
1980  *
1981  * RETURNS
1982  *
1983  */
1984 DWORD INTERNET_GetLastError()
1985 {
1986     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
1987     return lpwite->dwError;
1988 }
1989
1990
1991 /***********************************************************************
1992  *           INTERNET_WorkerThreadFunc (internal)
1993  *
1994  * Worker thread execution function
1995  *
1996  * RETURNS
1997  *
1998  */
1999 DWORD INTERNET_WorkerThreadFunc(LPVOID *lpvParam)
2000 {
2001     DWORD dwWaitRes;
2002
2003     while (1)
2004     {
2005         if(dwNumJobs > 0) {
2006             INTERNET_ExecuteWork();
2007             continue;
2008         }
2009         dwWaitRes = WaitForMultipleObjects(2, hEventArray, FALSE, MAX_IDLE_WORKER);
2010
2011         if (dwWaitRes == WAIT_OBJECT_0 + 1)
2012             INTERNET_ExecuteWork();
2013         else
2014             break;
2015
2016         InterlockedIncrement(&dwNumIdleThreads);
2017     }
2018
2019     InterlockedDecrement(&dwNumIdleThreads);
2020     InterlockedDecrement(&dwNumThreads);
2021     TRACE("Worker thread exiting\n");
2022     return TRUE;
2023 }
2024
2025
2026 /***********************************************************************
2027  *           INTERNET_InsertWorkRequest (internal)
2028  *
2029  * Insert work request into queue
2030  *
2031  * RETURNS
2032  *
2033  */
2034 BOOL INTERNET_InsertWorkRequest(LPWORKREQUEST lpWorkRequest)
2035 {
2036     BOOL bSuccess = FALSE;
2037     LPWORKREQUEST lpNewRequest;
2038
2039     TRACE("\n");
2040
2041     lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
2042     if (lpNewRequest)
2043     {
2044         memcpy(lpNewRequest, lpWorkRequest, sizeof(WORKREQUEST));
2045         lpNewRequest->prev = NULL;
2046
2047         EnterCriticalSection(&csQueue);
2048
2049         lpNewRequest->next = lpWorkQueueTail;
2050         if (lpWorkQueueTail)
2051             lpWorkQueueTail->prev = lpNewRequest;
2052         lpWorkQueueTail = lpNewRequest;
2053         if (!lpHeadWorkQueue)
2054             lpHeadWorkQueue = lpWorkQueueTail;
2055
2056         LeaveCriticalSection(&csQueue);
2057
2058         bSuccess = TRUE;
2059         InterlockedIncrement(&dwNumJobs);
2060     }
2061
2062     return bSuccess;
2063 }
2064
2065
2066 /***********************************************************************
2067  *           INTERNET_GetWorkRequest (internal)
2068  *
2069  * Retrieves work request from queue
2070  *
2071  * RETURNS
2072  *
2073  */
2074 BOOL INTERNET_GetWorkRequest(LPWORKREQUEST lpWorkRequest)
2075 {
2076     BOOL bSuccess = FALSE;
2077     LPWORKREQUEST lpRequest = NULL;
2078
2079     TRACE("\n");
2080
2081     EnterCriticalSection(&csQueue);
2082
2083     if (lpHeadWorkQueue)
2084     {
2085         lpRequest = lpHeadWorkQueue;
2086         lpHeadWorkQueue = lpHeadWorkQueue->prev;
2087         if (lpRequest == lpWorkQueueTail)
2088             lpWorkQueueTail = lpHeadWorkQueue;
2089     }
2090
2091     LeaveCriticalSection(&csQueue);
2092
2093     if (lpRequest)
2094     {
2095         memcpy(lpWorkRequest, lpRequest, sizeof(WORKREQUEST));
2096         HeapFree(GetProcessHeap(), 0, lpRequest);
2097         bSuccess = TRUE;
2098         InterlockedDecrement(&dwNumJobs);
2099     }
2100
2101     return bSuccess;
2102 }
2103
2104
2105 /***********************************************************************
2106  *           INTERNET_AsyncCall (internal)
2107  *
2108  * Retrieves work request from queue
2109  *
2110  * RETURNS
2111  *
2112  */
2113 BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
2114 {
2115     HANDLE hThread;
2116     DWORD dwTID;
2117     BOOL bSuccess = FALSE;
2118
2119     TRACE("\n");
2120
2121     if (InterlockedDecrement(&dwNumIdleThreads) < 0)
2122     {
2123         InterlockedIncrement(&dwNumIdleThreads);
2124
2125         if (InterlockedIncrement(&dwNumThreads) > MAX_WORKER_THREADS ||
2126             !(hThread = CreateThread(NULL, 0,
2127             (LPTHREAD_START_ROUTINE)INTERNET_WorkerThreadFunc, NULL, 0, &dwTID)))
2128         {
2129             InterlockedDecrement(&dwNumThreads);
2130             INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED);
2131             goto lerror;
2132         }
2133
2134         TRACE("Created new thread\n");
2135     }
2136
2137     bSuccess = TRUE;
2138     INTERNET_InsertWorkRequest(lpWorkRequest);
2139     SetEvent(hWorkEvent);
2140
2141 lerror:
2142
2143     return bSuccess;
2144 }
2145
2146
2147 /***********************************************************************
2148  *           INTERNET_ExecuteWork (internal)
2149  *
2150  * RETURNS
2151  *
2152  */
2153 VOID INTERNET_ExecuteWork()
2154 {
2155     WORKREQUEST workRequest;
2156
2157     TRACE("\n");
2158
2159     if (!INTERNET_GetWorkRequest(&workRequest))
2160         return;
2161     TRACE("Got work %d\n", workRequest.asyncall);
2162     switch (workRequest.asyncall)
2163     {
2164     case FTPPUTFILEA:
2165         {
2166         struct WORKREQ_FTPPUTFILEA *req = &workRequest.u.FtpPutFileA;
2167
2168         FTP_FtpPutFileA(workRequest.handle, req->lpszLocalFile,
2169                    req->lpszNewRemoteFile, req->dwFlags, req->dwContext);
2170
2171         HeapFree(GetProcessHeap(), 0, req->lpszLocalFile);
2172         HeapFree(GetProcessHeap(), 0, req->lpszNewRemoteFile);
2173         }
2174         break;
2175
2176     case FTPSETCURRENTDIRECTORYA:
2177         {
2178         struct WORKREQ_FTPSETCURRENTDIRECTORYA *req;
2179
2180         req = &workRequest.u.FtpSetCurrentDirectoryA;
2181         FTP_FtpSetCurrentDirectoryA(workRequest.handle, req->lpszDirectory);
2182         HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2183         }
2184         break;
2185
2186     case FTPCREATEDIRECTORYA:
2187         {
2188         struct WORKREQ_FTPCREATEDIRECTORYA *req;
2189
2190         req = &workRequest.u.FtpCreateDirectoryA;
2191         FTP_FtpCreateDirectoryA(workRequest.handle, req->lpszDirectory);
2192         HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2193         }
2194         break;
2195
2196     case FTPFINDFIRSTFILEA:
2197         {
2198         struct WORKREQ_FTPFINDFIRSTFILEA *req;
2199
2200         req = &workRequest.u.FtpFindFirstFileA;
2201         FTP_FtpFindFirstFileA(workRequest.handle, req->lpszSearchFile,
2202            req->lpFindFileData, req->dwFlags, req->dwContext);
2203         HeapFree(GetProcessHeap(), 0, req->lpszSearchFile);
2204         }
2205         break;
2206
2207     case FTPGETCURRENTDIRECTORYA:
2208         {
2209         struct WORKREQ_FTPGETCURRENTDIRECTORYA *req;
2210
2211         req = &workRequest.u.FtpGetCurrentDirectoryA;
2212         FTP_FtpGetCurrentDirectoryA(workRequest.handle,
2213                 req->lpszDirectory, req->lpdwDirectory);
2214         }
2215         break;
2216
2217     case FTPOPENFILEA:
2218         {
2219         struct WORKREQ_FTPOPENFILEA *req = &workRequest.u.FtpOpenFileA;
2220
2221         FTP_FtpOpenFileA(workRequest.handle, req->lpszFilename,
2222             req->dwAccess, req->dwFlags, req->dwContext);
2223         HeapFree(GetProcessHeap(), 0, req->lpszFilename);
2224         }
2225         break;
2226
2227     case FTPGETFILEA:
2228         {
2229         struct WORKREQ_FTPGETFILEA *req = &workRequest.u.FtpGetFileA;
2230
2231         FTP_FtpGetFileA(workRequest.handle, req->lpszRemoteFile,
2232                  req->lpszNewFile, req->fFailIfExists,
2233                  req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext);
2234         HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile);
2235         HeapFree(GetProcessHeap(), 0, req->lpszNewFile);
2236         }
2237         break;
2238
2239     case FTPDELETEFILEA:
2240         {
2241         struct WORKREQ_FTPDELETEFILEA *req = &workRequest.u.FtpDeleteFileA;
2242
2243         FTP_FtpDeleteFileA(workRequest.handle, req->lpszFilename);
2244         HeapFree(GetProcessHeap(), 0, req->lpszFilename);
2245         }
2246         break;
2247
2248     case FTPREMOVEDIRECTORYA:
2249         {
2250         struct WORKREQ_FTPREMOVEDIRECTORYA *req;
2251
2252         req = &workRequest.u.FtpRemoveDirectoryA;
2253         FTP_FtpRemoveDirectoryA(workRequest.handle, req->lpszDirectory);
2254         HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2255         }
2256         break;
2257
2258     case FTPRENAMEFILEA:
2259         {
2260         struct WORKREQ_FTPRENAMEFILEA *req = &workRequest.u.FtpRenameFileA;
2261
2262         FTP_FtpRenameFileA(workRequest.handle, req->lpszSrcFile, req->lpszDestFile);
2263         HeapFree(GetProcessHeap(), 0, req->lpszSrcFile);
2264         HeapFree(GetProcessHeap(), 0, req->lpszDestFile);
2265         }
2266         break;
2267
2268     case INTERNETFINDNEXTA:
2269         {
2270         struct WORKREQ_INTERNETFINDNEXTA *req;
2271
2272         req = &workRequest.u.InternetFindNextA;
2273         INTERNET_FindNextFileA(workRequest.handle, req->lpFindFileData);
2274         }
2275         break;
2276
2277     case HTTPSENDREQUESTA:
2278         {
2279         struct WORKREQ_HTTPSENDREQUESTA *req = &workRequest.u.HttpSendRequestA;
2280
2281         HTTP_HttpSendRequestA(workRequest.handle, req->lpszHeader,
2282                 req->dwHeaderLength, req->lpOptional, req->dwOptionalLength);
2283
2284         HeapFree(GetProcessHeap(), 0, req->lpszHeader);
2285         }
2286         break;
2287
2288     case HTTPOPENREQUESTA:
2289         {
2290         struct WORKREQ_HTTPOPENREQUESTA *req = &workRequest.u.HttpOpenRequestA;
2291
2292         HTTP_HttpOpenRequestA(workRequest.handle, req->lpszVerb,
2293             req->lpszObjectName, req->lpszVersion, req->lpszReferrer,
2294             req->lpszAcceptTypes, req->dwFlags, req->dwContext);
2295
2296         HeapFree(GetProcessHeap(), 0, req->lpszVerb);
2297         HeapFree(GetProcessHeap(), 0, req->lpszObjectName);
2298         HeapFree(GetProcessHeap(), 0, req->lpszVersion);
2299         HeapFree(GetProcessHeap(), 0, req->lpszReferrer);
2300         }
2301         break;
2302
2303     case SENDCALLBACK:
2304         {
2305         struct WORKREQ_SENDCALLBACK *req = &workRequest.u.SendCallback;
2306
2307         SendAsyncCallbackInt(workRequest.handle, req->hHttpSession,
2308                 req->dwContext, req->dwInternetStatus, req->lpvStatusInfo,
2309                 req->dwStatusInfoLength);
2310         }
2311         break;
2312     }
2313 }
2314
2315
2316 /***********************************************************************
2317  *          INTERNET_GetResponseBuffer
2318  *
2319  * RETURNS
2320  *
2321  */
2322 LPSTR INTERNET_GetResponseBuffer()
2323 {
2324     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
2325     TRACE("\n");
2326     return lpwite->response;
2327 }
2328
2329 /***********************************************************************
2330  *           INTERNET_GetNextLine  (internal)
2331  *
2332  * Parse next line in directory string listing
2333  *
2334  * RETURNS
2335  *   Pointer to beginning of next line
2336  *   NULL on failure
2337  *
2338  */
2339
2340 LPSTR INTERNET_GetNextLine(INT nSocket, LPSTR lpszBuffer, LPDWORD dwBuffer)
2341 {
2342     struct timeval tv;
2343     fd_set infd;
2344     BOOL bSuccess = FALSE;
2345     INT nRecv = 0;
2346
2347     TRACE("\n");
2348
2349     FD_ZERO(&infd);
2350     FD_SET(nSocket, &infd);
2351     tv.tv_sec=RESPONSE_TIMEOUT;
2352     tv.tv_usec=0;
2353
2354     while (nRecv < *dwBuffer)
2355     {
2356         if (select(nSocket+1,&infd,NULL,NULL,&tv) > 0)
2357         {
2358             if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
2359             {
2360                 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
2361                 goto lend;
2362             }
2363
2364             if (lpszBuffer[nRecv] == '\n')
2365             {
2366                 bSuccess = TRUE;
2367                 break;
2368             }
2369             if (lpszBuffer[nRecv] != '\r')
2370                 nRecv++;
2371         }
2372         else
2373         {
2374             INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
2375             goto lend;
2376         }
2377     }
2378
2379 lend:
2380     if (bSuccess)
2381     {
2382         lpszBuffer[nRecv] = '\0';
2383         *dwBuffer = nRecv - 1;
2384         TRACE(":%d %s\n", nRecv, lpszBuffer);
2385         return lpszBuffer;
2386     }
2387     else
2388     {
2389         return NULL;
2390     }
2391 }
2392
2393 /***********************************************************************
2394  *
2395  */
2396 BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile,
2397                                 LPDWORD lpdwNumberOfBytesAvailble,
2398                                 DWORD dwFlags, DWORD dwConext)
2399 {
2400     LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hFile;
2401     INT retval = -1;
2402     char buffer[4048];
2403
2404
2405     if (NULL == lpwhr)
2406     {
2407         SetLastError(ERROR_NO_MORE_FILES);
2408         return FALSE;
2409     }
2410
2411     TRACE("-->  %p %i\n",lpwhr,lpwhr->hdr.htype);
2412
2413     switch (lpwhr->hdr.htype)
2414     {
2415     case WH_HHTTPREQ:
2416         if (!NETCON_recv(&((LPWININETHTTPREQA)hFile)->netConnection, buffer,
2417                          4048, MSG_PEEK, (int *)lpdwNumberOfBytesAvailble))
2418         {
2419             SetLastError(ERROR_NO_MORE_FILES);
2420             retval = FALSE;
2421         }
2422         else
2423             retval = TRUE;
2424         break;
2425
2426     default:
2427         FIXME("unsupported file type\n");
2428         break;
2429     }
2430
2431     TRACE("<-- %i\n",retval);
2432     return (retval+1);
2433 }
2434
2435
2436 /***********************************************************************
2437  *
2438  */
2439 BOOL WINAPI InternetLockRequestFile( HINTERNET hInternet, HANDLE
2440 *lphLockReqHandle)
2441 {
2442     FIXME("STUB\n");
2443     return FALSE;
2444 }
2445
2446 BOOL WINAPI InternetUnlockRequestFile( HANDLE hLockHandle)
2447 {
2448     FIXME("STUB\n");
2449     return FALSE;
2450 }
2451
2452
2453 /***********************************************************************
2454  *           InternetAutodial
2455  *
2456  * On windows this function is supposed to dial the default internet
2457  * connection. We don't want to have Wine dial out to the internet so
2458  * we return TRUE by default. It might be nice to check if we are connected.
2459  *
2460  * RETURNS
2461  *   TRUE on success
2462  *   FALSE on failure
2463  *
2464  */
2465 BOOL WINAPI InternetAutodial(DWORD dwFlags, HWND hwndParent)
2466 {
2467     FIXME("STUB\n");
2468
2469     /* Tell that we are connected to the internet. */
2470     return TRUE;
2471 }
2472
2473 /***********************************************************************
2474  *           InternetAutodialHangup
2475  *
2476  * Hangs up an connection made with InternetAutodial
2477  *
2478  * PARAM
2479  *    dwReserved
2480  * RETURNS
2481  *   TRUE on success
2482  *   FALSE on failure
2483  *
2484  */
2485 BOOL WINAPI InternetAutodialHangup(DWORD dwReserved)
2486 {
2487     FIXME("STUB\n");
2488
2489     /* we didn't dial, we don't disconnect */
2490     return TRUE;
2491 }
2492
2493 /***********************************************************************
2494  *
2495  *         InternetCombineUrlA
2496  *
2497  * Combine a base URL with a relative URL
2498  *
2499  * RETURNS
2500  *   TRUE on success
2501  *   FALSE on failure
2502  *
2503  */
2504
2505 BOOL WINAPI InternetCombineUrlA(LPCSTR lpszBaseUrl, LPCSTR lpszRelativeUrl,
2506                                 LPSTR lpszBuffer, LPDWORD lpdwBufferLength,
2507                                 DWORD dwFlags)
2508 {
2509     HRESULT hr=S_OK;
2510     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
2511     dwFlags ^= ICU_NO_ENCODE;
2512     hr=UrlCombineA(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
2513
2514     return (hr==S_OK);
2515 }
2516
2517 /***********************************************************************
2518  *
2519  *         InternetCombineUrlW
2520  *
2521  * Combine a base URL with a relative URL
2522  *
2523  * RETURNS
2524  *   TRUE on success
2525  *   FALSE on failure
2526  *
2527  */
2528
2529 BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
2530                                 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength,
2531                                 DWORD dwFlags)
2532 {
2533     HRESULT hr=S_OK;
2534     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
2535     dwFlags ^= ICU_NO_ENCODE;
2536     hr=UrlCombineW(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
2537
2538     return (hr==S_OK);
2539 }
2540
2541 /***********************************************************************
2542  *
2543  *         InternetCreateUrlA
2544  *
2545  * RETURNS
2546  *   TRUE on success
2547  *   FALSE on failure
2548  *
2549  */
2550 BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
2551                                LPSTR lpszUrl, LPDWORD lpdwUrlLength)
2552 {
2553     FIXME("\n");
2554     return FALSE;
2555 }
2556
2557 /***********************************************************************
2558  *
2559  *         InternetCreateUrlW
2560  *
2561  * RETURNS
2562  *   TRUE on success
2563  *   FALSE on failure
2564  *
2565  */
2566 BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
2567                                LPWSTR lpszUrl, LPDWORD lpdwUrlLength)
2568 {
2569     FIXME("\n");
2570     return FALSE;
2571 }