Implemented InternetGetConnectedStateExA.
[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 "ntstatus.h"
52 #include "windef.h"
53 #include "winbase.h"
54 #include "winreg.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
67 #include "wine/unicode.h"
68
69 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
70
71 #define MAX_IDLE_WORKER 1000*60*1
72 #define MAX_WORKER_THREADS 10
73 #define RESPONSE_TIMEOUT        30
74
75 #define GET_HWININET_FROM_LPWININETFINDNEXT(lpwh) \
76 (LPWININETAPPINFOW)(((LPWININETFTPSESSIONW)(lpwh->hdr.lpwhparent))->hdr.lpwhparent)
77
78
79 typedef struct
80 {
81     DWORD  dwError;
82     CHAR   response[MAX_REPLY_LEN];
83 } WITHREADERROR, *LPWITHREADERROR;
84
85 static VOID INTERNET_CloseHandle(LPWININETHANDLEHEADER hdr);
86 BOOL WINAPI INTERNET_FindNextFileW(LPWININETFINDNEXTW lpwh, LPVOID lpvFindData);
87 HINTERNET WINAPI INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUrl,
88               LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext);
89 static VOID INTERNET_ExecuteWork();
90
91 DWORD g_dwTlsErrIndex = TLS_OUT_OF_INDEXES;
92 DWORD dwNumThreads;
93 DWORD dwNumIdleThreads;
94 DWORD dwNumJobs;
95 HANDLE hEventArray[2];
96 #define hQuitEvent hEventArray[0]
97 #define hWorkEvent hEventArray[1]
98 CRITICAL_SECTION csQueue;
99 LPWORKREQUEST lpHeadWorkQueue;
100 LPWORKREQUEST lpWorkQueueTail;
101
102 extern void URLCacheContainers_CreateDefaults();
103 extern void URLCacheContainers_DeleteAll();
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, { 0, (DWORD)(__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 = CreateEventA(0, TRUE, FALSE, NULL);
274             hWorkEvent = CreateEventA(0, FALSE, FALSE, NULL);
275             InitializeCriticalSection(&csQueue);
276
277             URLCacheContainers_CreateDefaults();
278
279             dwNumThreads = 0;
280             dwNumIdleThreads = 0;
281             dwNumJobs = 0;
282
283         case DLL_THREAD_ATTACH:
284             {
285                 LPWITHREADERROR lpwite = HeapAlloc(GetProcessHeap(), 0, sizeof(WITHREADERROR));
286                 if (NULL == lpwite)
287                     return FALSE;
288
289                 TlsSetValue(g_dwTlsErrIndex, (LPVOID)lpwite);
290             }
291             break;
292
293         case DLL_THREAD_DETACH:
294             if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
295                         {
296                                 LPVOID lpwite = TlsGetValue(g_dwTlsErrIndex);
297                                 if (lpwite)
298                    HeapFree(GetProcessHeap(), 0, lpwite);
299                         }
300             break;
301
302         case DLL_PROCESS_DETACH:
303
304             URLCacheContainers_DeleteAll();
305
306             if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
307             {
308                 HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex));
309                 TlsFree(g_dwTlsErrIndex);
310             }
311
312             SetEvent(hQuitEvent);
313
314             CloseHandle(hQuitEvent);
315             CloseHandle(hWorkEvent);
316             DeleteCriticalSection(&csQueue);
317             break;
318     }
319
320     return TRUE;
321 }
322
323
324 /***********************************************************************
325  *           InternetInitializeAutoProxyDll   (WININET.@)
326  *
327  * Setup the internal proxy
328  *
329  * PARAMETERS
330  *     dwReserved
331  *
332  * RETURNS
333  *     FALSE on failure
334  *
335  */
336 BOOL WINAPI InternetInitializeAutoProxyDll(DWORD dwReserved)
337 {
338     FIXME("STUB\n");
339     INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
340     return FALSE;
341 }
342
343 /***********************************************************************
344  *           DetectAutoProxyUrl   (WININET.@)
345  *
346  * Auto detect the proxy url
347  *
348  * RETURNS
349  *     FALSE on failure
350  *
351  */
352 BOOL WINAPI DetectAutoProxyUrl(LPSTR lpszAutoProxyUrl,
353         DWORD dwAutoProxyUrlLength, DWORD dwDetectFlags)
354 {
355     FIXME("STUB\n");
356     INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
357     return FALSE;
358 }
359
360
361 /***********************************************************************
362  *           INTERNET_ConfigureProxyFromReg
363  *
364  * FIXME:
365  * The proxy may be specified in the form 'http=proxy.my.org'
366  * Presumably that means there can be ftp=ftpproxy.my.org too.
367  */
368 static BOOL INTERNET_ConfigureProxyFromReg( LPWININETAPPINFOW lpwai )
369 {
370     HKEY key;
371     DWORD r, keytype, len, enabled;
372     LPSTR lpszInternetSettings =
373         "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
374     static const WCHAR szProxyServer[] = { 'P','r','o','x','y','S','e','r','v','e','r', 0 };
375
376     r = RegOpenKeyA(HKEY_CURRENT_USER, lpszInternetSettings, &key);
377     if ( r != ERROR_SUCCESS )
378         return FALSE;
379
380     len = sizeof enabled;
381     r = RegQueryValueExA( key, "ProxyEnable", NULL, &keytype,
382                           (BYTE*)&enabled, &len);
383     if( (r == ERROR_SUCCESS) && enabled )
384     {
385         TRACE("Proxy is enabled.\n");
386
387         /* figure out how much memory the proxy setting takes */
388         r = RegQueryValueExW( key, szProxyServer, NULL, &keytype, 
389                               NULL, &len);
390         if( (r == ERROR_SUCCESS) && len && (keytype == REG_SZ) )
391         {
392             LPWSTR szProxy, p;
393             static const WCHAR szHttp[] = {'h','t','t','p','=',0};
394
395             szProxy=HeapAlloc( GetProcessHeap(), 0, len );
396             RegQueryValueExW( key, szProxyServer, NULL, &keytype,
397                               (BYTE*)szProxy, &len);
398
399             /* find the http proxy, and strip away everything else */
400             p = strstrW( szProxy, szHttp );
401             if( p )
402             {
403                  p += lstrlenW(szHttp);
404                  lstrcpyW( szProxy, p );
405             }
406             p = strchrW( szProxy, ' ' );
407             if( p )
408                 *p = 0;
409
410             lpwai->dwAccessType = INTERNET_OPEN_TYPE_PROXY;
411             lpwai->lpszProxy = szProxy;
412
413             TRACE("http proxy = %s\n", debugstr_w(lpwai->lpszProxy));
414         }
415         else
416             ERR("Couldn't read proxy server settings.\n");
417     }
418     else
419         TRACE("Proxy is not enabled.\n");
420     RegCloseKey(key);
421
422     return enabled;
423 }
424
425 /***********************************************************************
426  *           InternetOpenW   (WININET.@)
427  *
428  * Per-application initialization of wininet
429  *
430  * RETURNS
431  *    HINTERNET on success
432  *    NULL on failure
433  *
434  */
435 HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType,
436     LPCWSTR lpszProxy, LPCWSTR lpszProxyBypass, DWORD dwFlags)
437 {
438     LPWININETAPPINFOW lpwai = NULL;
439     HINTERNET handle = NULL;
440
441     if (TRACE_ON(wininet)) {
442 #define FE(x) { x, #x }
443         static const wininet_flag_info access_type[] = {
444             FE(INTERNET_OPEN_TYPE_PRECONFIG),
445             FE(INTERNET_OPEN_TYPE_DIRECT),
446             FE(INTERNET_OPEN_TYPE_PROXY),
447             FE(INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY)
448         };
449         static const wininet_flag_info flag[] = {
450             FE(INTERNET_FLAG_ASYNC),
451             FE(INTERNET_FLAG_FROM_CACHE),
452             FE(INTERNET_FLAG_OFFLINE)
453         };
454 #undef FE
455         DWORD i;
456         const char *access_type_str = "Unknown";
457         DWORD flag_val = dwFlags;
458         
459         TRACE("(%s, %li, %s, %s, %li)\n", debugstr_w(lpszAgent), dwAccessType,
460               debugstr_w(lpszProxy), debugstr_w(lpszProxyBypass), dwFlags);
461         for (i = 0; i < (sizeof(access_type) / sizeof(access_type[0])); i++) {
462             if (access_type[i].val == dwAccessType) {
463                 access_type_str = access_type[i].name;
464                 break;
465             }
466         }
467         TRACE("  access type : %s\n", access_type_str);
468         TRACE("  flags       :");
469         for (i = 0; i < (sizeof(flag) / sizeof(flag[0])); i++) {
470             if (flag[i].val & flag_val) {
471                 DPRINTF(" %s", flag[i].name);
472                 flag_val &= ~flag[i].val;
473             }
474         }       
475         if (flag_val) DPRINTF(" Unknown flags (%08lx)", flag_val);
476         DPRINTF("\n");
477     }
478
479     /* Clear any error information */
480     INTERNET_SetLastError(0);
481
482     lpwai = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETAPPINFOW));
483     if (NULL == lpwai)
484     {
485         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
486         goto lend;
487     }
488  
489     memset(lpwai, 0, sizeof(WININETAPPINFOW));
490     lpwai->hdr.htype = WH_HINIT;
491     lpwai->hdr.lpwhparent = NULL;
492     lpwai->hdr.dwFlags = dwFlags;
493     lpwai->hdr.dwRefCount = 1;
494     lpwai->hdr.destroy = INTERNET_CloseHandle;
495     lpwai->dwAccessType = dwAccessType;
496     lpwai->lpszProxyUsername = NULL;
497     lpwai->lpszProxyPassword = NULL;
498
499     handle = WININET_AllocHandle( &lpwai->hdr );
500     if( !handle )
501     {
502         HeapFree( GetProcessHeap(), 0, lpwai );
503         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
504         goto lend;
505     }
506
507     if (NULL != lpszAgent)
508     {
509         lpwai->lpszAgent = HeapAlloc( GetProcessHeap(),0,
510                                       (strlenW(lpszAgent)+1)*sizeof(WCHAR));
511         if (lpwai->lpszAgent)
512             lstrcpyW( lpwai->lpszAgent, lpszAgent );
513     }
514     if(dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG)
515         INTERNET_ConfigureProxyFromReg( lpwai );
516     else if (NULL != lpszProxy)
517     {
518         lpwai->lpszProxy = HeapAlloc( GetProcessHeap(), 0,
519                                       (strlenW(lpszProxy)+1)*sizeof(WCHAR));
520         if (lpwai->lpszProxy)
521             lstrcpyW( lpwai->lpszProxy, lpszProxy );
522     }
523
524     if (NULL != lpszProxyBypass)
525     {
526         lpwai->lpszProxyBypass = HeapAlloc( GetProcessHeap(), 0,
527                                      (strlenW(lpszProxyBypass)+1)*sizeof(WCHAR));
528         if (lpwai->lpszProxyBypass)
529             lstrcpyW( lpwai->lpszProxyBypass, lpszProxyBypass );
530     }
531
532 lend:
533     if( lpwai )
534         WININET_Release( &lpwai->hdr );
535
536     TRACE("returning %p\n", lpwai);
537
538     return handle;
539 }
540
541
542 /***********************************************************************
543  *           InternetOpenA   (WININET.@)
544  *
545  * Per-application initialization of wininet
546  *
547  * RETURNS
548  *    HINTERNET on success
549  *    NULL on failure
550  *
551  */
552 HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType,
553     LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags)
554 {
555     HINTERNET rc = (HINTERNET)NULL;
556     INT len;
557     WCHAR *szAgent = NULL, *szProxy = NULL, *szBypass = NULL;
558
559     TRACE("(%s, 0x%08lx, %s, %s, 0x%08lx)\n", debugstr_a(lpszAgent),
560        dwAccessType, debugstr_a(lpszProxy), debugstr_a(lpszProxyBypass), dwFlags);
561
562     if( lpszAgent )
563     {
564         len = MultiByteToWideChar(CP_ACP, 0, lpszAgent, -1, NULL, 0);
565         szAgent = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
566         MultiByteToWideChar(CP_ACP, 0, lpszAgent, -1, szAgent, len);
567     }
568
569     if( lpszProxy )
570     {
571         len = MultiByteToWideChar(CP_ACP, 0, lpszProxy, -1, NULL, 0);
572         szProxy = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
573         MultiByteToWideChar(CP_ACP, 0, lpszProxy, -1, szProxy, len);
574     }
575
576     if( lpszProxyBypass )
577     {
578         len = MultiByteToWideChar(CP_ACP, 0, lpszProxyBypass, -1, NULL, 0);
579         szBypass = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
580         MultiByteToWideChar(CP_ACP, 0, lpszProxyBypass, -1, szBypass, len);
581     }
582
583     rc = InternetOpenW(szAgent, dwAccessType, szProxy, szBypass, dwFlags);
584
585     if( szAgent )
586         HeapFree(GetProcessHeap(), 0, szAgent);
587     if( szProxy )
588         HeapFree(GetProcessHeap(), 0, szProxy);
589     if( szBypass )
590         HeapFree(GetProcessHeap(), 0, szBypass);
591
592     return rc;
593 }
594
595 /***********************************************************************
596  *           InternetGetLastResponseInfoA (WININET.@)
597  *
598  * Return last wininet error description on the calling thread
599  *
600  * RETURNS
601  *    TRUE on success of writing to buffer
602  *    FALSE on failure
603  *
604  */
605 BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError,
606     LPSTR lpszBuffer, LPDWORD lpdwBufferLength)
607 {
608     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
609
610     TRACE("\n");
611
612     *lpdwError = lpwite->dwError;
613     if (lpwite->dwError)
614     {
615         strncpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
616         *lpdwBufferLength = strlen(lpszBuffer);
617     }
618     else
619         *lpdwBufferLength = 0;
620
621     return TRUE;
622 }
623
624
625 /***********************************************************************
626  *           InternetGetConnectedState (WININET.@)
627  *
628  * Return connected state
629  *
630  * RETURNS
631  *    TRUE if connected
632  *    if lpdwStatus is not null, return the status (off line,
633  *    modem, lan...) in it.
634  *    FALSE if not connected
635  */
636 BOOL WINAPI InternetGetConnectedState(LPDWORD lpdwStatus, DWORD dwReserved)
637 {
638     TRACE("(%p, 0x%08lx)\n", lpdwStatus, dwReserved);
639
640     if (lpdwStatus) {
641         FIXME("always returning LAN connection.\n");
642         *lpdwStatus = INTERNET_CONNECTION_LAN;
643     }
644     return TRUE;
645 }
646
647
648 /***********************************************************************
649  *           InternetGetConnectedStateExW (WININET.@)
650  *
651  * Return connected state
652  *
653  * RETURNS
654  *    TRUE if connected
655  *    if lpdwStatus is not null, return the status (off line,
656  *    modem, lan...) in it.
657  *    FALSE if not connected
658  */
659 BOOL WINAPI InternetGetConnectedStateExW(LPDWORD lpdwStatus, LPWSTR lpszConnectionName,
660                                          DWORD dwNameLen, DWORD dwReserved)
661 {
662     TRACE("(%p, %s, %ld, 0x%08lx)\n", lpdwStatus, debugstr_w(lpszConnectionName), dwNameLen, dwReserved);
663
664     /* Must be zero */
665     if(dwReserved)
666         return FALSE;
667
668     if (lpdwStatus) {
669         FIXME("always returning LAN connection.\n");
670         *lpdwStatus = INTERNET_CONNECTION_LAN;
671     }
672     return TRUE;
673 }
674
675
676 /***********************************************************************
677  *           InternetGetConnectedStateExA (WININET.@)
678  */
679 BOOL WINAPI InternetGetConnectedStateExA(LPDWORD lpdwStatus, LPSTR lpszConnectionName,
680                                          DWORD dwNameLen, DWORD dwReserved)
681 {
682     LPWSTR lpwszConnectionName = NULL;
683     BOOL rc;
684
685     TRACE("(%p, %s, %ld, 0x%08lx)\n", lpdwStatus, debugstr_a(lpszConnectionName), dwNameLen, dwReserved);
686
687     if (lpszConnectionName && dwNameLen > 0)
688         lpwszConnectionName= HeapAlloc(GetProcessHeap(), 0, dwNameLen * sizeof(WCHAR));
689
690     rc = InternetGetConnectedStateExW(lpdwStatus,lpwszConnectionName, dwNameLen,
691                                       dwReserved);
692     if (rc && lpwszConnectionName)
693     {
694         WideCharToMultiByte(CP_ACP,0,lpwszConnectionName,-1,lpszConnectionName,
695                             dwNameLen, NULL, NULL);
696
697         HeapFree(GetProcessHeap(),0,lpwszConnectionName);
698     }
699
700     return rc;
701 }
702
703
704 /***********************************************************************
705  *           InternetConnectW (WININET.@)
706  *
707  * Open a ftp, gopher or http session
708  *
709  * RETURNS
710  *    HINTERNET a session handle on success
711  *    NULL on failure
712  *
713  */
714 HINTERNET WINAPI InternetConnectW(HINTERNET hInternet,
715     LPCWSTR lpszServerName, INTERNET_PORT nServerPort,
716     LPCWSTR lpszUserName, LPCWSTR lpszPassword,
717     DWORD dwService, DWORD dwFlags, DWORD dwContext)
718 {
719     LPWININETAPPINFOW hIC;
720     HINTERNET rc = (HINTERNET) NULL;
721
722     TRACE("(%p, %s, %i, %s, %s, %li, %li, %li)\n", hInternet, debugstr_w(lpszServerName),
723           nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword),
724           dwService, dwFlags, dwContext);
725
726     /* Clear any error information */
727     INTERNET_SetLastError(0);
728     hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
729     if ( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) )
730         goto lend;
731
732     switch (dwService)
733     {
734         case INTERNET_SERVICE_FTP:
735             rc = FTP_Connect(hIC, lpszServerName, nServerPort,
736             lpszUserName, lpszPassword, dwFlags, dwContext, 0);
737             break;
738
739         case INTERNET_SERVICE_HTTP:
740             rc = HTTP_Connect(hIC, lpszServerName, nServerPort,
741             lpszUserName, lpszPassword, dwFlags, dwContext, 0);
742             break;
743
744         case INTERNET_SERVICE_GOPHER:
745         default:
746             break;
747     }
748 lend:
749     if( hIC )
750         WININET_Release( &hIC->hdr );
751
752     TRACE("returning %p\n", rc);
753     return rc;
754 }
755
756
757 /***********************************************************************
758  *           InternetConnectA (WININET.@)
759  *
760  * Open a ftp, gopher or http session
761  *
762  * RETURNS
763  *    HINTERNET a session handle on success
764  *    NULL on failure
765  *
766  */
767 HINTERNET WINAPI InternetConnectA(HINTERNET hInternet,
768     LPCSTR lpszServerName, INTERNET_PORT nServerPort,
769     LPCSTR lpszUserName, LPCSTR lpszPassword,
770     DWORD dwService, DWORD dwFlags, DWORD dwContext)
771 {
772     HINTERNET rc = (HINTERNET)NULL;
773     INT len = 0;
774     LPWSTR szServerName = NULL;
775     LPWSTR szUserName = NULL;
776     LPWSTR szPassword = NULL;
777
778     if (lpszServerName)
779     {
780         len = MultiByteToWideChar(CP_ACP, 0, lpszServerName, -1, NULL, 0);
781         szServerName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
782         MultiByteToWideChar(CP_ACP, 0, lpszServerName, -1, szServerName, len);
783     }
784     if (lpszUserName)
785     {
786         len = MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, NULL, 0);
787         szUserName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
788         MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, szUserName, len);
789     }
790     if (lpszPassword)
791     {
792         len = MultiByteToWideChar(CP_ACP, 0, lpszPassword, -1, NULL, 0);
793         szPassword = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
794         MultiByteToWideChar(CP_ACP, 0, lpszPassword, -1, szPassword, len);
795     }
796
797
798     rc = InternetConnectW(hInternet, szServerName, nServerPort,
799         szUserName, szPassword, dwService, dwFlags, dwContext);
800
801     if (szServerName) HeapFree(GetProcessHeap(), 0, szServerName);
802     if (szUserName) HeapFree(GetProcessHeap(), 0, szUserName);
803     if (szPassword) HeapFree(GetProcessHeap(), 0, szPassword);
804     return rc;
805 }
806
807
808 /***********************************************************************
809  *           InternetFindNextFileA (WININET.@)
810  *
811  * Continues a file search from a previous call to FindFirstFile
812  *
813  * RETURNS
814  *    TRUE on success
815  *    FALSE on failure
816  *
817  */
818 BOOL WINAPI InternetFindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
819 {
820     BOOL ret;
821     WIN32_FIND_DATAW fd;
822     
823     ret = InternetFindNextFileW(hFind, lpvFindData?&fd:NULL);
824     if(lpvFindData)
825         WININET_find_data_WtoA(&fd, (LPWIN32_FIND_DATAA)lpvFindData);
826     return ret;
827 }
828
829 /***********************************************************************
830  *           InternetFindNextFileW (WININET.@)
831  *
832  * Continues a file search from a previous call to FindFirstFile
833  *
834  * RETURNS
835  *    TRUE on success
836  *    FALSE on failure
837  *
838  */
839 BOOL WINAPI InternetFindNextFileW(HINTERNET hFind, LPVOID lpvFindData)
840 {
841     LPWININETAPPINFOW hIC = NULL;
842     LPWININETFINDNEXTW lpwh;
843     BOOL bSuccess = FALSE;
844
845     TRACE("\n");
846
847     lpwh = (LPWININETFINDNEXTW) WININET_GetObject( hFind );
848     if (NULL == lpwh || lpwh->hdr.htype != WH_HFINDNEXT)
849     {
850         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
851         goto lend;
852     }
853
854     hIC = GET_HWININET_FROM_LPWININETFINDNEXT(lpwh);
855     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
856     {
857         WORKREQUEST workRequest;
858         struct WORKREQ_INTERNETFINDNEXTW *req;
859
860         workRequest.asyncall = INTERNETFINDNEXTW;
861         workRequest.hdr = WININET_AddRef( &lpwh->hdr );
862         req = &workRequest.u.InternetFindNextW;
863         req->lpFindFileData = lpvFindData;
864
865         bSuccess = INTERNET_AsyncCall(&workRequest);
866     }
867     else
868     {
869         bSuccess = INTERNET_FindNextFileW(lpwh, lpvFindData);
870     }
871 lend:
872     if( lpwh )
873         WININET_Release( &lpwh->hdr );
874     return bSuccess;
875 }
876
877 /***********************************************************************
878  *           INTERNET_FindNextFileW (Internal)
879  *
880  * Continues a file search from a previous call to FindFirstFile
881  *
882  * RETURNS
883  *    TRUE on success
884  *    FALSE on failure
885  *
886  */
887 BOOL WINAPI INTERNET_FindNextFileW(LPWININETFINDNEXTW lpwh, LPVOID lpvFindData)
888 {
889     BOOL bSuccess = TRUE;
890     LPWIN32_FIND_DATAW lpFindFileData;
891
892     TRACE("\n");
893
894     assert (lpwh->hdr.htype == WH_HFINDNEXT);
895
896     /* Clear any error information */
897     INTERNET_SetLastError(0);
898
899     if (lpwh->hdr.lpwhparent->htype != WH_HFTPSESSION)
900     {
901         FIXME("Only FTP find next supported\n");
902         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
903         return FALSE;
904     }
905
906     TRACE("index(%ld) size(%ld)\n", lpwh->index, lpwh->size);
907
908     lpFindFileData = (LPWIN32_FIND_DATAW) lpvFindData;
909     ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
910
911     if (lpwh->index >= lpwh->size)
912     {
913         INTERNET_SetLastError(ERROR_NO_MORE_FILES);
914         bSuccess = FALSE;
915         goto lend;
916     }
917
918     FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
919     lpwh->index++;
920
921     TRACE("\nName: %s\nSize: %ld\n", debugstr_w(lpFindFileData->cFileName), lpFindFileData->nFileSizeLow);
922
923 lend:
924
925     if (lpwh->hdr.dwFlags & INTERNET_FLAG_ASYNC && lpwh->hdr.lpfnStatusCB)
926     {
927         INTERNET_ASYNC_RESULT iar;
928
929         iar.dwResult = (DWORD)bSuccess;
930         iar.dwError = iar.dwError = bSuccess ? ERROR_SUCCESS :
931                                                INTERNET_GetLastError();
932
933         SendAsyncCallback(&lpwh->hdr, lpwh->hdr.dwContext,
934                       INTERNET_STATUS_REQUEST_COMPLETE, &iar,
935                        sizeof(INTERNET_ASYNC_RESULT));
936     }
937
938     return bSuccess;
939 }
940
941
942 /***********************************************************************
943  *           INTERNET_CloseHandle (internal)
944  *
945  * Close internet handle
946  *
947  * RETURNS
948  *    Void
949  *
950  */
951 static VOID INTERNET_CloseHandle(LPWININETHANDLEHEADER hdr)
952 {
953     LPWININETAPPINFOW lpwai = (LPWININETAPPINFOW) hdr;
954
955     TRACE("%p\n",lpwai);
956
957     if (lpwai->lpszAgent)
958         HeapFree(GetProcessHeap(), 0, lpwai->lpszAgent);
959
960     if (lpwai->lpszProxy)
961         HeapFree(GetProcessHeap(), 0, lpwai->lpszProxy);
962
963     if (lpwai->lpszProxyBypass)
964         HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyBypass);
965
966     if (lpwai->lpszProxyUsername)
967         HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyUsername);
968
969     if (lpwai->lpszProxyPassword)
970         HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyPassword);
971
972     HeapFree(GetProcessHeap(), 0, lpwai);
973 }
974
975
976 /***********************************************************************
977  *           InternetCloseHandle (WININET.@)
978  *
979  * Generic close handle function
980  *
981  * RETURNS
982  *    TRUE on success
983  *    FALSE on failure
984  *
985  */
986 BOOL WINAPI InternetCloseHandle(HINTERNET hInternet)
987 {
988     LPWININETHANDLEHEADER lpwh;
989     
990     TRACE("%p\n",hInternet);
991
992     lpwh = WININET_GetObject( hInternet );
993     if (NULL == lpwh)
994     {
995         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
996         return FALSE;
997     }
998
999     SendAsyncCallback(lpwh, lpwh->dwContext,
1000                       INTERNET_STATUS_HANDLE_CLOSING, hInternet,
1001                       sizeof(HINTERNET));
1002
1003     if( lpwh->lpwhparent )
1004         WININET_Release( lpwh->lpwhparent );
1005     WININET_FreeHandle( hInternet );
1006     WININET_Release( lpwh );
1007
1008     return TRUE;
1009 }
1010
1011
1012 /***********************************************************************
1013  *           ConvertUrlComponentValue (Internal)
1014  *
1015  * Helper function for InternetCrackUrlW
1016  *
1017  */
1018 void ConvertUrlComponentValue(LPSTR* lppszComponent, LPDWORD dwComponentLen,
1019                               LPWSTR lpwszComponent, DWORD dwwComponentLen,
1020                               LPCSTR lpszStart,
1021                               LPCWSTR lpwszStart)
1022 {
1023     if (*dwComponentLen != 0)
1024     {
1025         DWORD nASCIILength=WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,NULL,0,NULL,NULL);
1026         if (*lppszComponent == NULL)
1027         {
1028             int nASCIIOffset=WideCharToMultiByte(CP_ACP,0,lpwszStart,lpwszComponent-lpwszStart,NULL,0,NULL,NULL);
1029             *lppszComponent = (LPSTR)lpszStart+nASCIIOffset;
1030             *dwComponentLen = nASCIILength;
1031         }
1032         else
1033         {
1034             DWORD ncpylen = min((*dwComponentLen)-1, nASCIILength);
1035             WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,*lppszComponent,ncpylen+1,NULL,NULL);
1036             (*lppszComponent)[ncpylen]=0;
1037             *dwComponentLen = ncpylen;
1038         }
1039     }
1040 }
1041
1042
1043 /***********************************************************************
1044  *           InternetCrackUrlA (WININET.@)
1045  *
1046  * Break up URL into its components
1047  *
1048  * TODO: Handle dwFlags
1049  *
1050  * RETURNS
1051  *    TRUE on success
1052  *    FALSE on failure
1053  *
1054  */
1055 BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
1056     LPURL_COMPONENTSA lpUrlComponents)
1057 {
1058   DWORD nLength;
1059   URL_COMPONENTSW UCW;
1060   WCHAR* lpwszUrl;
1061
1062   if(dwUrlLength<=0)
1063       dwUrlLength=-1;
1064   nLength=MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,NULL,0);
1065   lpwszUrl=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR)*nLength);
1066   MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,lpwszUrl,nLength);
1067
1068   memset(&UCW,0,sizeof(UCW));
1069   if(lpUrlComponents->dwHostNameLength!=0)
1070       UCW.dwHostNameLength=1;
1071   if(lpUrlComponents->dwUserNameLength!=0)
1072       UCW.dwUserNameLength=1;
1073   if(lpUrlComponents->dwPasswordLength!=0)
1074       UCW.dwPasswordLength=1;
1075   if(lpUrlComponents->dwUrlPathLength!=0)
1076       UCW.dwUrlPathLength=1;
1077   if(lpUrlComponents->dwSchemeLength!=0)
1078       UCW.dwSchemeLength=1;
1079   if(lpUrlComponents->dwExtraInfoLength!=0)
1080       UCW.dwExtraInfoLength=1;
1081   if(!InternetCrackUrlW(lpwszUrl,nLength,dwFlags,&UCW))
1082   {
1083       HeapFree(GetProcessHeap(), 0, lpwszUrl);
1084       return FALSE;
1085   }
1086   ConvertUrlComponentValue(&lpUrlComponents->lpszHostName, &lpUrlComponents->dwHostNameLength,
1087                            UCW.lpszHostName, UCW.dwHostNameLength,
1088                            lpszUrl, lpwszUrl);
1089   ConvertUrlComponentValue(&lpUrlComponents->lpszUserName, &lpUrlComponents->dwUserNameLength,
1090                            UCW.lpszUserName, UCW.dwUserNameLength,
1091                            lpszUrl, lpwszUrl);
1092   ConvertUrlComponentValue(&lpUrlComponents->lpszPassword, &lpUrlComponents->dwPasswordLength,
1093                            UCW.lpszPassword, UCW.dwPasswordLength,
1094                            lpszUrl, lpwszUrl);
1095   ConvertUrlComponentValue(&lpUrlComponents->lpszUrlPath, &lpUrlComponents->dwUrlPathLength,
1096                            UCW.lpszUrlPath, UCW.dwUrlPathLength,
1097                            lpszUrl, lpwszUrl);
1098   ConvertUrlComponentValue(&lpUrlComponents->lpszScheme, &lpUrlComponents->dwSchemeLength,
1099                            UCW.lpszScheme, UCW.dwSchemeLength,
1100                            lpszUrl, lpwszUrl);
1101   ConvertUrlComponentValue(&lpUrlComponents->lpszExtraInfo, &lpUrlComponents->dwExtraInfoLength,
1102                            UCW.lpszExtraInfo, UCW.dwExtraInfoLength,
1103                            lpszUrl, lpwszUrl);
1104   lpUrlComponents->nScheme=UCW.nScheme;
1105   lpUrlComponents->nPort=UCW.nPort;
1106   HeapFree(GetProcessHeap(), 0, lpwszUrl);
1107   
1108   TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", lpszUrl,
1109           debugstr_an(lpUrlComponents->lpszScheme,lpUrlComponents->dwSchemeLength),
1110           debugstr_an(lpUrlComponents->lpszHostName,lpUrlComponents->dwHostNameLength),
1111           debugstr_an(lpUrlComponents->lpszUrlPath,lpUrlComponents->dwUrlPathLength),
1112           debugstr_an(lpUrlComponents->lpszExtraInfo,lpUrlComponents->dwExtraInfoLength));
1113
1114   return TRUE;
1115 }
1116
1117 /***********************************************************************
1118  *           GetInternetSchemeW (internal)
1119  *
1120  * Get scheme of url
1121  *
1122  * RETURNS
1123  *    scheme on success
1124  *    INTERNET_SCHEME_UNKNOWN on failure
1125  *
1126  */
1127 static INTERNET_SCHEME GetInternetSchemeW(LPCWSTR lpszScheme, DWORD nMaxCmp)
1128 {
1129     INTERNET_SCHEME iScheme=INTERNET_SCHEME_UNKNOWN;
1130     static const WCHAR lpszFtp[]={'f','t','p',0};
1131     static const WCHAR lpszGopher[]={'g','o','p','h','e','r',0};
1132     static const WCHAR lpszHttp[]={'h','t','t','p',0};
1133     static const WCHAR lpszHttps[]={'h','t','t','p','s',0};
1134     static const WCHAR lpszFile[]={'f','i','l','e',0};
1135     static const WCHAR lpszNews[]={'n','e','w','s',0};
1136     static const WCHAR lpszMailto[]={'m','a','i','l','t','o',0};
1137     static const WCHAR lpszRes[]={'r','e','s',0};
1138     WCHAR* tempBuffer=NULL;
1139     TRACE("\n");
1140     if(lpszScheme==NULL)
1141         return INTERNET_SCHEME_UNKNOWN;
1142
1143     tempBuffer=HeapAlloc(GetProcessHeap(),0,(nMaxCmp+1)*sizeof(WCHAR));
1144     strncpyW(tempBuffer,lpszScheme,nMaxCmp);
1145     tempBuffer[nMaxCmp]=0;
1146     strlwrW(tempBuffer);
1147     if (nMaxCmp==strlenW(lpszFtp) && !strncmpW(lpszFtp, tempBuffer, nMaxCmp))
1148         iScheme=INTERNET_SCHEME_FTP;
1149     else if (nMaxCmp==strlenW(lpszGopher) && !strncmpW(lpszGopher, tempBuffer, nMaxCmp))
1150         iScheme=INTERNET_SCHEME_GOPHER;
1151     else if (nMaxCmp==strlenW(lpszHttp) && !strncmpW(lpszHttp, tempBuffer, nMaxCmp))
1152         iScheme=INTERNET_SCHEME_HTTP;
1153     else if (nMaxCmp==strlenW(lpszHttps) && !strncmpW(lpszHttps, tempBuffer, nMaxCmp))
1154         iScheme=INTERNET_SCHEME_HTTPS;
1155     else if (nMaxCmp==strlenW(lpszFile) && !strncmpW(lpszFile, tempBuffer, nMaxCmp))
1156         iScheme=INTERNET_SCHEME_FILE;
1157     else if (nMaxCmp==strlenW(lpszNews) && !strncmpW(lpszNews, tempBuffer, nMaxCmp))
1158         iScheme=INTERNET_SCHEME_NEWS;
1159     else if (nMaxCmp==strlenW(lpszMailto) && !strncmpW(lpszMailto, tempBuffer, nMaxCmp))
1160         iScheme=INTERNET_SCHEME_MAILTO;
1161     else if (nMaxCmp==strlenW(lpszRes) && !strncmpW(lpszRes, tempBuffer, nMaxCmp))
1162         iScheme=INTERNET_SCHEME_RES;
1163     HeapFree(GetProcessHeap(),0,tempBuffer);
1164     return iScheme;
1165 }
1166
1167 /***********************************************************************
1168  *           SetUrlComponentValueW (Internal)
1169  *
1170  * Helper function for InternetCrackUrlW
1171  *
1172  * RETURNS
1173  *    TRUE on success
1174  *    FALSE on failure
1175  *
1176  */
1177 static BOOL SetUrlComponentValueW(LPWSTR* lppszComponent, LPDWORD dwComponentLen, LPCWSTR lpszStart, DWORD len)
1178 {
1179     TRACE("%s (%ld)\n", debugstr_wn(lpszStart,len), len);
1180
1181     if ( (*dwComponentLen == 0) && (*lppszComponent == NULL) )
1182         return FALSE;
1183
1184     if (*dwComponentLen != 0 || *lppszComponent == NULL)
1185     {
1186         if (*lppszComponent == NULL)
1187         {
1188             *lppszComponent = (LPWSTR)lpszStart;
1189             *dwComponentLen = len;
1190         }
1191         else
1192         {
1193             DWORD ncpylen = min((*dwComponentLen)-1, len);
1194             strncpyW(*lppszComponent, lpszStart, ncpylen);
1195             (*lppszComponent)[ncpylen] = '\0';
1196             *dwComponentLen = ncpylen;
1197         }
1198     }
1199
1200     return TRUE;
1201 }
1202
1203 /***********************************************************************
1204  *           InternetCrackUrlW   (WININET.@)
1205  */
1206 BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
1207                               LPURL_COMPONENTSW lpUC)
1208 {
1209   /*
1210    * RFC 1808
1211    * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1212    *
1213    */
1214     LPCWSTR lpszParam    = NULL;
1215     BOOL  bIsAbsolute = FALSE;
1216     LPCWSTR lpszap = lpszUrl;
1217     LPCWSTR lpszcp = NULL;
1218     const WCHAR lpszSeparators[3]={';','?',0};
1219     const WCHAR lpszSlash[2]={'/',0};
1220     if(dwUrlLength==0)
1221         dwUrlLength=strlenW(lpszUrl);
1222
1223     TRACE("\n");
1224
1225     /* Determine if the URI is absolute. */
1226     while (*lpszap != '\0')
1227     {
1228         if (isalnumW(*lpszap))
1229         {
1230             lpszap++;
1231             continue;
1232         }
1233         if ((*lpszap == ':') && (lpszap - lpszUrl >= 2))
1234         {
1235             bIsAbsolute = TRUE;
1236             lpszcp = lpszap;
1237         }
1238         else
1239         {
1240             lpszcp = lpszUrl; /* Relative url */
1241         }
1242
1243         break;
1244     }
1245
1246     /* Parse <params> */
1247     lpszParam = strpbrkW(lpszap, lpszSeparators);
1248     if (lpszParam != NULL)
1249     {
1250         SetUrlComponentValueW(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength,
1251                                    lpszParam, dwUrlLength-(lpszParam-lpszUrl));
1252     }
1253
1254     if (bIsAbsolute) /* Parse <protocol>:[//<net_loc>] */
1255     {
1256         LPCWSTR lpszNetLoc;
1257         static const WCHAR wszAbout[]={'a','b','o','u','t',':',0};
1258
1259         /* Get scheme first. */
1260         lpUC->nScheme = GetInternetSchemeW(lpszUrl, lpszcp - lpszUrl);
1261         SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength,
1262                                    lpszUrl, lpszcp - lpszUrl);
1263
1264         /* Eat ':' in protocol. */
1265         lpszcp++;
1266
1267         /* if the scheme is "about", there is no host */
1268         if(strncmpW(wszAbout,lpszUrl, lpszcp - lpszUrl)==0)
1269         {
1270             SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1271             SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1272             SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
1273             lpUC->nPort = 0;
1274         }
1275         else
1276         {
1277             /* Skip over slashes. */
1278             if (*lpszcp == '/')
1279             {
1280                 lpszcp++;
1281                 if (*lpszcp == '/')
1282                 {
1283                     lpszcp++;
1284                     if (*lpszcp == '/')
1285                         lpszcp++;
1286                 }
1287             }
1288
1289             lpszNetLoc = strpbrkW(lpszcp, lpszSlash);
1290             if (lpszParam)
1291             {
1292                 if (lpszNetLoc)
1293                     lpszNetLoc = min(lpszNetLoc, lpszParam);
1294                 else
1295                     lpszNetLoc = lpszParam;
1296             }
1297             else if (!lpszNetLoc)
1298                 lpszNetLoc = lpszcp + dwUrlLength-(lpszcp-lpszUrl);
1299
1300             /* Parse net-loc */
1301             if (lpszNetLoc)
1302             {
1303                 LPCWSTR lpszHost;
1304                 LPCWSTR lpszPort;
1305
1306                 /* [<user>[<:password>]@]<host>[:<port>] */
1307                 /* First find the user and password if they exist */
1308
1309                 lpszHost = strchrW(lpszcp, '@');
1310                 if (lpszHost == NULL || lpszHost > lpszNetLoc)
1311                 {
1312                     /* username and password not specified. */
1313                     SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1314                     SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1315                 }
1316                 else /* Parse out username and password */
1317                 {
1318                     LPCWSTR lpszUser = lpszcp;
1319                     LPCWSTR lpszPasswd = lpszHost;
1320
1321                     while (lpszcp < lpszHost)
1322                     {
1323                         if (*lpszcp == ':')
1324                             lpszPasswd = lpszcp;
1325
1326                         lpszcp++;
1327                     }
1328
1329                     SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength,
1330                                           lpszUser, lpszPasswd - lpszUser);
1331
1332                     if (lpszPasswd != lpszHost)
1333                         lpszPasswd++;
1334                     SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength,
1335                                           lpszPasswd == lpszHost ? NULL : lpszPasswd,
1336                                           lpszHost - lpszPasswd);
1337
1338                     lpszcp++; /* Advance to beginning of host */
1339                 }
1340
1341                 /* Parse <host><:port> */
1342
1343                 lpszHost = lpszcp;
1344                 lpszPort = lpszNetLoc;
1345
1346                 /* special case for res:// URLs: there is no port here, so the host is the
1347                    entire string up to the first '/' */
1348                 if(lpUC->nScheme==INTERNET_SCHEME_RES)
1349                 {
1350                     SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1351                                           lpszHost, lpszPort - lpszHost);
1352                     lpUC->nPort = 0;
1353                     lpszcp=lpszNetLoc;
1354                 }
1355                 else
1356                 {
1357                     while (lpszcp < lpszNetLoc)
1358                     {
1359                         if (*lpszcp == ':')
1360                             lpszPort = lpszcp;
1361
1362                         lpszcp++;
1363                     }
1364
1365                     /* If the scheme is "file" and the host is just one letter, it's not a host */
1366                     if(lpUC->nScheme==INTERNET_SCHEME_FILE && (lpszPort-lpszHost)==1)
1367                     {
1368                         lpszcp=lpszHost;
1369                         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1370                                               NULL, 0);
1371                         lpUC->nPort = 0;
1372                     }
1373                     else
1374                     {
1375                         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1376                                               lpszHost, lpszPort - lpszHost);
1377                         if (lpszPort != lpszNetLoc)
1378                             lpUC->nPort = atoiW(++lpszPort);
1379                         else
1380                             lpUC->nPort = 0;
1381                     }
1382                 }
1383             }
1384         }
1385     }
1386
1387     /* Here lpszcp points to:
1388      *
1389      * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1390      *                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1391      */
1392     if (lpszcp != 0 && *lpszcp != '\0' && (!lpszParam || lpszcp < lpszParam))
1393     {
1394         INT len;
1395
1396         /* Only truncate the parameter list if it's already been saved
1397          * in lpUC->lpszExtraInfo.
1398          */
1399         if (lpszParam && lpUC->dwExtraInfoLength && lpUC->lpszExtraInfo)
1400             len = lpszParam - lpszcp;
1401         else
1402         {
1403             /* Leave the parameter list in lpszUrlPath.  Strip off any trailing
1404              * newlines if necessary.
1405              */
1406             LPWSTR lpsznewline = strchrW(lpszcp, '\n');
1407             if (lpsznewline != NULL)
1408                 len = lpsznewline - lpszcp;
1409             else
1410                 len = dwUrlLength-(lpszcp-lpszUrl);
1411         }
1412
1413         SetUrlComponentValueW(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength,
1414                                    lpszcp, len);
1415     }
1416     else
1417     {
1418         lpUC->dwUrlPathLength = 0;
1419     }
1420
1421     TRACE("%s: host(%s) path(%s) extra(%s)\n", debugstr_wn(lpszUrl,dwUrlLength),
1422              debugstr_wn(lpUC->lpszHostName,lpUC->dwHostNameLength),
1423              debugstr_wn(lpUC->lpszUrlPath,lpUC->dwUrlPathLength),
1424              debugstr_wn(lpUC->lpszExtraInfo,lpUC->dwExtraInfoLength));
1425
1426     return TRUE;
1427 }
1428
1429 /***********************************************************************
1430  *           InternetAttemptConnect (WININET.@)
1431  *
1432  * Attempt to make a connection to the internet
1433  *
1434  * RETURNS
1435  *    ERROR_SUCCESS on success
1436  *    Error value   on failure
1437  *
1438  */
1439 DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
1440 {
1441     FIXME("Stub\n");
1442     return ERROR_SUCCESS;
1443 }
1444
1445
1446 /***********************************************************************
1447  *           InternetCanonicalizeUrlA (WININET.@)
1448  *
1449  * Escape unsafe characters and spaces
1450  *
1451  * RETURNS
1452  *    TRUE on success
1453  *    FALSE on failure
1454  *
1455  */
1456 BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
1457         LPDWORD lpdwBufferLength, DWORD dwFlags)
1458 {
1459     HRESULT hr;
1460     TRACE("%s %p %p %08lx\n",debugstr_a(lpszUrl), lpszBuffer,
1461           lpdwBufferLength, dwFlags);
1462
1463     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1464     dwFlags ^= ICU_NO_ENCODE;
1465
1466     dwFlags |= 0x80000000; /* Don't know what this means */
1467
1468     hr = UrlCanonicalizeA(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
1469
1470     return (hr == S_OK) ? TRUE : FALSE;
1471 }
1472
1473 /***********************************************************************
1474  *           InternetCanonicalizeUrlW (WININET.@)
1475  *
1476  * Escape unsafe characters and spaces
1477  *
1478  * RETURNS
1479  *    TRUE on success
1480  *    FALSE on failure
1481  *
1482  */
1483 BOOL WINAPI InternetCanonicalizeUrlW(LPCWSTR lpszUrl, LPWSTR lpszBuffer,
1484     LPDWORD lpdwBufferLength, DWORD dwFlags)
1485 {
1486     HRESULT hr;
1487     TRACE("%s %p %p %08lx\n", debugstr_w(lpszUrl), lpszBuffer,
1488         lpdwBufferLength, dwFlags);
1489
1490     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1491     dwFlags ^= ICU_NO_ENCODE;
1492
1493     dwFlags |= 0x80000000; /* Don't know what this means */
1494
1495     hr = UrlCanonicalizeW(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
1496
1497     return (hr == S_OK) ? TRUE : FALSE;
1498 }
1499
1500
1501 /***********************************************************************
1502  *           InternetSetStatusCallbackA (WININET.@)
1503  *
1504  * Sets up a callback function which is called as progress is made
1505  * during an operation.
1506  *
1507  * RETURNS
1508  *    Previous callback or NULL         on success
1509  *    INTERNET_INVALID_STATUS_CALLBACK  on failure
1510  *
1511  */
1512 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackA(
1513         HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
1514 {
1515     INTERNET_STATUS_CALLBACK retVal;
1516     LPWININETHANDLEHEADER lpwh;
1517
1518     TRACE("0x%08lx\n", (ULONG)hInternet);
1519     
1520     lpwh = WININET_GetObject(hInternet);
1521     if (!lpwh)
1522         return INTERNET_INVALID_STATUS_CALLBACK;
1523
1524     lpwh->dwInternalFlags &= ~INET_CALLBACKW;
1525     retVal = lpwh->lpfnStatusCB;
1526     lpwh->lpfnStatusCB = lpfnIntCB;
1527
1528     WININET_Release( lpwh );
1529
1530     return retVal;
1531 }
1532
1533 /***********************************************************************
1534  *           InternetSetStatusCallbackW (WININET.@)
1535  *
1536  * Sets up a callback function which is called as progress is made
1537  * during an operation.
1538  *
1539  * RETURNS
1540  *    Previous callback or NULL         on success
1541  *    INTERNET_INVALID_STATUS_CALLBACK  on failure
1542  *
1543  */
1544 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackW(
1545         HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
1546 {
1547     INTERNET_STATUS_CALLBACK retVal;
1548     LPWININETHANDLEHEADER lpwh;
1549
1550     TRACE("0x%08lx\n", (ULONG)hInternet);
1551     
1552     lpwh = WININET_GetObject(hInternet);
1553     if (!lpwh)
1554         return INTERNET_INVALID_STATUS_CALLBACK;
1555
1556     lpwh->dwInternalFlags |= INET_CALLBACKW;
1557     retVal = lpwh->lpfnStatusCB;
1558     lpwh->lpfnStatusCB = lpfnIntCB;
1559
1560     WININET_Release( lpwh );
1561
1562     return retVal;
1563 }
1564
1565 /***********************************************************************
1566  *           InternetSetFilePointer (WININET.@)
1567  */
1568 DWORD WINAPI InternetSetFilePointer(HINTERNET f1, LONG f2, PVOID f3, DWORD f4, DWORD f5)
1569 {
1570     FIXME("stub\n");
1571     return FALSE;
1572 }
1573
1574 /***********************************************************************
1575  *           InternetWriteFile (WININET.@)
1576  *
1577  * Write data to an open internet file
1578  *
1579  * RETURNS
1580  *    TRUE  on success
1581  *    FALSE on failure
1582  *
1583  */
1584 BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer ,
1585         DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
1586 {
1587     BOOL retval = FALSE;
1588     int nSocket = -1;
1589     LPWININETHANDLEHEADER lpwh;
1590
1591     TRACE("\n");
1592     lpwh = (LPWININETHANDLEHEADER) WININET_GetObject( hFile );
1593     if (NULL == lpwh)
1594         return FALSE;
1595
1596     switch (lpwh->htype)
1597     {
1598         case WH_HHTTPREQ:
1599             FIXME("This shouldn't be here! We don't support this kind"
1600                   " of connection anymore. Must use NETCON functions,"
1601                   " especially if using SSL\n");
1602             nSocket = ((LPWININETHTTPREQW)lpwh)->netConnection.socketFD;
1603             break;
1604
1605         case WH_HFILE:
1606             nSocket = ((LPWININETFILE)lpwh)->nDataSocket;
1607             break;
1608
1609         default:
1610             break;
1611     }
1612
1613     if (nSocket != -1)
1614     {
1615         int res = send(nSocket, lpBuffer, dwNumOfBytesToWrite, 0);
1616         retval = (res >= 0);
1617         *lpdwNumOfBytesWritten = retval ? res : 0;
1618     }
1619     WININET_Release( lpwh );
1620
1621     return retval;
1622 }
1623
1624
1625 /***********************************************************************
1626  *           InternetReadFile (WININET.@)
1627  *
1628  * Read data from an open internet file
1629  *
1630  * RETURNS
1631  *    TRUE  on success
1632  *    FALSE on failure
1633  *
1634  */
1635 BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
1636         DWORD dwNumOfBytesToRead, LPDWORD dwNumOfBytesRead)
1637 {
1638     BOOL retval = FALSE;
1639     int nSocket = -1;
1640     LPWININETHANDLEHEADER lpwh;
1641
1642     TRACE("%p %p %ld %p\n", hFile, lpBuffer, dwNumOfBytesToRead, dwNumOfBytesRead);
1643
1644     lpwh = (LPWININETHANDLEHEADER) WININET_GetObject( hFile );
1645     if (NULL == lpwh)
1646         return FALSE;
1647
1648     /* FIXME: this should use NETCON functions! */
1649     switch (lpwh->htype)
1650     {
1651         case WH_HHTTPREQ:
1652             if (!NETCON_recv(&((LPWININETHTTPREQW)lpwh)->netConnection, lpBuffer,
1653                              dwNumOfBytesToRead, MSG_WAITALL, (int *)dwNumOfBytesRead))
1654             {
1655                 *dwNumOfBytesRead = 0;
1656                 retval = TRUE; /* Under windows, it seems to return 0 even if nothing was read... */
1657             }
1658             else
1659                 retval = TRUE;
1660             break;
1661
1662         case WH_HFILE:
1663             /* FIXME: FTP should use NETCON_ stuff */
1664             nSocket = ((LPWININETFILE)lpwh)->nDataSocket;
1665             if (nSocket != -1)
1666             {
1667                 int res = recv(nSocket, lpBuffer, dwNumOfBytesToRead, MSG_WAITALL);
1668                 retval = (res >= 0);
1669                 *dwNumOfBytesRead = retval ? res : 0;
1670             }
1671             break;
1672
1673         default:
1674             break;
1675     }
1676     WININET_Release( lpwh );
1677
1678     TRACE("-- %s (bytes read: %ld)\n", retval ? "TRUE": "FALSE", dwNumOfBytesRead ? *dwNumOfBytesRead : -1);
1679     return retval;
1680 }
1681
1682 /***********************************************************************
1683  *           InternetReadFileExA (WININET.@)
1684  *
1685  * Read data from an open internet file
1686  *
1687  * RETURNS
1688  *    TRUE  on success
1689  *    FALSE on failure
1690  *
1691  */
1692 BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffer,
1693         DWORD dwFlags, DWORD dwContext)
1694 {
1695   FIXME("stub\n");
1696   return FALSE;
1697 }
1698
1699 /***********************************************************************
1700  *           InternetReadFileExW (WININET.@)
1701  *
1702  * Read data from an open internet file
1703  *
1704  * RETURNS
1705  *    TRUE  on success
1706  *    FALSE on failure
1707  *
1708  */
1709 BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer,
1710         DWORD dwFlags, DWORD dwContext)
1711 {
1712   FIXME("stub\n");
1713
1714   INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1715   return FALSE;
1716 }
1717
1718 /***********************************************************************
1719  *           INET_QueryOptionHelper (internal)
1720  */
1721 static BOOL INET_QueryOptionHelper(BOOL bIsUnicode, HINTERNET hInternet, DWORD dwOption,
1722                                    LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1723 {
1724     LPWININETHANDLEHEADER lpwhh;
1725     BOOL bSuccess = FALSE;
1726
1727     TRACE("(%p, 0x%08lx, %p, %p)\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
1728
1729     lpwhh = (LPWININETHANDLEHEADER) WININET_GetObject( hInternet );
1730
1731     switch (dwOption)
1732     {
1733         case INTERNET_OPTION_HANDLE_TYPE:
1734         {
1735             ULONG type;
1736
1737             if (!lpwhh)
1738             {
1739                 WARN("Invalid hInternet handle\n");
1740                 SetLastError(ERROR_INVALID_HANDLE);
1741                 return FALSE;
1742             }
1743
1744             type = lpwhh->htype;
1745
1746             TRACE("INTERNET_OPTION_HANDLE_TYPE: %ld\n", type);
1747
1748             if (*lpdwBufferLength < sizeof(ULONG))
1749                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1750             else
1751             {
1752                 memcpy(lpBuffer, &type, sizeof(ULONG));
1753                     *lpdwBufferLength = sizeof(ULONG);
1754                 bSuccess = TRUE;
1755             }
1756             break;
1757         }
1758
1759         case INTERNET_OPTION_REQUEST_FLAGS:
1760         {
1761             ULONG flags = 4;
1762             TRACE("INTERNET_OPTION_REQUEST_FLAGS: %ld\n", flags);
1763             if (*lpdwBufferLength < sizeof(ULONG))
1764                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1765             else
1766             {
1767                 memcpy(lpBuffer, &flags, sizeof(ULONG));
1768                     *lpdwBufferLength = sizeof(ULONG);
1769                 bSuccess = TRUE;
1770             }
1771             break;
1772         }
1773
1774         case INTERNET_OPTION_URL:
1775         case INTERNET_OPTION_DATAFILE_NAME:
1776         {
1777             if (!lpwhh)
1778             {
1779                 WARN("Invalid hInternet handle\n");
1780                 SetLastError(ERROR_INVALID_HANDLE);
1781                 return FALSE;
1782             }
1783             if (lpwhh->htype == WH_HHTTPREQ)
1784             {
1785                 LPWININETHTTPREQW lpreq = (LPWININETHTTPREQW) lpwhh;
1786                 WCHAR url[1023];
1787                 static const WCHAR szFmt[] = {'h','t','t','p',':','/','/','%','s','%','s',0};
1788
1789                 sprintfW(url,szFmt,lpreq->StdHeaders[HTTP_QUERY_HOST].lpszValue,lpreq->lpszPath);
1790                 TRACE("INTERNET_OPTION_URL: %s\n",debugstr_w(url));
1791                 if (*lpdwBufferLength < strlenW(url)+1)
1792                     INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1793                 else
1794                 {
1795                     if(!bIsUnicode)
1796                     {
1797                         *lpdwBufferLength=WideCharToMultiByte(CP_ACP,0,url,-1,lpBuffer,*lpdwBufferLength,NULL,NULL);
1798                     }
1799                     else
1800                     {
1801                         strcpyW(lpBuffer, url);
1802                         *lpdwBufferLength = strlenW(url)+1;
1803                     }
1804                     bSuccess = TRUE;
1805                 }
1806             }
1807             break;
1808         }
1809        case INTERNET_OPTION_HTTP_VERSION:
1810        {
1811             /*
1812              * Presently hardcoded to 1.1
1813              */
1814             ((HTTP_VERSION_INFO*)lpBuffer)->dwMajorVersion = 1;
1815             ((HTTP_VERSION_INFO*)lpBuffer)->dwMinorVersion = 1;
1816             bSuccess = TRUE;
1817             break;
1818        }
1819        case INTERNET_OPTION_CONNECTED_STATE:
1820        {
1821            INTERNET_CONNECTED_INFO * pCi = (INTERNET_CONNECTED_INFO *)lpBuffer;
1822            FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n");
1823            pCi->dwConnectedState = INTERNET_STATE_CONNECTED;
1824            pCi->dwFlags = 0;
1825            bSuccess = TRUE;
1826            break;
1827        }
1828        case INTERNET_OPTION_SECURITY_FLAGS:
1829          FIXME("INTERNET_OPTION_SECURITY_FLAGS: Stub\n");
1830          break;
1831
1832        default:
1833          FIXME("Stub! %ld \n",dwOption);
1834          break;
1835     }
1836     if (lpwhh)
1837         WININET_Release( lpwhh );
1838
1839     return bSuccess;
1840 }
1841
1842 /***********************************************************************
1843  *           InternetQueryOptionW (WININET.@)
1844  *
1845  * Queries an options on the specified handle
1846  *
1847  * RETURNS
1848  *    TRUE  on success
1849  *    FALSE on failure
1850  *
1851  */
1852 BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption,
1853                                  LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1854 {
1855     return INET_QueryOptionHelper(TRUE, hInternet, dwOption, lpBuffer, lpdwBufferLength);
1856 }
1857
1858 /***********************************************************************
1859  *           InternetQueryOptionA (WININET.@)
1860  *
1861  * Queries an options on the specified handle
1862  *
1863  * RETURNS
1864  *    TRUE  on success
1865  *    FALSE on failure
1866  *
1867  */
1868 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
1869                                  LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1870 {
1871     return INET_QueryOptionHelper(FALSE, hInternet, dwOption, lpBuffer, lpdwBufferLength);
1872 }
1873
1874
1875 /***********************************************************************
1876  *           InternetSetOptionW (WININET.@)
1877  *
1878  * Sets an options on the specified handle
1879  *
1880  * RETURNS
1881  *    TRUE  on success
1882  *    FALSE on failure
1883  *
1884  */
1885 BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
1886                            LPVOID lpBuffer, DWORD dwBufferLength)
1887 {
1888     LPWININETHANDLEHEADER lpwhh;
1889     BOOL ret = TRUE;
1890
1891     TRACE("0x%08lx\n", dwOption);
1892
1893     lpwhh = (LPWININETHANDLEHEADER) WININET_GetObject( hInternet );
1894     if( !lpwhh )
1895         return FALSE;
1896
1897     switch (dwOption)
1898     {
1899     case INTERNET_OPTION_HTTP_VERSION:
1900       {
1901         HTTP_VERSION_INFO* pVersion=(HTTP_VERSION_INFO*)lpBuffer;
1902         FIXME("Option INTERNET_OPTION_HTTP_VERSION(%ld,%ld): STUB\n",pVersion->dwMajorVersion,pVersion->dwMinorVersion);
1903       }
1904       break;
1905     case INTERNET_OPTION_ERROR_MASK:
1906       {
1907         unsigned long flags=*(unsigned long*)lpBuffer;
1908         FIXME("Option INTERNET_OPTION_ERROR_MASK(%ld): STUB\n",flags);
1909       }
1910       break;
1911     case INTERNET_OPTION_CODEPAGE:
1912       {
1913         unsigned long codepage=*(unsigned long*)lpBuffer;
1914         FIXME("Option INTERNET_OPTION_CODEPAGE (%ld): STUB\n",codepage);
1915       }
1916       break;
1917     case INTERNET_OPTION_REQUEST_PRIORITY:
1918       {
1919         unsigned long priority=*(unsigned long*)lpBuffer;
1920         FIXME("Option INTERNET_OPTION_REQUEST_PRIORITY (%ld): STUB\n",priority);
1921       }
1922       break;
1923     case INTERNET_OPTION_CONNECT_TIMEOUT:
1924       {
1925         unsigned long connecttimeout=*(unsigned long*)lpBuffer;
1926         FIXME("Option INTERNET_OPTION_CONNECT_TIMEOUT (%ld): STUB\n",connecttimeout);
1927       }
1928       break;
1929     case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT:
1930       {
1931         unsigned long receivetimeout=*(unsigned long*)lpBuffer;
1932         FIXME("Option INTERNET_OPTION_DATA_RECEIVE_TIMEOUT (%ld): STUB\n",receivetimeout);
1933       }
1934       break;
1935     case INTERNET_OPTION_RESET_URLCACHE_SESSION:
1936         FIXME("Option INTERNET_OPTION_RESET_URLCACHE_SESSION: STUB\n");
1937         break;
1938     case INTERNET_OPTION_END_BROWSER_SESSION:
1939         FIXME("Option INTERNET_OPTION_END_BROWSER_SESSION: STUB\n");
1940         break;
1941     case INTERNET_OPTION_CONNECTED_STATE:
1942         FIXME("Option INTERNET_OPTION_CONNECTED_STATE: STUB\n");
1943         break;
1944     default:
1945         FIXME("Option %ld STUB\n",dwOption);
1946         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1947         ret = FALSE;
1948         break;
1949     }
1950     WININET_Release( lpwhh );
1951
1952     return TRUE;
1953 }
1954
1955
1956 /***********************************************************************
1957  *           InternetSetOptionA (WININET.@)
1958  *
1959  * Sets an options on the specified handle.
1960  *
1961  * RETURNS
1962  *    TRUE  on success
1963  *    FALSE on failure
1964  *
1965  */
1966 BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
1967                            LPVOID lpBuffer, DWORD dwBufferLength)
1968 {
1969     LPVOID wbuffer;
1970     DWORD wlen;
1971     BOOL r;
1972
1973     switch( dwOption )
1974     {
1975     case INTERNET_OPTION_PROXY:
1976         {
1977         LPINTERNET_PROXY_INFOA pi = (LPINTERNET_PROXY_INFOA) lpBuffer;
1978         LPINTERNET_PROXY_INFOW piw;
1979         DWORD proxlen, prbylen;
1980         LPWSTR prox, prby;
1981
1982         proxlen = MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, NULL, 0);
1983         prbylen= MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, NULL, 0);
1984         wlen = sizeof(*piw) + proxlen + prbylen;
1985         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
1986         piw = (LPINTERNET_PROXY_INFOW) wbuffer;
1987         piw->dwAccessType = pi->dwAccessType;
1988         prox = (LPWSTR) &piw[1];
1989         prby = &prox[proxlen+1];
1990         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, prox, proxlen);
1991         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, prby, prbylen);
1992         piw->lpszProxy = prox;
1993         piw->lpszProxyBypass = prby;
1994         }
1995         break;
1996     case INTERNET_OPTION_USER_AGENT:
1997     case INTERNET_OPTION_USERNAME:
1998     case INTERNET_OPTION_PASSWORD:
1999         wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
2000                                    NULL, 0 );
2001         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
2002         MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
2003                                    wbuffer, wlen );
2004         break;
2005     default:
2006         wbuffer = lpBuffer;
2007         wlen = dwBufferLength;
2008     }
2009
2010     r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen);
2011
2012     if( lpBuffer != wbuffer )
2013         HeapFree( GetProcessHeap(), 0, wbuffer );
2014
2015     return r;
2016 }
2017
2018
2019 /***********************************************************************
2020  *           InternetSetOptionExA (WININET.@)
2021  */
2022 BOOL WINAPI InternetSetOptionExA(HINTERNET hInternet, DWORD dwOption,
2023                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2024 {
2025     FIXME("Flags %08lx ignored\n", dwFlags);
2026     return InternetSetOptionA( hInternet, dwOption, lpBuffer, dwBufferLength );
2027 }
2028
2029 /***********************************************************************
2030  *           InternetSetOptionExW (WININET.@)
2031  */
2032 BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption,
2033                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2034 {
2035     FIXME("Flags %08lx ignored\n", dwFlags);
2036     if( dwFlags & ~ISO_VALID_FLAGS )
2037     {
2038         SetLastError( ERROR_INVALID_PARAMETER );
2039         return FALSE;
2040     }
2041     return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength );
2042 }
2043
2044
2045 /***********************************************************************
2046  *      InternetCheckConnectionA (WININET.@)
2047  *
2048  * Pings a requested host to check internet connection
2049  *
2050  * RETURNS
2051  *   TRUE on success and FALSE on failure. If a failure then
2052  *   ERROR_NOT_CONNECTED is placesd into GetLastError
2053  *
2054  */
2055 BOOL WINAPI InternetCheckConnectionA( LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
2056 {
2057 /*
2058  * this is a kludge which runs the resident ping program and reads the output.
2059  *
2060  * Anyone have a better idea?
2061  */
2062
2063   BOOL   rc = FALSE;
2064   char command[1024];
2065   char host[1024];
2066   int status = -1;
2067
2068   FIXME("\n");
2069
2070   /*
2071    * Crack or set the Address
2072    */
2073   if (lpszUrl == NULL)
2074   {
2075      /*
2076       * According to the doc we are supost to use the ip for the next
2077       * server in the WnInet internal server database. I have
2078       * no idea what that is or how to get it.
2079       *
2080       * So someone needs to implement this.
2081       */
2082      FIXME("Unimplemented with URL of NULL\n");
2083      return TRUE;
2084   }
2085   else
2086   {
2087      URL_COMPONENTSA componets;
2088
2089      ZeroMemory(&componets,sizeof(URL_COMPONENTSA));
2090      componets.lpszHostName = (LPSTR)&host;
2091      componets.dwHostNameLength = 1024;
2092
2093      if (!InternetCrackUrlA(lpszUrl,0,0,&componets))
2094        goto End;
2095
2096      TRACE("host name : %s\n",componets.lpszHostName);
2097   }
2098
2099   /*
2100    * Build our ping command
2101    */
2102   strcpy(command,"ping -w 1 ");
2103   strcat(command,host);
2104   strcat(command," >/dev/null 2>/dev/null");
2105
2106   TRACE("Ping command is : %s\n",command);
2107
2108   status = system(command);
2109
2110   TRACE("Ping returned a code of %i \n",status);
2111
2112   /* Ping return code of 0 indicates success */
2113   if (status == 0)
2114      rc = TRUE;
2115
2116 End:
2117
2118   if (rc == FALSE)
2119     SetLastError(ERROR_NOT_CONNECTED);
2120
2121   return rc;
2122 }
2123
2124
2125 /***********************************************************************
2126  *      InternetCheckConnectionW (WININET.@)
2127  *
2128  * Pings a requested host to check internet connection
2129  *
2130  * RETURNS
2131  *   TRUE on success and FALSE on failure. If a failure then
2132  *   ERROR_NOT_CONNECTED is placed into GetLastError
2133  *
2134  */
2135 BOOL WINAPI InternetCheckConnectionW(LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
2136 {
2137     CHAR *szUrl;
2138     INT len;
2139     BOOL rc;
2140
2141     len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
2142     if (!(szUrl = (CHAR *)HeapAlloc(GetProcessHeap(), 0, len*sizeof(CHAR))))
2143         return FALSE;
2144     WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, szUrl, len, NULL, NULL);
2145     rc = InternetCheckConnectionA((LPCSTR)szUrl, dwFlags, dwReserved);
2146     HeapFree(GetProcessHeap(), 0, szUrl);
2147     
2148     return rc;
2149 }
2150
2151
2152 /**********************************************************
2153  *      INTERNET_InternetOpenUrlW (internal)
2154  *
2155  * Opens an URL
2156  *
2157  * RETURNS
2158  *   handle of connection or NULL on failure
2159  */
2160 HINTERNET WINAPI INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUrl,
2161     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
2162 {
2163     URL_COMPONENTSW urlComponents;
2164     WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024];
2165     WCHAR password[1024], path[2048], extra[1024];
2166     HINTERNET client = NULL, client1 = NULL;
2167     
2168     TRACE("(%p, %s, %s, %08lx, %08lx, %08lx\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
2169           dwHeadersLength, dwFlags, dwContext);
2170     
2171     urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
2172     urlComponents.lpszScheme = protocol;
2173     urlComponents.dwSchemeLength = 32;
2174     urlComponents.lpszHostName = hostName;
2175     urlComponents.dwHostNameLength = MAXHOSTNAME;
2176     urlComponents.lpszUserName = userName;
2177     urlComponents.dwUserNameLength = 1024;
2178     urlComponents.lpszPassword = password;
2179     urlComponents.dwPasswordLength = 1024;
2180     urlComponents.lpszUrlPath = path;
2181     urlComponents.dwUrlPathLength = 2048;
2182     urlComponents.lpszExtraInfo = extra;
2183     urlComponents.dwExtraInfoLength = 1024;
2184     if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
2185         return NULL;
2186     switch(urlComponents.nScheme) {
2187     case INTERNET_SCHEME_FTP:
2188         if(urlComponents.nPort == 0)
2189             urlComponents.nPort = INTERNET_DEFAULT_FTP_PORT;
2190         client = FTP_Connect(hIC, hostName, urlComponents.nPort,
2191                              userName, password, dwFlags, dwContext, INET_OPENURL);
2192         if(client == NULL)
2193             break;
2194         client1 = FtpOpenFileW(client, path, GENERIC_READ, dwFlags, dwContext);
2195         if(client1 == NULL) {
2196             InternetCloseHandle(client);
2197             break;
2198         }
2199         break;
2200         
2201     case INTERNET_SCHEME_HTTP:
2202     case INTERNET_SCHEME_HTTPS: {
2203         static const WCHAR szStars[] = { '*','/','*', 0 };
2204         LPCWSTR accept[2] = { szStars, NULL };
2205         if(urlComponents.nPort == 0) {
2206             if(urlComponents.nScheme == INTERNET_SCHEME_HTTP)
2207                 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
2208             else
2209                 urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
2210         }
2211         /* FIXME: should use pointers, not handles, as handles are not thread-safe */
2212         client = HTTP_Connect(hIC, hostName, urlComponents.nPort,
2213                               userName, password, dwFlags, dwContext, INET_OPENURL);
2214         if(client == NULL)
2215             break;
2216         client1 = HttpOpenRequestW(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
2217         if(client1 == NULL) {
2218             InternetCloseHandle(client);
2219             break;
2220         }
2221         HttpAddRequestHeadersW(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
2222         if (!HttpSendRequestW(client1, NULL, 0, NULL, 0)) {
2223             InternetCloseHandle(client1);
2224             client1 = NULL;
2225             break;
2226         }
2227     }
2228     case INTERNET_SCHEME_GOPHER:
2229         /* gopher doesn't seem to be implemented in wine, but it's supposed
2230          * to be supported by InternetOpenUrlA. */
2231     default:
2232         break;
2233     }
2234
2235     TRACE(" %p <--\n", client1);
2236     
2237     return client1;
2238 }
2239
2240 /**********************************************************
2241  *      InternetOpenUrlW (WININET.@)
2242  *
2243  * Opens an URL
2244  *
2245  * RETURNS
2246  *   handle of connection or NULL on failure
2247  */
2248 HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
2249     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
2250 {
2251     HINTERNET ret = NULL;
2252     LPWININETAPPINFOW hIC = NULL;
2253
2254     TRACE("(%p, %s, %s, %08lx, %08lx, %08lx\n", hInternet, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
2255           dwHeadersLength, dwFlags, dwContext);
2256  
2257     hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
2258     if (NULL == hIC ||  hIC->hdr.htype != WH_HINIT) {
2259         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2260         goto lend;
2261     }
2262     
2263     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) {
2264         WORKREQUEST workRequest;
2265         struct WORKREQ_INTERNETOPENURLW *req;
2266         
2267         workRequest.asyncall = INTERNETOPENURLW;
2268         workRequest.hdr = WININET_AddRef( &hIC->hdr );
2269         req = &workRequest.u.InternetOpenUrlW;
2270         if (lpszUrl)
2271             req->lpszUrl = WININET_strdupW(lpszUrl);
2272         else
2273             req->lpszUrl = 0;
2274         if (lpszHeaders)
2275             req->lpszHeaders = WININET_strdupW(lpszHeaders);
2276         else
2277             req->lpszHeaders = 0;
2278         req->dwHeadersLength = dwHeadersLength;
2279         req->dwFlags = dwFlags;
2280         req->dwContext = dwContext;
2281         
2282         INTERNET_AsyncCall(&workRequest);
2283         /*
2284          * This is from windows.
2285          */
2286         SetLastError(ERROR_IO_PENDING);
2287     } else {
2288         ret = INTERNET_InternetOpenUrlW(hIC, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext);
2289     }
2290     
2291   lend:
2292     if( hIC )
2293         WININET_Release( &hIC->hdr );
2294     TRACE(" %p <--\n", ret);
2295     
2296     return ret;
2297 }
2298
2299 /**********************************************************
2300  *      InternetOpenUrlA (WININET.@)
2301  *
2302  * Opens an URL
2303  *
2304  * RETURNS
2305  *   handle of connection or NULL on failure
2306  */
2307 HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
2308     LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
2309 {
2310     HINTERNET rc = (HINTERNET)NULL;
2311
2312     INT lenUrl;
2313     INT lenHeaders = 0;
2314     LPWSTR szUrl = NULL;
2315     LPWSTR szHeaders = NULL;
2316
2317     TRACE("\n");
2318
2319     if(lpszUrl) {
2320         lenUrl = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0 );
2321         szUrl = HeapAlloc(GetProcessHeap(), 0, lenUrl*sizeof(WCHAR));
2322         if(!szUrl)
2323             return (HINTERNET)NULL;
2324         MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, szUrl, lenUrl);
2325     }
2326     
2327     if(lpszHeaders) {
2328         lenHeaders = MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, NULL, 0 );
2329         szHeaders = HeapAlloc(GetProcessHeap(), 0, lenHeaders*sizeof(WCHAR));
2330         if(!szHeaders) {
2331             if(szUrl) HeapFree(GetProcessHeap(), 0, szUrl);
2332             return (HINTERNET)NULL;
2333         }
2334         MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, szHeaders, lenHeaders);
2335     }
2336     
2337     rc = InternetOpenUrlW(hInternet, szUrl, szHeaders,
2338         lenHeaders, dwFlags, dwContext);
2339
2340     if(szUrl) HeapFree(GetProcessHeap(), 0, szUrl);
2341     if(szHeaders) HeapFree(GetProcessHeap(), 0, szHeaders);
2342
2343     return rc;
2344 }
2345
2346
2347 /***********************************************************************
2348  *           INTERNET_SetLastError (internal)
2349  *
2350  * Set last thread specific error
2351  *
2352  * RETURNS
2353  *
2354  */
2355 void INTERNET_SetLastError(DWORD dwError)
2356 {
2357     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
2358
2359     SetLastError(dwError);
2360     if(lpwite)
2361         lpwite->dwError = dwError;
2362 }
2363
2364
2365 /***********************************************************************
2366  *           INTERNET_GetLastError (internal)
2367  *
2368  * Get last thread specific error
2369  *
2370  * RETURNS
2371  *
2372  */
2373 DWORD INTERNET_GetLastError()
2374 {
2375     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
2376     return lpwite->dwError;
2377 }
2378
2379
2380 /***********************************************************************
2381  *           INTERNET_WorkerThreadFunc (internal)
2382  *
2383  * Worker thread execution function
2384  *
2385  * RETURNS
2386  *
2387  */
2388 DWORD INTERNET_WorkerThreadFunc(LPVOID *lpvParam)
2389 {
2390     DWORD dwWaitRes;
2391
2392     while (1)
2393     {
2394         if(dwNumJobs > 0) {
2395             INTERNET_ExecuteWork();
2396             continue;
2397         }
2398         dwWaitRes = WaitForMultipleObjects(2, hEventArray, FALSE, MAX_IDLE_WORKER);
2399
2400         if (dwWaitRes == WAIT_OBJECT_0 + 1)
2401             INTERNET_ExecuteWork();
2402         else
2403             break;
2404
2405         InterlockedIncrement(&dwNumIdleThreads);
2406     }
2407
2408     InterlockedDecrement(&dwNumIdleThreads);
2409     InterlockedDecrement(&dwNumThreads);
2410     TRACE("Worker thread exiting\n");
2411     return TRUE;
2412 }
2413
2414
2415 /***********************************************************************
2416  *           INTERNET_InsertWorkRequest (internal)
2417  *
2418  * Insert work request into queue
2419  *
2420  * RETURNS
2421  *
2422  */
2423 BOOL INTERNET_InsertWorkRequest(LPWORKREQUEST lpWorkRequest)
2424 {
2425     BOOL bSuccess = FALSE;
2426     LPWORKREQUEST lpNewRequest;
2427
2428     TRACE("\n");
2429
2430     lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
2431     if (lpNewRequest)
2432     {
2433         memcpy(lpNewRequest, lpWorkRequest, sizeof(WORKREQUEST));
2434         lpNewRequest->prev = NULL;
2435
2436         EnterCriticalSection(&csQueue);
2437
2438         lpNewRequest->next = lpWorkQueueTail;
2439         if (lpWorkQueueTail)
2440             lpWorkQueueTail->prev = lpNewRequest;
2441         lpWorkQueueTail = lpNewRequest;
2442         if (!lpHeadWorkQueue)
2443             lpHeadWorkQueue = lpWorkQueueTail;
2444
2445         LeaveCriticalSection(&csQueue);
2446
2447         bSuccess = TRUE;
2448         InterlockedIncrement(&dwNumJobs);
2449     }
2450
2451     return bSuccess;
2452 }
2453
2454
2455 /***********************************************************************
2456  *           INTERNET_GetWorkRequest (internal)
2457  *
2458  * Retrieves work request from queue
2459  *
2460  * RETURNS
2461  *
2462  */
2463 BOOL INTERNET_GetWorkRequest(LPWORKREQUEST lpWorkRequest)
2464 {
2465     BOOL bSuccess = FALSE;
2466     LPWORKREQUEST lpRequest = NULL;
2467
2468     TRACE("\n");
2469
2470     EnterCriticalSection(&csQueue);
2471
2472     if (lpHeadWorkQueue)
2473     {
2474         lpRequest = lpHeadWorkQueue;
2475         lpHeadWorkQueue = lpHeadWorkQueue->prev;
2476         if (lpRequest == lpWorkQueueTail)
2477             lpWorkQueueTail = lpHeadWorkQueue;
2478     }
2479
2480     LeaveCriticalSection(&csQueue);
2481
2482     if (lpRequest)
2483     {
2484         memcpy(lpWorkRequest, lpRequest, sizeof(WORKREQUEST));
2485         HeapFree(GetProcessHeap(), 0, lpRequest);
2486         bSuccess = TRUE;
2487         InterlockedDecrement(&dwNumJobs);
2488     }
2489
2490     return bSuccess;
2491 }
2492
2493
2494 /***********************************************************************
2495  *           INTERNET_AsyncCall (internal)
2496  *
2497  * Retrieves work request from queue
2498  *
2499  * RETURNS
2500  *
2501  */
2502 BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
2503 {
2504     HANDLE hThread;
2505     DWORD dwTID;
2506     BOOL bSuccess = FALSE;
2507
2508     TRACE("\n");
2509
2510     if (InterlockedDecrement(&dwNumIdleThreads) < 0)
2511     {
2512         InterlockedIncrement(&dwNumIdleThreads);
2513
2514         if (InterlockedIncrement(&dwNumThreads) > MAX_WORKER_THREADS ||
2515             !(hThread = CreateThread(NULL, 0,
2516             (LPTHREAD_START_ROUTINE)INTERNET_WorkerThreadFunc, NULL, 0, &dwTID)))
2517         {
2518             InterlockedDecrement(&dwNumThreads);
2519             INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED);
2520             goto lerror;
2521         }
2522
2523         TRACE("Created new thread\n");
2524     }
2525
2526     bSuccess = TRUE;
2527     INTERNET_InsertWorkRequest(lpWorkRequest);
2528     SetEvent(hWorkEvent);
2529
2530 lerror:
2531
2532     return bSuccess;
2533 }
2534
2535
2536 /***********************************************************************
2537  *           INTERNET_ExecuteWork (internal)
2538  *
2539  * RETURNS
2540  *
2541  */
2542 static VOID INTERNET_ExecuteWork()
2543 {
2544     WORKREQUEST workRequest;
2545
2546     TRACE("\n");
2547
2548     if (!INTERNET_GetWorkRequest(&workRequest))
2549         return;
2550
2551     switch (workRequest.asyncall)
2552     {
2553     case FTPPUTFILEW:
2554         {
2555         struct WORKREQ_FTPPUTFILEW *req = &workRequest.u.FtpPutFileW;
2556         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2557
2558         TRACE("FTPPUTFILEW %p\n", lpwfs);
2559
2560         FTP_FtpPutFileW(lpwfs, req->lpszLocalFile,
2561                    req->lpszNewRemoteFile, req->dwFlags, req->dwContext);
2562
2563         HeapFree(GetProcessHeap(), 0, req->lpszLocalFile);
2564         HeapFree(GetProcessHeap(), 0, req->lpszNewRemoteFile);
2565         }
2566         break;
2567
2568     case FTPSETCURRENTDIRECTORYW:
2569         {
2570         struct WORKREQ_FTPSETCURRENTDIRECTORYW *req;
2571         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2572
2573         TRACE("FTPSETCURRENTDIRECTORYW %p\n", lpwfs);
2574
2575         req = &workRequest.u.FtpSetCurrentDirectoryW;
2576         FTP_FtpSetCurrentDirectoryW(lpwfs, req->lpszDirectory);
2577         HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2578         }
2579         break;
2580
2581     case FTPCREATEDIRECTORYW:
2582         {
2583         struct WORKREQ_FTPCREATEDIRECTORYW *req;
2584         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2585
2586         TRACE("FTPCREATEDIRECTORYW %p\n", lpwfs);
2587
2588         req = &workRequest.u.FtpCreateDirectoryW;
2589         FTP_FtpCreateDirectoryW(lpwfs, req->lpszDirectory);
2590         HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2591         }
2592         break;
2593
2594     case FTPFINDFIRSTFILEW:
2595         {
2596         struct WORKREQ_FTPFINDFIRSTFILEW *req;
2597         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2598
2599         TRACE("FTPFINDFIRSTFILEW %p\n", lpwfs);
2600
2601         req = &workRequest.u.FtpFindFirstFileW;
2602         FTP_FtpFindFirstFileW(lpwfs, req->lpszSearchFile,
2603            req->lpFindFileData, req->dwFlags, req->dwContext);
2604         if (req->lpszSearchFile != NULL)
2605             HeapFree(GetProcessHeap(), 0, req->lpszSearchFile);
2606         }
2607         break;
2608
2609     case FTPGETCURRENTDIRECTORYW:
2610         {
2611         struct WORKREQ_FTPGETCURRENTDIRECTORYW *req;
2612         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2613
2614         TRACE("FTPGETCURRENTDIRECTORYW %p\n", lpwfs);
2615
2616         req = &workRequest.u.FtpGetCurrentDirectoryW;
2617         FTP_FtpGetCurrentDirectoryW(lpwfs,
2618                 req->lpszDirectory, req->lpdwDirectory);
2619         }
2620         break;
2621
2622     case FTPOPENFILEW:
2623         {
2624         struct WORKREQ_FTPOPENFILEW *req = &workRequest.u.FtpOpenFileW;
2625         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2626
2627         TRACE("FTPOPENFILEW %p\n", lpwfs);
2628
2629         FTP_FtpOpenFileW(lpwfs, req->lpszFilename,
2630             req->dwAccess, req->dwFlags, req->dwContext);
2631         HeapFree(GetProcessHeap(), 0, req->lpszFilename);
2632         }
2633         break;
2634
2635     case FTPGETFILEW:
2636         {
2637         struct WORKREQ_FTPGETFILEW *req = &workRequest.u.FtpGetFileW;
2638         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2639
2640         TRACE("FTPGETFILEW %p\n", lpwfs);
2641
2642         FTP_FtpGetFileW(lpwfs, req->lpszRemoteFile,
2643                  req->lpszNewFile, req->fFailIfExists,
2644                  req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext);
2645         HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile);
2646         HeapFree(GetProcessHeap(), 0, req->lpszNewFile);
2647         }
2648         break;
2649
2650     case FTPDELETEFILEW:
2651         {
2652         struct WORKREQ_FTPDELETEFILEW *req = &workRequest.u.FtpDeleteFileW;
2653         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2654
2655         TRACE("FTPDELETEFILEW %p\n", lpwfs);
2656
2657         FTP_FtpDeleteFileW(lpwfs, req->lpszFilename);
2658         HeapFree(GetProcessHeap(), 0, req->lpszFilename);
2659         }
2660         break;
2661
2662     case FTPREMOVEDIRECTORYW:
2663         {
2664         struct WORKREQ_FTPREMOVEDIRECTORYW *req;
2665         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2666
2667         TRACE("FTPREMOVEDIRECTORYW %p\n", lpwfs);
2668
2669         req = &workRequest.u.FtpRemoveDirectoryW;
2670         FTP_FtpRemoveDirectoryW(lpwfs, req->lpszDirectory);
2671         HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2672         }
2673         break;
2674
2675     case FTPRENAMEFILEW:
2676         {
2677         struct WORKREQ_FTPRENAMEFILEW *req = &workRequest.u.FtpRenameFileW;
2678         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2679
2680         TRACE("FTPRENAMEFILEW %p\n", lpwfs);
2681
2682         FTP_FtpRenameFileW(lpwfs, req->lpszSrcFile, req->lpszDestFile);
2683         HeapFree(GetProcessHeap(), 0, req->lpszSrcFile);
2684         HeapFree(GetProcessHeap(), 0, req->lpszDestFile);
2685         }
2686         break;
2687
2688     case INTERNETFINDNEXTW:
2689         {
2690         struct WORKREQ_INTERNETFINDNEXTW *req;
2691         LPWININETFINDNEXTW lpwh = (LPWININETFINDNEXTW) workRequest.hdr;
2692
2693         TRACE("INTERNETFINDNEXTW %p\n", lpwh);
2694
2695         req = &workRequest.u.InternetFindNextW;
2696         INTERNET_FindNextFileW(lpwh, req->lpFindFileData);
2697         }
2698         break;
2699
2700     case HTTPSENDREQUESTW:
2701         {
2702         struct WORKREQ_HTTPSENDREQUESTW *req = &workRequest.u.HttpSendRequestW;
2703         LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) workRequest.hdr;
2704
2705         TRACE("HTTPSENDREQUESTW %p\n", lpwhr);
2706
2707         HTTP_HttpSendRequestW(lpwhr, req->lpszHeader,
2708                 req->dwHeaderLength, req->lpOptional, req->dwOptionalLength);
2709
2710         HeapFree(GetProcessHeap(), 0, req->lpszHeader);
2711         }
2712         break;
2713
2714     case HTTPOPENREQUESTW:
2715         {
2716         struct WORKREQ_HTTPOPENREQUESTW *req = &workRequest.u.HttpOpenRequestW;
2717         LPWININETHTTPSESSIONW lpwhs = (LPWININETHTTPSESSIONW) workRequest.hdr;
2718
2719         TRACE("HTTPOPENREQUESTW %p\n", lpwhs);
2720
2721         HTTP_HttpOpenRequestW(lpwhs, req->lpszVerb,
2722             req->lpszObjectName, req->lpszVersion, req->lpszReferrer,
2723             req->lpszAcceptTypes, req->dwFlags, req->dwContext);
2724
2725         HeapFree(GetProcessHeap(), 0, req->lpszVerb);
2726         HeapFree(GetProcessHeap(), 0, req->lpszObjectName);
2727         HeapFree(GetProcessHeap(), 0, req->lpszVersion);
2728         HeapFree(GetProcessHeap(), 0, req->lpszReferrer);
2729         }
2730         break;
2731
2732     case SENDCALLBACK:
2733         {
2734         struct WORKREQ_SENDCALLBACK *req = &workRequest.u.SendCallback;
2735
2736         TRACE("SENDCALLBACK %p\n", workRequest.hdr);
2737
2738         SendSyncCallback(workRequest.hdr,
2739                 req->dwContext, req->dwInternetStatus, req->lpvStatusInfo,
2740                 req->dwStatusInfoLength);
2741         }
2742         break;
2743
2744     case INTERNETOPENURLW:
2745         {
2746         struct WORKREQ_INTERNETOPENURLW *req = &workRequest.u.InternetOpenUrlW;
2747         LPWININETAPPINFOW hIC = (LPWININETAPPINFOW) workRequest.hdr;
2748         
2749         TRACE("INTERNETOPENURLW %p\n", hIC);
2750
2751         INTERNET_InternetOpenUrlW(hIC, req->lpszUrl,
2752                                   req->lpszHeaders, req->dwHeadersLength, req->dwFlags, req->dwContext);
2753         HeapFree(GetProcessHeap(), 0, req->lpszUrl);
2754         HeapFree(GetProcessHeap(), 0, req->lpszHeaders);
2755         }
2756         break;
2757     }
2758     WININET_Release( workRequest.hdr );
2759 }
2760
2761
2762 /***********************************************************************
2763  *          INTERNET_GetResponseBuffer
2764  *
2765  * RETURNS
2766  *
2767  */
2768 LPSTR INTERNET_GetResponseBuffer()
2769 {
2770     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
2771     TRACE("\n");
2772     return lpwite->response;
2773 }
2774
2775 /***********************************************************************
2776  *           INTERNET_GetNextLine  (internal)
2777  *
2778  * Parse next line in directory string listing
2779  *
2780  * RETURNS
2781  *   Pointer to beginning of next line
2782  *   NULL on failure
2783  *
2784  */
2785
2786 LPSTR INTERNET_GetNextLine(INT nSocket, LPDWORD dwLen)
2787 {
2788     struct timeval tv;
2789     fd_set infd;
2790     BOOL bSuccess = FALSE;
2791     INT nRecv = 0;
2792     LPSTR lpszBuffer = INTERNET_GetResponseBuffer();
2793
2794     TRACE("\n");
2795
2796     FD_ZERO(&infd);
2797     FD_SET(nSocket, &infd);
2798     tv.tv_sec=RESPONSE_TIMEOUT;
2799     tv.tv_usec=0;
2800
2801     while (nRecv < MAX_REPLY_LEN)
2802     {
2803         if (select(nSocket+1,&infd,NULL,NULL,&tv) > 0)
2804         {
2805             if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
2806             {
2807                 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
2808                 goto lend;
2809             }
2810
2811             if (lpszBuffer[nRecv] == '\n')
2812             {
2813                 bSuccess = TRUE;
2814                 break;
2815             }
2816             if (lpszBuffer[nRecv] != '\r')
2817                 nRecv++;
2818         }
2819         else
2820         {
2821             INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
2822             goto lend;
2823         }
2824     }
2825
2826 lend:
2827     if (bSuccess)
2828     {
2829         lpszBuffer[nRecv] = '\0';
2830         *dwLen = nRecv - 1;
2831         TRACE(":%d %s\n", nRecv, lpszBuffer);
2832         return lpszBuffer;
2833     }
2834     else
2835     {
2836         return NULL;
2837     }
2838 }
2839
2840 /***********************************************************************
2841  *
2842  */
2843 BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile,
2844                                 LPDWORD lpdwNumberOfBytesAvailble,
2845                                 DWORD dwFlags, DWORD dwConext)
2846 {
2847     LPWININETHTTPREQW lpwhr;
2848     INT retval = -1;
2849     char buffer[4048];
2850
2851     lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hFile );
2852     if (NULL == lpwhr)
2853     {
2854         SetLastError(ERROR_NO_MORE_FILES);
2855         return FALSE;
2856     }
2857
2858     TRACE("-->  %p %i\n",lpwhr,lpwhr->hdr.htype);
2859
2860     switch (lpwhr->hdr.htype)
2861     {
2862     case WH_HHTTPREQ:
2863         if (!NETCON_recv(&lpwhr->netConnection, buffer,
2864                          4048, MSG_PEEK, (int *)lpdwNumberOfBytesAvailble))
2865         {
2866             SetLastError(ERROR_NO_MORE_FILES);
2867             retval = FALSE;
2868         }
2869         else
2870             retval = TRUE;
2871         break;
2872
2873     default:
2874         FIXME("unsupported file type\n");
2875         break;
2876     }
2877     WININET_Release( &lpwhr->hdr );
2878
2879     TRACE("<-- %i\n",retval);
2880     return (retval+1);
2881 }
2882
2883
2884 /***********************************************************************
2885  *
2886  */
2887 BOOL WINAPI InternetLockRequestFile( HINTERNET hInternet, HANDLE
2888 *lphLockReqHandle)
2889 {
2890     FIXME("STUB\n");
2891     return FALSE;
2892 }
2893
2894 BOOL WINAPI InternetUnlockRequestFile( HANDLE hLockHandle)
2895 {
2896     FIXME("STUB\n");
2897     return FALSE;
2898 }
2899
2900
2901 /***********************************************************************
2902  *           InternetAutodial
2903  *
2904  * On windows this function is supposed to dial the default internet
2905  * connection. We don't want to have Wine dial out to the internet so
2906  * we return TRUE by default. It might be nice to check if we are connected.
2907  *
2908  * RETURNS
2909  *   TRUE on success
2910  *   FALSE on failure
2911  *
2912  */
2913 BOOL WINAPI InternetAutodial(DWORD dwFlags, HWND hwndParent)
2914 {
2915     FIXME("STUB\n");
2916
2917     /* Tell that we are connected to the internet. */
2918     return TRUE;
2919 }
2920
2921 /***********************************************************************
2922  *           InternetAutodialHangup
2923  *
2924  * Hangs up an connection made with InternetAutodial
2925  *
2926  * PARAM
2927  *    dwReserved
2928  * RETURNS
2929  *   TRUE on success
2930  *   FALSE on failure
2931  *
2932  */
2933 BOOL WINAPI InternetAutodialHangup(DWORD dwReserved)
2934 {
2935     FIXME("STUB\n");
2936
2937     /* we didn't dial, we don't disconnect */
2938     return TRUE;
2939 }
2940
2941 /***********************************************************************
2942  *
2943  *         InternetCombineUrlA
2944  *
2945  * Combine a base URL with a relative URL
2946  *
2947  * RETURNS
2948  *   TRUE on success
2949  *   FALSE on failure
2950  *
2951  */
2952
2953 BOOL WINAPI InternetCombineUrlA(LPCSTR lpszBaseUrl, LPCSTR lpszRelativeUrl,
2954                                 LPSTR lpszBuffer, LPDWORD lpdwBufferLength,
2955                                 DWORD dwFlags)
2956 {
2957     HRESULT hr=S_OK;
2958
2959     TRACE("(%s, %s, %p, %p, 0x%08lx)\n", debugstr_a(lpszBaseUrl), debugstr_a(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
2960
2961     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
2962     dwFlags ^= ICU_NO_ENCODE;
2963     hr=UrlCombineA(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
2964
2965     return (hr==S_OK);
2966 }
2967
2968 /***********************************************************************
2969  *
2970  *         InternetCombineUrlW
2971  *
2972  * Combine a base URL with a relative URL
2973  *
2974  * RETURNS
2975  *   TRUE on success
2976  *   FALSE on failure
2977  *
2978  */
2979
2980 BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
2981                                 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength,
2982                                 DWORD dwFlags)
2983 {
2984     HRESULT hr=S_OK;
2985
2986     TRACE("(%s, %s, %p, %p, 0x%08lx)\n", debugstr_w(lpszBaseUrl), debugstr_w(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
2987
2988     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
2989     dwFlags ^= ICU_NO_ENCODE;
2990     hr=UrlCombineW(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
2991
2992     return (hr==S_OK);
2993 }
2994
2995 /***********************************************************************
2996  *
2997  *         InternetCreateUrlA
2998  *
2999  * RETURNS
3000  *   TRUE on success
3001  *   FALSE on failure
3002  *
3003  */
3004 BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
3005                                LPSTR lpszUrl, LPDWORD lpdwUrlLength)
3006 {
3007     FIXME("\n");
3008     return FALSE;
3009 }
3010
3011 /***********************************************************************
3012  *
3013  *         InternetCreateUrlW
3014  *
3015  * RETURNS
3016  *   TRUE on success
3017  *   FALSE on failure
3018  *
3019  */
3020 BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
3021                                LPWSTR lpszUrl, LPDWORD lpdwUrlLength)
3022 {
3023     FIXME("\n");
3024     return FALSE;
3025 }