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