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