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