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