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