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