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