Properly retrieve and release handles.
[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_dwMaxHandles ) )
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_dwMaxHandles ) )
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     static 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             static 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     static const WCHAR lpszFtp[]={'f','t','p',0};
1074     static const WCHAR lpszGopher[]={'g','o','p','h','e','r',0};
1075     static const WCHAR lpszHttp[]={'h','t','t','p',0};
1076     static const WCHAR lpszHttps[]={'h','t','t','p','s',0};
1077     static const WCHAR lpszFile[]={'f','i','l','e',0};
1078     static const WCHAR lpszNews[]={'n','e','w','s',0};
1079     static const WCHAR lpszMailto[]={'m','a','i','l','t','o',0};
1080     static 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         static 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                 static 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_InternetOpenUrlW (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         static 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  *      InternetOpenUrlW (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  *      InternetOpenUrlA (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;
2187     INT lenHeaders = 0;
2188     LPWSTR szUrl = NULL;
2189     LPWSTR szHeaders = NULL;
2190
2191     TRACE("\n");
2192
2193     if(lpszUrl) {
2194         lenUrl = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0 );
2195         szUrl = HeapAlloc(GetProcessHeap(), 0, lenUrl*sizeof(WCHAR));
2196         if(!szUrl)
2197             return (HINTERNET)NULL;
2198         MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, szUrl, lenUrl);
2199     }
2200     
2201     if(lpszHeaders) {
2202         lenHeaders = MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, NULL, 0 );
2203         szHeaders = HeapAlloc(GetProcessHeap(), 0, lenHeaders*sizeof(WCHAR));
2204         if(!szHeaders) {
2205             if(szUrl) HeapFree(GetProcessHeap(), 0, szUrl);
2206             return (HINTERNET)NULL;
2207         }
2208         MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, szHeaders, lenHeaders);
2209     }
2210     
2211     rc = InternetOpenUrlW(hInternet, szUrl, szHeaders,
2212         lenHeaders, dwFlags, dwContext);
2213
2214     if(szUrl) HeapFree(GetProcessHeap(), 0, szUrl);
2215     if(szHeaders) HeapFree(GetProcessHeap(), 0, szHeaders);
2216
2217     return rc;
2218 }
2219
2220
2221 /***********************************************************************
2222  *           INTERNET_SetLastError (internal)
2223  *
2224  * Set last thread specific error
2225  *
2226  * RETURNS
2227  *
2228  */
2229 void INTERNET_SetLastError(DWORD dwError)
2230 {
2231     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
2232
2233     SetLastError(dwError);
2234     if(lpwite)
2235         lpwite->dwError = dwError;
2236 }
2237
2238
2239 /***********************************************************************
2240  *           INTERNET_GetLastError (internal)
2241  *
2242  * Get last thread specific error
2243  *
2244  * RETURNS
2245  *
2246  */
2247 DWORD INTERNET_GetLastError()
2248 {
2249     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
2250     return lpwite->dwError;
2251 }
2252
2253
2254 /***********************************************************************
2255  *           INTERNET_WorkerThreadFunc (internal)
2256  *
2257  * Worker thread execution function
2258  *
2259  * RETURNS
2260  *
2261  */
2262 DWORD INTERNET_WorkerThreadFunc(LPVOID *lpvParam)
2263 {
2264     DWORD dwWaitRes;
2265
2266     while (1)
2267     {
2268         if(dwNumJobs > 0) {
2269             INTERNET_ExecuteWork();
2270             continue;
2271         }
2272         dwWaitRes = WaitForMultipleObjects(2, hEventArray, FALSE, MAX_IDLE_WORKER);
2273
2274         if (dwWaitRes == WAIT_OBJECT_0 + 1)
2275             INTERNET_ExecuteWork();
2276         else
2277             break;
2278
2279         InterlockedIncrement(&dwNumIdleThreads);
2280     }
2281
2282     InterlockedDecrement(&dwNumIdleThreads);
2283     InterlockedDecrement(&dwNumThreads);
2284     TRACE("Worker thread exiting\n");
2285     return TRUE;
2286 }
2287
2288
2289 /***********************************************************************
2290  *           INTERNET_InsertWorkRequest (internal)
2291  *
2292  * Insert work request into queue
2293  *
2294  * RETURNS
2295  *
2296  */
2297 BOOL INTERNET_InsertWorkRequest(LPWORKREQUEST lpWorkRequest)
2298 {
2299     BOOL bSuccess = FALSE;
2300     LPWORKREQUEST lpNewRequest;
2301
2302     TRACE("\n");
2303
2304     lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
2305     if (lpNewRequest)
2306     {
2307         memcpy(lpNewRequest, lpWorkRequest, sizeof(WORKREQUEST));
2308         lpNewRequest->prev = NULL;
2309
2310         EnterCriticalSection(&csQueue);
2311
2312         lpNewRequest->next = lpWorkQueueTail;
2313         if (lpWorkQueueTail)
2314             lpWorkQueueTail->prev = lpNewRequest;
2315         lpWorkQueueTail = lpNewRequest;
2316         if (!lpHeadWorkQueue)
2317             lpHeadWorkQueue = lpWorkQueueTail;
2318
2319         LeaveCriticalSection(&csQueue);
2320
2321         bSuccess = TRUE;
2322         InterlockedIncrement(&dwNumJobs);
2323     }
2324
2325     return bSuccess;
2326 }
2327
2328
2329 /***********************************************************************
2330  *           INTERNET_GetWorkRequest (internal)
2331  *
2332  * Retrieves work request from queue
2333  *
2334  * RETURNS
2335  *
2336  */
2337 BOOL INTERNET_GetWorkRequest(LPWORKREQUEST lpWorkRequest)
2338 {
2339     BOOL bSuccess = FALSE;
2340     LPWORKREQUEST lpRequest = NULL;
2341
2342     TRACE("\n");
2343
2344     EnterCriticalSection(&csQueue);
2345
2346     if (lpHeadWorkQueue)
2347     {
2348         lpRequest = lpHeadWorkQueue;
2349         lpHeadWorkQueue = lpHeadWorkQueue->prev;
2350         if (lpRequest == lpWorkQueueTail)
2351             lpWorkQueueTail = lpHeadWorkQueue;
2352     }
2353
2354     LeaveCriticalSection(&csQueue);
2355
2356     if (lpRequest)
2357     {
2358         memcpy(lpWorkRequest, lpRequest, sizeof(WORKREQUEST));
2359         HeapFree(GetProcessHeap(), 0, lpRequest);
2360         bSuccess = TRUE;
2361         InterlockedDecrement(&dwNumJobs);
2362     }
2363
2364     return bSuccess;
2365 }
2366
2367
2368 /***********************************************************************
2369  *           INTERNET_AsyncCall (internal)
2370  *
2371  * Retrieves work request from queue
2372  *
2373  * RETURNS
2374  *
2375  */
2376 BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
2377 {
2378     HANDLE hThread;
2379     DWORD dwTID;
2380     BOOL bSuccess = FALSE;
2381
2382     TRACE("\n");
2383
2384     if (InterlockedDecrement(&dwNumIdleThreads) < 0)
2385     {
2386         InterlockedIncrement(&dwNumIdleThreads);
2387
2388         if (InterlockedIncrement(&dwNumThreads) > MAX_WORKER_THREADS ||
2389             !(hThread = CreateThread(NULL, 0,
2390             (LPTHREAD_START_ROUTINE)INTERNET_WorkerThreadFunc, NULL, 0, &dwTID)))
2391         {
2392             InterlockedDecrement(&dwNumThreads);
2393             INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED);
2394             goto lerror;
2395         }
2396
2397         TRACE("Created new thread\n");
2398     }
2399
2400     bSuccess = TRUE;
2401     INTERNET_InsertWorkRequest(lpWorkRequest);
2402     SetEvent(hWorkEvent);
2403
2404 lerror:
2405
2406     return bSuccess;
2407 }
2408
2409
2410 /***********************************************************************
2411  *           INTERNET_ExecuteWork (internal)
2412  *
2413  * RETURNS
2414  *
2415  */
2416 VOID INTERNET_ExecuteWork()
2417 {
2418     WORKREQUEST workRequest;
2419
2420     TRACE("\n");
2421
2422     if (!INTERNET_GetWorkRequest(&workRequest))
2423         return;
2424
2425     if (TRACE_ON(wininet)) {
2426         static const wininet_flag_info work_request_types[] = {
2427 #define FE(x) { x, #x }
2428             FE(FTPPUTFILEA),
2429             FE(FTPSETCURRENTDIRECTORYA),
2430             FE(FTPCREATEDIRECTORYA),
2431             FE(FTPFINDFIRSTFILEA),
2432             FE(FTPGETCURRENTDIRECTORYA),
2433             FE(FTPOPENFILEA),
2434             FE(FTPGETFILEA),
2435             FE(FTPDELETEFILEA),
2436             FE(FTPREMOVEDIRECTORYA),
2437             FE(FTPRENAMEFILEA),
2438             FE(INTERNETFINDNEXTA),
2439             FE(HTTPSENDREQUESTW),
2440             FE(HTTPOPENREQUESTW),
2441             FE(SENDCALLBACK),
2442             FE(INTERNETOPENURLW)
2443 #undef FE
2444         };
2445         int i;
2446         const char *val = "Unknown";
2447
2448         for (i = 0; i < (sizeof(work_request_types) / sizeof(work_request_types[0])); i++) {
2449             if (work_request_types[i].val == workRequest.asyncall) {
2450                 val = work_request_types[i].name;
2451                 break;
2452             }
2453         }
2454
2455         TRACE("Got work %d (%s)\n", workRequest.asyncall, val);
2456     }
2457     switch (workRequest.asyncall)
2458     {
2459     case FTPPUTFILEA:
2460         {
2461         struct WORKREQ_FTPPUTFILEA *req = &workRequest.u.FtpPutFileA;
2462
2463         FTP_FtpPutFileA(workRequest.handle, req->lpszLocalFile,
2464                    req->lpszNewRemoteFile, req->dwFlags, req->dwContext);
2465
2466         HeapFree(GetProcessHeap(), 0, req->lpszLocalFile);
2467         HeapFree(GetProcessHeap(), 0, req->lpszNewRemoteFile);
2468         }
2469         break;
2470
2471     case FTPSETCURRENTDIRECTORYA:
2472         {
2473         struct WORKREQ_FTPSETCURRENTDIRECTORYA *req;
2474
2475         req = &workRequest.u.FtpSetCurrentDirectoryA;
2476         FTP_FtpSetCurrentDirectoryA(workRequest.handle, req->lpszDirectory);
2477         HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2478         }
2479         break;
2480
2481     case FTPCREATEDIRECTORYA:
2482         {
2483         struct WORKREQ_FTPCREATEDIRECTORYA *req;
2484
2485         req = &workRequest.u.FtpCreateDirectoryA;
2486         FTP_FtpCreateDirectoryA(workRequest.handle, req->lpszDirectory);
2487         HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2488         }
2489         break;
2490
2491     case FTPFINDFIRSTFILEA:
2492         {
2493         struct WORKREQ_FTPFINDFIRSTFILEA *req;
2494
2495         req = &workRequest.u.FtpFindFirstFileA;
2496         FTP_FtpFindFirstFileA(workRequest.handle, req->lpszSearchFile,
2497            req->lpFindFileData, req->dwFlags, req->dwContext);
2498         HeapFree(GetProcessHeap(), 0, req->lpszSearchFile);
2499         }
2500         break;
2501
2502     case FTPGETCURRENTDIRECTORYA:
2503         {
2504         struct WORKREQ_FTPGETCURRENTDIRECTORYA *req;
2505
2506         req = &workRequest.u.FtpGetCurrentDirectoryA;
2507         FTP_FtpGetCurrentDirectoryA(workRequest.handle,
2508                 req->lpszDirectory, req->lpdwDirectory);
2509         }
2510         break;
2511
2512     case FTPOPENFILEA:
2513         {
2514         struct WORKREQ_FTPOPENFILEA *req = &workRequest.u.FtpOpenFileA;
2515
2516         FTP_FtpOpenFileA(workRequest.handle, req->lpszFilename,
2517             req->dwAccess, req->dwFlags, req->dwContext);
2518         HeapFree(GetProcessHeap(), 0, req->lpszFilename);
2519         }
2520         break;
2521
2522     case FTPGETFILEA:
2523         {
2524         struct WORKREQ_FTPGETFILEA *req = &workRequest.u.FtpGetFileA;
2525
2526         FTP_FtpGetFileA(workRequest.handle, req->lpszRemoteFile,
2527                  req->lpszNewFile, req->fFailIfExists,
2528                  req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext);
2529         HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile);
2530         HeapFree(GetProcessHeap(), 0, req->lpszNewFile);
2531         }
2532         break;
2533
2534     case FTPDELETEFILEA:
2535         {
2536         struct WORKREQ_FTPDELETEFILEA *req = &workRequest.u.FtpDeleteFileA;
2537
2538         FTP_FtpDeleteFileA(workRequest.handle, req->lpszFilename);
2539         HeapFree(GetProcessHeap(), 0, req->lpszFilename);
2540         }
2541         break;
2542
2543     case FTPREMOVEDIRECTORYA:
2544         {
2545         struct WORKREQ_FTPREMOVEDIRECTORYA *req;
2546
2547         req = &workRequest.u.FtpRemoveDirectoryA;
2548         FTP_FtpRemoveDirectoryA(workRequest.handle, req->lpszDirectory);
2549         HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2550         }
2551         break;
2552
2553     case FTPRENAMEFILEA:
2554         {
2555         struct WORKREQ_FTPRENAMEFILEA *req = &workRequest.u.FtpRenameFileA;
2556
2557         FTP_FtpRenameFileA(workRequest.handle, req->lpszSrcFile, req->lpszDestFile);
2558         HeapFree(GetProcessHeap(), 0, req->lpszSrcFile);
2559         HeapFree(GetProcessHeap(), 0, req->lpszDestFile);
2560         }
2561         break;
2562
2563     case INTERNETFINDNEXTA:
2564         {
2565         struct WORKREQ_INTERNETFINDNEXTA *req;
2566
2567         req = &workRequest.u.InternetFindNextA;
2568         INTERNET_FindNextFileA(workRequest.handle, req->lpFindFileData);
2569         }
2570         break;
2571
2572     case HTTPSENDREQUESTW:
2573         {
2574         struct WORKREQ_HTTPSENDREQUESTW *req = &workRequest.u.HttpSendRequestW;
2575
2576         HTTP_HttpSendRequestW(workRequest.handle, req->lpszHeader,
2577                 req->dwHeaderLength, req->lpOptional, req->dwOptionalLength);
2578
2579         HeapFree(GetProcessHeap(), 0, req->lpszHeader);
2580         }
2581         break;
2582
2583     case HTTPOPENREQUESTW:
2584         {
2585         struct WORKREQ_HTTPOPENREQUESTW *req = &workRequest.u.HttpOpenRequestW;
2586
2587         HTTP_HttpOpenRequestW(workRequest.handle, req->lpszVerb,
2588             req->lpszObjectName, req->lpszVersion, req->lpszReferrer,
2589             req->lpszAcceptTypes, req->dwFlags, req->dwContext);
2590
2591         HeapFree(GetProcessHeap(), 0, req->lpszVerb);
2592         HeapFree(GetProcessHeap(), 0, req->lpszObjectName);
2593         HeapFree(GetProcessHeap(), 0, req->lpszVersion);
2594         HeapFree(GetProcessHeap(), 0, req->lpszReferrer);
2595         }
2596         break;
2597
2598     case SENDCALLBACK:
2599         {
2600         struct WORKREQ_SENDCALLBACK *req = &workRequest.u.SendCallback;
2601
2602         SendAsyncCallbackInt(workRequest.handle, req->hHttpSession,
2603                 req->dwContext, req->dwInternetStatus, req->lpvStatusInfo,
2604                 req->dwStatusInfoLength);
2605         }
2606         break;
2607
2608     case INTERNETOPENURLW:
2609         {
2610         struct WORKREQ_INTERNETOPENURLW *req = &workRequest.u.InternetOpenUrlW;
2611         
2612         INTERNET_InternetOpenUrlW(workRequest.handle, req->lpszUrl,
2613                                   req->lpszHeaders, req->dwHeadersLength, req->dwFlags, req->dwContext);
2614         HeapFree(GetProcessHeap(), 0, req->lpszUrl);
2615         HeapFree(GetProcessHeap(), 0, req->lpszHeaders);
2616         }
2617         break;
2618     }
2619 }
2620
2621
2622 /***********************************************************************
2623  *          INTERNET_GetResponseBuffer
2624  *
2625  * RETURNS
2626  *
2627  */
2628 LPSTR INTERNET_GetResponseBuffer()
2629 {
2630     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
2631     TRACE("\n");
2632     return lpwite->response;
2633 }
2634
2635 /***********************************************************************
2636  *           INTERNET_GetNextLine  (internal)
2637  *
2638  * Parse next line in directory string listing
2639  *
2640  * RETURNS
2641  *   Pointer to beginning of next line
2642  *   NULL on failure
2643  *
2644  */
2645
2646 LPSTR INTERNET_GetNextLine(INT nSocket, LPSTR lpszBuffer, LPDWORD dwBuffer)
2647 {
2648     struct timeval tv;
2649     fd_set infd;
2650     BOOL bSuccess = FALSE;
2651     INT nRecv = 0;
2652
2653     TRACE("\n");
2654
2655     FD_ZERO(&infd);
2656     FD_SET(nSocket, &infd);
2657     tv.tv_sec=RESPONSE_TIMEOUT;
2658     tv.tv_usec=0;
2659
2660     while (nRecv < *dwBuffer)
2661     {
2662         if (select(nSocket+1,&infd,NULL,NULL,&tv) > 0)
2663         {
2664             if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
2665             {
2666                 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
2667                 goto lend;
2668             }
2669
2670             if (lpszBuffer[nRecv] == '\n')
2671             {
2672                 bSuccess = TRUE;
2673                 break;
2674             }
2675             if (lpszBuffer[nRecv] != '\r')
2676                 nRecv++;
2677         }
2678         else
2679         {
2680             INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
2681             goto lend;
2682         }
2683     }
2684
2685 lend:
2686     if (bSuccess)
2687     {
2688         lpszBuffer[nRecv] = '\0';
2689         *dwBuffer = nRecv - 1;
2690         TRACE(":%d %s\n", nRecv, lpszBuffer);
2691         return lpszBuffer;
2692     }
2693     else
2694     {
2695         return NULL;
2696     }
2697 }
2698
2699 /***********************************************************************
2700  *
2701  */
2702 BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile,
2703                                 LPDWORD lpdwNumberOfBytesAvailble,
2704                                 DWORD dwFlags, DWORD dwConext)
2705 {
2706     LPWININETHTTPREQW lpwhr;
2707     INT retval = -1;
2708     char buffer[4048];
2709
2710
2711     lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hFile );
2712     if (NULL == lpwhr)
2713     {
2714         SetLastError(ERROR_NO_MORE_FILES);
2715         return FALSE;
2716     }
2717
2718     TRACE("-->  %p %i\n",lpwhr,lpwhr->hdr.htype);
2719
2720     switch (lpwhr->hdr.htype)
2721     {
2722     case WH_HHTTPREQ:
2723         if (!NETCON_recv(&lpwhr->netConnection, buffer,
2724                          4048, MSG_PEEK, (int *)lpdwNumberOfBytesAvailble))
2725         {
2726             SetLastError(ERROR_NO_MORE_FILES);
2727             retval = FALSE;
2728         }
2729         else
2730             retval = TRUE;
2731         break;
2732
2733     default:
2734         FIXME("unsupported file type\n");
2735         break;
2736     }
2737
2738     TRACE("<-- %i\n",retval);
2739     return (retval+1);
2740 }
2741
2742
2743 /***********************************************************************
2744  *
2745  */
2746 BOOL WINAPI InternetLockRequestFile( HINTERNET hInternet, HANDLE
2747 *lphLockReqHandle)
2748 {
2749     FIXME("STUB\n");
2750     return FALSE;
2751 }
2752
2753 BOOL WINAPI InternetUnlockRequestFile( HANDLE hLockHandle)
2754 {
2755     FIXME("STUB\n");
2756     return FALSE;
2757 }
2758
2759
2760 /***********************************************************************
2761  *           InternetAutodial
2762  *
2763  * On windows this function is supposed to dial the default internet
2764  * connection. We don't want to have Wine dial out to the internet so
2765  * we return TRUE by default. It might be nice to check if we are connected.
2766  *
2767  * RETURNS
2768  *   TRUE on success
2769  *   FALSE on failure
2770  *
2771  */
2772 BOOL WINAPI InternetAutodial(DWORD dwFlags, HWND hwndParent)
2773 {
2774     FIXME("STUB\n");
2775
2776     /* Tell that we are connected to the internet. */
2777     return TRUE;
2778 }
2779
2780 /***********************************************************************
2781  *           InternetAutodialHangup
2782  *
2783  * Hangs up an connection made with InternetAutodial
2784  *
2785  * PARAM
2786  *    dwReserved
2787  * RETURNS
2788  *   TRUE on success
2789  *   FALSE on failure
2790  *
2791  */
2792 BOOL WINAPI InternetAutodialHangup(DWORD dwReserved)
2793 {
2794     FIXME("STUB\n");
2795
2796     /* we didn't dial, we don't disconnect */
2797     return TRUE;
2798 }
2799
2800 /***********************************************************************
2801  *
2802  *         InternetCombineUrlA
2803  *
2804  * Combine a base URL with a relative URL
2805  *
2806  * RETURNS
2807  *   TRUE on success
2808  *   FALSE on failure
2809  *
2810  */
2811
2812 BOOL WINAPI InternetCombineUrlA(LPCSTR lpszBaseUrl, LPCSTR lpszRelativeUrl,
2813                                 LPSTR lpszBuffer, LPDWORD lpdwBufferLength,
2814                                 DWORD dwFlags)
2815 {
2816     HRESULT hr=S_OK;
2817
2818     TRACE("(%s, %s, %p, %p, 0x%08lx)\n", debugstr_a(lpszBaseUrl), debugstr_a(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
2819
2820     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
2821     dwFlags ^= ICU_NO_ENCODE;
2822     hr=UrlCombineA(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
2823
2824     return (hr==S_OK);
2825 }
2826
2827 /***********************************************************************
2828  *
2829  *         InternetCombineUrlW
2830  *
2831  * Combine a base URL with a relative URL
2832  *
2833  * RETURNS
2834  *   TRUE on success
2835  *   FALSE on failure
2836  *
2837  */
2838
2839 BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
2840                                 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength,
2841                                 DWORD dwFlags)
2842 {
2843     HRESULT hr=S_OK;
2844
2845     TRACE("(%s, %s, %p, %p, 0x%08lx)\n", debugstr_w(lpszBaseUrl), debugstr_w(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
2846
2847     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
2848     dwFlags ^= ICU_NO_ENCODE;
2849     hr=UrlCombineW(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
2850
2851     return (hr==S_OK);
2852 }
2853
2854 /***********************************************************************
2855  *
2856  *         InternetCreateUrlA
2857  *
2858  * RETURNS
2859  *   TRUE on success
2860  *   FALSE on failure
2861  *
2862  */
2863 BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
2864                                LPSTR lpszUrl, LPDWORD lpdwUrlLength)
2865 {
2866     FIXME("\n");
2867     return FALSE;
2868 }
2869
2870 /***********************************************************************
2871  *
2872  *         InternetCreateUrlW
2873  *
2874  * RETURNS
2875  *   TRUE on success
2876  *   FALSE on failure
2877  *
2878  */
2879 BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
2880                                LPWSTR lpszUrl, LPDWORD lpdwUrlLength)
2881 {
2882     FIXME("\n");
2883     return FALSE;
2884 }