msvcrt: Resolve symbols clashes with FreeBSD libc.
[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   INTERNET_PORT port;
2743   int status = -1;
2744
2745   FIXME("\n");
2746
2747   /*
2748    * Crack or set the Address
2749    */
2750   if (lpszUrl == NULL)
2751   {
2752      /*
2753       * According to the doc we are supost to use the ip for the next
2754       * server in the WnInet internal server database. I have
2755       * no idea what that is or how to get it.
2756       *
2757       * So someone needs to implement this.
2758       */
2759      FIXME("Unimplemented with URL of NULL\n");
2760      return TRUE;
2761   }
2762   else
2763   {
2764      URL_COMPONENTSW components;
2765
2766      ZeroMemory(&components,sizeof(URL_COMPONENTSW));
2767      components.lpszHostName = (LPWSTR)&hostW;
2768      components.dwHostNameLength = 1024;
2769
2770      if (!InternetCrackUrlW(lpszUrl,0,0,&components))
2771        goto End;
2772
2773      TRACE("host name : %s\n",debugstr_w(components.lpszHostName));
2774      port = components.nPort;
2775      TRACE("port: %d\n", port);
2776   }
2777
2778   if (dwFlags & FLAG_ICC_FORCE_CONNECTION)
2779   {
2780       struct sockaddr_in sin;
2781       int fd;
2782
2783       if (!GetAddress(hostW, port, &sin))
2784           goto End;
2785       fd = socket(sin.sin_family, SOCK_STREAM, 0);
2786       if (fd != -1)
2787       {
2788           if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) == 0)
2789               rc = TRUE;
2790           close(fd);
2791       }
2792   }
2793   else
2794   {
2795       /*
2796        * Build our ping command
2797        */
2798       len = WideCharToMultiByte(CP_UNIXCP, 0, hostW, -1, NULL, 0, NULL, NULL);
2799       command = HeapAlloc( GetProcessHeap(), 0, strlen(ping)+len+strlen(redirect) );
2800       strcpy(command,ping);
2801       WideCharToMultiByte(CP_UNIXCP, 0, hostW, -1, command+strlen(ping), len, NULL, NULL);
2802       strcat(command,redirect);
2803
2804       TRACE("Ping command is : %s\n",command);
2805
2806       status = system(command);
2807
2808       TRACE("Ping returned a code of %i\n",status);
2809
2810       /* Ping return code of 0 indicates success */
2811       if (status == 0)
2812          rc = TRUE;
2813   }
2814
2815 End:
2816
2817   HeapFree( GetProcessHeap(), 0, command );
2818   if (rc == FALSE)
2819     INTERNET_SetLastError(ERROR_NOT_CONNECTED);
2820
2821   return rc;
2822 }
2823
2824
2825 /***********************************************************************
2826  *      InternetCheckConnectionA (WININET.@)
2827  *
2828  * Pings a requested host to check internet connection
2829  *
2830  * RETURNS
2831  *   TRUE on success and FALSE on failure. If a failure then
2832  *   ERROR_NOT_CONNECTED is placed into GetLastError
2833  *
2834  */
2835 BOOL WINAPI InternetCheckConnectionA(LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
2836 {
2837     WCHAR *szUrl;
2838     INT len;
2839     BOOL rc;
2840
2841     len = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0);
2842     if (!(szUrl = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR))))
2843         return FALSE;
2844     MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, szUrl, len);
2845     rc = InternetCheckConnectionW(szUrl, dwFlags, dwReserved);
2846     HeapFree(GetProcessHeap(), 0, szUrl);
2847     
2848     return rc;
2849 }
2850
2851
2852 /**********************************************************
2853  *      INTERNET_InternetOpenUrlW (internal)
2854  *
2855  * Opens an URL
2856  *
2857  * RETURNS
2858  *   handle of connection or NULL on failure
2859  */
2860 HINTERNET WINAPI INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUrl,
2861     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
2862 {
2863     URL_COMPONENTSW urlComponents;
2864     WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024];
2865     WCHAR password[1024], path[2048], extra[1024];
2866     HINTERNET client = NULL, client1 = NULL;
2867     
2868     TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
2869           dwHeadersLength, dwFlags, dwContext);
2870     
2871     urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
2872     urlComponents.lpszScheme = protocol;
2873     urlComponents.dwSchemeLength = 32;
2874     urlComponents.lpszHostName = hostName;
2875     urlComponents.dwHostNameLength = MAXHOSTNAME;
2876     urlComponents.lpszUserName = userName;
2877     urlComponents.dwUserNameLength = 1024;
2878     urlComponents.lpszPassword = password;
2879     urlComponents.dwPasswordLength = 1024;
2880     urlComponents.lpszUrlPath = path;
2881     urlComponents.dwUrlPathLength = 2048;
2882     urlComponents.lpszExtraInfo = extra;
2883     urlComponents.dwExtraInfoLength = 1024;
2884     if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
2885         return NULL;
2886     switch(urlComponents.nScheme) {
2887     case INTERNET_SCHEME_FTP:
2888         if(urlComponents.nPort == 0)
2889             urlComponents.nPort = INTERNET_DEFAULT_FTP_PORT;
2890         client = FTP_Connect(hIC, hostName, urlComponents.nPort,
2891                              userName, password, dwFlags, dwContext, INET_OPENURL);
2892         if(client == NULL)
2893             break;
2894         client1 = FtpOpenFileW(client, path, GENERIC_READ, dwFlags, dwContext);
2895         if(client1 == NULL) {
2896             InternetCloseHandle(client);
2897             break;
2898         }
2899         break;
2900         
2901     case INTERNET_SCHEME_HTTP:
2902     case INTERNET_SCHEME_HTTPS: {
2903         static const WCHAR szStars[] = { '*','/','*', 0 };
2904         LPCWSTR accept[2] = { szStars, NULL };
2905         if(urlComponents.nPort == 0) {
2906             if(urlComponents.nScheme == INTERNET_SCHEME_HTTP)
2907                 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
2908             else
2909                 urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
2910         }
2911         /* FIXME: should use pointers, not handles, as handles are not thread-safe */
2912         client = HTTP_Connect(hIC, hostName, urlComponents.nPort,
2913                               userName, password, dwFlags, dwContext, INET_OPENURL);
2914         if(client == NULL)
2915             break;
2916
2917         if (urlComponents.dwExtraInfoLength) {
2918                 WCHAR *path_extra;
2919                 DWORD len = urlComponents.dwUrlPathLength + urlComponents.dwExtraInfoLength + 1;
2920
2921                 if (!(path_extra = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
2922                 {
2923                         InternetCloseHandle(client);
2924                         break;
2925                 }
2926                 strcpyW(path_extra, urlComponents.lpszUrlPath);
2927                 strcatW(path_extra, urlComponents.lpszExtraInfo);
2928                 client1 = HttpOpenRequestW(client, NULL, path_extra, NULL, NULL, accept, dwFlags, dwContext);
2929                 HeapFree(GetProcessHeap(), 0, path_extra);
2930         }
2931         else
2932                 client1 = HttpOpenRequestW(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
2933
2934         if(client1 == NULL) {
2935             InternetCloseHandle(client);
2936             break;
2937         }
2938         HttpAddRequestHeadersW(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
2939         if (!HttpSendRequestW(client1, NULL, 0, NULL, 0) &&
2940             GetLastError() != ERROR_IO_PENDING) {
2941             InternetCloseHandle(client1);
2942             client1 = NULL;
2943             break;
2944         }
2945     }
2946     case INTERNET_SCHEME_GOPHER:
2947         /* gopher doesn't seem to be implemented in wine, but it's supposed
2948          * to be supported by InternetOpenUrlA. */
2949     default:
2950         INTERNET_SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME);
2951         break;
2952     }
2953
2954     TRACE(" %p <--\n", client1);
2955     
2956     return client1;
2957 }
2958
2959 /**********************************************************
2960  *      InternetOpenUrlW (WININET.@)
2961  *
2962  * Opens an URL
2963  *
2964  * RETURNS
2965  *   handle of connection or NULL on failure
2966  */
2967 static void AsyncInternetOpenUrlProc(WORKREQUEST *workRequest)
2968 {
2969     struct WORKREQ_INTERNETOPENURLW const *req = &workRequest->u.InternetOpenUrlW;
2970     LPWININETAPPINFOW hIC = (LPWININETAPPINFOW) workRequest->hdr;
2971
2972     TRACE("%p\n", hIC);
2973
2974     INTERNET_InternetOpenUrlW(hIC, req->lpszUrl,
2975                               req->lpszHeaders, req->dwHeadersLength, req->dwFlags, req->dwContext);
2976     HeapFree(GetProcessHeap(), 0, req->lpszUrl);
2977     HeapFree(GetProcessHeap(), 0, req->lpszHeaders);
2978 }
2979
2980 HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
2981     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
2982 {
2983     HINTERNET ret = NULL;
2984     LPWININETAPPINFOW hIC = NULL;
2985
2986     if (TRACE_ON(wininet)) {
2987         TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hInternet, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
2988               dwHeadersLength, dwFlags, dwContext);
2989         TRACE("  flags :");
2990         dump_INTERNET_FLAGS(dwFlags);
2991     }
2992
2993     if (!lpszUrl)
2994     {
2995         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2996         goto lend;
2997     }
2998
2999     hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
3000     if (NULL == hIC ||  hIC->hdr.htype != WH_HINIT) {
3001         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3002         goto lend;
3003     }
3004     
3005     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) {
3006         WORKREQUEST workRequest;
3007         struct WORKREQ_INTERNETOPENURLW *req;
3008
3009         workRequest.asyncproc = AsyncInternetOpenUrlProc;
3010         workRequest.hdr = WININET_AddRef( &hIC->hdr );
3011         req = &workRequest.u.InternetOpenUrlW;
3012         req->lpszUrl = WININET_strdupW(lpszUrl);
3013         if (lpszHeaders)
3014             req->lpszHeaders = WININET_strdupW(lpszHeaders);
3015         else
3016             req->lpszHeaders = 0;
3017         req->dwHeadersLength = dwHeadersLength;
3018         req->dwFlags = dwFlags;
3019         req->dwContext = dwContext;
3020         
3021         INTERNET_AsyncCall(&workRequest);
3022         /*
3023          * This is from windows.
3024          */
3025         INTERNET_SetLastError(ERROR_IO_PENDING);
3026     } else {
3027         ret = INTERNET_InternetOpenUrlW(hIC, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext);
3028     }
3029     
3030   lend:
3031     if( hIC )
3032         WININET_Release( &hIC->hdr );
3033     TRACE(" %p <--\n", ret);
3034     
3035     return ret;
3036 }
3037
3038 /**********************************************************
3039  *      InternetOpenUrlA (WININET.@)
3040  *
3041  * Opens an URL
3042  *
3043  * RETURNS
3044  *   handle of connection or NULL on failure
3045  */
3046 HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
3047     LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3048 {
3049     HINTERNET rc = (HINTERNET)NULL;
3050
3051     INT lenUrl;
3052     INT lenHeaders = 0;
3053     LPWSTR szUrl = NULL;
3054     LPWSTR szHeaders = NULL;
3055
3056     TRACE("\n");
3057
3058     if(lpszUrl) {
3059         lenUrl = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0 );
3060         szUrl = HeapAlloc(GetProcessHeap(), 0, lenUrl*sizeof(WCHAR));
3061         if(!szUrl)
3062             return (HINTERNET)NULL;
3063         MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, szUrl, lenUrl);
3064     }
3065     
3066     if(lpszHeaders) {
3067         lenHeaders = MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, NULL, 0 );
3068         szHeaders = HeapAlloc(GetProcessHeap(), 0, lenHeaders*sizeof(WCHAR));
3069         if(!szHeaders) {
3070             HeapFree(GetProcessHeap(), 0, szUrl);
3071             return (HINTERNET)NULL;
3072         }
3073         MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, szHeaders, lenHeaders);
3074     }
3075     
3076     rc = InternetOpenUrlW(hInternet, szUrl, szHeaders,
3077         lenHeaders, dwFlags, dwContext);
3078
3079     HeapFree(GetProcessHeap(), 0, szUrl);
3080     HeapFree(GetProcessHeap(), 0, szHeaders);
3081
3082     return rc;
3083 }
3084
3085
3086 static LPWITHREADERROR INTERNET_AllocThreadError(void)
3087 {
3088     LPWITHREADERROR lpwite = HeapAlloc(GetProcessHeap(), 0, sizeof(*lpwite));
3089
3090     if (lpwite)
3091     {
3092         lpwite->dwError = 0;
3093         lpwite->response[0] = '\0';
3094     }
3095
3096     if (!TlsSetValue(g_dwTlsErrIndex, lpwite))
3097     {
3098         HeapFree(GetProcessHeap(), 0, lpwite);
3099         return NULL;
3100     }
3101
3102     return lpwite;
3103 }
3104
3105
3106 /***********************************************************************
3107  *           INTERNET_SetLastError (internal)
3108  *
3109  * Set last thread specific error
3110  *
3111  * RETURNS
3112  *
3113  */
3114 void INTERNET_SetLastError(DWORD dwError)
3115 {
3116     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
3117
3118     if (!lpwite)
3119         lpwite = INTERNET_AllocThreadError();
3120
3121     SetLastError(dwError);
3122     if(lpwite)
3123         lpwite->dwError = dwError;
3124 }
3125
3126
3127 /***********************************************************************
3128  *           INTERNET_GetLastError (internal)
3129  *
3130  * Get last thread specific error
3131  *
3132  * RETURNS
3133  *
3134  */
3135 DWORD INTERNET_GetLastError(void)
3136 {
3137     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
3138     if (!lpwite) return 0;
3139     /* TlsGetValue clears last error, so set it again here */
3140     SetLastError(lpwite->dwError);
3141     return lpwite->dwError;
3142 }
3143
3144
3145 /***********************************************************************
3146  *           INTERNET_WorkerThreadFunc (internal)
3147  *
3148  * Worker thread execution function
3149  *
3150  * RETURNS
3151  *
3152  */
3153 static DWORD CALLBACK INTERNET_WorkerThreadFunc(LPVOID lpvParam)
3154 {
3155     LPWORKREQUEST lpRequest = lpvParam;
3156     WORKREQUEST workRequest;
3157
3158     TRACE("\n");
3159
3160     memcpy(&workRequest, lpRequest, sizeof(WORKREQUEST));
3161     HeapFree(GetProcessHeap(), 0, lpRequest);
3162
3163     workRequest.asyncproc(&workRequest);
3164
3165     WININET_Release( workRequest.hdr );
3166     return TRUE;
3167 }
3168
3169
3170 /***********************************************************************
3171  *           INTERNET_AsyncCall (internal)
3172  *
3173  * Retrieves work request from queue
3174  *
3175  * RETURNS
3176  *
3177  */
3178 BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
3179 {
3180     BOOL bSuccess;
3181     LPWORKREQUEST lpNewRequest;
3182
3183     TRACE("\n");
3184
3185     lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
3186     if (!lpNewRequest)
3187         return FALSE;
3188
3189     memcpy(lpNewRequest, lpWorkRequest, sizeof(WORKREQUEST));
3190
3191     bSuccess = QueueUserWorkItem(INTERNET_WorkerThreadFunc, lpNewRequest, WT_EXECUTELONGFUNCTION);
3192     if (!bSuccess)
3193     {
3194         HeapFree(GetProcessHeap(), 0, lpNewRequest);
3195         INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED);
3196     }
3197
3198     return bSuccess;
3199 }
3200
3201
3202 /***********************************************************************
3203  *          INTERNET_GetResponseBuffer  (internal)
3204  *
3205  * RETURNS
3206  *
3207  */
3208 LPSTR INTERNET_GetResponseBuffer(void)
3209 {
3210     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
3211     if (!lpwite)
3212         lpwite = INTERNET_AllocThreadError();
3213     TRACE("\n");
3214     return lpwite->response;
3215 }
3216
3217 /***********************************************************************
3218  *           INTERNET_GetNextLine  (internal)
3219  *
3220  * Parse next line in directory string listing
3221  *
3222  * RETURNS
3223  *   Pointer to beginning of next line
3224  *   NULL on failure
3225  *
3226  */
3227
3228 LPSTR INTERNET_GetNextLine(INT nSocket, LPDWORD dwLen)
3229 {
3230     struct timeval tv;
3231     fd_set infd;
3232     BOOL bSuccess = FALSE;
3233     INT nRecv = 0;
3234     LPSTR lpszBuffer = INTERNET_GetResponseBuffer();
3235
3236     TRACE("\n");
3237
3238     FD_ZERO(&infd);
3239     FD_SET(nSocket, &infd);
3240     tv.tv_sec=RESPONSE_TIMEOUT;
3241     tv.tv_usec=0;
3242
3243     while (nRecv < MAX_REPLY_LEN)
3244     {
3245         if (select(nSocket+1,&infd,NULL,NULL,&tv) > 0)
3246         {
3247             if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
3248             {
3249                 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
3250                 goto lend;
3251             }
3252
3253             if (lpszBuffer[nRecv] == '\n')
3254             {
3255                 bSuccess = TRUE;
3256                 break;
3257             }
3258             if (lpszBuffer[nRecv] != '\r')
3259                 nRecv++;
3260         }
3261         else
3262         {
3263             INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
3264             goto lend;
3265         }
3266     }
3267
3268 lend:
3269     if (bSuccess)
3270     {
3271         lpszBuffer[nRecv] = '\0';
3272         *dwLen = nRecv - 1;
3273         TRACE(":%d %s\n", nRecv, lpszBuffer);
3274         return lpszBuffer;
3275     }
3276     else
3277     {
3278         return NULL;
3279     }
3280 }
3281
3282 /**********************************************************
3283  *      InternetQueryDataAvailable (WININET.@)
3284  *
3285  * Determines how much data is available to be read.
3286  *
3287  * RETURNS
3288  *   TRUE on success, FALSE if an error occurred. If
3289  *   INTERNET_FLAG_ASYNC was specified in InternetOpen, and
3290  *   no data is presently available, FALSE is returned with
3291  *   the last error ERROR_IO_PENDING; a callback with status
3292  *   INTERNET_STATUS_REQUEST_COMPLETE will be sent when more
3293  *   data is available.
3294  */
3295 void AsyncInternetQueryDataAvailableProc(WORKREQUEST *workRequest)
3296 {
3297     LPWININETHTTPREQW lpwhr;
3298     INTERNET_ASYNC_RESULT iar;
3299     char buffer[4048];
3300
3301     TRACE("INTERNETQUERYDATAAVAILABLE %p\n", workRequest->hdr);
3302
3303     switch (workRequest->hdr->htype)
3304     {
3305     case WH_HHTTPREQ:
3306         lpwhr = (LPWININETHTTPREQW)workRequest->hdr;
3307         iar.dwResult = NETCON_recv(&lpwhr->netConnection, buffer,
3308                                    min(sizeof(buffer),
3309                                        lpwhr->dwContentLength - lpwhr->dwContentRead),
3310                                    MSG_PEEK, (int *)&iar.dwError);
3311         INTERNET_SendCallback(workRequest->hdr, workRequest->hdr->dwContext,
3312                               INTERNET_STATUS_REQUEST_COMPLETE, &iar,
3313                               sizeof(INTERNET_ASYNC_RESULT));
3314         break;
3315
3316     default:
3317         FIXME("unsupported file type\n");
3318         break;
3319     }
3320 }
3321
3322 BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile,
3323                                 LPDWORD lpdwNumberOfBytesAvailble,
3324                                 DWORD dwFlags, DWORD_PTR dwContext)
3325 {
3326     LPWININETHTTPREQW lpwhr;
3327     BOOL retval = FALSE;
3328     char buffer[4048];
3329
3330     lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hFile );
3331     if (NULL == lpwhr)
3332     {
3333         INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3334         return FALSE;
3335     }
3336
3337     TRACE("-->  %p %i\n",lpwhr,lpwhr->hdr.htype);
3338
3339     switch (lpwhr->hdr.htype)
3340     {
3341     case WH_HHTTPREQ:
3342         retval = TRUE;
3343         if (NETCON_query_data_available(&lpwhr->netConnection,
3344                                         lpdwNumberOfBytesAvailble) &&
3345             !*lpdwNumberOfBytesAvailble)
3346         {
3347             /* Even if we are in async mode, we need to determine whether
3348              * there is actually more data available. We do this by trying
3349              * to peek only a single byte in async mode. */
3350             BOOL async = (lpwhr->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC);
3351             if (NETCON_recv(&lpwhr->netConnection, buffer,
3352                             min(async ? 1 : sizeof(buffer),
3353                                 lpwhr->dwContentLength - lpwhr->dwContentRead),
3354                             MSG_PEEK, (int *)lpdwNumberOfBytesAvailble) &&
3355                 async && *lpdwNumberOfBytesAvailble)
3356             {
3357                 WORKREQUEST workRequest;
3358
3359                 *lpdwNumberOfBytesAvailble = 0;
3360                 workRequest.asyncproc = AsyncInternetQueryDataAvailableProc;
3361                 workRequest.hdr = WININET_AddRef( &lpwhr->hdr );
3362
3363                 retval = INTERNET_AsyncCall(&workRequest);
3364                 if (!retval)
3365                 {
3366                     WININET_Release( &lpwhr->hdr );
3367                 }
3368                 else
3369                 {
3370                     INTERNET_SetLastError(ERROR_IO_PENDING);
3371                     retval = FALSE;
3372                 }
3373             }
3374         }
3375         break;
3376
3377     default:
3378         FIXME("unsupported file type\n");
3379         break;
3380     }
3381     WININET_Release( &lpwhr->hdr );
3382
3383     TRACE("<-- %i\n",retval);
3384     return retval;
3385 }
3386
3387
3388 /***********************************************************************
3389  *      InternetLockRequestFile (WININET.@)
3390  */
3391 BOOL WINAPI InternetLockRequestFile( HINTERNET hInternet, HANDLE
3392 *lphLockReqHandle)
3393 {
3394     FIXME("STUB\n");
3395     return FALSE;
3396 }
3397
3398 BOOL WINAPI InternetUnlockRequestFile( HANDLE hLockHandle)
3399 {
3400     FIXME("STUB\n");
3401     return FALSE;
3402 }
3403
3404
3405 /***********************************************************************
3406  *      InternetAutodial (WININET.@)
3407  *
3408  * On windows this function is supposed to dial the default internet
3409  * connection. We don't want to have Wine dial out to the internet so
3410  * we return TRUE by default. It might be nice to check if we are connected.
3411  *
3412  * RETURNS
3413  *   TRUE on success
3414  *   FALSE on failure
3415  *
3416  */
3417 BOOL WINAPI InternetAutodial(DWORD dwFlags, HWND hwndParent)
3418 {
3419     FIXME("STUB\n");
3420
3421     /* Tell that we are connected to the internet. */
3422     return TRUE;
3423 }
3424
3425 /***********************************************************************
3426  *      InternetAutodialHangup (WININET.@)
3427  *
3428  * Hangs up a connection made with InternetAutodial
3429  *
3430  * PARAM
3431  *    dwReserved
3432  * RETURNS
3433  *   TRUE on success
3434  *   FALSE on failure
3435  *
3436  */
3437 BOOL WINAPI InternetAutodialHangup(DWORD dwReserved)
3438 {
3439     FIXME("STUB\n");
3440
3441     /* we didn't dial, we don't disconnect */
3442     return TRUE;
3443 }
3444
3445 /***********************************************************************
3446  *      InternetCombineUrlA (WININET.@)
3447  *
3448  * Combine a base URL with a relative URL
3449  *
3450  * RETURNS
3451  *   TRUE on success
3452  *   FALSE on failure
3453  *
3454  */
3455
3456 BOOL WINAPI InternetCombineUrlA(LPCSTR lpszBaseUrl, LPCSTR lpszRelativeUrl,
3457                                 LPSTR lpszBuffer, LPDWORD lpdwBufferLength,
3458                                 DWORD dwFlags)
3459 {
3460     HRESULT hr=S_OK;
3461
3462     TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_a(lpszBaseUrl), debugstr_a(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
3463
3464     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
3465     dwFlags ^= ICU_NO_ENCODE;
3466     hr=UrlCombineA(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
3467
3468     return (hr==S_OK);
3469 }
3470
3471 /***********************************************************************
3472  *      InternetCombineUrlW (WININET.@)
3473  *
3474  * Combine a base URL with a relative URL
3475  *
3476  * RETURNS
3477  *   TRUE on success
3478  *   FALSE on failure
3479  *
3480  */
3481
3482 BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
3483                                 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength,
3484                                 DWORD dwFlags)
3485 {
3486     HRESULT hr=S_OK;
3487
3488     TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_w(lpszBaseUrl), debugstr_w(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
3489
3490     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
3491     dwFlags ^= ICU_NO_ENCODE;
3492     hr=UrlCombineW(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
3493
3494     return (hr==S_OK);
3495 }
3496
3497 /* max port num is 65535 => 5 digits */
3498 #define MAX_WORD_DIGITS 5
3499
3500 #define URL_GET_COMP_LENGTH(url, component) ((url)->dw##component##Length ? \
3501     (url)->dw##component##Length : strlenW((url)->lpsz##component))
3502 #define URL_GET_COMP_LENGTHA(url, component) ((url)->dw##component##Length ? \
3503     (url)->dw##component##Length : strlen((url)->lpsz##component))
3504
3505 static BOOL url_uses_default_port(INTERNET_SCHEME nScheme, INTERNET_PORT nPort)
3506 {
3507     if ((nScheme == INTERNET_SCHEME_HTTP) &&
3508         (nPort == INTERNET_DEFAULT_HTTP_PORT))
3509         return TRUE;
3510     if ((nScheme == INTERNET_SCHEME_HTTPS) &&
3511         (nPort == INTERNET_DEFAULT_HTTPS_PORT))
3512         return TRUE;
3513     if ((nScheme == INTERNET_SCHEME_FTP) &&
3514         (nPort == INTERNET_DEFAULT_FTP_PORT))
3515         return TRUE;
3516     if ((nScheme == INTERNET_SCHEME_GOPHER) &&
3517         (nPort == INTERNET_DEFAULT_GOPHER_PORT))
3518         return TRUE;
3519
3520     if (nPort == INTERNET_INVALID_PORT_NUMBER)
3521         return TRUE;
3522
3523     return FALSE;
3524 }
3525
3526 /* opaque urls do not fit into the standard url hierarchy and don't have
3527  * two following slashes */
3528 static inline BOOL scheme_is_opaque(INTERNET_SCHEME nScheme)
3529 {
3530     return (nScheme != INTERNET_SCHEME_FTP) &&
3531            (nScheme != INTERNET_SCHEME_GOPHER) &&
3532            (nScheme != INTERNET_SCHEME_HTTP) &&
3533            (nScheme != INTERNET_SCHEME_HTTPS) &&
3534            (nScheme != INTERNET_SCHEME_FILE);
3535 }
3536
3537 static LPCWSTR INTERNET_GetSchemeString(INTERNET_SCHEME scheme)
3538 {
3539     int index;
3540     if (scheme < INTERNET_SCHEME_FIRST)
3541         return NULL;
3542     index = scheme - INTERNET_SCHEME_FIRST;
3543     if (index >= sizeof(url_schemes)/sizeof(url_schemes[0]))
3544         return NULL;
3545     return (LPCWSTR)&url_schemes[index];
3546 }
3547
3548 /* we can calculate using ansi strings because we're just
3549  * calculating string length, not size
3550  */
3551 static BOOL calc_url_length(LPURL_COMPONENTSW lpUrlComponents,
3552                             LPDWORD lpdwUrlLength)
3553 {
3554     INTERNET_SCHEME nScheme;
3555
3556     *lpdwUrlLength = 0;
3557
3558     if (lpUrlComponents->lpszScheme)
3559     {
3560         DWORD dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
3561         *lpdwUrlLength += dwLen;
3562         nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
3563     }
3564     else
3565     {
3566         LPCWSTR scheme;
3567
3568         nScheme = lpUrlComponents->nScheme;
3569
3570         if (nScheme == INTERNET_SCHEME_DEFAULT)
3571             nScheme = INTERNET_SCHEME_HTTP;
3572         scheme = INTERNET_GetSchemeString(nScheme);
3573         *lpdwUrlLength += strlenW(scheme);
3574     }
3575
3576     (*lpdwUrlLength)++; /* ':' */
3577     if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
3578         *lpdwUrlLength += strlen("//");
3579
3580     if (lpUrlComponents->lpszUserName)
3581     {
3582         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
3583         *lpdwUrlLength += strlen("@");
3584     }
3585     else
3586     {
3587         if (lpUrlComponents->lpszPassword)
3588         {
3589             INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3590             return FALSE;
3591         }
3592     }
3593
3594     if (lpUrlComponents->lpszPassword)
3595     {
3596         *lpdwUrlLength += strlen(":");
3597         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, Password);
3598     }
3599
3600     if (lpUrlComponents->lpszHostName)
3601     {
3602         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
3603
3604         if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
3605         {
3606             char szPort[MAX_WORD_DIGITS+1];
3607
3608             sprintf(szPort, "%d", lpUrlComponents->nPort);
3609             *lpdwUrlLength += strlen(szPort);
3610             *lpdwUrlLength += strlen(":");
3611         }
3612
3613         if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
3614             (*lpdwUrlLength)++; /* '/' */
3615     }
3616
3617     if (lpUrlComponents->lpszUrlPath)
3618         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
3619
3620     return TRUE;
3621 }
3622
3623 static void convert_urlcomp_atow(LPURL_COMPONENTSA lpUrlComponents, LPURL_COMPONENTSW urlCompW)
3624 {
3625     INT len;
3626
3627     ZeroMemory(urlCompW, sizeof(URL_COMPONENTSW));
3628
3629     urlCompW->dwStructSize = sizeof(URL_COMPONENTSW);
3630     urlCompW->dwSchemeLength = lpUrlComponents->dwSchemeLength;
3631     urlCompW->nScheme = lpUrlComponents->nScheme;
3632     urlCompW->dwHostNameLength = lpUrlComponents->dwHostNameLength;
3633     urlCompW->nPort = lpUrlComponents->nPort;
3634     urlCompW->dwUserNameLength = lpUrlComponents->dwUserNameLength;
3635     urlCompW->dwPasswordLength = lpUrlComponents->dwPasswordLength;
3636     urlCompW->dwUrlPathLength = lpUrlComponents->dwUrlPathLength;
3637     urlCompW->dwExtraInfoLength = lpUrlComponents->dwExtraInfoLength;
3638
3639     if (lpUrlComponents->lpszScheme)
3640     {
3641         len = URL_GET_COMP_LENGTHA(lpUrlComponents, Scheme) + 1;
3642         urlCompW->lpszScheme = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3643         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszScheme,
3644                             -1, urlCompW->lpszScheme, len);
3645     }
3646
3647     if (lpUrlComponents->lpszHostName)
3648     {
3649         len = URL_GET_COMP_LENGTHA(lpUrlComponents, HostName) + 1;
3650         urlCompW->lpszHostName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3651         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszHostName,
3652                             -1, urlCompW->lpszHostName, len);
3653     }
3654
3655     if (lpUrlComponents->lpszUserName)
3656     {
3657         len = URL_GET_COMP_LENGTHA(lpUrlComponents, UserName) + 1;
3658         urlCompW->lpszUserName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3659         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUserName,
3660                             -1, urlCompW->lpszUserName, len);
3661     }
3662
3663     if (lpUrlComponents->lpszPassword)
3664     {
3665         len = URL_GET_COMP_LENGTHA(lpUrlComponents, Password) + 1;
3666         urlCompW->lpszPassword = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3667         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszPassword,
3668                             -1, urlCompW->lpszPassword, len);
3669     }
3670
3671     if (lpUrlComponents->lpszUrlPath)
3672     {
3673         len = URL_GET_COMP_LENGTHA(lpUrlComponents, UrlPath) + 1;
3674         urlCompW->lpszUrlPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3675         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUrlPath,
3676                             -1, urlCompW->lpszUrlPath, len);
3677     }
3678
3679     if (lpUrlComponents->lpszExtraInfo)
3680     {
3681         len = URL_GET_COMP_LENGTHA(lpUrlComponents, ExtraInfo) + 1;
3682         urlCompW->lpszExtraInfo = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3683         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszExtraInfo,
3684                             -1, urlCompW->lpszExtraInfo, len);
3685     }
3686 }
3687
3688 /***********************************************************************
3689  *      InternetCreateUrlA (WININET.@)
3690  *
3691  * See InternetCreateUrlW.
3692  */
3693 BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
3694                                LPSTR lpszUrl, LPDWORD lpdwUrlLength)
3695 {
3696     BOOL ret;
3697     LPWSTR urlW = NULL;
3698     URL_COMPONENTSW urlCompW;
3699
3700     TRACE("(%p,%d,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
3701
3702     if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
3703     {
3704         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3705         return FALSE;
3706     }
3707
3708     convert_urlcomp_atow(lpUrlComponents, &urlCompW);
3709
3710     if (lpszUrl)
3711         urlW = HeapAlloc(GetProcessHeap(), 0, *lpdwUrlLength * sizeof(WCHAR));
3712
3713     ret = InternetCreateUrlW(&urlCompW, dwFlags, urlW, lpdwUrlLength);
3714
3715     if (!ret && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
3716         *lpdwUrlLength /= sizeof(WCHAR);
3717
3718     /* on success, lpdwUrlLength points to the size of urlW in WCHARS
3719     * minus one, so add one to leave room for NULL terminator
3720     */
3721     if (ret)
3722         WideCharToMultiByte(CP_ACP, 0, urlW, -1, lpszUrl, *lpdwUrlLength + 1, NULL, NULL);
3723
3724     HeapFree(GetProcessHeap(), 0, urlCompW.lpszScheme);
3725     HeapFree(GetProcessHeap(), 0, urlCompW.lpszHostName);
3726     HeapFree(GetProcessHeap(), 0, urlCompW.lpszUserName);
3727     HeapFree(GetProcessHeap(), 0, urlCompW.lpszPassword);
3728     HeapFree(GetProcessHeap(), 0, urlCompW.lpszUrlPath);
3729     HeapFree(GetProcessHeap(), 0, urlCompW.lpszExtraInfo);
3730     HeapFree(GetProcessHeap(), 0, urlW);
3731
3732     return ret;
3733 }
3734
3735 /***********************************************************************
3736  *      InternetCreateUrlW (WININET.@)
3737  *
3738  * Creates a URL from its component parts.
3739  *
3740  * PARAMS
3741  *  lpUrlComponents [I] URL Components.
3742  *  dwFlags         [I] Flags. See notes.
3743  *  lpszUrl         [I] Buffer in which to store the created URL.
3744  *  lpdwUrlLength   [I/O] On input, the length of the buffer pointed to by
3745  *                        lpszUrl in characters. On output, the number of bytes
3746  *                        required to store the URL including terminator.
3747  *
3748  * NOTES
3749  *
3750  * The dwFlags parameter can be zero or more of the following:
3751  *|ICU_ESCAPE - Generates escape sequences for unsafe characters in the path and extra info of the URL.
3752  *
3753  * RETURNS
3754  *   TRUE on success
3755  *   FALSE on failure
3756  *
3757  */
3758 BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
3759                                LPWSTR lpszUrl, LPDWORD lpdwUrlLength)
3760 {
3761     DWORD dwLen;
3762     INTERNET_SCHEME nScheme;
3763
3764     static const WCHAR slashSlashW[] = {'/','/'};
3765     static const WCHAR percentD[] = {'%','d',0};
3766
3767     TRACE("(%p,%d,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
3768
3769     if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
3770     {
3771         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3772         return FALSE;
3773     }
3774
3775     if (!calc_url_length(lpUrlComponents, &dwLen))
3776         return FALSE;
3777
3778     if (!lpszUrl || *lpdwUrlLength < dwLen)
3779     {
3780         *lpdwUrlLength = (dwLen + 1) * sizeof(WCHAR);
3781         INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
3782         return FALSE;
3783     }
3784
3785     *lpdwUrlLength = dwLen;
3786     lpszUrl[0] = 0x00;
3787
3788     dwLen = 0;
3789
3790     if (lpUrlComponents->lpszScheme)
3791     {
3792         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
3793         memcpy(lpszUrl, lpUrlComponents->lpszScheme, dwLen * sizeof(WCHAR));
3794         lpszUrl += dwLen;
3795
3796         nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
3797     }
3798     else
3799     {
3800         LPCWSTR scheme;
3801         nScheme = lpUrlComponents->nScheme;
3802
3803         if (nScheme == INTERNET_SCHEME_DEFAULT)
3804             nScheme = INTERNET_SCHEME_HTTP;
3805
3806         scheme = INTERNET_GetSchemeString(nScheme);
3807         dwLen = strlenW(scheme);
3808         memcpy(lpszUrl, scheme, dwLen * sizeof(WCHAR));
3809         lpszUrl += dwLen;
3810     }
3811
3812     /* all schemes are followed by at least a colon */
3813     *lpszUrl = ':';
3814     lpszUrl++;
3815
3816     if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
3817     {
3818         memcpy(lpszUrl, slashSlashW, sizeof(slashSlashW));
3819         lpszUrl += sizeof(slashSlashW)/sizeof(slashSlashW[0]);
3820     }
3821
3822     if (lpUrlComponents->lpszUserName)
3823     {
3824         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
3825         memcpy(lpszUrl, lpUrlComponents->lpszUserName, dwLen * sizeof(WCHAR));
3826         lpszUrl += dwLen;
3827
3828         if (lpUrlComponents->lpszPassword)
3829         {
3830             *lpszUrl = ':';
3831             lpszUrl++;
3832
3833             dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Password);
3834             memcpy(lpszUrl, lpUrlComponents->lpszPassword, dwLen * sizeof(WCHAR));
3835             lpszUrl += dwLen;
3836         }
3837
3838         *lpszUrl = '@';
3839         lpszUrl++;
3840     }
3841
3842     if (lpUrlComponents->lpszHostName)
3843     {
3844         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
3845         memcpy(lpszUrl, lpUrlComponents->lpszHostName, dwLen * sizeof(WCHAR));
3846         lpszUrl += dwLen;
3847
3848         if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
3849         {
3850             WCHAR szPort[MAX_WORD_DIGITS+1];
3851
3852             sprintfW(szPort, percentD, lpUrlComponents->nPort);
3853             *lpszUrl = ':';
3854             lpszUrl++;
3855             dwLen = strlenW(szPort);
3856             memcpy(lpszUrl, szPort, dwLen * sizeof(WCHAR));
3857             lpszUrl += dwLen;
3858         }
3859
3860         /* add slash between hostname and path if necessary */
3861         if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
3862         {
3863             *lpszUrl = '/';
3864             lpszUrl++;
3865         }
3866     }
3867
3868
3869     if (lpUrlComponents->lpszUrlPath)
3870     {
3871         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
3872         memcpy(lpszUrl, lpUrlComponents->lpszUrlPath, dwLen * sizeof(WCHAR));
3873         lpszUrl += dwLen;
3874     }
3875
3876     *lpszUrl = '\0';
3877
3878     return TRUE;
3879 }
3880
3881 /***********************************************************************
3882  *      InternetConfirmZoneCrossingA (WININET.@)
3883  *
3884  */
3885 DWORD WINAPI InternetConfirmZoneCrossingA( HWND hWnd, LPSTR szUrlPrev, LPSTR szUrlNew, BOOL bPost )
3886 {
3887     FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_a(szUrlPrev), debugstr_a(szUrlNew), bPost);
3888     return ERROR_SUCCESS;
3889 }
3890
3891 /***********************************************************************
3892  *      InternetConfirmZoneCrossingW (WININET.@)
3893  *
3894  */
3895 DWORD WINAPI InternetConfirmZoneCrossingW( HWND hWnd, LPWSTR szUrlPrev, LPWSTR szUrlNew, BOOL bPost )
3896 {
3897     FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_w(szUrlPrev), debugstr_w(szUrlNew), bPost);
3898     return ERROR_SUCCESS;
3899 }
3900
3901 DWORD WINAPI InternetDialA( HWND hwndParent, LPSTR lpszConnectoid, DWORD dwFlags,
3902                             DWORD_PTR* lpdwConnection, DWORD dwReserved )
3903 {
3904     FIXME("(%p, %p, 0x%08x, %p, 0x%08x) stub\n", hwndParent, lpszConnectoid, dwFlags,
3905           lpdwConnection, dwReserved);
3906     return ERROR_SUCCESS;
3907 }
3908
3909 DWORD WINAPI InternetDialW( HWND hwndParent, LPWSTR lpszConnectoid, DWORD dwFlags,
3910                             DWORD_PTR* lpdwConnection, DWORD dwReserved )
3911 {
3912     FIXME("(%p, %p, 0x%08x, %p, 0x%08x) stub\n", hwndParent, lpszConnectoid, dwFlags,
3913           lpdwConnection, dwReserved);
3914     return ERROR_SUCCESS;
3915 }
3916
3917 BOOL WINAPI InternetGoOnlineA( LPSTR lpszURL, HWND hwndParent, DWORD dwReserved )
3918 {
3919     FIXME("(%s, %p, 0x%08x) stub\n", debugstr_a(lpszURL), hwndParent, dwReserved);
3920     return TRUE;
3921 }
3922
3923 BOOL WINAPI InternetGoOnlineW( LPWSTR lpszURL, HWND hwndParent, DWORD dwReserved )
3924 {
3925     FIXME("(%s, %p, 0x%08x) stub\n", debugstr_w(lpszURL), hwndParent, dwReserved);
3926     return TRUE;
3927 }
3928
3929 DWORD WINAPI InternetHangUp( DWORD_PTR dwConnection, DWORD dwReserved )
3930 {
3931     FIXME("(0x%08lx, 0x%08x) stub\n", dwConnection, dwReserved);
3932     return ERROR_SUCCESS;
3933 }
3934
3935 BOOL WINAPI CreateMD5SSOHash( PWSTR pszChallengeInfo, PWSTR pwszRealm, PWSTR pwszTarget,
3936                               PBYTE pbHexHash )
3937 {
3938     FIXME("(%s, %s, %s, %p) stub\n", debugstr_w(pszChallengeInfo), debugstr_w(pwszRealm),
3939           debugstr_w(pwszTarget), pbHexHash);
3940     return FALSE;
3941 }
3942
3943 BOOL WINAPI ResumeSuspendedDownload( HINTERNET hInternet, DWORD dwError )
3944 {
3945     FIXME("(%p, 0x%08x) stub\n", hInternet, dwError);
3946     return FALSE;
3947 }
3948
3949 BOOL WINAPI InternetQueryFortezzaStatus(DWORD *a, DWORD_PTR b)
3950 {
3951     FIXME("(%p, %08lx) stub\n", a, b);
3952     return 0;
3953 }