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