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