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