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