wininet: Make the reference count of WININETHANDLEHEADER thread-safe by using Interlo...
[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  * Copyright 2004 Mike McCormack for CodeWeavers
9  *
10  * Ulrich Czekalla
11  * Aric Stewart
12  * David Hammerton
13  *
14  * This library is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU Lesser General Public
16  * License as published by the Free Software Foundation; either
17  * version 2.1 of the License, or (at your option) any later version.
18  *
19  * This library is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22  * Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public
25  * License along with this library; if not, write to the Free Software
26  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27  */
28
29 #include "config.h"
30 #include "wine/port.h"
31
32 #define MAXHOSTNAME 100 /* from http.c */
33
34 #include <string.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <sys/types.h>
38 #ifdef HAVE_SYS_SOCKET_H
39 # include <sys/socket.h>
40 #endif
41 #ifdef HAVE_SYS_TIME_H
42 # include <sys/time.h>
43 #endif
44 #include <stdlib.h>
45 #include <ctype.h>
46 #ifdef HAVE_UNISTD_H
47 # include <unistd.h>
48 #endif
49 #include <assert.h>
50
51 #include "windef.h"
52 #include "winbase.h"
53 #include "winreg.h"
54 #include "winuser.h"
55 #include "wininet.h"
56 #include "winineti.h"
57 #include "winnls.h"
58 #include "wine/debug.h"
59 #include "winerror.h"
60 #define NO_SHLWAPI_STREAM
61 #include "shlwapi.h"
62 #include "wincrypt.h"
63
64 #include "wine/exception.h"
65
66 #include "internet.h"
67 #include "resource.h"
68
69 #include "wine/unicode.h"
70
71 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
72
73 #define RESPONSE_TIMEOUT        30
74
75 typedef struct
76 {
77     DWORD  dwError;
78     CHAR   response[MAX_REPLY_LEN];
79 } WITHREADERROR, *LPWITHREADERROR;
80
81 HINTERNET WINAPI INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUrl,
82               LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext);
83
84 static DWORD g_dwTlsErrIndex = TLS_OUT_OF_INDEXES;
85 static HMODULE WININET_hModule;
86
87 #define HANDLE_CHUNK_SIZE 0x10
88
89 static CRITICAL_SECTION WININET_cs;
90 static CRITICAL_SECTION_DEBUG WININET_cs_debug = 
91 {
92     0, 0, &WININET_cs,
93     { &WININET_cs_debug.ProcessLocksList, &WININET_cs_debug.ProcessLocksList },
94       0, 0, { (DWORD_PTR)(__FILE__ ": WININET_cs") }
95 };
96 static CRITICAL_SECTION WININET_cs = { &WININET_cs_debug, -1, 0, 0, 0, 0 };
97
98 static LPWININETHANDLEHEADER *WININET_Handles;
99 static UINT WININET_dwNextHandle;
100 static UINT WININET_dwMaxHandles;
101
102 HINTERNET WININET_AllocHandle( LPWININETHANDLEHEADER info )
103 {
104     LPWININETHANDLEHEADER *p;
105     UINT handle = 0, num;
106
107     list_init( &info->children );
108
109     EnterCriticalSection( &WININET_cs );
110     if( !WININET_dwMaxHandles )
111     {
112         num = HANDLE_CHUNK_SIZE;
113         p = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 
114                    sizeof (UINT)* num);
115         if( !p )
116             goto end;
117         WININET_Handles = p;
118         WININET_dwMaxHandles = num;
119     }
120     if( WININET_dwMaxHandles == WININET_dwNextHandle )
121     {
122         num = WININET_dwMaxHandles + HANDLE_CHUNK_SIZE;
123         p = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
124                    WININET_Handles, sizeof (UINT)* num);
125         if( !p )
126             goto end;
127         WININET_Handles = p;
128         WININET_dwMaxHandles = num;
129     }
130
131     handle = WININET_dwNextHandle;
132     if( WININET_Handles[handle] )
133         ERR("handle isn't free but should be\n");
134     WININET_Handles[handle] = WININET_AddRef( info );
135
136     while( WININET_Handles[WININET_dwNextHandle] && 
137            (WININET_dwNextHandle < WININET_dwMaxHandles ) )
138         WININET_dwNextHandle++;
139     
140 end:
141     LeaveCriticalSection( &WININET_cs );
142
143     return info->hInternet = (HINTERNET) (handle+1);
144 }
145
146 LPWININETHANDLEHEADER WININET_AddRef( LPWININETHANDLEHEADER info )
147 {
148     ULONG refs = InterlockedIncrement(&info->refs);
149     TRACE("%p -> refcount = %d\n", info, refs );
150     return info;
151 }
152
153 LPWININETHANDLEHEADER WININET_GetObject( HINTERNET hinternet )
154 {
155     LPWININETHANDLEHEADER info = NULL;
156     UINT handle = (UINT) hinternet;
157
158     EnterCriticalSection( &WININET_cs );
159
160     if( (handle > 0) && ( handle <= WININET_dwMaxHandles ) && 
161         WININET_Handles[handle-1] )
162         info = WININET_AddRef( WININET_Handles[handle-1] );
163
164     LeaveCriticalSection( &WININET_cs );
165
166     TRACE("handle %d -> %p\n", handle, info);
167
168     return info;
169 }
170
171 BOOL WININET_Release( LPWININETHANDLEHEADER info )
172 {
173     ULONG refs = InterlockedDecrement(&info->refs);
174     TRACE( "object %p refcount = %d\n", info, refs );
175     if( !refs )
176     {
177         if ( info->vtbl->CloseConnection )
178         {
179             TRACE( "closing connection %p\n", info);
180             info->vtbl->CloseConnection( info );
181         }
182         INTERNET_SendCallback(info, info->dwContext,
183                               INTERNET_STATUS_HANDLE_CLOSING, &info->hInternet,
184                               sizeof(HINTERNET));
185         TRACE( "destroying object %p\n", info);
186         if ( info->htype != WH_HINIT )
187             list_remove( &info->entry );
188         info->vtbl->Destroy( info );
189     }
190     return TRUE;
191 }
192
193 BOOL WININET_FreeHandle( HINTERNET hinternet )
194 {
195     BOOL ret = FALSE;
196     UINT handle = (UINT) hinternet;
197     LPWININETHANDLEHEADER info = NULL, child, next;
198
199     EnterCriticalSection( &WININET_cs );
200
201     if( (handle > 0) && ( handle <= WININET_dwMaxHandles ) )
202     {
203         handle--;
204         if( WININET_Handles[handle] )
205         {
206             info = WININET_Handles[handle];
207             TRACE( "destroying handle %d for object %p\n", handle+1, info);
208             WININET_Handles[handle] = NULL;
209             ret = TRUE;
210         }
211     }
212
213     LeaveCriticalSection( &WININET_cs );
214
215     /* As on native when the equivalent of WININET_Release is called, the handle
216      * is already invalid, but if a new handle is created at this time it does
217      * not yet get assigned the freed handle number */
218     if( info )
219     {
220         /* Free all children as native does */
221         LIST_FOR_EACH_ENTRY_SAFE( child, next, &info->children, WININETHANDLEHEADER, entry )
222         {
223             TRACE( "freeing child handle %d for parent handle %d\n",
224                    (UINT)child->hInternet, handle+1);
225             WININET_FreeHandle( child->hInternet );
226         }
227         WININET_Release( info );
228     }
229
230     EnterCriticalSection( &WININET_cs );
231
232     if( WININET_dwNextHandle > handle && !WININET_Handles[handle] )
233         WININET_dwNextHandle = handle;
234
235     LeaveCriticalSection( &WININET_cs );
236
237     return ret;
238 }
239
240 /***********************************************************************
241  * DllMain [Internal] Initializes the internal 'WININET.DLL'.
242  *
243  * PARAMS
244  *     hinstDLL    [I] handle to the DLL's instance
245  *     fdwReason   [I]
246  *     lpvReserved [I] reserved, must be NULL
247  *
248  * RETURNS
249  *     Success: TRUE
250  *     Failure: FALSE
251  */
252
253 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
254 {
255     TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
256
257     switch (fdwReason) {
258         case DLL_PROCESS_ATTACH:
259
260             g_dwTlsErrIndex = TlsAlloc();
261
262             if (g_dwTlsErrIndex == TLS_OUT_OF_INDEXES)
263                 return FALSE;
264
265             URLCacheContainers_CreateDefaults();
266
267             WININET_hModule = hinstDLL;
268
269         case DLL_THREAD_ATTACH:
270             break;
271
272         case DLL_THREAD_DETACH:
273             if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
274                         {
275                                 LPVOID lpwite = TlsGetValue(g_dwTlsErrIndex);
276                                 HeapFree(GetProcessHeap(), 0, lpwite);
277                         }
278             break;
279
280         case DLL_PROCESS_DETACH:
281
282             URLCacheContainers_DeleteAll();
283
284             if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
285             {
286                 HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex));
287                 TlsFree(g_dwTlsErrIndex);
288             }
289             break;
290     }
291
292     return TRUE;
293 }
294
295
296 /***********************************************************************
297  *           InternetInitializeAutoProxyDll   (WININET.@)
298  *
299  * Setup the internal proxy
300  *
301  * PARAMETERS
302  *     dwReserved
303  *
304  * RETURNS
305  *     FALSE on failure
306  *
307  */
308 BOOL WINAPI InternetInitializeAutoProxyDll(DWORD dwReserved)
309 {
310     FIXME("STUB\n");
311     INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
312     return FALSE;
313 }
314
315 /***********************************************************************
316  *           DetectAutoProxyUrl   (WININET.@)
317  *
318  * Auto detect the proxy url
319  *
320  * RETURNS
321  *     FALSE on failure
322  *
323  */
324 BOOL WINAPI DetectAutoProxyUrl(LPSTR lpszAutoProxyUrl,
325         DWORD dwAutoProxyUrlLength, DWORD dwDetectFlags)
326 {
327     FIXME("STUB\n");
328     INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
329     return FALSE;
330 }
331
332
333 /***********************************************************************
334  *           INTERNET_ConfigureProxyFromReg
335  *
336  * FIXME:
337  * The proxy may be specified in the form 'http=proxy.my.org'
338  * Presumably that means there can be ftp=ftpproxy.my.org too.
339  */
340 static BOOL INTERNET_ConfigureProxyFromReg( LPWININETAPPINFOW lpwai )
341 {
342     HKEY key;
343     DWORD r, keytype, len, enabled;
344     LPCSTR lpszInternetSettings =
345         "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
346     static const WCHAR szProxyServer[] = { 'P','r','o','x','y','S','e','r','v','e','r', 0 };
347
348     r = RegOpenKeyA(HKEY_CURRENT_USER, lpszInternetSettings, &key);
349     if ( r != ERROR_SUCCESS )
350         return FALSE;
351
352     len = sizeof enabled;
353     r = RegQueryValueExA( key, "ProxyEnable", NULL, &keytype,
354                           (BYTE*)&enabled, &len);
355     if( (r == ERROR_SUCCESS) && enabled )
356     {
357         TRACE("Proxy is enabled.\n");
358
359         /* figure out how much memory the proxy setting takes */
360         r = RegQueryValueExW( key, szProxyServer, NULL, &keytype, 
361                               NULL, &len);
362         if( (r == ERROR_SUCCESS) && len && (keytype == REG_SZ) )
363         {
364             LPWSTR szProxy, p;
365             static const WCHAR szHttp[] = {'h','t','t','p','=',0};
366
367             szProxy=HeapAlloc( GetProcessHeap(), 0, len );
368             RegQueryValueExW( key, szProxyServer, NULL, &keytype,
369                               (BYTE*)szProxy, &len);
370
371             /* find the http proxy, and strip away everything else */
372             p = strstrW( szProxy, szHttp );
373             if( p )
374             {
375                  p += lstrlenW(szHttp);
376                  lstrcpyW( szProxy, p );
377             }
378             p = strchrW( szProxy, ' ' );
379             if( p )
380                 *p = 0;
381
382             lpwai->dwAccessType = INTERNET_OPEN_TYPE_PROXY;
383             lpwai->lpszProxy = szProxy;
384
385             TRACE("http proxy = %s\n", debugstr_w(lpwai->lpszProxy));
386         }
387         else
388             ERR("Couldn't read proxy server settings.\n");
389     }
390     else
391         TRACE("Proxy is not enabled.\n");
392     RegCloseKey(key);
393
394     return enabled;
395 }
396
397 /***********************************************************************
398  *           dump_INTERNET_FLAGS
399  *
400  * Helper function to TRACE the internet flags.
401  *
402  * RETURNS
403  *    None
404  *
405  */
406 static void dump_INTERNET_FLAGS(DWORD dwFlags) 
407 {
408 #define FE(x) { x, #x }
409     static const wininet_flag_info flag[] = {
410         FE(INTERNET_FLAG_RELOAD),
411         FE(INTERNET_FLAG_RAW_DATA),
412         FE(INTERNET_FLAG_EXISTING_CONNECT),
413         FE(INTERNET_FLAG_ASYNC),
414         FE(INTERNET_FLAG_PASSIVE),
415         FE(INTERNET_FLAG_NO_CACHE_WRITE),
416         FE(INTERNET_FLAG_MAKE_PERSISTENT),
417         FE(INTERNET_FLAG_FROM_CACHE),
418         FE(INTERNET_FLAG_SECURE),
419         FE(INTERNET_FLAG_KEEP_CONNECTION),
420         FE(INTERNET_FLAG_NO_AUTO_REDIRECT),
421         FE(INTERNET_FLAG_READ_PREFETCH),
422         FE(INTERNET_FLAG_NO_COOKIES),
423         FE(INTERNET_FLAG_NO_AUTH),
424         FE(INTERNET_FLAG_CACHE_IF_NET_FAIL),
425         FE(INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP),
426         FE(INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS),
427         FE(INTERNET_FLAG_IGNORE_CERT_DATE_INVALID),
428         FE(INTERNET_FLAG_IGNORE_CERT_CN_INVALID),
429         FE(INTERNET_FLAG_RESYNCHRONIZE),
430         FE(INTERNET_FLAG_HYPERLINK),
431         FE(INTERNET_FLAG_NO_UI),
432         FE(INTERNET_FLAG_PRAGMA_NOCACHE),
433         FE(INTERNET_FLAG_CACHE_ASYNC),
434         FE(INTERNET_FLAG_FORMS_SUBMIT),
435         FE(INTERNET_FLAG_NEED_FILE),
436         FE(INTERNET_FLAG_TRANSFER_ASCII),
437         FE(INTERNET_FLAG_TRANSFER_BINARY)
438     };
439 #undef FE
440     int i;
441     
442     for (i = 0; i < (sizeof(flag) / sizeof(flag[0])); i++) {
443         if (flag[i].val & dwFlags) {
444             TRACE(" %s", flag[i].name);
445             dwFlags &= ~flag[i].val;
446         }
447     }   
448     if (dwFlags)
449         TRACE(" Unknown flags (%08x)\n", dwFlags);
450     else
451         TRACE("\n");
452 }
453
454 /***********************************************************************
455  *           INTERNET_CloseHandle (internal)
456  *
457  * Close internet handle
458  *
459  */
460 static VOID APPINFO_Destroy(WININETHANDLEHEADER *hdr)
461 {
462     LPWININETAPPINFOW lpwai = (LPWININETAPPINFOW) hdr;
463
464     TRACE("%p\n",lpwai);
465
466     HeapFree(GetProcessHeap(), 0, lpwai->lpszAgent);
467     HeapFree(GetProcessHeap(), 0, lpwai->lpszProxy);
468     HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyBypass);
469     HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyUsername);
470     HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyPassword);
471     HeapFree(GetProcessHeap(), 0, lpwai);
472 }
473
474 static const HANDLEHEADERVtbl APPINFOVtbl = {
475     APPINFO_Destroy,
476     NULL,
477     NULL,
478     NULL,
479     NULL,
480     NULL,
481     NULL,
482     NULL
483 };
484
485
486 /***********************************************************************
487  *           InternetOpenW   (WININET.@)
488  *
489  * Per-application initialization of wininet
490  *
491  * RETURNS
492  *    HINTERNET on success
493  *    NULL on failure
494  *
495  */
496 HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType,
497     LPCWSTR lpszProxy, LPCWSTR lpszProxyBypass, DWORD dwFlags)
498 {
499     LPWININETAPPINFOW lpwai = NULL;
500     HINTERNET handle = NULL;
501
502     if (TRACE_ON(wininet)) {
503 #define FE(x) { x, #x }
504         static const wininet_flag_info access_type[] = {
505             FE(INTERNET_OPEN_TYPE_PRECONFIG),
506             FE(INTERNET_OPEN_TYPE_DIRECT),
507             FE(INTERNET_OPEN_TYPE_PROXY),
508             FE(INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY)
509         };
510 #undef FE
511         DWORD i;
512         const char *access_type_str = "Unknown";
513         
514         TRACE("(%s, %i, %s, %s, %i)\n", debugstr_w(lpszAgent), dwAccessType,
515               debugstr_w(lpszProxy), debugstr_w(lpszProxyBypass), dwFlags);
516         for (i = 0; i < (sizeof(access_type) / sizeof(access_type[0])); i++) {
517             if (access_type[i].val == dwAccessType) {
518                 access_type_str = access_type[i].name;
519                 break;
520             }
521         }
522         TRACE("  access type : %s\n", access_type_str);
523         TRACE("  flags       :");
524         dump_INTERNET_FLAGS(dwFlags);
525     }
526
527     /* Clear any error information */
528     INTERNET_SetLastError(0);
529
530     lpwai = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETAPPINFOW));
531     if (NULL == lpwai)
532     {
533         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
534         goto lend;
535     }
536
537     lpwai->hdr.htype = WH_HINIT;
538     lpwai->hdr.vtbl = &APPINFOVtbl;
539     lpwai->hdr.dwFlags = dwFlags;
540     lpwai->hdr.refs = 1;
541     lpwai->dwAccessType = dwAccessType;
542     lpwai->lpszProxyUsername = NULL;
543     lpwai->lpszProxyPassword = NULL;
544
545     handle = WININET_AllocHandle( &lpwai->hdr );
546     if( !handle )
547     {
548         HeapFree( GetProcessHeap(), 0, lpwai );
549         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
550         goto lend;
551     }
552
553     if (NULL != lpszAgent)
554     {
555         lpwai->lpszAgent = HeapAlloc( GetProcessHeap(),0,
556                                       (strlenW(lpszAgent)+1)*sizeof(WCHAR));
557         if (lpwai->lpszAgent)
558             lstrcpyW( lpwai->lpszAgent, lpszAgent );
559     }
560     if(dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG)
561         INTERNET_ConfigureProxyFromReg( lpwai );
562     else if (NULL != lpszProxy)
563     {
564         lpwai->lpszProxy = HeapAlloc( GetProcessHeap(), 0,
565                                       (strlenW(lpszProxy)+1)*sizeof(WCHAR));
566         if (lpwai->lpszProxy)
567             lstrcpyW( lpwai->lpszProxy, lpszProxy );
568     }
569
570     if (NULL != lpszProxyBypass)
571     {
572         lpwai->lpszProxyBypass = HeapAlloc( GetProcessHeap(), 0,
573                                      (strlenW(lpszProxyBypass)+1)*sizeof(WCHAR));
574         if (lpwai->lpszProxyBypass)
575             lstrcpyW( lpwai->lpszProxyBypass, lpszProxyBypass );
576     }
577
578 lend:
579     if( lpwai )
580         WININET_Release( &lpwai->hdr );
581
582     TRACE("returning %p\n", lpwai);
583
584     return handle;
585 }
586
587
588 /***********************************************************************
589  *           InternetOpenA   (WININET.@)
590  *
591  * Per-application initialization of wininet
592  *
593  * RETURNS
594  *    HINTERNET on success
595  *    NULL on failure
596  *
597  */
598 HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType,
599     LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags)
600 {
601     HINTERNET rc = NULL;
602     INT len;
603     WCHAR *szAgent = NULL, *szProxy = NULL, *szBypass = NULL;
604
605     TRACE("(%s, 0x%08x, %s, %s, 0x%08x)\n", debugstr_a(lpszAgent),
606        dwAccessType, debugstr_a(lpszProxy), debugstr_a(lpszProxyBypass), dwFlags);
607
608     if( lpszAgent )
609     {
610         len = MultiByteToWideChar(CP_ACP, 0, lpszAgent, -1, NULL, 0);
611         szAgent = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
612         MultiByteToWideChar(CP_ACP, 0, lpszAgent, -1, szAgent, len);
613     }
614
615     if( lpszProxy )
616     {
617         len = MultiByteToWideChar(CP_ACP, 0, lpszProxy, -1, NULL, 0);
618         szProxy = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
619         MultiByteToWideChar(CP_ACP, 0, lpszProxy, -1, szProxy, len);
620     }
621
622     if( lpszProxyBypass )
623     {
624         len = MultiByteToWideChar(CP_ACP, 0, lpszProxyBypass, -1, NULL, 0);
625         szBypass = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
626         MultiByteToWideChar(CP_ACP, 0, lpszProxyBypass, -1, szBypass, len);
627     }
628
629     rc = InternetOpenW(szAgent, dwAccessType, szProxy, szBypass, dwFlags);
630
631     HeapFree(GetProcessHeap(), 0, szAgent);
632     HeapFree(GetProcessHeap(), 0, szProxy);
633     HeapFree(GetProcessHeap(), 0, szBypass);
634
635     return rc;
636 }
637
638 /***********************************************************************
639  *           InternetGetLastResponseInfoA (WININET.@)
640  *
641  * Return last wininet error description on the calling thread
642  *
643  * RETURNS
644  *    TRUE on success of writing to buffer
645  *    FALSE on failure
646  *
647  */
648 BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError,
649     LPSTR lpszBuffer, LPDWORD lpdwBufferLength)
650 {
651     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
652
653     TRACE("\n");
654
655     if (lpwite)
656     {
657         *lpdwError = lpwite->dwError;
658         if (lpwite->dwError)
659         {
660             memcpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
661             *lpdwBufferLength = strlen(lpszBuffer);
662         }
663         else
664             *lpdwBufferLength = 0;
665     }
666     else
667     {
668         *lpdwError = 0;
669         *lpdwBufferLength = 0;
670     }
671
672     return TRUE;
673 }
674
675 /***********************************************************************
676  *           InternetGetLastResponseInfoW (WININET.@)
677  *
678  * Return last wininet error description on the calling thread
679  *
680  * RETURNS
681  *    TRUE on success of writing to buffer
682  *    FALSE on failure
683  *
684  */
685 BOOL WINAPI InternetGetLastResponseInfoW(LPDWORD lpdwError,
686     LPWSTR lpszBuffer, LPDWORD lpdwBufferLength)
687 {
688     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
689
690     TRACE("\n");
691
692     if (lpwite)
693     {
694         *lpdwError = lpwite->dwError;
695         if (lpwite->dwError)
696         {
697             memcpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
698             *lpdwBufferLength = lstrlenW(lpszBuffer);
699         }
700         else
701             *lpdwBufferLength = 0;
702     }
703     else
704     {
705         *lpdwError = 0;
706         *lpdwBufferLength = 0;
707     }
708
709     return TRUE;
710 }
711
712 /***********************************************************************
713  *           InternetGetConnectedState (WININET.@)
714  *
715  * Return connected state
716  *
717  * RETURNS
718  *    TRUE if connected
719  *    if lpdwStatus is not null, return the status (off line,
720  *    modem, lan...) in it.
721  *    FALSE if not connected
722  */
723 BOOL WINAPI InternetGetConnectedState(LPDWORD lpdwStatus, DWORD dwReserved)
724 {
725     TRACE("(%p, 0x%08x)\n", lpdwStatus, dwReserved);
726
727     if (lpdwStatus) {
728         FIXME("always returning LAN connection.\n");
729         *lpdwStatus = INTERNET_CONNECTION_LAN;
730     }
731     return TRUE;
732 }
733
734
735 /***********************************************************************
736  *           InternetGetConnectedStateExW (WININET.@)
737  *
738  * Return connected state
739  *
740  * PARAMS
741  *
742  * lpdwStatus         [O] Flags specifying the status of the internet connection.
743  * lpszConnectionName [O] Pointer to buffer to receive the friendly name of the internet connection.
744  * dwNameLen          [I] Size of the buffer, in characters.
745  * dwReserved         [I] Reserved. Must be set to 0.
746  *
747  * RETURNS
748  *    TRUE if connected
749  *    if lpdwStatus is not null, return the status (off line,
750  *    modem, lan...) in it.
751  *    FALSE if not connected
752  *
753  * NOTES
754  *   If the system has no available network connections, an empty string is
755  *   stored in lpszConnectionName. If there is a LAN connection, a localized
756  *   "LAN Connection" string is stored. Presumably, if only a dial-up
757  *   connection is available then the name of the dial-up connection is
758  *   returned. Why any application, other than the "Internet Settings" CPL,
759  *   would want to use this function instead of the simpler InternetGetConnectedStateW
760  *   function is beyond me.
761  */
762 BOOL WINAPI InternetGetConnectedStateExW(LPDWORD lpdwStatus, LPWSTR lpszConnectionName,
763                                          DWORD dwNameLen, DWORD dwReserved)
764 {
765     TRACE("(%p, %p, %d, 0x%08x)\n", lpdwStatus, lpszConnectionName, dwNameLen, dwReserved);
766
767     /* Must be zero */
768     if(dwReserved)
769         return FALSE;
770
771     if (lpdwStatus) {
772         FIXME("always returning LAN connection.\n");
773         *lpdwStatus = INTERNET_CONNECTION_LAN;
774     }
775     return LoadStringW(WININET_hModule, IDS_LANCONNECTION, lpszConnectionName, dwNameLen);
776 }
777
778
779 /***********************************************************************
780  *           InternetGetConnectedStateExA (WININET.@)
781  */
782 BOOL WINAPI InternetGetConnectedStateExA(LPDWORD lpdwStatus, LPSTR lpszConnectionName,
783                                          DWORD dwNameLen, DWORD dwReserved)
784 {
785     LPWSTR lpwszConnectionName = NULL;
786     BOOL rc;
787
788     TRACE("(%p, %p, %d, 0x%08x)\n", lpdwStatus, lpszConnectionName, dwNameLen, dwReserved);
789
790     if (lpszConnectionName && dwNameLen > 0)
791         lpwszConnectionName= HeapAlloc(GetProcessHeap(), 0, dwNameLen * sizeof(WCHAR));
792
793     rc = InternetGetConnectedStateExW(lpdwStatus,lpwszConnectionName, dwNameLen,
794                                       dwReserved);
795     if (rc && lpwszConnectionName)
796     {
797         WideCharToMultiByte(CP_ACP,0,lpwszConnectionName,-1,lpszConnectionName,
798                             dwNameLen, NULL, NULL);
799
800         HeapFree(GetProcessHeap(),0,lpwszConnectionName);
801     }
802
803     return rc;
804 }
805
806
807 /***********************************************************************
808  *           InternetConnectW (WININET.@)
809  *
810  * Open a ftp, gopher or http session
811  *
812  * RETURNS
813  *    HINTERNET a session handle on success
814  *    NULL on failure
815  *
816  */
817 HINTERNET WINAPI InternetConnectW(HINTERNET hInternet,
818     LPCWSTR lpszServerName, INTERNET_PORT nServerPort,
819     LPCWSTR lpszUserName, LPCWSTR lpszPassword,
820     DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext)
821 {
822     LPWININETAPPINFOW hIC;
823     HINTERNET rc = NULL;
824
825     TRACE("(%p, %s, %i, %s, %s, %i, %i, %lx)\n", hInternet, debugstr_w(lpszServerName),
826           nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword),
827           dwService, dwFlags, dwContext);
828
829     if (!lpszServerName)
830     {
831         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
832         return NULL;
833     }
834
835     /* Clear any error information */
836     INTERNET_SetLastError(0);
837     hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
838     if ( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) )
839     {
840         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
841         goto lend;
842     }
843
844     switch (dwService)
845     {
846         case INTERNET_SERVICE_FTP:
847             rc = FTP_Connect(hIC, lpszServerName, nServerPort,
848             lpszUserName, lpszPassword, dwFlags, dwContext, 0);
849             break;
850
851         case INTERNET_SERVICE_HTTP:
852             rc = HTTP_Connect(hIC, lpszServerName, nServerPort,
853             lpszUserName, lpszPassword, dwFlags, dwContext, 0);
854             break;
855
856         case INTERNET_SERVICE_GOPHER:
857         default:
858             break;
859     }
860 lend:
861     if( hIC )
862         WININET_Release( &hIC->hdr );
863
864     TRACE("returning %p\n", rc);
865     return rc;
866 }
867
868
869 /***********************************************************************
870  *           InternetConnectA (WININET.@)
871  *
872  * Open a ftp, gopher or http session
873  *
874  * RETURNS
875  *    HINTERNET a session handle on success
876  *    NULL on failure
877  *
878  */
879 HINTERNET WINAPI InternetConnectA(HINTERNET hInternet,
880     LPCSTR lpszServerName, INTERNET_PORT nServerPort,
881     LPCSTR lpszUserName, LPCSTR lpszPassword,
882     DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext)
883 {
884     HINTERNET rc = NULL;
885     INT len = 0;
886     LPWSTR szServerName = NULL;
887     LPWSTR szUserName = NULL;
888     LPWSTR szPassword = NULL;
889
890     if (lpszServerName)
891     {
892         len = MultiByteToWideChar(CP_ACP, 0, lpszServerName, -1, NULL, 0);
893         szServerName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
894         MultiByteToWideChar(CP_ACP, 0, lpszServerName, -1, szServerName, len);
895     }
896     if (lpszUserName)
897     {
898         len = MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, NULL, 0);
899         szUserName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
900         MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, szUserName, len);
901     }
902     if (lpszPassword)
903     {
904         len = MultiByteToWideChar(CP_ACP, 0, lpszPassword, -1, NULL, 0);
905         szPassword = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
906         MultiByteToWideChar(CP_ACP, 0, lpszPassword, -1, szPassword, len);
907     }
908
909
910     rc = InternetConnectW(hInternet, szServerName, nServerPort,
911         szUserName, szPassword, dwService, dwFlags, dwContext);
912
913     HeapFree(GetProcessHeap(), 0, szServerName);
914     HeapFree(GetProcessHeap(), 0, szUserName);
915     HeapFree(GetProcessHeap(), 0, szPassword);
916     return rc;
917 }
918
919
920 /***********************************************************************
921  *           InternetFindNextFileA (WININET.@)
922  *
923  * Continues a file search from a previous call to FindFirstFile
924  *
925  * RETURNS
926  *    TRUE on success
927  *    FALSE on failure
928  *
929  */
930 BOOL WINAPI InternetFindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
931 {
932     BOOL ret;
933     WIN32_FIND_DATAW fd;
934     
935     ret = InternetFindNextFileW(hFind, lpvFindData?&fd:NULL);
936     if(lpvFindData)
937         WININET_find_data_WtoA(&fd, (LPWIN32_FIND_DATAA)lpvFindData);
938     return ret;
939 }
940
941 /***********************************************************************
942  *           InternetFindNextFileW (WININET.@)
943  *
944  * Continues a file search from a previous call to FindFirstFile
945  *
946  * RETURNS
947  *    TRUE on success
948  *    FALSE on failure
949  *
950  */
951 BOOL WINAPI InternetFindNextFileW(HINTERNET hFind, LPVOID lpvFindData)
952 {
953     WININETHANDLEHEADER *hdr;
954     DWORD res;
955
956     TRACE("\n");
957
958     hdr = WININET_GetObject(hFind);
959     if(!hdr) {
960         WARN("Invalid handle\n");
961         SetLastError(ERROR_INVALID_HANDLE);
962         return FALSE;
963     }
964
965     if(hdr->vtbl->FindNextFileW) {
966         res = hdr->vtbl->FindNextFileW(hdr, lpvFindData);
967     }else {
968         WARN("Handle doesn't support NextFile\n");
969         res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
970     }
971
972     WININET_Release(hdr);
973
974     if(res != ERROR_SUCCESS)
975         SetLastError(res);
976     return res == ERROR_SUCCESS;
977 }
978
979 /***********************************************************************
980  *           InternetCloseHandle (WININET.@)
981  *
982  * Generic close handle function
983  *
984  * RETURNS
985  *    TRUE on success
986  *    FALSE on failure
987  *
988  */
989 BOOL WINAPI InternetCloseHandle(HINTERNET hInternet)
990 {
991     LPWININETHANDLEHEADER lpwh;
992     
993     TRACE("%p\n",hInternet);
994
995     lpwh = WININET_GetObject( hInternet );
996     if (NULL == lpwh)
997     {
998         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
999         return FALSE;
1000     }
1001
1002     WININET_Release( lpwh );
1003     WININET_FreeHandle( hInternet );
1004
1005     return TRUE;
1006 }
1007
1008
1009 /***********************************************************************
1010  *           ConvertUrlComponentValue (Internal)
1011  *
1012  * Helper function for InternetCrackUrlW
1013  *
1014  */
1015 static void ConvertUrlComponentValue(LPSTR* lppszComponent, LPDWORD dwComponentLen,
1016                                      LPWSTR lpwszComponent, DWORD dwwComponentLen,
1017                                      LPCSTR lpszStart, LPCWSTR lpwszStart)
1018 {
1019     TRACE("%p %d %p %d %p %p\n", lppszComponent, *dwComponentLen, lpwszComponent, dwwComponentLen, lpszStart, lpwszStart);
1020     if (*dwComponentLen != 0)
1021     {
1022         DWORD nASCIILength=WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,NULL,0,NULL,NULL);
1023         if (*lppszComponent == NULL)
1024         {
1025             int nASCIIOffset=WideCharToMultiByte(CP_ACP,0,lpwszStart,lpwszComponent-lpwszStart,NULL,0,NULL,NULL);
1026             if (lpwszComponent)
1027                 *lppszComponent = (LPSTR)lpszStart+nASCIIOffset;
1028             else
1029                 *lppszComponent = NULL;
1030             *dwComponentLen = nASCIILength;
1031         }
1032         else
1033         {
1034             DWORD ncpylen = min((*dwComponentLen)-1, nASCIILength);
1035             WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,*lppszComponent,ncpylen+1,NULL,NULL);
1036             (*lppszComponent)[ncpylen]=0;
1037             *dwComponentLen = ncpylen;
1038         }
1039     }
1040 }
1041
1042
1043 /***********************************************************************
1044  *           InternetCrackUrlA (WININET.@)
1045  *
1046  * See InternetCrackUrlW.
1047  */
1048 BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
1049     LPURL_COMPONENTSA lpUrlComponents)
1050 {
1051   DWORD nLength;
1052   URL_COMPONENTSW UCW;
1053   WCHAR* lpwszUrl;
1054
1055   TRACE("(%s %u %x %p)\n", debugstr_a(lpszUrl), dwUrlLength, dwFlags, lpUrlComponents);
1056
1057   if (!lpszUrl || !*lpszUrl || !lpUrlComponents ||
1058           lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSA))
1059   {
1060       INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1061       return FALSE;
1062   }
1063
1064   if(dwUrlLength<=0)
1065       dwUrlLength=-1;
1066   nLength=MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,NULL,0);
1067
1068   /* if dwUrlLength=-1 then nLength includes null but length to 
1069        InternetCrackUrlW should not include it                  */
1070   if (dwUrlLength == -1) nLength--;
1071
1072   lpwszUrl=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR)*nLength);
1073   MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,lpwszUrl,nLength);
1074
1075   memset(&UCW,0,sizeof(UCW));
1076   UCW.dwStructSize = sizeof(URL_COMPONENTSW);
1077   if(lpUrlComponents->dwHostNameLength!=0)
1078       UCW.dwHostNameLength= lpUrlComponents->dwHostNameLength;
1079   if(lpUrlComponents->dwUserNameLength!=0)
1080       UCW.dwUserNameLength=lpUrlComponents->dwUserNameLength;
1081   if(lpUrlComponents->dwPasswordLength!=0)
1082       UCW.dwPasswordLength=lpUrlComponents->dwPasswordLength;
1083   if(lpUrlComponents->dwUrlPathLength!=0)
1084       UCW.dwUrlPathLength=lpUrlComponents->dwUrlPathLength;
1085   if(lpUrlComponents->dwSchemeLength!=0)
1086       UCW.dwSchemeLength=lpUrlComponents->dwSchemeLength;
1087   if(lpUrlComponents->dwExtraInfoLength!=0)
1088       UCW.dwExtraInfoLength=lpUrlComponents->dwExtraInfoLength;
1089   if(!InternetCrackUrlW(lpwszUrl,nLength,dwFlags,&UCW))
1090   {
1091       HeapFree(GetProcessHeap(), 0, lpwszUrl);
1092       return FALSE;
1093   }
1094
1095   ConvertUrlComponentValue(&lpUrlComponents->lpszHostName, &lpUrlComponents->dwHostNameLength,
1096                            UCW.lpszHostName, UCW.dwHostNameLength,
1097                            lpszUrl, lpwszUrl);
1098   ConvertUrlComponentValue(&lpUrlComponents->lpszUserName, &lpUrlComponents->dwUserNameLength,
1099                            UCW.lpszUserName, UCW.dwUserNameLength,
1100                            lpszUrl, lpwszUrl);
1101   ConvertUrlComponentValue(&lpUrlComponents->lpszPassword, &lpUrlComponents->dwPasswordLength,
1102                            UCW.lpszPassword, UCW.dwPasswordLength,
1103                            lpszUrl, lpwszUrl);
1104   ConvertUrlComponentValue(&lpUrlComponents->lpszUrlPath, &lpUrlComponents->dwUrlPathLength,
1105                            UCW.lpszUrlPath, UCW.dwUrlPathLength,
1106                            lpszUrl, lpwszUrl);
1107   ConvertUrlComponentValue(&lpUrlComponents->lpszScheme, &lpUrlComponents->dwSchemeLength,
1108                            UCW.lpszScheme, UCW.dwSchemeLength,
1109                            lpszUrl, lpwszUrl);
1110   ConvertUrlComponentValue(&lpUrlComponents->lpszExtraInfo, &lpUrlComponents->dwExtraInfoLength,
1111                            UCW.lpszExtraInfo, UCW.dwExtraInfoLength,
1112                            lpszUrl, lpwszUrl);
1113   lpUrlComponents->nScheme=UCW.nScheme;
1114   lpUrlComponents->nPort=UCW.nPort;
1115   HeapFree(GetProcessHeap(), 0, lpwszUrl);
1116   
1117   TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", lpszUrl,
1118           debugstr_an(lpUrlComponents->lpszScheme,lpUrlComponents->dwSchemeLength),
1119           debugstr_an(lpUrlComponents->lpszHostName,lpUrlComponents->dwHostNameLength),
1120           debugstr_an(lpUrlComponents->lpszUrlPath,lpUrlComponents->dwUrlPathLength),
1121           debugstr_an(lpUrlComponents->lpszExtraInfo,lpUrlComponents->dwExtraInfoLength));
1122
1123   return TRUE;
1124 }
1125
1126 static const WCHAR url_schemes[][7] =
1127 {
1128     {'f','t','p',0},
1129     {'g','o','p','h','e','r',0},
1130     {'h','t','t','p',0},
1131     {'h','t','t','p','s',0},
1132     {'f','i','l','e',0},
1133     {'n','e','w','s',0},
1134     {'m','a','i','l','t','o',0},
1135     {'r','e','s',0},
1136 };
1137
1138 /***********************************************************************
1139  *           GetInternetSchemeW (internal)
1140  *
1141  * Get scheme of url
1142  *
1143  * RETURNS
1144  *    scheme on success
1145  *    INTERNET_SCHEME_UNKNOWN on failure
1146  *
1147  */
1148 static INTERNET_SCHEME GetInternetSchemeW(LPCWSTR lpszScheme, DWORD nMaxCmp)
1149 {
1150     int i;
1151
1152     TRACE("%s %d\n",debugstr_wn(lpszScheme, nMaxCmp), nMaxCmp);
1153
1154     if(lpszScheme==NULL)
1155         return INTERNET_SCHEME_UNKNOWN;
1156
1157     for (i = 0; i < sizeof(url_schemes)/sizeof(url_schemes[0]); i++)
1158         if (!strncmpW(lpszScheme, url_schemes[i], nMaxCmp))
1159             return INTERNET_SCHEME_FIRST + i;
1160
1161     return INTERNET_SCHEME_UNKNOWN;
1162 }
1163
1164 /***********************************************************************
1165  *           SetUrlComponentValueW (Internal)
1166  *
1167  * Helper function for InternetCrackUrlW
1168  *
1169  * PARAMS
1170  *     lppszComponent [O] Holds the returned string
1171  *     dwComponentLen [I] Holds the size of lppszComponent
1172  *                    [O] Holds the length of the string in lppszComponent without '\0'
1173  *     lpszStart      [I] Holds the string to copy from
1174  *     len            [I] Holds the length of lpszStart without '\0'
1175  *
1176  * RETURNS
1177  *    TRUE on success
1178  *    FALSE on failure
1179  *
1180  */
1181 static BOOL SetUrlComponentValueW(LPWSTR* lppszComponent, LPDWORD dwComponentLen, LPCWSTR lpszStart, DWORD len)
1182 {
1183     TRACE("%s (%d)\n", debugstr_wn(lpszStart,len), len);
1184
1185     if ( (*dwComponentLen == 0) && (*lppszComponent == NULL) )
1186         return FALSE;
1187
1188     if (*dwComponentLen != 0 || *lppszComponent == NULL)
1189     {
1190         if (*lppszComponent == NULL)
1191         {
1192             *lppszComponent = (LPWSTR)lpszStart;
1193             *dwComponentLen = len;
1194         }
1195         else
1196         {
1197             DWORD ncpylen = min((*dwComponentLen)-1, len);
1198             memcpy(*lppszComponent, lpszStart, ncpylen*sizeof(WCHAR));
1199             (*lppszComponent)[ncpylen] = '\0';
1200             *dwComponentLen = ncpylen;
1201         }
1202     }
1203
1204     return TRUE;
1205 }
1206
1207 /***********************************************************************
1208  *           InternetCrackUrlW   (WININET.@)
1209  *
1210  * Break up URL into its components
1211  *
1212  * RETURNS
1213  *    TRUE on success
1214  *    FALSE on failure
1215  */
1216 BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWORD dwFlags,
1217                               LPURL_COMPONENTSW lpUC)
1218 {
1219   /*
1220    * RFC 1808
1221    * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1222    *
1223    */
1224     LPCWSTR lpszParam    = NULL;
1225     BOOL  bIsAbsolute = FALSE;
1226     LPCWSTR lpszap, lpszUrl = lpszUrl_orig;
1227     LPCWSTR lpszcp = NULL;
1228     LPWSTR  lpszUrl_decode = NULL;
1229     DWORD dwUrlLength = dwUrlLength_orig;
1230     const WCHAR lpszSeparators[3]={';','?',0};
1231     const WCHAR lpszSlash[2]={'/',0};
1232
1233     TRACE("(%s %u %x %p)\n", debugstr_w(lpszUrl), dwUrlLength, dwFlags, lpUC);
1234
1235     if (!lpszUrl_orig || !*lpszUrl_orig || !lpUC)
1236     {
1237         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1238         return FALSE;
1239     }
1240     if (!dwUrlLength) dwUrlLength = strlenW(lpszUrl);
1241
1242     if (dwFlags & ICU_DECODE)
1243     {
1244         lpszUrl_decode=HeapAlloc( GetProcessHeap(), 0,  dwUrlLength * sizeof (WCHAR) );
1245         if( InternetCanonicalizeUrlW(lpszUrl_orig, lpszUrl_decode, &dwUrlLength, dwFlags))
1246         {
1247             lpszUrl =  lpszUrl_decode;
1248         }
1249     }
1250     lpszap = lpszUrl;
1251     
1252     /* Determine if the URI is absolute. */
1253     while (*lpszap != '\0')
1254     {
1255         if (isalnumW(*lpszap))
1256         {
1257             lpszap++;
1258             continue;
1259         }
1260         if ((*lpszap == ':') && (lpszap - lpszUrl >= 2))
1261         {
1262             bIsAbsolute = TRUE;
1263             lpszcp = lpszap;
1264         }
1265         else
1266         {
1267             lpszcp = lpszUrl; /* Relative url */
1268         }
1269
1270         break;
1271     }
1272
1273     lpUC->nScheme = INTERNET_SCHEME_UNKNOWN;
1274     lpUC->nPort = INTERNET_INVALID_PORT_NUMBER;
1275
1276     /* Parse <params> */
1277     lpszParam = strpbrkW(lpszap, lpszSeparators);
1278     SetUrlComponentValueW(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength,
1279                           lpszParam, lpszParam ? dwUrlLength-(lpszParam-lpszUrl) : 0);
1280
1281     if (bIsAbsolute) /* Parse <protocol>:[//<net_loc>] */
1282     {
1283         LPCWSTR lpszNetLoc;
1284
1285         /* Get scheme first. */
1286         lpUC->nScheme = GetInternetSchemeW(lpszUrl, lpszcp - lpszUrl);
1287         SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength,
1288                                    lpszUrl, lpszcp - lpszUrl);
1289
1290         /* Eat ':' in protocol. */
1291         lpszcp++;
1292
1293         /* double slash indicates the net_loc portion is present */
1294         if ((lpszcp[0] == '/') && (lpszcp[1] == '/'))
1295         {
1296             lpszcp += 2;
1297
1298             lpszNetLoc = strpbrkW(lpszcp, lpszSlash);
1299             if (lpszParam)
1300             {
1301                 if (lpszNetLoc)
1302                     lpszNetLoc = min(lpszNetLoc, lpszParam);
1303                 else
1304                     lpszNetLoc = lpszParam;
1305             }
1306             else if (!lpszNetLoc)
1307                 lpszNetLoc = lpszcp + dwUrlLength-(lpszcp-lpszUrl);
1308
1309             /* Parse net-loc */
1310             if (lpszNetLoc)
1311             {
1312                 LPCWSTR lpszHost;
1313                 LPCWSTR lpszPort;
1314
1315                 /* [<user>[<:password>]@]<host>[:<port>] */
1316                 /* First find the user and password if they exist */
1317
1318                 lpszHost = strchrW(lpszcp, '@');
1319                 if (lpszHost == NULL || lpszHost > lpszNetLoc)
1320                 {
1321                     /* username and password not specified. */
1322                     SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1323                     SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1324                 }
1325                 else /* Parse out username and password */
1326                 {
1327                     LPCWSTR lpszUser = lpszcp;
1328                     LPCWSTR lpszPasswd = lpszHost;
1329
1330                     while (lpszcp < lpszHost)
1331                     {
1332                         if (*lpszcp == ':')
1333                             lpszPasswd = lpszcp;
1334
1335                         lpszcp++;
1336                     }
1337
1338                     SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength,
1339                                           lpszUser, lpszPasswd - lpszUser);
1340
1341                     if (lpszPasswd != lpszHost)
1342                         lpszPasswd++;
1343                     SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength,
1344                                           lpszPasswd == lpszHost ? NULL : lpszPasswd,
1345                                           lpszHost - lpszPasswd);
1346
1347                     lpszcp++; /* Advance to beginning of host */
1348                 }
1349
1350                 /* Parse <host><:port> */
1351
1352                 lpszHost = lpszcp;
1353                 lpszPort = lpszNetLoc;
1354
1355                 /* special case for res:// URLs: there is no port here, so the host is the
1356                    entire string up to the first '/' */
1357                 if(lpUC->nScheme==INTERNET_SCHEME_RES)
1358                 {
1359                     SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1360                                           lpszHost, lpszPort - lpszHost);
1361                     lpszcp=lpszNetLoc;
1362                 }
1363                 else
1364                 {
1365                     while (lpszcp < lpszNetLoc)
1366                     {
1367                         if (*lpszcp == ':')
1368                             lpszPort = lpszcp;
1369
1370                         lpszcp++;
1371                     }
1372
1373                     /* If the scheme is "file" and the host is just one letter, it's not a host */
1374                     if(lpUC->nScheme==INTERNET_SCHEME_FILE && (lpszPort-lpszHost)==1)
1375                     {
1376                         lpszcp=lpszHost;
1377                         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1378                                               NULL, 0);
1379                     }
1380                     else
1381                     {
1382                         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1383                                               lpszHost, lpszPort - lpszHost);
1384                         if (lpszPort != lpszNetLoc)
1385                             lpUC->nPort = atoiW(++lpszPort);
1386                         else switch (lpUC->nScheme)
1387                         {
1388                         case INTERNET_SCHEME_HTTP:
1389                             lpUC->nPort = INTERNET_DEFAULT_HTTP_PORT;
1390                             break;
1391                         case INTERNET_SCHEME_HTTPS:
1392                             lpUC->nPort = INTERNET_DEFAULT_HTTPS_PORT;
1393                             break;
1394                         case INTERNET_SCHEME_FTP:
1395                             lpUC->nPort = INTERNET_DEFAULT_FTP_PORT;
1396                             break;
1397                         case INTERNET_SCHEME_GOPHER:
1398                             lpUC->nPort = INTERNET_DEFAULT_GOPHER_PORT;
1399                             break;
1400                         default:
1401                             break;
1402                         }
1403                     }
1404                 }
1405             }
1406         }
1407         else
1408         {
1409             SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1410             SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1411             SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
1412         }
1413     }
1414     else
1415     {
1416         SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength, NULL, 0);
1417         SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1418         SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1419         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
1420     }
1421
1422     /* Here lpszcp points to:
1423      *
1424      * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1425      *                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1426      */
1427     if (lpszcp != 0 && *lpszcp != '\0' && (!lpszParam || lpszcp < lpszParam))
1428     {
1429         INT len;
1430
1431         /* Only truncate the parameter list if it's already been saved
1432          * in lpUC->lpszExtraInfo.
1433          */
1434         if (lpszParam && lpUC->dwExtraInfoLength && lpUC->lpszExtraInfo)
1435             len = lpszParam - lpszcp;
1436         else
1437         {
1438             /* Leave the parameter list in lpszUrlPath.  Strip off any trailing
1439              * newlines if necessary.
1440              */
1441             LPWSTR lpsznewline = strchrW(lpszcp, '\n');
1442             if (lpsznewline != NULL)
1443                 len = lpsznewline - lpszcp;
1444             else
1445                 len = dwUrlLength-(lpszcp-lpszUrl);
1446         }
1447         SetUrlComponentValueW(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength,
1448                                    lpszcp, len);
1449     }
1450     else
1451     {
1452         lpUC->dwUrlPathLength = 0;
1453     }
1454
1455     TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", debugstr_wn(lpszUrl,dwUrlLength),
1456              debugstr_wn(lpUC->lpszScheme,lpUC->dwSchemeLength),
1457              debugstr_wn(lpUC->lpszHostName,lpUC->dwHostNameLength),
1458              debugstr_wn(lpUC->lpszUrlPath,lpUC->dwUrlPathLength),
1459              debugstr_wn(lpUC->lpszExtraInfo,lpUC->dwExtraInfoLength));
1460
1461     HeapFree(GetProcessHeap(), 0, lpszUrl_decode );
1462     return TRUE;
1463 }
1464
1465 /***********************************************************************
1466  *           InternetAttemptConnect (WININET.@)
1467  *
1468  * Attempt to make a connection to the internet
1469  *
1470  * RETURNS
1471  *    ERROR_SUCCESS on success
1472  *    Error value   on failure
1473  *
1474  */
1475 DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
1476 {
1477     FIXME("Stub\n");
1478     return ERROR_SUCCESS;
1479 }
1480
1481
1482 /***********************************************************************
1483  *           InternetCanonicalizeUrlA (WININET.@)
1484  *
1485  * Escape unsafe characters and spaces
1486  *
1487  * RETURNS
1488  *    TRUE on success
1489  *    FALSE on failure
1490  *
1491  */
1492 BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
1493         LPDWORD lpdwBufferLength, DWORD dwFlags)
1494 {
1495     HRESULT hr;
1496     DWORD dwURLFlags = URL_WININET_COMPATIBILITY | URL_ESCAPE_UNSAFE;
1497
1498     TRACE("(%s, %p, %p, 0x%08x) bufferlength: %d\n", debugstr_a(lpszUrl), lpszBuffer,
1499         lpdwBufferLength, lpdwBufferLength ? *lpdwBufferLength : -1, dwFlags);
1500
1501     if(dwFlags & ICU_DECODE)
1502     {
1503         dwURLFlags |= URL_UNESCAPE;
1504         dwFlags &= ~ICU_DECODE;
1505     }
1506
1507     if(dwFlags & ICU_ESCAPE)
1508     {
1509         dwURLFlags |= URL_UNESCAPE;
1510         dwFlags &= ~ICU_ESCAPE;
1511     }
1512
1513     if(dwFlags & ICU_BROWSER_MODE)
1514     {
1515         dwURLFlags |= URL_BROWSER_MODE;
1516         dwFlags &= ~ICU_BROWSER_MODE;
1517     }
1518
1519     if(dwFlags & ICU_NO_ENCODE)
1520     {
1521         /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1522         dwURLFlags ^= URL_ESCAPE_UNSAFE;
1523         dwFlags &= ~ICU_NO_ENCODE;
1524     }
1525
1526     if (dwFlags) FIXME("Unhandled flags 0x%08x\n", dwFlags);
1527
1528     hr = UrlCanonicalizeA(lpszUrl, lpszBuffer, lpdwBufferLength, dwURLFlags);
1529     if (hr == E_POINTER) SetLastError(ERROR_INSUFFICIENT_BUFFER);
1530     if (hr == E_INVALIDARG) SetLastError(ERROR_INVALID_PARAMETER);
1531
1532     return (hr == S_OK) ? TRUE : FALSE;
1533 }
1534
1535 /***********************************************************************
1536  *           InternetCanonicalizeUrlW (WININET.@)
1537  *
1538  * Escape unsafe characters and spaces
1539  *
1540  * RETURNS
1541  *    TRUE on success
1542  *    FALSE on failure
1543  *
1544  */
1545 BOOL WINAPI InternetCanonicalizeUrlW(LPCWSTR lpszUrl, LPWSTR lpszBuffer,
1546     LPDWORD lpdwBufferLength, DWORD dwFlags)
1547 {
1548     HRESULT hr;
1549     DWORD dwURLFlags = URL_WININET_COMPATIBILITY | URL_ESCAPE_UNSAFE;
1550
1551     TRACE("(%s, %p, %p, 0x%08x) bufferlength: %d\n", debugstr_w(lpszUrl), lpszBuffer,
1552         lpdwBufferLength, lpdwBufferLength ? *lpdwBufferLength : -1, dwFlags);
1553
1554     if(dwFlags & ICU_DECODE)
1555     {
1556         dwURLFlags |= URL_UNESCAPE;
1557         dwFlags &= ~ICU_DECODE;
1558     }
1559
1560     if(dwFlags & ICU_ESCAPE)
1561     {
1562         dwURLFlags |= URL_UNESCAPE;
1563         dwFlags &= ~ICU_ESCAPE;
1564     }
1565
1566     if(dwFlags & ICU_BROWSER_MODE)
1567     {
1568         dwURLFlags |= URL_BROWSER_MODE;
1569         dwFlags &= ~ICU_BROWSER_MODE;
1570     }
1571
1572     if(dwFlags & ICU_NO_ENCODE)
1573     {
1574         /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1575         dwURLFlags ^= URL_ESCAPE_UNSAFE;
1576         dwFlags &= ~ICU_NO_ENCODE;
1577     }
1578
1579     if (dwFlags) FIXME("Unhandled flags 0x%08x\n", dwFlags);
1580
1581     hr = UrlCanonicalizeW(lpszUrl, lpszBuffer, lpdwBufferLength, dwURLFlags);
1582     if (hr == E_POINTER) SetLastError(ERROR_INSUFFICIENT_BUFFER);
1583     if (hr == E_INVALIDARG) SetLastError(ERROR_INVALID_PARAMETER);
1584
1585     return (hr == S_OK) ? TRUE : FALSE;
1586 }
1587
1588 /* #################################################### */
1589
1590 static INTERNET_STATUS_CALLBACK set_status_callback(
1591     LPWININETHANDLEHEADER lpwh, INTERNET_STATUS_CALLBACK callback, BOOL unicode)
1592 {
1593     INTERNET_STATUS_CALLBACK ret;
1594
1595     if (unicode) lpwh->dwInternalFlags |= INET_CALLBACKW;
1596     else lpwh->dwInternalFlags &= ~INET_CALLBACKW;
1597
1598     ret = lpwh->lpfnStatusCB;
1599     lpwh->lpfnStatusCB = callback;
1600
1601     return ret;
1602 }
1603
1604 /***********************************************************************
1605  *           InternetSetStatusCallbackA (WININET.@)
1606  *
1607  * Sets up a callback function which is called as progress is made
1608  * during an operation.
1609  *
1610  * RETURNS
1611  *    Previous callback or NULL         on success
1612  *    INTERNET_INVALID_STATUS_CALLBACK  on failure
1613  *
1614  */
1615 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackA(
1616         HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
1617 {
1618     INTERNET_STATUS_CALLBACK retVal;
1619     LPWININETHANDLEHEADER lpwh;
1620
1621     TRACE("0x%08x\n", (ULONG)hInternet);
1622     
1623     if (!(lpwh = WININET_GetObject(hInternet)))
1624         return INTERNET_INVALID_STATUS_CALLBACK;
1625
1626     retVal = set_status_callback(lpwh, lpfnIntCB, FALSE);
1627
1628     WININET_Release( lpwh );
1629     return retVal;
1630 }
1631
1632 /***********************************************************************
1633  *           InternetSetStatusCallbackW (WININET.@)
1634  *
1635  * Sets up a callback function which is called as progress is made
1636  * during an operation.
1637  *
1638  * RETURNS
1639  *    Previous callback or NULL         on success
1640  *    INTERNET_INVALID_STATUS_CALLBACK  on failure
1641  *
1642  */
1643 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackW(
1644         HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
1645 {
1646     INTERNET_STATUS_CALLBACK retVal;
1647     LPWININETHANDLEHEADER lpwh;
1648
1649     TRACE("0x%08x\n", (ULONG)hInternet);
1650
1651     if (!(lpwh = WININET_GetObject(hInternet)))
1652         return INTERNET_INVALID_STATUS_CALLBACK;
1653
1654     retVal = set_status_callback(lpwh, lpfnIntCB, TRUE);
1655
1656     WININET_Release( lpwh );
1657     return retVal;
1658 }
1659
1660 /***********************************************************************
1661  *           InternetSetFilePointer (WININET.@)
1662  */
1663 DWORD WINAPI InternetSetFilePointer(HINTERNET hFile, LONG lDistanceToMove,
1664     PVOID pReserved, DWORD dwMoveContext, DWORD_PTR dwContext)
1665 {
1666     FIXME("stub\n");
1667     return FALSE;
1668 }
1669
1670 /***********************************************************************
1671  *           InternetWriteFile (WININET.@)
1672  *
1673  * Write data to an open internet file
1674  *
1675  * RETURNS
1676  *    TRUE  on success
1677  *    FALSE on failure
1678  *
1679  */
1680 BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer,
1681         DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
1682 {
1683     LPWININETHANDLEHEADER lpwh;
1684     BOOL retval = FALSE;
1685
1686     TRACE("(%p %p %d %p)\n", hFile, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten);
1687
1688     lpwh = WININET_GetObject( hFile );
1689
1690     if(lpwh && lpwh->vtbl->WriteFile) {
1691         retval = lpwh->vtbl->WriteFile(lpwh, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten);
1692     }else {
1693         WARN("Invalid handle\n");
1694         SetLastError(ERROR_INVALID_HANDLE);
1695         retval = FALSE;
1696     }
1697
1698     WININET_Release( lpwh );
1699
1700     return retval;
1701 }
1702
1703
1704 /***********************************************************************
1705  *           InternetReadFile (WININET.@)
1706  *
1707  * Read data from an open internet file
1708  *
1709  * RETURNS
1710  *    TRUE  on success
1711  *    FALSE on failure
1712  *
1713  */
1714 BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
1715         DWORD dwNumOfBytesToRead, LPDWORD pdwNumOfBytesRead)
1716 {
1717     LPWININETHANDLEHEADER hdr;
1718     DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
1719
1720     TRACE("%p %p %d %p\n", hFile, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead);
1721
1722     hdr = WININET_GetObject(hFile);
1723     if (!hdr) {
1724         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1725         return FALSE;
1726     }
1727
1728     if(hdr->vtbl->ReadFile)
1729         res = hdr->vtbl->ReadFile(hdr, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead);
1730
1731     WININET_Release(hdr);
1732
1733     TRACE("-- %s (%u) (bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE", res,
1734           pdwNumOfBytesRead ? *pdwNumOfBytesRead : -1);
1735
1736     if(res != ERROR_SUCCESS)
1737         SetLastError(res);
1738     return res == ERROR_SUCCESS;
1739 }
1740
1741 /***********************************************************************
1742  *           InternetReadFileExA (WININET.@)
1743  *
1744  * Read data from an open internet file
1745  *
1746  * PARAMS
1747  *  hFile         [I] Handle returned by InternetOpenUrl or HttpOpenRequest.
1748  *  lpBuffersOut  [I/O] Buffer.
1749  *  dwFlags       [I] Flags. See notes.
1750  *  dwContext     [I] Context for callbacks.
1751  *
1752  * RETURNS
1753  *    TRUE  on success
1754  *    FALSE on failure
1755  *
1756  * NOTES
1757  *  The parameter dwFlags include zero or more of the following flags:
1758  *|IRF_ASYNC - Makes the call asynchronous.
1759  *|IRF_SYNC - Makes the call synchronous.
1760  *|IRF_USE_CONTEXT - Forces dwContext to be used.
1761  *|IRF_NO_WAIT - Don't block if the data is not available, just return what is available.
1762  *
1763  * However, in testing IRF_USE_CONTEXT seems to have no effect - dwContext isn't used.
1764  *
1765  * SEE
1766  *  InternetOpenUrlA(), HttpOpenRequestA()
1767  */
1768 BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffersOut,
1769         DWORD dwFlags, DWORD_PTR dwContext)
1770 {
1771     LPWININETHANDLEHEADER hdr;
1772     DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
1773
1774     TRACE("(%p %p 0x%x 0x%lx)\n", hFile, lpBuffersOut, dwFlags, dwContext);
1775
1776     hdr = WININET_GetObject(hFile);
1777     if (!hdr) {
1778         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1779         return FALSE;
1780     }
1781
1782     if(hdr->vtbl->ReadFileExA)
1783         res = hdr->vtbl->ReadFileExA(hdr, lpBuffersOut, dwFlags, dwContext);
1784
1785     WININET_Release(hdr);
1786
1787     TRACE("-- %s (%u, bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE",
1788           res, lpBuffersOut->dwBufferLength);
1789
1790     if(res != ERROR_SUCCESS)
1791         SetLastError(res);
1792     return res == ERROR_SUCCESS;
1793 }
1794
1795 /***********************************************************************
1796  *           InternetReadFileExW (WININET.@)
1797  *
1798  * Read data from an open internet file.
1799  *
1800  * PARAMS
1801  *  hFile         [I] Handle returned by InternetOpenUrl() or HttpOpenRequest().
1802  *  lpBuffersOut  [I/O] Buffer.
1803  *  dwFlags       [I] Flags.
1804  *  dwContext     [I] Context for callbacks.
1805  *
1806  * RETURNS
1807  *    FALSE, last error is set to ERROR_CALL_NOT_IMPLEMENTED
1808  *
1809  * NOTES
1810  *  Not implemented in Wine or native either (as of IE6 SP2).
1811  *
1812  */
1813 BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer,
1814         DWORD dwFlags, DWORD_PTR dwContext)
1815 {
1816   ERR("(%p, %p, 0x%x, 0x%lx): not implemented in native\n", hFile, lpBuffer, dwFlags, dwContext);
1817
1818   INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1819   return FALSE;
1820 }
1821
1822 /***********************************************************************
1823  *           INET_QueryOptionHelper (internal)
1824  */
1825 static BOOL INET_QueryOptionHelper(BOOL bIsUnicode, HINTERNET hInternet, DWORD dwOption,
1826                                    LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1827 {
1828     LPWININETHANDLEHEADER lpwhh;
1829     BOOL bSuccess = FALSE;
1830
1831     TRACE("(%p, 0x%08x, %p, %p)\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
1832
1833     lpwhh = (LPWININETHANDLEHEADER) WININET_GetObject( hInternet );
1834
1835     switch (dwOption)
1836     {
1837         case INTERNET_OPTION_HANDLE_TYPE:
1838         {
1839             ULONG type;
1840
1841             if (!lpwhh)
1842             {
1843                 WARN("Invalid hInternet handle\n");
1844                 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1845                 return FALSE;
1846             }
1847
1848             type = lpwhh->htype;
1849
1850             TRACE("INTERNET_OPTION_HANDLE_TYPE: %d\n", type);
1851
1852             if (*lpdwBufferLength < sizeof(ULONG))
1853                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1854             else
1855             {
1856                 memcpy(lpBuffer, &type, sizeof(ULONG));
1857                 bSuccess = TRUE;
1858             }
1859             *lpdwBufferLength = sizeof(ULONG);
1860             break;
1861         }
1862
1863         case INTERNET_OPTION_REQUEST_FLAGS:
1864         {
1865             ULONG flags = 4;
1866             TRACE("INTERNET_OPTION_REQUEST_FLAGS: %d\n", flags);
1867             if (*lpdwBufferLength < sizeof(ULONG))
1868                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1869             else
1870             {
1871                 memcpy(lpBuffer, &flags, sizeof(ULONG));
1872                 bSuccess = TRUE;
1873             }
1874             *lpdwBufferLength = sizeof(ULONG);
1875             break;
1876         }
1877
1878         case INTERNET_OPTION_URL:
1879         {
1880             TRACE("INTERNET_OPTION_URL\n");
1881
1882             if (!lpwhh)
1883             {
1884                 WARN("Invalid hInternet handle\n");
1885                 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1886                 return FALSE;
1887             }
1888             if (lpwhh->htype == WH_HHTTPREQ)
1889             {
1890                 LPWININETHTTPREQW lpreq = (LPWININETHTTPREQW) lpwhh;
1891                 WCHAR url[1023];
1892                 static const WCHAR szFmt[] = {'h','t','t','p',':','/','/','%','s','%','s',0};
1893                 static const WCHAR szHost[] = {'H','o','s','t',0};
1894                 DWORD sizeRequired;
1895                 LPHTTPHEADERW Host;
1896
1897                 Host = HTTP_GetHeader(lpreq,szHost);
1898                 sprintfW(url,szFmt,Host->lpszValue,lpreq->lpszPath);
1899                 TRACE("INTERNET_OPTION_URL: %s\n",debugstr_w(url));
1900                 if(!bIsUnicode)
1901                 {
1902                     sizeRequired = WideCharToMultiByte(CP_ACP,0,url,-1,
1903                      lpBuffer,*lpdwBufferLength,NULL,NULL);
1904                     if (sizeRequired > *lpdwBufferLength)
1905                         INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1906                     else
1907                         bSuccess = TRUE;
1908                     *lpdwBufferLength = sizeRequired;
1909                 }
1910                 else
1911                 {
1912                     sizeRequired = (lstrlenW(url)+1) * sizeof(WCHAR);
1913                     if (*lpdwBufferLength < sizeRequired)
1914                         INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1915                     else
1916                     {
1917                         strcpyW(lpBuffer, url);
1918                         bSuccess = TRUE;
1919                     }
1920                     *lpdwBufferLength = sizeRequired;
1921                 }
1922             }
1923             break;
1924         }
1925
1926         case INTERNET_OPTION_DATAFILE_NAME:
1927         {
1928             TRACE("INTERNET_OPTION_DATAFILE_NAME\n");
1929             if (!lpwhh)
1930             {
1931                 WARN("Invalid hInternet handle\n");
1932                 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1933                 return FALSE;
1934             }
1935             if (lpwhh->htype == WH_HHTTPREQ)
1936             {
1937                 LPWININETHTTPREQW lpreq = (LPWININETHTTPREQW) lpwhh;
1938                 DWORD size;
1939
1940                 if(!lpreq->lpszCacheFile) {
1941                     *lpdwBufferLength = 0;
1942                     INTERNET_SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND);
1943                 }
1944                 else if(bIsUnicode)
1945                 {
1946                     size = (lstrlenW(lpreq->lpszCacheFile)+1) * sizeof(WCHAR);
1947                     if (*lpdwBufferLength < size)
1948                         INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1949                     else
1950                     {
1951                         memcpy(lpBuffer, lpreq->lpszCacheFile, size);
1952                         bSuccess = TRUE;
1953                     }
1954                     *lpdwBufferLength = size;
1955                 }
1956                 else
1957                 {
1958                     size = WideCharToMultiByte(CP_ACP, 0, lpreq->lpszCacheFile, -1, NULL, 0, NULL, NULL);
1959                     if (size > *lpdwBufferLength) {
1960                         INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1961                     }else {
1962                         *lpdwBufferLength = WideCharToMultiByte(CP_ACP, 0, lpreq->lpszCacheFile,
1963                                 -1, lpBuffer, *lpdwBufferLength, NULL, NULL);
1964                         bSuccess = TRUE;
1965                     }
1966                 }
1967             }
1968             break;
1969         }
1970
1971         case INTERNET_OPTION_HTTP_VERSION:
1972         {
1973             if (*lpdwBufferLength < sizeof(HTTP_VERSION_INFO))
1974                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1975             else
1976             {
1977                 /*
1978                  * Presently hardcoded to 1.1
1979                  */
1980                 ((HTTP_VERSION_INFO*)lpBuffer)->dwMajorVersion = 1;
1981                 ((HTTP_VERSION_INFO*)lpBuffer)->dwMinorVersion = 1;
1982                 bSuccess = TRUE;
1983             }
1984             *lpdwBufferLength = sizeof(HTTP_VERSION_INFO);
1985             break;
1986         }
1987        case INTERNET_OPTION_CONNECTED_STATE:
1988        {
1989             DWORD *pdwConnectedState = (DWORD *)lpBuffer;
1990             FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n");
1991
1992             if (*lpdwBufferLength < sizeof(*pdwConnectedState))
1993                  INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1994             else
1995             {
1996                 *pdwConnectedState = INTERNET_STATE_CONNECTED;
1997                 bSuccess = TRUE;
1998             }
1999             *lpdwBufferLength = sizeof(*pdwConnectedState);
2000             break;
2001         }
2002         case INTERNET_OPTION_PROXY:
2003         {
2004             LPWININETAPPINFOW lpwai = (LPWININETAPPINFOW)lpwhh;
2005             WININETAPPINFOW wai;
2006
2007             if (lpwai == NULL)
2008             {
2009                 TRACE("Getting global proxy info\n");
2010                 memset(&wai, 0, sizeof(WININETAPPINFOW));
2011                 INTERNET_ConfigureProxyFromReg( &wai );
2012                 lpwai = &wai;
2013             }
2014
2015             if (bIsUnicode)
2016             {
2017                 INTERNET_PROXY_INFOW *pPI = (INTERNET_PROXY_INFOW *)lpBuffer;
2018                 DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
2019
2020                 if (lpwai->lpszProxy)
2021                     proxyBytesRequired = (lstrlenW(lpwai->lpszProxy) + 1) *
2022                      sizeof(WCHAR);
2023                 if (lpwai->lpszProxyBypass)
2024                     proxyBypassBytesRequired =
2025                      (lstrlenW(lpwai->lpszProxyBypass) + 1) * sizeof(WCHAR);
2026                 if (*lpdwBufferLength < sizeof(INTERNET_PROXY_INFOW) +
2027                  proxyBytesRequired + proxyBypassBytesRequired)
2028                     INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2029                 else
2030                 {
2031                     LPWSTR proxy = (LPWSTR)((LPBYTE)lpBuffer +
2032                                             sizeof(INTERNET_PROXY_INFOW));
2033                     LPWSTR proxy_bypass = (LPWSTR)((LPBYTE)lpBuffer +
2034                                                    sizeof(INTERNET_PROXY_INFOW) +
2035                                                    proxyBytesRequired);
2036
2037                     pPI->dwAccessType = lpwai->dwAccessType;
2038                     pPI->lpszProxy = NULL;
2039                     pPI->lpszProxyBypass = NULL;
2040                     if (lpwai->lpszProxy)
2041                     {
2042                         lstrcpyW(proxy, lpwai->lpszProxy);
2043                         pPI->lpszProxy = proxy;
2044                     }
2045
2046                     if (lpwai->lpszProxyBypass)
2047                     {
2048                         lstrcpyW(proxy_bypass, lpwai->lpszProxyBypass);
2049                         pPI->lpszProxyBypass = proxy_bypass;
2050                     }
2051                     bSuccess = TRUE;
2052                 }
2053                 *lpdwBufferLength = sizeof(INTERNET_PROXY_INFOW) +
2054                  proxyBytesRequired + proxyBypassBytesRequired;
2055             }
2056             else
2057             {
2058                 INTERNET_PROXY_INFOA *pPI = (INTERNET_PROXY_INFOA *)lpBuffer;
2059                 DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
2060
2061                 if (lpwai->lpszProxy)
2062                     proxyBytesRequired = WideCharToMultiByte(CP_ACP, 0,
2063                      lpwai->lpszProxy, -1, NULL, 0, NULL, NULL);
2064                 if (lpwai->lpszProxyBypass)
2065                     proxyBypassBytesRequired = WideCharToMultiByte(CP_ACP, 0,
2066                      lpwai->lpszProxyBypass, -1, NULL, 0, NULL, NULL);
2067                 if (*lpdwBufferLength < sizeof(INTERNET_PROXY_INFOA) +
2068                  proxyBytesRequired + proxyBypassBytesRequired)
2069                     INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2070                 else
2071                 {
2072                     LPSTR proxy = (LPSTR)((LPBYTE)lpBuffer +
2073                                           sizeof(INTERNET_PROXY_INFOA));
2074                     LPSTR proxy_bypass = (LPSTR)((LPBYTE)lpBuffer +
2075                                                  sizeof(INTERNET_PROXY_INFOA) +
2076                                                  proxyBytesRequired);
2077
2078                     pPI->dwAccessType = lpwai->dwAccessType;
2079                     pPI->lpszProxy = NULL;
2080                     pPI->lpszProxyBypass = NULL;
2081                     if (lpwai->lpszProxy)
2082                     {
2083                         WideCharToMultiByte(CP_ACP, 0, lpwai->lpszProxy, -1,
2084                                             proxy, proxyBytesRequired, NULL, NULL);
2085                         pPI->lpszProxy = proxy;
2086                     }
2087
2088                     if (lpwai->lpszProxyBypass)
2089                     {
2090                         WideCharToMultiByte(CP_ACP, 0, lpwai->lpszProxyBypass,
2091                                             -1, proxy_bypass, proxyBypassBytesRequired,
2092                                             NULL, NULL);
2093                         pPI->lpszProxyBypass = proxy_bypass;
2094                     }
2095                     bSuccess = TRUE;
2096                 }
2097                 *lpdwBufferLength = sizeof(INTERNET_PROXY_INFOA) +
2098                  proxyBytesRequired + proxyBypassBytesRequired;
2099             }
2100             break;
2101         }
2102         case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2103         {
2104             ULONG conn = 2;
2105             TRACE("INTERNET_OPTION_MAX_CONNS_PER_SERVER: %d\n", conn);
2106             if (*lpdwBufferLength < sizeof(ULONG))
2107                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2108             else
2109             {
2110                 memcpy(lpBuffer, &conn, sizeof(ULONG));
2111                 bSuccess = TRUE;
2112             }
2113             *lpdwBufferLength = sizeof(ULONG);
2114             break;
2115         }
2116         case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2117         {
2118             ULONG conn = 4;
2119             TRACE("INTERNET_OPTION_MAX_CONNS_1_0_SERVER: %d\n", conn);
2120             if (*lpdwBufferLength < sizeof(ULONG))
2121                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2122             else
2123             {
2124                 memcpy(lpBuffer, &conn, sizeof(ULONG));
2125                 bSuccess = TRUE;
2126             }
2127             *lpdwBufferLength = sizeof(ULONG);
2128             break;
2129         }
2130         case INTERNET_OPTION_SECURITY_FLAGS:
2131             FIXME("INTERNET_OPTION_SECURITY_FLAGS: Stub\n");
2132             bSuccess = TRUE;
2133             break;
2134
2135         case INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT:
2136             if (!lpwhh)
2137             {
2138                 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2139                 return FALSE;
2140             }
2141             if (*lpdwBufferLength < sizeof(INTERNET_CERTIFICATE_INFOW))
2142             {
2143                 *lpdwBufferLength = sizeof(INTERNET_CERTIFICATE_INFOW);
2144                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2145             }
2146             else if (lpwhh->htype == WH_HHTTPREQ)
2147             {
2148                 LPWININETHTTPREQW lpwhr;
2149                 PCCERT_CONTEXT context;
2150
2151                 lpwhr = (LPWININETHTTPREQW)lpwhh;
2152                 context = (PCCERT_CONTEXT)NETCON_GetCert(&(lpwhr->netConnection));
2153                 if (context)
2154                 {
2155                     LPINTERNET_CERTIFICATE_INFOW info = (LPINTERNET_CERTIFICATE_INFOW)lpBuffer;
2156                     DWORD strLen;
2157
2158                     memset(info,0,sizeof(INTERNET_CERTIFICATE_INFOW));
2159                     info->ftExpiry = context->pCertInfo->NotAfter;
2160                     info->ftStart = context->pCertInfo->NotBefore;
2161                     if (bIsUnicode)
2162                     {
2163                         strLen = CertNameToStrW(context->dwCertEncodingType,
2164                          &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR,
2165                          NULL, 0);
2166                         info->lpszSubjectInfo = LocalAlloc(0,
2167                          strLen * sizeof(WCHAR));
2168                         if (info->lpszSubjectInfo)
2169                             CertNameToStrW(context->dwCertEncodingType,
2170                              &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR,
2171                              info->lpszSubjectInfo, strLen);
2172                         strLen = CertNameToStrW(context->dwCertEncodingType,
2173                          &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR,
2174                          NULL, 0);
2175                         info->lpszIssuerInfo = LocalAlloc(0,
2176                          strLen * sizeof(WCHAR));
2177                         if (info->lpszIssuerInfo)
2178                             CertNameToStrW(context->dwCertEncodingType,
2179                              &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR,
2180                              info->lpszIssuerInfo, strLen);
2181                     }
2182                     else
2183                     {
2184                         LPINTERNET_CERTIFICATE_INFOA infoA =
2185                          (LPINTERNET_CERTIFICATE_INFOA)info;
2186
2187                         strLen = CertNameToStrA(context->dwCertEncodingType,
2188                          &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR,
2189                          NULL, 0);
2190                         infoA->lpszSubjectInfo = LocalAlloc(0, strLen);
2191                         if (infoA->lpszSubjectInfo)
2192                             CertNameToStrA(context->dwCertEncodingType,
2193                              &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR,
2194                              infoA->lpszSubjectInfo, strLen);
2195                         strLen = CertNameToStrA(context->dwCertEncodingType,
2196                          &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR,
2197                          NULL, 0);
2198                         infoA->lpszIssuerInfo = LocalAlloc(0, strLen);
2199                         if (infoA->lpszIssuerInfo)
2200                             CertNameToStrA(context->dwCertEncodingType,
2201                              &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR,
2202                              infoA->lpszIssuerInfo, strLen);
2203                     }
2204                     /*
2205                      * Contrary to MSDN, these do not appear to be set.
2206                      * lpszProtocolName
2207                      * lpszSignatureAlgName
2208                      * lpszEncryptionAlgName
2209                      * dwKeySize
2210                      */
2211                     CertFreeCertificateContext(context);
2212                     bSuccess = TRUE;
2213                 }
2214             }
2215             break;
2216         case INTERNET_OPTION_VERSION:
2217         {
2218             TRACE("INTERNET_OPTION_VERSION\n");
2219             if (*lpdwBufferLength < sizeof(INTERNET_VERSION_INFO))
2220                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2221             else
2222             {
2223                 static const INTERNET_VERSION_INFO info = { 1, 2 };
2224                 memcpy(lpBuffer, &info, sizeof(info));
2225                 *lpdwBufferLength = sizeof(info);
2226                 bSuccess = TRUE;
2227             }
2228             break;
2229         }
2230         case INTERNET_OPTION_PER_CONNECTION_OPTION:
2231             FIXME("INTERNET_OPTION_PER_CONNECTION_OPTION stub\n");
2232             if (*lpdwBufferLength < sizeof(INTERNET_PER_CONN_OPTION_LISTW))
2233                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2234             else
2235             {
2236                 INTERNET_PER_CONN_OPTION_LISTW *con = lpBuffer;
2237                 int x;
2238                 bSuccess = TRUE;
2239                 for (x = 0; x < con->dwOptionCount; ++x)
2240                 {
2241                     INTERNET_PER_CONN_OPTIONW *option = con->pOptions + x;
2242                     switch (option->dwOption)
2243                     {
2244                     case INTERNET_PER_CONN_FLAGS:
2245                         option->Value.dwValue = PROXY_TYPE_DIRECT;
2246                         break;
2247
2248                     case INTERNET_PER_CONN_PROXY_SERVER:
2249                     case INTERNET_PER_CONN_PROXY_BYPASS:
2250                     case INTERNET_PER_CONN_AUTOCONFIG_URL:
2251                     case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
2252                     case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
2253                     case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
2254                     case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
2255                     case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
2256                         FIXME("Unhandled dwOption %d\n", option->dwOption);
2257                         option->Value.dwValue = 0;
2258                         bSuccess = FALSE;
2259                         break;
2260
2261                     default:
2262                         FIXME("Unknown dwOption %d\n", option->dwOption);
2263                         bSuccess = FALSE;
2264                         break;
2265                     }
2266                 }
2267                 if (!bSuccess)
2268                     INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2269             }
2270             break;
2271     case 66:
2272         FIXME("66\n");
2273         bSuccess = TRUE;
2274         break;
2275         default:
2276             FIXME("Stub! %d\n", dwOption);
2277             break;
2278     }
2279     if (lpwhh)
2280         WININET_Release( lpwhh );
2281
2282     return bSuccess;
2283 }
2284
2285 /***********************************************************************
2286  *           InternetQueryOptionW (WININET.@)
2287  *
2288  * Queries an options on the specified handle
2289  *
2290  * RETURNS
2291  *    TRUE  on success
2292  *    FALSE on failure
2293  *
2294  */
2295 BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption,
2296                                  LPVOID lpBuffer, LPDWORD lpdwBufferLength)
2297 {
2298     return INET_QueryOptionHelper(TRUE, hInternet, dwOption, lpBuffer, lpdwBufferLength);
2299 }
2300
2301 /***********************************************************************
2302  *           InternetQueryOptionA (WININET.@)
2303  *
2304  * Queries an options on the specified handle
2305  *
2306  * RETURNS
2307  *    TRUE  on success
2308  *    FALSE on failure
2309  *
2310  */
2311 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
2312                                  LPVOID lpBuffer, LPDWORD lpdwBufferLength)
2313 {
2314     return INET_QueryOptionHelper(FALSE, hInternet, dwOption, lpBuffer, lpdwBufferLength);
2315 }
2316
2317
2318 /***********************************************************************
2319  *           InternetSetOptionW (WININET.@)
2320  *
2321  * Sets an options on the specified handle
2322  *
2323  * RETURNS
2324  *    TRUE  on success
2325  *    FALSE on failure
2326  *
2327  */
2328 BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
2329                            LPVOID lpBuffer, DWORD dwBufferLength)
2330 {
2331     LPWININETHANDLEHEADER lpwhh;
2332     BOOL ret = TRUE;
2333
2334     TRACE("(%p %d %p %d)\n", hInternet, dwOption, lpBuffer, dwBufferLength);
2335
2336     lpwhh = (LPWININETHANDLEHEADER) WININET_GetObject( hInternet );
2337     if(lpwhh && lpwhh->vtbl->SetOption) {
2338         DWORD res;
2339
2340         res = lpwhh->vtbl->SetOption(lpwhh, dwOption, lpBuffer, dwBufferLength);
2341         if(res != ERROR_INTERNET_INVALID_OPTION) {
2342             WININET_Release( lpwhh );
2343
2344             if(res != ERROR_SUCCESS)
2345                 SetLastError(res);
2346
2347             return res == ERROR_SUCCESS;
2348         }
2349     }
2350
2351     switch (dwOption)
2352     {
2353     case INTERNET_OPTION_CALLBACK:
2354       {
2355         INTERNET_STATUS_CALLBACK callback = *(INTERNET_STATUS_CALLBACK *)lpBuffer;
2356         ret = (set_status_callback(lpwhh, callback, TRUE) != INTERNET_INVALID_STATUS_CALLBACK);
2357         break;
2358       }
2359     case INTERNET_OPTION_HTTP_VERSION:
2360       {
2361         HTTP_VERSION_INFO* pVersion=(HTTP_VERSION_INFO*)lpBuffer;
2362         FIXME("Option INTERNET_OPTION_HTTP_VERSION(%d,%d): STUB\n",pVersion->dwMajorVersion,pVersion->dwMinorVersion);
2363       }
2364       break;
2365     case INTERNET_OPTION_ERROR_MASK:
2366       {
2367         unsigned long flags=*(unsigned long*)lpBuffer;
2368         FIXME("Option INTERNET_OPTION_ERROR_MASK(%ld): STUB\n",flags);
2369       }
2370       break;
2371     case INTERNET_OPTION_CODEPAGE:
2372       {
2373         unsigned long codepage=*(unsigned long*)lpBuffer;
2374         FIXME("Option INTERNET_OPTION_CODEPAGE (%ld): STUB\n",codepage);
2375       }
2376       break;
2377     case INTERNET_OPTION_REQUEST_PRIORITY:
2378       {
2379         unsigned long priority=*(unsigned long*)lpBuffer;
2380         FIXME("Option INTERNET_OPTION_REQUEST_PRIORITY (%ld): STUB\n",priority);
2381       }
2382       break;
2383     case INTERNET_OPTION_CONNECT_TIMEOUT:
2384       {
2385         unsigned long connecttimeout=*(unsigned long*)lpBuffer;
2386         FIXME("Option INTERNET_OPTION_CONNECT_TIMEOUT (%ld): STUB\n",connecttimeout);
2387       }
2388       break;
2389     case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT:
2390       {
2391         unsigned long receivetimeout=*(unsigned long*)lpBuffer;
2392         FIXME("Option INTERNET_OPTION_DATA_RECEIVE_TIMEOUT (%ld): STUB\n",receivetimeout);
2393       }
2394       break;
2395     case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2396       {
2397         unsigned long conns=*(unsigned long*)lpBuffer;
2398         FIXME("Option INTERNET_OPTION_MAX_CONNS_PER_SERVER (%ld): STUB\n",conns);
2399       }
2400       break;
2401     case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2402       {
2403         unsigned long conns=*(unsigned long*)lpBuffer;
2404         FIXME("Option INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER (%ld): STUB\n",conns);
2405       }
2406       break;
2407     case INTERNET_OPTION_RESET_URLCACHE_SESSION:
2408         FIXME("Option INTERNET_OPTION_RESET_URLCACHE_SESSION: STUB\n");
2409         break;
2410     case INTERNET_OPTION_END_BROWSER_SESSION:
2411         FIXME("Option INTERNET_OPTION_END_BROWSER_SESSION: STUB\n");
2412         break;
2413     case INTERNET_OPTION_CONNECTED_STATE:
2414         FIXME("Option INTERNET_OPTION_CONNECTED_STATE: STUB\n");
2415         break;
2416     case INTERNET_OPTION_DISABLE_PASSPORT_AUTH:
2417         TRACE("Option INTERNET_OPTION_DISABLE_PASSPORT_AUTH: harmless stub, since not enabled\n");
2418         break;
2419     case INTERNET_OPTION_SEND_TIMEOUT:
2420     case INTERNET_OPTION_RECEIVE_TIMEOUT:
2421         FIXME("INTERNET_OPTION_SEND/RECEIVE_TIMEOUT\n");
2422         break;
2423     case INTERNET_OPTION_CONNECT_RETRIES:
2424         FIXME("Option INTERNET_OPTION_CONNECT_RETRIES: STUB\n");
2425         break;
2426     case INTERNET_OPTION_CONTEXT_VALUE:
2427          FIXME("Option INTERNET_OPTION_CONTEXT_VALUE; STUB\n");
2428          break;
2429     case INTERNET_OPTION_SECURITY_FLAGS:
2430          FIXME("Option INTERNET_OPTION_SECURITY_FLAGS; STUB\n");
2431          break;
2432     case 86:
2433         FIXME("86\n");
2434         break;
2435     default:
2436         FIXME("Option %d STUB\n",dwOption);
2437         INTERNET_SetLastError(ERROR_INTERNET_INVALID_OPTION);
2438         ret = FALSE;
2439         break;
2440     }
2441
2442     if(lpwhh)
2443         WININET_Release( lpwhh );
2444
2445     return ret;
2446 }
2447
2448
2449 /***********************************************************************
2450  *           InternetSetOptionA (WININET.@)
2451  *
2452  * Sets an options on the specified handle.
2453  *
2454  * RETURNS
2455  *    TRUE  on success
2456  *    FALSE on failure
2457  *
2458  */
2459 BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
2460                            LPVOID lpBuffer, DWORD dwBufferLength)
2461 {
2462     LPVOID wbuffer;
2463     DWORD wlen;
2464     BOOL r;
2465
2466     switch( dwOption )
2467     {
2468     case INTERNET_OPTION_CALLBACK:
2469         {
2470         LPWININETHANDLEHEADER lpwh;
2471         INTERNET_STATUS_CALLBACK callback = *(INTERNET_STATUS_CALLBACK *)lpBuffer;
2472
2473         if (!(lpwh = WININET_GetObject(hInternet))) return FALSE;
2474         r = (set_status_callback(lpwh, callback, FALSE) != INTERNET_INVALID_STATUS_CALLBACK);
2475         WININET_Release(lpwh);
2476         return r;
2477         }
2478     case INTERNET_OPTION_PROXY:
2479         {
2480         LPINTERNET_PROXY_INFOA pi = (LPINTERNET_PROXY_INFOA) lpBuffer;
2481         LPINTERNET_PROXY_INFOW piw;
2482         DWORD proxlen, prbylen;
2483         LPWSTR prox, prby;
2484
2485         proxlen = MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, NULL, 0);
2486         prbylen= MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, NULL, 0);
2487         wlen = sizeof(*piw) + proxlen + prbylen;
2488         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
2489         piw = (LPINTERNET_PROXY_INFOW) wbuffer;
2490         piw->dwAccessType = pi->dwAccessType;
2491         prox = (LPWSTR) &piw[1];
2492         prby = &prox[proxlen+1];
2493         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, prox, proxlen);
2494         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, prby, prbylen);
2495         piw->lpszProxy = prox;
2496         piw->lpszProxyBypass = prby;
2497         }
2498         break;
2499     case INTERNET_OPTION_USER_AGENT:
2500     case INTERNET_OPTION_USERNAME:
2501     case INTERNET_OPTION_PASSWORD:
2502         wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
2503                                    NULL, 0 );
2504         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
2505         MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
2506                                    wbuffer, wlen );
2507         break;
2508     default:
2509         wbuffer = lpBuffer;
2510         wlen = dwBufferLength;
2511     }
2512
2513     r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen);
2514
2515     if( lpBuffer != wbuffer )
2516         HeapFree( GetProcessHeap(), 0, wbuffer );
2517
2518     return r;
2519 }
2520
2521
2522 /***********************************************************************
2523  *           InternetSetOptionExA (WININET.@)
2524  */
2525 BOOL WINAPI InternetSetOptionExA(HINTERNET hInternet, DWORD dwOption,
2526                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2527 {
2528     FIXME("Flags %08x ignored\n", dwFlags);
2529     return InternetSetOptionA( hInternet, dwOption, lpBuffer, dwBufferLength );
2530 }
2531
2532 /***********************************************************************
2533  *           InternetSetOptionExW (WININET.@)
2534  */
2535 BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption,
2536                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2537 {
2538     FIXME("Flags %08x ignored\n", dwFlags);
2539     if( dwFlags & ~ISO_VALID_FLAGS )
2540     {
2541         INTERNET_SetLastError( ERROR_INVALID_PARAMETER );
2542         return FALSE;
2543     }
2544     return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength );
2545 }
2546
2547 static const WCHAR WININET_wkday[7][4] =
2548     { { 'S','u','n', 0 }, { 'M','o','n', 0 }, { 'T','u','e', 0 }, { 'W','e','d', 0 },
2549       { 'T','h','u', 0 }, { 'F','r','i', 0 }, { 'S','a','t', 0 } };
2550 static const WCHAR WININET_month[12][4] =
2551     { { 'J','a','n', 0 }, { 'F','e','b', 0 }, { 'M','a','r', 0 }, { 'A','p','r', 0 },
2552       { 'M','a','y', 0 }, { 'J','u','n', 0 }, { 'J','u','l', 0 }, { 'A','u','g', 0 },
2553       { 'S','e','p', 0 }, { 'O','c','t', 0 }, { 'N','o','v', 0 }, { 'D','e','c', 0 } };
2554
2555 /***********************************************************************
2556  *           InternetTimeFromSystemTimeA (WININET.@)
2557  */
2558 BOOL WINAPI InternetTimeFromSystemTimeA( const SYSTEMTIME* time, DWORD format, LPSTR string, DWORD size )
2559 {
2560     BOOL ret;
2561     WCHAR stringW[INTERNET_RFC1123_BUFSIZE];
2562
2563     TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size );
2564
2565     ret = InternetTimeFromSystemTimeW( time, format, stringW, sizeof(stringW) );
2566     if (ret) WideCharToMultiByte( CP_ACP, 0, stringW, -1, string, size, NULL, NULL );
2567
2568     return ret;
2569 }
2570
2571 /***********************************************************************
2572  *           InternetTimeFromSystemTimeW (WININET.@)
2573  */
2574 BOOL WINAPI InternetTimeFromSystemTimeW( const SYSTEMTIME* time, DWORD format, LPWSTR string, DWORD size )
2575 {
2576     static const WCHAR date[] =
2577         { '%','s',',',' ','%','0','2','d',' ','%','s',' ','%','4','d',' ','%','0',
2578           '2','d',':','%','0','2','d',':','%','0','2','d',' ','G','M','T', 0 };
2579
2580     TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size );
2581
2582     if (!time || !string) return FALSE;
2583
2584     if (format != INTERNET_RFC1123_FORMAT || size < INTERNET_RFC1123_BUFSIZE * sizeof(WCHAR))
2585         return FALSE;
2586
2587     sprintfW( string, date,
2588               WININET_wkday[time->wDayOfWeek],
2589               time->wDay,
2590               WININET_month[time->wMonth - 1],
2591               time->wYear,
2592               time->wHour,
2593               time->wMinute,
2594               time->wSecond );
2595
2596     return TRUE;
2597 }
2598
2599 /***********************************************************************
2600  *           InternetTimeToSystemTimeA (WININET.@)
2601  */
2602 BOOL WINAPI InternetTimeToSystemTimeA( LPCSTR string, SYSTEMTIME* time, DWORD reserved )
2603 {
2604     BOOL ret = FALSE;
2605     WCHAR *stringW;
2606     int len;
2607
2608     TRACE( "%s %p 0x%08x\n", debugstr_a(string), time, reserved );
2609
2610     len = MultiByteToWideChar( CP_ACP, 0, string, -1, NULL, 0 );
2611     stringW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2612
2613     if (stringW)
2614     {
2615         MultiByteToWideChar( CP_ACP, 0, string, -1, stringW, len );
2616         ret = InternetTimeToSystemTimeW( stringW, time, reserved );
2617         HeapFree( GetProcessHeap(), 0, stringW );
2618     }
2619     return ret;
2620 }
2621
2622 /***********************************************************************
2623  *           InternetTimeToSystemTimeW (WININET.@)
2624  */
2625 BOOL WINAPI InternetTimeToSystemTimeW( LPCWSTR string, SYSTEMTIME* time, DWORD reserved )
2626 {
2627     unsigned int i;
2628     const WCHAR *s = string;
2629     WCHAR       *end;
2630
2631     TRACE( "%s %p 0x%08x\n", debugstr_w(string), time, reserved );
2632
2633     if (!string || !time) return FALSE;
2634
2635     /* Windows does this too */
2636     GetSystemTime( time );
2637
2638     /*  Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
2639      *  a SYSTEMTIME structure.
2640      */
2641
2642     while (*s && !isalphaW( *s )) s++;
2643     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2644     time->wDayOfWeek = 7;
2645
2646     for (i = 0; i < 7; i++)
2647     {
2648         if (toupperW( WININET_wkday[i][0] ) == toupperW( s[0] ) &&
2649             toupperW( WININET_wkday[i][1] ) == toupperW( s[1] ) &&
2650             toupperW( WININET_wkday[i][2] ) == toupperW( s[2] ) )
2651         {
2652             time->wDayOfWeek = i;
2653             break;
2654         }
2655     }
2656
2657     if (time->wDayOfWeek > 6) return TRUE;
2658     while (*s && !isdigitW( *s )) s++;
2659     time->wDay = strtolW( s, &end, 10 );
2660     s = end;
2661
2662     while (*s && !isalphaW( *s )) s++;
2663     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2664     time->wMonth = 0;
2665
2666     for (i = 0; i < 12; i++)
2667     {
2668         if (toupperW( WININET_month[i][0]) == toupperW( s[0] ) &&
2669             toupperW( WININET_month[i][1]) == toupperW( s[1] ) &&
2670             toupperW( WININET_month[i][2]) == toupperW( s[2] ) )
2671         {
2672             time->wMonth = i + 1;
2673             break;
2674         }
2675     }
2676     if (time->wMonth == 0) return TRUE;
2677
2678     while (*s && !isdigitW( *s )) s++;
2679     if (*s == '\0') return TRUE;
2680     time->wYear = strtolW( s, &end, 10 );
2681     s = end;
2682
2683     while (*s && !isdigitW( *s )) s++;
2684     if (*s == '\0') return TRUE;
2685     time->wHour = strtolW( s, &end, 10 );
2686     s = end;
2687
2688     while (*s && !isdigitW( *s )) s++;
2689     if (*s == '\0') return TRUE;
2690     time->wMinute = strtolW( s, &end, 10 );
2691     s = end;
2692
2693     while (*s && !isdigitW( *s )) s++;
2694     if (*s == '\0') return TRUE;
2695     time->wSecond = strtolW( s, &end, 10 );
2696     s = end;
2697
2698     time->wMilliseconds = 0;
2699     return TRUE;
2700 }
2701
2702 /***********************************************************************
2703  *      InternetCheckConnectionW (WININET.@)
2704  *
2705  * Pings a requested host to check internet connection
2706  *
2707  * RETURNS
2708  *   TRUE on success and FALSE on failure. If a failure then
2709  *   ERROR_NOT_CONNECTED is placed into GetLastError
2710  *
2711  */
2712 BOOL WINAPI InternetCheckConnectionW( LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
2713 {
2714 /*
2715  * this is a kludge which runs the resident ping program and reads the output.
2716  *
2717  * Anyone have a better idea?
2718  */
2719
2720   BOOL   rc = FALSE;
2721   static const CHAR ping[] = "ping -c 1 ";
2722   static const CHAR redirect[] = " >/dev/null 2>/dev/null";
2723   CHAR *command = NULL;
2724   WCHAR hostW[1024];
2725   DWORD len;
2726   INTERNET_PORT port;
2727   int status = -1;
2728
2729   FIXME("\n");
2730
2731   /*
2732    * Crack or set the Address
2733    */
2734   if (lpszUrl == NULL)
2735   {
2736      /*
2737       * According to the doc we are supposed to use the ip for the next
2738       * server in the WnInet internal server database. I have
2739       * no idea what that is or how to get it.
2740       *
2741       * So someone needs to implement this.
2742       */
2743      FIXME("Unimplemented with URL of NULL\n");
2744      return TRUE;
2745   }
2746   else
2747   {
2748      URL_COMPONENTSW components;
2749
2750      ZeroMemory(&components,sizeof(URL_COMPONENTSW));
2751      components.lpszHostName = (LPWSTR)&hostW;
2752      components.dwHostNameLength = 1024;
2753
2754      if (!InternetCrackUrlW(lpszUrl,0,0,&components))
2755        goto End;
2756
2757      TRACE("host name : %s\n",debugstr_w(components.lpszHostName));
2758      port = components.nPort;
2759      TRACE("port: %d\n", port);
2760   }
2761
2762   if (dwFlags & FLAG_ICC_FORCE_CONNECTION)
2763   {
2764       struct sockaddr_in sin;
2765       int fd;
2766
2767       if (!GetAddress(hostW, port, &sin))
2768           goto End;
2769       fd = socket(sin.sin_family, SOCK_STREAM, 0);
2770       if (fd != -1)
2771       {
2772           if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) == 0)
2773               rc = TRUE;
2774           close(fd);
2775       }
2776   }
2777   else
2778   {
2779       /*
2780        * Build our ping command
2781        */
2782       len = WideCharToMultiByte(CP_UNIXCP, 0, hostW, -1, NULL, 0, NULL, NULL);
2783       command = HeapAlloc( GetProcessHeap(), 0, strlen(ping)+len+strlen(redirect) );
2784       strcpy(command,ping);
2785       WideCharToMultiByte(CP_UNIXCP, 0, hostW, -1, command+strlen(ping), len, NULL, NULL);
2786       strcat(command,redirect);
2787
2788       TRACE("Ping command is : %s\n",command);
2789
2790       status = system(command);
2791
2792       TRACE("Ping returned a code of %i\n",status);
2793
2794       /* Ping return code of 0 indicates success */
2795       if (status == 0)
2796          rc = TRUE;
2797   }
2798
2799 End:
2800
2801   HeapFree( GetProcessHeap(), 0, command );
2802   if (rc == FALSE)
2803     INTERNET_SetLastError(ERROR_NOT_CONNECTED);
2804
2805   return rc;
2806 }
2807
2808
2809 /***********************************************************************
2810  *      InternetCheckConnectionA (WININET.@)
2811  *
2812  * Pings a requested host to check internet connection
2813  *
2814  * RETURNS
2815  *   TRUE on success and FALSE on failure. If a failure then
2816  *   ERROR_NOT_CONNECTED is placed into GetLastError
2817  *
2818  */
2819 BOOL WINAPI InternetCheckConnectionA(LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
2820 {
2821     WCHAR *szUrl;
2822     INT len;
2823     BOOL rc;
2824
2825     len = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0);
2826     if (!(szUrl = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR))))
2827         return FALSE;
2828     MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, szUrl, len);
2829     rc = InternetCheckConnectionW(szUrl, dwFlags, dwReserved);
2830     HeapFree(GetProcessHeap(), 0, szUrl);
2831     
2832     return rc;
2833 }
2834
2835
2836 /**********************************************************
2837  *      INTERNET_InternetOpenUrlW (internal)
2838  *
2839  * Opens an URL
2840  *
2841  * RETURNS
2842  *   handle of connection or NULL on failure
2843  */
2844 HINTERNET WINAPI INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUrl,
2845     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
2846 {
2847     URL_COMPONENTSW urlComponents;
2848     WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024];
2849     WCHAR password[1024], path[2048], extra[1024];
2850     HINTERNET client = NULL, client1 = NULL;
2851     
2852     TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
2853           dwHeadersLength, dwFlags, dwContext);
2854     
2855     urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
2856     urlComponents.lpszScheme = protocol;
2857     urlComponents.dwSchemeLength = 32;
2858     urlComponents.lpszHostName = hostName;
2859     urlComponents.dwHostNameLength = MAXHOSTNAME;
2860     urlComponents.lpszUserName = userName;
2861     urlComponents.dwUserNameLength = 1024;
2862     urlComponents.lpszPassword = password;
2863     urlComponents.dwPasswordLength = 1024;
2864     urlComponents.lpszUrlPath = path;
2865     urlComponents.dwUrlPathLength = 2048;
2866     urlComponents.lpszExtraInfo = extra;
2867     urlComponents.dwExtraInfoLength = 1024;
2868     if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
2869         return NULL;
2870     switch(urlComponents.nScheme) {
2871     case INTERNET_SCHEME_FTP:
2872         if(urlComponents.nPort == 0)
2873             urlComponents.nPort = INTERNET_DEFAULT_FTP_PORT;
2874         client = FTP_Connect(hIC, hostName, urlComponents.nPort,
2875                              userName, password, dwFlags, dwContext, INET_OPENURL);
2876         if(client == NULL)
2877             break;
2878         client1 = FtpOpenFileW(client, path, GENERIC_READ, dwFlags, dwContext);
2879         if(client1 == NULL) {
2880             InternetCloseHandle(client);
2881             break;
2882         }
2883         break;
2884         
2885     case INTERNET_SCHEME_HTTP:
2886     case INTERNET_SCHEME_HTTPS: {
2887         static const WCHAR szStars[] = { '*','/','*', 0 };
2888         LPCWSTR accept[2] = { szStars, NULL };
2889         if(urlComponents.nPort == 0) {
2890             if(urlComponents.nScheme == INTERNET_SCHEME_HTTP)
2891                 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
2892             else
2893                 urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
2894         }
2895         /* FIXME: should use pointers, not handles, as handles are not thread-safe */
2896         client = HTTP_Connect(hIC, hostName, urlComponents.nPort,
2897                               userName, password, dwFlags, dwContext, INET_OPENURL);
2898         if(client == NULL)
2899             break;
2900
2901         if (urlComponents.dwExtraInfoLength) {
2902                 WCHAR *path_extra;
2903                 DWORD len = urlComponents.dwUrlPathLength + urlComponents.dwExtraInfoLength + 1;
2904
2905                 if (!(path_extra = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
2906                 {
2907                         InternetCloseHandle(client);
2908                         break;
2909                 }
2910                 strcpyW(path_extra, urlComponents.lpszUrlPath);
2911                 strcatW(path_extra, urlComponents.lpszExtraInfo);
2912                 client1 = HttpOpenRequestW(client, NULL, path_extra, NULL, NULL, accept, dwFlags, dwContext);
2913                 HeapFree(GetProcessHeap(), 0, path_extra);
2914         }
2915         else
2916                 client1 = HttpOpenRequestW(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
2917
2918         if(client1 == NULL) {
2919             InternetCloseHandle(client);
2920             break;
2921         }
2922         HttpAddRequestHeadersW(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
2923         if (!HttpSendRequestW(client1, NULL, 0, NULL, 0) &&
2924             GetLastError() != ERROR_IO_PENDING) {
2925             InternetCloseHandle(client1);
2926             client1 = NULL;
2927             break;
2928         }
2929     }
2930     case INTERNET_SCHEME_GOPHER:
2931         /* gopher doesn't seem to be implemented in wine, but it's supposed
2932          * to be supported by InternetOpenUrlA. */
2933     default:
2934         INTERNET_SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME);
2935         break;
2936     }
2937
2938     TRACE(" %p <--\n", client1);
2939     
2940     return client1;
2941 }
2942
2943 /**********************************************************
2944  *      InternetOpenUrlW (WININET.@)
2945  *
2946  * Opens an URL
2947  *
2948  * RETURNS
2949  *   handle of connection or NULL on failure
2950  */
2951 static void AsyncInternetOpenUrlProc(WORKREQUEST *workRequest)
2952 {
2953     struct WORKREQ_INTERNETOPENURLW const *req = &workRequest->u.InternetOpenUrlW;
2954     LPWININETAPPINFOW hIC = (LPWININETAPPINFOW) workRequest->hdr;
2955
2956     TRACE("%p\n", hIC);
2957
2958     INTERNET_InternetOpenUrlW(hIC, req->lpszUrl,
2959                               req->lpszHeaders, req->dwHeadersLength, req->dwFlags, req->dwContext);
2960     HeapFree(GetProcessHeap(), 0, req->lpszUrl);
2961     HeapFree(GetProcessHeap(), 0, req->lpszHeaders);
2962 }
2963
2964 HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
2965     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
2966 {
2967     HINTERNET ret = NULL;
2968     LPWININETAPPINFOW hIC = NULL;
2969
2970     if (TRACE_ON(wininet)) {
2971         TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hInternet, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
2972               dwHeadersLength, dwFlags, dwContext);
2973         TRACE("  flags :");
2974         dump_INTERNET_FLAGS(dwFlags);
2975     }
2976
2977     if (!lpszUrl)
2978     {
2979         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2980         goto lend;
2981     }
2982
2983     hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
2984     if (NULL == hIC ||  hIC->hdr.htype != WH_HINIT) {
2985         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2986         goto lend;
2987     }
2988     
2989     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) {
2990         WORKREQUEST workRequest;
2991         struct WORKREQ_INTERNETOPENURLW *req;
2992
2993         workRequest.asyncproc = AsyncInternetOpenUrlProc;
2994         workRequest.hdr = WININET_AddRef( &hIC->hdr );
2995         req = &workRequest.u.InternetOpenUrlW;
2996         req->lpszUrl = WININET_strdupW(lpszUrl);
2997         if (lpszHeaders)
2998             req->lpszHeaders = WININET_strdupW(lpszHeaders);
2999         else
3000             req->lpszHeaders = 0;
3001         req->dwHeadersLength = dwHeadersLength;
3002         req->dwFlags = dwFlags;
3003         req->dwContext = dwContext;
3004         
3005         INTERNET_AsyncCall(&workRequest);
3006         /*
3007          * This is from windows.
3008          */
3009         INTERNET_SetLastError(ERROR_IO_PENDING);
3010     } else {
3011         ret = INTERNET_InternetOpenUrlW(hIC, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext);
3012     }
3013     
3014   lend:
3015     if( hIC )
3016         WININET_Release( &hIC->hdr );
3017     TRACE(" %p <--\n", ret);
3018     
3019     return ret;
3020 }
3021
3022 /**********************************************************
3023  *      InternetOpenUrlA (WININET.@)
3024  *
3025  * Opens an URL
3026  *
3027  * RETURNS
3028  *   handle of connection or NULL on failure
3029  */
3030 HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
3031     LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3032 {
3033     HINTERNET rc = NULL;
3034
3035     INT lenUrl;
3036     INT lenHeaders = 0;
3037     LPWSTR szUrl = NULL;
3038     LPWSTR szHeaders = NULL;
3039
3040     TRACE("\n");
3041
3042     if(lpszUrl) {
3043         lenUrl = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0 );
3044         szUrl = HeapAlloc(GetProcessHeap(), 0, lenUrl*sizeof(WCHAR));
3045         if(!szUrl)
3046             return NULL;
3047         MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, szUrl, lenUrl);
3048     }
3049
3050     if(lpszHeaders) {
3051         lenHeaders = MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, NULL, 0 );
3052         szHeaders = HeapAlloc(GetProcessHeap(), 0, lenHeaders*sizeof(WCHAR));
3053         if(!szHeaders) {
3054             HeapFree(GetProcessHeap(), 0, szUrl);
3055             return NULL;
3056         }
3057         MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, szHeaders, lenHeaders);
3058     }
3059     
3060     rc = InternetOpenUrlW(hInternet, szUrl, szHeaders,
3061         lenHeaders, dwFlags, dwContext);
3062
3063     HeapFree(GetProcessHeap(), 0, szUrl);
3064     HeapFree(GetProcessHeap(), 0, szHeaders);
3065
3066     return rc;
3067 }
3068
3069
3070 static LPWITHREADERROR INTERNET_AllocThreadError(void)
3071 {
3072     LPWITHREADERROR lpwite = HeapAlloc(GetProcessHeap(), 0, sizeof(*lpwite));
3073
3074     if (lpwite)
3075     {
3076         lpwite->dwError = 0;
3077         lpwite->response[0] = '\0';
3078     }
3079
3080     if (!TlsSetValue(g_dwTlsErrIndex, lpwite))
3081     {
3082         HeapFree(GetProcessHeap(), 0, lpwite);
3083         return NULL;
3084     }
3085
3086     return lpwite;
3087 }
3088
3089
3090 /***********************************************************************
3091  *           INTERNET_SetLastError (internal)
3092  *
3093  * Set last thread specific error
3094  *
3095  * RETURNS
3096  *
3097  */
3098 void INTERNET_SetLastError(DWORD dwError)
3099 {
3100     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
3101
3102     if (!lpwite)
3103         lpwite = INTERNET_AllocThreadError();
3104
3105     SetLastError(dwError);
3106     if(lpwite)
3107         lpwite->dwError = dwError;
3108 }
3109
3110
3111 /***********************************************************************
3112  *           INTERNET_GetLastError (internal)
3113  *
3114  * Get last thread specific error
3115  *
3116  * RETURNS
3117  *
3118  */
3119 DWORD INTERNET_GetLastError(void)
3120 {
3121     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
3122     if (!lpwite) return 0;
3123     /* TlsGetValue clears last error, so set it again here */
3124     SetLastError(lpwite->dwError);
3125     return lpwite->dwError;
3126 }
3127
3128
3129 /***********************************************************************
3130  *           INTERNET_WorkerThreadFunc (internal)
3131  *
3132  * Worker thread execution function
3133  *
3134  * RETURNS
3135  *
3136  */
3137 static DWORD CALLBACK INTERNET_WorkerThreadFunc(LPVOID lpvParam)
3138 {
3139     LPWORKREQUEST lpRequest = lpvParam;
3140     WORKREQUEST workRequest;
3141
3142     TRACE("\n");
3143
3144     memcpy(&workRequest, lpRequest, sizeof(WORKREQUEST));
3145     HeapFree(GetProcessHeap(), 0, lpRequest);
3146
3147     workRequest.asyncproc(&workRequest);
3148
3149     WININET_Release( workRequest.hdr );
3150     return TRUE;
3151 }
3152
3153
3154 /***********************************************************************
3155  *           INTERNET_AsyncCall (internal)
3156  *
3157  * Retrieves work request from queue
3158  *
3159  * RETURNS
3160  *
3161  */
3162 BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
3163 {
3164     BOOL bSuccess;
3165     LPWORKREQUEST lpNewRequest;
3166
3167     TRACE("\n");
3168
3169     lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
3170     if (!lpNewRequest)
3171         return FALSE;
3172
3173     memcpy(lpNewRequest, lpWorkRequest, sizeof(WORKREQUEST));
3174
3175     bSuccess = QueueUserWorkItem(INTERNET_WorkerThreadFunc, lpNewRequest, WT_EXECUTELONGFUNCTION);
3176     if (!bSuccess)
3177     {
3178         HeapFree(GetProcessHeap(), 0, lpNewRequest);
3179         INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED);
3180     }
3181
3182     return bSuccess;
3183 }
3184
3185
3186 /***********************************************************************
3187  *          INTERNET_GetResponseBuffer  (internal)
3188  *
3189  * RETURNS
3190  *
3191  */
3192 LPSTR INTERNET_GetResponseBuffer(void)
3193 {
3194     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
3195     if (!lpwite)
3196         lpwite = INTERNET_AllocThreadError();
3197     TRACE("\n");
3198     return lpwite->response;
3199 }
3200
3201 /***********************************************************************
3202  *           INTERNET_GetNextLine  (internal)
3203  *
3204  * Parse next line in directory string listing
3205  *
3206  * RETURNS
3207  *   Pointer to beginning of next line
3208  *   NULL on failure
3209  *
3210  */
3211
3212 LPSTR INTERNET_GetNextLine(INT nSocket, LPDWORD dwLen)
3213 {
3214     struct timeval tv;
3215     fd_set infd;
3216     BOOL bSuccess = FALSE;
3217     INT nRecv = 0;
3218     LPSTR lpszBuffer = INTERNET_GetResponseBuffer();
3219
3220     TRACE("\n");
3221
3222     FD_ZERO(&infd);
3223     FD_SET(nSocket, &infd);
3224     tv.tv_sec=RESPONSE_TIMEOUT;
3225     tv.tv_usec=0;
3226
3227     while (nRecv < MAX_REPLY_LEN)
3228     {
3229         if (select(nSocket+1,&infd,NULL,NULL,&tv) > 0)
3230         {
3231             if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
3232             {
3233                 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
3234                 goto lend;
3235             }
3236
3237             if (lpszBuffer[nRecv] == '\n')
3238             {
3239                 bSuccess = TRUE;
3240                 break;
3241             }
3242             if (lpszBuffer[nRecv] != '\r')
3243                 nRecv++;
3244         }
3245         else
3246         {
3247             INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
3248             goto lend;
3249         }
3250     }
3251
3252 lend:
3253     if (bSuccess)
3254     {
3255         lpszBuffer[nRecv] = '\0';
3256         *dwLen = nRecv - 1;
3257         TRACE(":%d %s\n", nRecv, lpszBuffer);
3258         return lpszBuffer;
3259     }
3260     else
3261     {
3262         return NULL;
3263     }
3264 }
3265
3266 /**********************************************************
3267  *      InternetQueryDataAvailable (WININET.@)
3268  *
3269  * Determines how much data is available to be read.
3270  *
3271  * RETURNS
3272  *   TRUE on success, FALSE if an error occurred. If
3273  *   INTERNET_FLAG_ASYNC was specified in InternetOpen, and
3274  *   no data is presently available, FALSE is returned with
3275  *   the last error ERROR_IO_PENDING; a callback with status
3276  *   INTERNET_STATUS_REQUEST_COMPLETE will be sent when more
3277  *   data is available.
3278  */
3279 BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile,
3280                                 LPDWORD lpdwNumberOfBytesAvailble,
3281                                 DWORD dwFlags, DWORD_PTR dwContext)
3282 {
3283     WININETHANDLEHEADER *hdr;
3284     DWORD res;
3285
3286     TRACE("(%p %p %x %lx)\n", hFile, lpdwNumberOfBytesAvailble, dwFlags, dwContext);
3287
3288     hdr = WININET_GetObject( hFile );
3289     if (!hdr) {
3290         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
3291         return FALSE;
3292     }
3293
3294     if(hdr->vtbl->QueryDataAvailable) {
3295         res = hdr->vtbl->QueryDataAvailable(hdr, lpdwNumberOfBytesAvailble, dwFlags, dwContext);
3296     }else {
3297         WARN("wrong handle\n");
3298         res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
3299     }
3300
3301     WININET_Release(hdr);
3302
3303     if(res != ERROR_SUCCESS)
3304         SetLastError(res);
3305     return res == ERROR_SUCCESS;
3306 }
3307
3308
3309 /***********************************************************************
3310  *      InternetLockRequestFile (WININET.@)
3311  */
3312 BOOL WINAPI InternetLockRequestFile( HINTERNET hInternet, HANDLE
3313 *lphLockReqHandle)
3314 {
3315     FIXME("STUB\n");
3316     return FALSE;
3317 }
3318
3319 BOOL WINAPI InternetUnlockRequestFile( HANDLE hLockHandle)
3320 {
3321     FIXME("STUB\n");
3322     return FALSE;
3323 }
3324
3325
3326 /***********************************************************************
3327  *      InternetAutodial (WININET.@)
3328  *
3329  * On windows this function is supposed to dial the default internet
3330  * connection. We don't want to have Wine dial out to the internet so
3331  * we return TRUE by default. It might be nice to check if we are connected.
3332  *
3333  * RETURNS
3334  *   TRUE on success
3335  *   FALSE on failure
3336  *
3337  */
3338 BOOL WINAPI InternetAutodial(DWORD dwFlags, HWND hwndParent)
3339 {
3340     FIXME("STUB\n");
3341
3342     /* Tell that we are connected to the internet. */
3343     return TRUE;
3344 }
3345
3346 /***********************************************************************
3347  *      InternetAutodialHangup (WININET.@)
3348  *
3349  * Hangs up a connection made with InternetAutodial
3350  *
3351  * PARAM
3352  *    dwReserved
3353  * RETURNS
3354  *   TRUE on success
3355  *   FALSE on failure
3356  *
3357  */
3358 BOOL WINAPI InternetAutodialHangup(DWORD dwReserved)
3359 {
3360     FIXME("STUB\n");
3361
3362     /* we didn't dial, we don't disconnect */
3363     return TRUE;
3364 }
3365
3366 /***********************************************************************
3367  *      InternetCombineUrlA (WININET.@)
3368  *
3369  * Combine a base URL with a relative URL
3370  *
3371  * RETURNS
3372  *   TRUE on success
3373  *   FALSE on failure
3374  *
3375  */
3376
3377 BOOL WINAPI InternetCombineUrlA(LPCSTR lpszBaseUrl, LPCSTR lpszRelativeUrl,
3378                                 LPSTR lpszBuffer, LPDWORD lpdwBufferLength,
3379                                 DWORD dwFlags)
3380 {
3381     HRESULT hr=S_OK;
3382
3383     TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_a(lpszBaseUrl), debugstr_a(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
3384
3385     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
3386     dwFlags ^= ICU_NO_ENCODE;
3387     hr=UrlCombineA(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
3388
3389     return (hr==S_OK);
3390 }
3391
3392 /***********************************************************************
3393  *      InternetCombineUrlW (WININET.@)
3394  *
3395  * Combine a base URL with a relative URL
3396  *
3397  * RETURNS
3398  *   TRUE on success
3399  *   FALSE on failure
3400  *
3401  */
3402
3403 BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
3404                                 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength,
3405                                 DWORD dwFlags)
3406 {
3407     HRESULT hr=S_OK;
3408
3409     TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_w(lpszBaseUrl), debugstr_w(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
3410
3411     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
3412     dwFlags ^= ICU_NO_ENCODE;
3413     hr=UrlCombineW(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
3414
3415     return (hr==S_OK);
3416 }
3417
3418 /* max port num is 65535 => 5 digits */
3419 #define MAX_WORD_DIGITS 5
3420
3421 #define URL_GET_COMP_LENGTH(url, component) ((url)->dw##component##Length ? \
3422     (url)->dw##component##Length : strlenW((url)->lpsz##component))
3423 #define URL_GET_COMP_LENGTHA(url, component) ((url)->dw##component##Length ? \
3424     (url)->dw##component##Length : strlen((url)->lpsz##component))
3425
3426 static BOOL url_uses_default_port(INTERNET_SCHEME nScheme, INTERNET_PORT nPort)
3427 {
3428     if ((nScheme == INTERNET_SCHEME_HTTP) &&
3429         (nPort == INTERNET_DEFAULT_HTTP_PORT))
3430         return TRUE;
3431     if ((nScheme == INTERNET_SCHEME_HTTPS) &&
3432         (nPort == INTERNET_DEFAULT_HTTPS_PORT))
3433         return TRUE;
3434     if ((nScheme == INTERNET_SCHEME_FTP) &&
3435         (nPort == INTERNET_DEFAULT_FTP_PORT))
3436         return TRUE;
3437     if ((nScheme == INTERNET_SCHEME_GOPHER) &&
3438         (nPort == INTERNET_DEFAULT_GOPHER_PORT))
3439         return TRUE;
3440
3441     if (nPort == INTERNET_INVALID_PORT_NUMBER)
3442         return TRUE;
3443
3444     return FALSE;
3445 }
3446
3447 /* opaque urls do not fit into the standard url hierarchy and don't have
3448  * two following slashes */
3449 static inline BOOL scheme_is_opaque(INTERNET_SCHEME nScheme)
3450 {
3451     return (nScheme != INTERNET_SCHEME_FTP) &&
3452            (nScheme != INTERNET_SCHEME_GOPHER) &&
3453            (nScheme != INTERNET_SCHEME_HTTP) &&
3454            (nScheme != INTERNET_SCHEME_HTTPS) &&
3455            (nScheme != INTERNET_SCHEME_FILE);
3456 }
3457
3458 static LPCWSTR INTERNET_GetSchemeString(INTERNET_SCHEME scheme)
3459 {
3460     int index;
3461     if (scheme < INTERNET_SCHEME_FIRST)
3462         return NULL;
3463     index = scheme - INTERNET_SCHEME_FIRST;
3464     if (index >= sizeof(url_schemes)/sizeof(url_schemes[0]))
3465         return NULL;
3466     return (LPCWSTR)&url_schemes[index];
3467 }
3468
3469 /* we can calculate using ansi strings because we're just
3470  * calculating string length, not size
3471  */
3472 static BOOL calc_url_length(LPURL_COMPONENTSW lpUrlComponents,
3473                             LPDWORD lpdwUrlLength)
3474 {
3475     INTERNET_SCHEME nScheme;
3476
3477     *lpdwUrlLength = 0;
3478
3479     if (lpUrlComponents->lpszScheme)
3480     {
3481         DWORD dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
3482         *lpdwUrlLength += dwLen;
3483         nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
3484     }
3485     else
3486     {
3487         LPCWSTR scheme;
3488
3489         nScheme = lpUrlComponents->nScheme;
3490
3491         if (nScheme == INTERNET_SCHEME_DEFAULT)
3492             nScheme = INTERNET_SCHEME_HTTP;
3493         scheme = INTERNET_GetSchemeString(nScheme);
3494         *lpdwUrlLength += strlenW(scheme);
3495     }
3496
3497     (*lpdwUrlLength)++; /* ':' */
3498     if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
3499         *lpdwUrlLength += strlen("//");
3500
3501     if (lpUrlComponents->lpszUserName)
3502     {
3503         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
3504         *lpdwUrlLength += strlen("@");
3505     }
3506     else
3507     {
3508         if (lpUrlComponents->lpszPassword)
3509         {
3510             INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3511             return FALSE;
3512         }
3513     }
3514
3515     if (lpUrlComponents->lpszPassword)
3516     {
3517         *lpdwUrlLength += strlen(":");
3518         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, Password);
3519     }
3520
3521     if (lpUrlComponents->lpszHostName)
3522     {
3523         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
3524
3525         if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
3526         {
3527             char szPort[MAX_WORD_DIGITS+1];
3528
3529             sprintf(szPort, "%d", lpUrlComponents->nPort);
3530             *lpdwUrlLength += strlen(szPort);
3531             *lpdwUrlLength += strlen(":");
3532         }
3533
3534         if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
3535             (*lpdwUrlLength)++; /* '/' */
3536     }
3537
3538     if (lpUrlComponents->lpszUrlPath)
3539         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
3540
3541     return TRUE;
3542 }
3543
3544 static void convert_urlcomp_atow(LPURL_COMPONENTSA lpUrlComponents, LPURL_COMPONENTSW urlCompW)
3545 {
3546     INT len;
3547
3548     ZeroMemory(urlCompW, sizeof(URL_COMPONENTSW));
3549
3550     urlCompW->dwStructSize = sizeof(URL_COMPONENTSW);
3551     urlCompW->dwSchemeLength = lpUrlComponents->dwSchemeLength;
3552     urlCompW->nScheme = lpUrlComponents->nScheme;
3553     urlCompW->dwHostNameLength = lpUrlComponents->dwHostNameLength;
3554     urlCompW->nPort = lpUrlComponents->nPort;
3555     urlCompW->dwUserNameLength = lpUrlComponents->dwUserNameLength;
3556     urlCompW->dwPasswordLength = lpUrlComponents->dwPasswordLength;
3557     urlCompW->dwUrlPathLength = lpUrlComponents->dwUrlPathLength;
3558     urlCompW->dwExtraInfoLength = lpUrlComponents->dwExtraInfoLength;
3559
3560     if (lpUrlComponents->lpszScheme)
3561     {
3562         len = URL_GET_COMP_LENGTHA(lpUrlComponents, Scheme) + 1;
3563         urlCompW->lpszScheme = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3564         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszScheme,
3565                             -1, urlCompW->lpszScheme, len);
3566     }
3567
3568     if (lpUrlComponents->lpszHostName)
3569     {
3570         len = URL_GET_COMP_LENGTHA(lpUrlComponents, HostName) + 1;
3571         urlCompW->lpszHostName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3572         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszHostName,
3573                             -1, urlCompW->lpszHostName, len);
3574     }
3575
3576     if (lpUrlComponents->lpszUserName)
3577     {
3578         len = URL_GET_COMP_LENGTHA(lpUrlComponents, UserName) + 1;
3579         urlCompW->lpszUserName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3580         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUserName,
3581                             -1, urlCompW->lpszUserName, len);
3582     }
3583
3584     if (lpUrlComponents->lpszPassword)
3585     {
3586         len = URL_GET_COMP_LENGTHA(lpUrlComponents, Password) + 1;
3587         urlCompW->lpszPassword = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3588         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszPassword,
3589                             -1, urlCompW->lpszPassword, len);
3590     }
3591
3592     if (lpUrlComponents->lpszUrlPath)
3593     {
3594         len = URL_GET_COMP_LENGTHA(lpUrlComponents, UrlPath) + 1;
3595         urlCompW->lpszUrlPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3596         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUrlPath,
3597                             -1, urlCompW->lpszUrlPath, len);
3598     }
3599
3600     if (lpUrlComponents->lpszExtraInfo)
3601     {
3602         len = URL_GET_COMP_LENGTHA(lpUrlComponents, ExtraInfo) + 1;
3603         urlCompW->lpszExtraInfo = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3604         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszExtraInfo,
3605                             -1, urlCompW->lpszExtraInfo, len);
3606     }
3607 }
3608
3609 /***********************************************************************
3610  *      InternetCreateUrlA (WININET.@)
3611  *
3612  * See InternetCreateUrlW.
3613  */
3614 BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
3615                                LPSTR lpszUrl, LPDWORD lpdwUrlLength)
3616 {
3617     BOOL ret;
3618     LPWSTR urlW = NULL;
3619     URL_COMPONENTSW urlCompW;
3620
3621     TRACE("(%p,%d,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
3622
3623     if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
3624     {
3625         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3626         return FALSE;
3627     }
3628
3629     convert_urlcomp_atow(lpUrlComponents, &urlCompW);
3630
3631     if (lpszUrl)
3632         urlW = HeapAlloc(GetProcessHeap(), 0, *lpdwUrlLength * sizeof(WCHAR));
3633
3634     ret = InternetCreateUrlW(&urlCompW, dwFlags, urlW, lpdwUrlLength);
3635
3636     if (!ret && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
3637         *lpdwUrlLength /= sizeof(WCHAR);
3638
3639     /* on success, lpdwUrlLength points to the size of urlW in WCHARS
3640     * minus one, so add one to leave room for NULL terminator
3641     */
3642     if (ret)
3643         WideCharToMultiByte(CP_ACP, 0, urlW, -1, lpszUrl, *lpdwUrlLength + 1, NULL, NULL);
3644
3645     HeapFree(GetProcessHeap(), 0, urlCompW.lpszScheme);
3646     HeapFree(GetProcessHeap(), 0, urlCompW.lpszHostName);
3647     HeapFree(GetProcessHeap(), 0, urlCompW.lpszUserName);
3648     HeapFree(GetProcessHeap(), 0, urlCompW.lpszPassword);
3649     HeapFree(GetProcessHeap(), 0, urlCompW.lpszUrlPath);
3650     HeapFree(GetProcessHeap(), 0, urlCompW.lpszExtraInfo);
3651     HeapFree(GetProcessHeap(), 0, urlW);
3652
3653     return ret;
3654 }
3655
3656 /***********************************************************************
3657  *      InternetCreateUrlW (WININET.@)
3658  *
3659  * Creates a URL from its component parts.
3660  *
3661  * PARAMS
3662  *  lpUrlComponents [I] URL Components.
3663  *  dwFlags         [I] Flags. See notes.
3664  *  lpszUrl         [I] Buffer in which to store the created URL.
3665  *  lpdwUrlLength   [I/O] On input, the length of the buffer pointed to by
3666  *                        lpszUrl in characters. On output, the number of bytes
3667  *                        required to store the URL including terminator.
3668  *
3669  * NOTES
3670  *
3671  * The dwFlags parameter can be zero or more of the following:
3672  *|ICU_ESCAPE - Generates escape sequences for unsafe characters in the path and extra info of the URL.
3673  *
3674  * RETURNS
3675  *   TRUE on success
3676  *   FALSE on failure
3677  *
3678  */
3679 BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
3680                                LPWSTR lpszUrl, LPDWORD lpdwUrlLength)
3681 {
3682     DWORD dwLen;
3683     INTERNET_SCHEME nScheme;
3684
3685     static const WCHAR slashSlashW[] = {'/','/'};
3686     static const WCHAR percentD[] = {'%','d',0};
3687
3688     TRACE("(%p,%d,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
3689
3690     if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
3691     {
3692         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3693         return FALSE;
3694     }
3695
3696     if (!calc_url_length(lpUrlComponents, &dwLen))
3697         return FALSE;
3698
3699     if (!lpszUrl || *lpdwUrlLength < dwLen)
3700     {
3701         *lpdwUrlLength = (dwLen + 1) * sizeof(WCHAR);
3702         INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
3703         return FALSE;
3704     }
3705
3706     *lpdwUrlLength = dwLen;
3707     lpszUrl[0] = 0x00;
3708
3709     dwLen = 0;
3710
3711     if (lpUrlComponents->lpszScheme)
3712     {
3713         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
3714         memcpy(lpszUrl, lpUrlComponents->lpszScheme, dwLen * sizeof(WCHAR));
3715         lpszUrl += dwLen;
3716
3717         nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
3718     }
3719     else
3720     {
3721         LPCWSTR scheme;
3722         nScheme = lpUrlComponents->nScheme;
3723
3724         if (nScheme == INTERNET_SCHEME_DEFAULT)
3725             nScheme = INTERNET_SCHEME_HTTP;
3726
3727         scheme = INTERNET_GetSchemeString(nScheme);
3728         dwLen = strlenW(scheme);
3729         memcpy(lpszUrl, scheme, dwLen * sizeof(WCHAR));
3730         lpszUrl += dwLen;
3731     }
3732
3733     /* all schemes are followed by at least a colon */
3734     *lpszUrl = ':';
3735     lpszUrl++;
3736
3737     if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
3738     {
3739         memcpy(lpszUrl, slashSlashW, sizeof(slashSlashW));
3740         lpszUrl += sizeof(slashSlashW)/sizeof(slashSlashW[0]);
3741     }
3742
3743     if (lpUrlComponents->lpszUserName)
3744     {
3745         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
3746         memcpy(lpszUrl, lpUrlComponents->lpszUserName, dwLen * sizeof(WCHAR));
3747         lpszUrl += dwLen;
3748
3749         if (lpUrlComponents->lpszPassword)
3750         {
3751             *lpszUrl = ':';
3752             lpszUrl++;
3753
3754             dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Password);
3755             memcpy(lpszUrl, lpUrlComponents->lpszPassword, dwLen * sizeof(WCHAR));
3756             lpszUrl += dwLen;
3757         }
3758
3759         *lpszUrl = '@';
3760         lpszUrl++;
3761     }
3762
3763     if (lpUrlComponents->lpszHostName)
3764     {
3765         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
3766         memcpy(lpszUrl, lpUrlComponents->lpszHostName, dwLen * sizeof(WCHAR));
3767         lpszUrl += dwLen;
3768
3769         if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
3770         {
3771             WCHAR szPort[MAX_WORD_DIGITS+1];
3772
3773             sprintfW(szPort, percentD, lpUrlComponents->nPort);
3774             *lpszUrl = ':';
3775             lpszUrl++;
3776             dwLen = strlenW(szPort);
3777             memcpy(lpszUrl, szPort, dwLen * sizeof(WCHAR));
3778             lpszUrl += dwLen;
3779         }
3780
3781         /* add slash between hostname and path if necessary */
3782         if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
3783         {
3784             *lpszUrl = '/';
3785             lpszUrl++;
3786         }
3787     }
3788
3789
3790     if (lpUrlComponents->lpszUrlPath)
3791     {
3792         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
3793         memcpy(lpszUrl, lpUrlComponents->lpszUrlPath, dwLen * sizeof(WCHAR));
3794         lpszUrl += dwLen;
3795     }
3796
3797     *lpszUrl = '\0';
3798
3799     return TRUE;
3800 }
3801
3802 /***********************************************************************
3803  *      InternetConfirmZoneCrossingA (WININET.@)
3804  *
3805  */
3806 DWORD WINAPI InternetConfirmZoneCrossingA( HWND hWnd, LPSTR szUrlPrev, LPSTR szUrlNew, BOOL bPost )
3807 {
3808     FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_a(szUrlPrev), debugstr_a(szUrlNew), bPost);
3809     return ERROR_SUCCESS;
3810 }
3811
3812 /***********************************************************************
3813  *      InternetConfirmZoneCrossingW (WININET.@)
3814  *
3815  */
3816 DWORD WINAPI InternetConfirmZoneCrossingW( HWND hWnd, LPWSTR szUrlPrev, LPWSTR szUrlNew, BOOL bPost )
3817 {
3818     FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_w(szUrlPrev), debugstr_w(szUrlNew), bPost);
3819     return ERROR_SUCCESS;
3820 }
3821
3822 DWORD WINAPI InternetDialA( HWND hwndParent, LPSTR lpszConnectoid, DWORD dwFlags,
3823                             DWORD_PTR* lpdwConnection, DWORD dwReserved )
3824 {
3825     FIXME("(%p, %p, 0x%08x, %p, 0x%08x) stub\n", hwndParent, lpszConnectoid, dwFlags,
3826           lpdwConnection, dwReserved);
3827     return ERROR_SUCCESS;
3828 }
3829
3830 DWORD WINAPI InternetDialW( HWND hwndParent, LPWSTR lpszConnectoid, DWORD dwFlags,
3831                             DWORD_PTR* lpdwConnection, DWORD dwReserved )
3832 {
3833     FIXME("(%p, %p, 0x%08x, %p, 0x%08x) stub\n", hwndParent, lpszConnectoid, dwFlags,
3834           lpdwConnection, dwReserved);
3835     return ERROR_SUCCESS;
3836 }
3837
3838 BOOL WINAPI InternetGoOnlineA( LPSTR lpszURL, HWND hwndParent, DWORD dwReserved )
3839 {
3840     FIXME("(%s, %p, 0x%08x) stub\n", debugstr_a(lpszURL), hwndParent, dwReserved);
3841     return TRUE;
3842 }
3843
3844 BOOL WINAPI InternetGoOnlineW( LPWSTR lpszURL, HWND hwndParent, DWORD dwReserved )
3845 {
3846     FIXME("(%s, %p, 0x%08x) stub\n", debugstr_w(lpszURL), hwndParent, dwReserved);
3847     return TRUE;
3848 }
3849
3850 DWORD WINAPI InternetHangUp( DWORD_PTR dwConnection, DWORD dwReserved )
3851 {
3852     FIXME("(0x%08lx, 0x%08x) stub\n", dwConnection, dwReserved);
3853     return ERROR_SUCCESS;
3854 }
3855
3856 BOOL WINAPI CreateMD5SSOHash( PWSTR pszChallengeInfo, PWSTR pwszRealm, PWSTR pwszTarget,
3857                               PBYTE pbHexHash )
3858 {
3859     FIXME("(%s, %s, %s, %p) stub\n", debugstr_w(pszChallengeInfo), debugstr_w(pwszRealm),
3860           debugstr_w(pwszTarget), pbHexHash);
3861     return FALSE;
3862 }
3863
3864 BOOL WINAPI ResumeSuspendedDownload( HINTERNET hInternet, DWORD dwError )
3865 {
3866     FIXME("(%p, 0x%08x) stub\n", hInternet, dwError);
3867     return FALSE;
3868 }
3869
3870 BOOL WINAPI InternetQueryFortezzaStatus(DWORD *a, DWORD_PTR b)
3871 {
3872     FIXME("(%p, %08lx) stub\n", a, b);
3873     return 0;
3874 }