source: trunk/src/wininet/internet.c@ 4845

Last change on this file since 4845 was 4845, checked in by sandervl, 25 years ago

JH: Resync with latest Wine + fixes/additions

File size: 39.7 KB
Line 
1/* $Id: internet.c,v 1.4 2000-12-27 23:15:05 sandervl Exp $
2 *
3 * Wininet
4 *
5 * Copyright 1999 Corel Corporation
6 *
7 * Ulrich Czekalla
8 *
9 */
10
11#include <windows.h>
12#include <wininet.h>
13#include <debugtools.h>
14#include <winerror.h>
15#include <tchar.h>
16#include <winsock.h>
17#include <ipexport.h>
18#include <icmpapi.h>
19
20#ifdef __WIN32OS2__
21#include <stdlib.h>
22#include <string.h>
23#include <ctype.h>
24#define strncasecmp strnicmp
25#define TLS_OUT_OF_INDEXES -1
26#else
27#include <sys/types.h>
28#include <sys/socket.h>
29#include <stdlib.h>
30#endif
31
32#include "internet.h"
33
34DEFAULT_DEBUG_CHANNEL(wininet)
35
36#define MAX_IDLE_WORKER 1000*60*1
37#define MAX_WORKER_THREADS 10
38#define RESPONSE_TIMEOUT 30
39
40#define GET_HWININET_FROM_LPWININETFINDNEXT(lpwh)\
41(LPWININETAPPINFOA)(((LPWININETFTPSESSIONA)(lpwh->hdr.lpwhparent))->hdr.lpwhparent)
42
43typedef struct
44{
45 DWORD dwError;
46 CHAR response[ MAX_REPLY_LEN];
47} WITHREADERROR, *LPWITHREADERROR;
48
49INTERNET_SCHEME GetInternetScheme(LPCSTR lpszScheme, int nMaxCmp);
50BOOL INTERNET_FindNextFileA(HINTERNET hFind, LPVOID lpFindData);
51VOID INTERNET_ExecuteWork(void);
52
53DWORD g_dwTlsErrIndex = TLS_OUT_OF_INDEXES;
54LONG dwNumThreads;
55LONG dwNumIdleThreads;
56HANDLE hEventArray[2];
57#define hQuitEvent hEventArray[0]
58#define hWorkEvent hEventArray[1]
59CRITICAL_SECTION csQueue;
60LPWORKREQUEST lpHeadWorkQueue;
61LPWORKREQUEST lpWorkQueueTail;
62
63/***********************************************************************
64 * WININET_LibMain [Internal] Initializes the internal 'WININET.DLL'.
65 *
66 * PARAMS
67 * hinstDLL [I] handle to the 'dlls' instance
68 * fdwReason [I]
69 * lpvReserved [I] reserverd, must be NULL
70 *
71 * RETURNS
72 * Success: TRUE
73 * Failure: FALSE
74 */
75
76BOOL WINAPI
77WININET_LibMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
78{
79 TRACE("%x,%lx,%p\n", hinstDLL, fdwReason, lpvReserved);
80
81 switch (fdwReason) {
82 case DLL_PROCESS_ATTACH:
83 g_dwTlsErrIndex = TlsAlloc();
84
85 if(g_dwTlsErrIndex == TLS_OUT_OF_INDEXES)
86 return FALSE;
87
88 hQuitEvent = CreateEventA(0, TRUE, FALSE, NULL);
89 hWorkEvent = CreateEventA(0, FALSE, FALSE, NULL);
90 InitializeCriticalSection(&csQueue);
91
92 dwNumThreads=0;
93 dwNumIdleThreads=0;
94
95 case DLL_THREAD_ATTACH:
96 {
97 LPWITHREADERROR lpwite = HeapAlloc(GetProcessHeap(), 0, sizeof(WITHREADERROR));
98
99 if (NULL == lpwite)
100 return FALSE;
101
102 TlsSetValue(g_dwTlsErrIndex, (LPVOID)lpwite);
103 }
104 break;
105
106 case DLL_THREAD_DETACH:
107 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
108 {
109 LPVOID lpwite = TlsGetValue(g_dwTlsErrIndex);
110 if(lpwite)
111 HeapFree(GetProcessHeap(), 0, lpwite);
112 }
113 break;
114
115 case DLL_PROCESS_DETACH:
116 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
117 {
118 HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex));
119 TlsFree(g_dwTlsErrIndex);
120 }
121
122 SetEvent(hQuitEvent);
123
124 CloseHandle(hQuitEvent);
125 CloseHandle(hWorkEvent);
126 DeleteCriticalSection(&csQueue);
127 break;
128 }
129
130 return TRUE;
131}
132
133
134/***********************************************************************
135 * InternetOpenA (WININET.113)
136 *
137 * Per-application initialization of wininet
138 *
139 * RETURNS
140 * HINTERNET on success
141 * NULL on failure
142 *
143 */
144INTERNETAPI HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent,
145 DWORD dwAccessType, LPCSTR lpszProxy,
146 LPCSTR lpszProxyBypass, DWORD dwFlags)
147{
148 LPWININETAPPINFOA lpwai = NULL;
149
150 TRACE("InternetOpenA\n");
151
152 /* Clear any error information */
153 INTERNET_SetLastError(0);
154
155 TRACE("InternetOpenA...\n");
156
157 lpwai = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETAPPINFOA));
158 if (NULL == lpwai)
159 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
160 else
161 {
162 memset(lpwai, 0, sizeof(WININETAPPINFOA));
163 lpwai->hdr.htype = WH_HINIT;
164 lpwai->hdr.lpwhparent = NULL;
165 lpwai->hdr.dwFlags = dwFlags;
166 if (NULL != lpszAgent)
167 lpwai->lpszAgent = strdup(lpszAgent);
168 if (NULL != lpszProxy)
169 lpwai->lpszProxy = strdup(lpszProxy);
170 if (NULL != lpszProxyBypass)
171 lpwai->lpszProxyBypass = strdup(lpszProxyBypass);
172 lpwai->dwAccessType = dwAccessType;
173 }
174
175 return (HINTERNET)lpwai;
176}
177
178
179/***********************************************************************
180 * InternetGetLastResponseInfoA (WININET.108)
181 *
182 * Return last wininet error description on the calling thread
183 *
184 * RETURNS
185 * TRUE on success of writting to buffer
186 * FALSE on failure
187 *
188 */
189BOOLAPI InternetGetLastResponseInfoA(LPDWORD lpdwError,
190 LPSTR lpszBuffer, LPDWORD lpdwBufferLength)
191{
192 LPWITHREADERROR lpwite=(LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
193
194 *lpdwError = lpwite->dwError;
195 if (lpwite->dwError)
196 {
197 strncpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
198 *lpdwBufferLength = strlen( lpszBuffer);
199 }
200 else
201 *lpdwBufferLength=0;
202
203 return TRUE;
204}
205
206/***********************************************************************
207 * InternetGetConnectedState (WININET.105)
208 *
209 * Return connected state
210 *
211 * RETURNS
212 * True if connected
213 * if lpdwStatus is not NULL, return the status (off line,
214 * modem, lan...) in it.
215 * FALSE if not connected
216 */
217BOOLAPI InternetGetConnectedState(LPDWORD lpdwStatus, DWORD dwReserved)
218{
219 FIXME("Stub\n");
220 return FALSE;
221}
222
223/***********************************************************************
224 * InternetConnectA (WININET.93)
225 *
226 * Open a ftp, gopher or http session
227 *
228 * RETURNS
229 * HINTERNET a session handle on success
230 * NULL on failure
231 *
232 */
233INTERNETAPI HINTERNET WINAPI InternetConnectA(HINTERNET hInternet,
234 LPCSTR lpszServerName, INTERNET_PORT nServerPort,
235 LPCSTR lpszUserName, LPCSTR lpszPassword,
236 DWORD dwService, DWORD dwFlags, DWORD dwContext)
237{
238 HINTERNET rc = (HINTERNET) NULL;
239
240 TRACE("\n");
241
242 /* Clear any error information */
243 INTERNET_SetLastError(0);
244
245 switch (dwService)
246 {
247 case INTERNET_SERVICE_FTP:
248 rc = FTP_Connect(hInternet, lpszServerName, nServerPort,
249 lpszUserName, lpszPassword, dwFlags, dwContext);
250 break;
251
252 case INTERNET_SERVICE_HTTP:
253 rc = HTTP_Connect(hInternet, lpszServerName, nServerPort,
254 lpszUserName, lpszPassword, dwFlags, dwContext);
255 break;
256
257 case INTERNET_SERVICE_GOPHER:
258 default:
259 break;
260 }
261
262 return rc;
263}
264
265
266/***********************************************************************
267 * InternetFindNextFileA (WININET.102)
268 *
269 * Continues a file search from a previous call to FindFirstFile
270 *
271 * RETURNS
272 * TRUE on success
273 * FALSE on failure
274 *
275 */
276BOOLAPI InternetFindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
277{
278 LPWININETAPPINFOA hIC = NULL;
279 LPWININETFINDNEXTA lpwh = (LPWININETFINDNEXTA) hFind;
280
281 TRACE("\n");
282 if (NULL == lpwh || lpwh->hdr.htype != WH_HFINDNEXT)
283 {
284 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
285 return FALSE;
286 }
287
288 hIC = GET_HWININET_FROM_LPWININETFINDNEXT(lpwh);
289 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
290 {
291 WORKREQUEST workRequest;
292
293 workRequest.asyncall = INTERNETFINDNEXTA;
294 workRequest.HFTPSESSION = (DWORD)hFind;
295 workRequest.LPFINDFILEDATA = (DWORD)lpvFindData;
296
297 return INTERNET_AsyncCall(&workRequest);
298 }
299 else
300 return INTERNET_FindNextFileA(hFind, lpvFindData);
301}
302
303
304/***********************************************************************
305 * INTERNET_FindNextFileA (Internal)
306 *
307 * Continues a file search from a previous call to FindFirstFile
308 *
309 * RETURNS
310 * TRUE on success
311 * FALSE on failure
312 *
313 */
314BOOL INTERNET_FindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
315{
316 BOOL bSuccess = TRUE;
317 LPWININETAPPINFOA hIC = NULL;
318 LPWIN32_FIND_DATAA lpFindFileData;
319 LPWININETFINDNEXTA lpwh = (LPWININETFINDNEXTA) hFind;
320
321 if (NULL == lpwh || lpwh->hdr.htype != WH_HFINDNEXT)
322 {
323 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
324 return FALSE;
325 }
326
327 /* Clear any error information */
328 INTERNET_SetLastError(0);
329
330 if(lpwh->hdr.lpwhparent->htype != WH_HFTPSESSION)
331 {
332 FIXME("Only FTP find next supported\n");
333 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
334 return FALSE;
335 }
336
337 lpFindFileData = (LPWIN32_FIND_DATAA) lpvFindData;
338 memset(lpFindFileData, 0, sizeof(WIN32_FIND_DATAA));
339
340 if(lpwh->index >= lpwh->size)
341 {
342 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
343 bSuccess = FALSE;
344 goto lend;
345 }
346
347 FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
348 lpwh->index++;
349
350lend:
351 hIC = GET_HWININET_FROM_LPWININETFINDNEXT(lpwh);
352 if(hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
353 {
354 INTERNET_ASYNC_RESULT iar;
355
356 iar.dwResult = (DWORD)bSuccess;
357 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
358
359 hIC->lpfnStatusCB(hFind, lpwh->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
360 &iar, sizeof(INTERNET_ASYNC_RESULT));
361 }
362
363 return bSuccess;
364}
365
366
367/***********************************************************************
368 * INTERNET_CloseHandle (Internal)
369 *
370 * Closes internet handle
371 *
372 * RETURNS
373 * void
374 *
375 */
376void INTERNET_CloseHandle(LPWININETAPPINFOA lpwai)
377{
378 if(lpwai->lpszAgent)
379 free(lpwai->lpszAgent);
380
381 if(lpwai->lpszProxy)
382 free(lpwai->lpszProxy);
383
384 if(lpwai->lpszProxyBypass)
385 free(lpwai->lpszProxyBypass);
386
387 HeapFree(GetProcessHeap(), 0, lpwai);
388}
389
390/***********************************************************************
391 * InternetCloseHandle (WININET.89)
392 *
393 * Continues a file search from a previous call to FindFirstFile
394 *
395 * RETURNS
396 * TRUE on success
397 * FALSE on failure
398 *
399 */
400BOOLAPI InternetCloseHandle(HINTERNET hInternet)
401{
402 BOOL retval = FALSE;
403 LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hInternet;
404
405 TRACE("\n");
406 if (NULL == lpwh)
407 return FALSE;
408
409 /* Clear any error information */
410 INTERNET_SetLastError(0);
411
412 switch (lpwh->htype)
413 {
414 case WH_HINIT:
415 INTERNET_CloseHandle((LPWININETAPPINFOA) lpwh);
416 retval = TRUE;
417 break;
418
419 case WH_HHTTPSESSION:
420 HTTP_CloseHTTPSessionHandle((LPWININETHTTPSESSIONA) lpwh);
421 retval = TRUE;
422 break;
423
424 case WH_HHTTPREQ:
425 HTTP_CloseHTTPRequestHandle((LPWININETHTTPREQA) lpwh);
426 retval = TRUE;
427 break;
428
429 case WH_HFTPSESSION:
430 retval = FTP_CloseSessionHandle((LPWININETFTPSESSIONA) lpwh);
431 break;
432
433 case WH_HFINDNEXT:
434 retval = FTP_CloseFindNextHandle((LPWININETFINDNEXTA) lpwh);
435 break;
436
437 default:
438 break;
439 }
440
441 return retval;
442}
443
444/***********************************************************************
445 * SetUrlComponentValue (Internal)
446 *
447 * Helper function for InternetCrackUrlA
448 *
449 * RETURNS
450 * TRUE on success
451 * FALSE on failure
452 *
453 */
454BOOL SetUrlComponentValue(LPSTR* lppszComponent, LPDWORD dwComponentLen, LPCSTR lpszStart, INT len)
455{
456 TRACE("%s (%d)\n", lpszStart, len);
457
458 if (*dwComponentLen != 0)
459 {
460 if (*lppszComponent == NULL)
461 {
462 *lppszComponent = (LPSTR)lpszStart;
463 *dwComponentLen = len;
464 }
465 else
466 {
467 INT ncpylen = min((*dwComponentLen)-1, len);
468 strncpy(*lppszComponent, lpszStart, ncpylen);
469 (*lppszComponent)[ncpylen] = '\0';
470 *dwComponentLen = ncpylen;
471 }
472 }
473
474 return TRUE;
475}
476
477
478/***********************************************************************
479 * InternetCrackUrlA (WININET.95)
480 *
481 * Break up URL into its components
482 *
483 * RETURNS
484 * TRUE on success
485 * FALSE on failure
486 *
487 */
488BOOLAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
489 LPURL_COMPONENTSA lpUrlComponents)
490{
491 /*
492 * RFC 1808
493 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
494 *
495 */
496 LPSTR lpszParam = NULL;
497 BOOL bIsAbsolute = FALSE;
498 LPSTR lpszap = (char*)lpszUrl;
499 LPSTR lpszcp = NULL;
500
501 TRACE("\n");
502
503 /* Determine if the URI is absolute. */
504 while (*lpszap != '\0')
505 {
506 if (isalnum(*lpszap))
507 {
508 lpszap++;
509 continue;
510 }
511 if ((*lpszap == ':') && (lpszap - lpszUrl >= 2))
512 {
513 bIsAbsolute = TRUE;
514 lpszcp = lpszap;
515 }
516 else
517 {
518 lpszcp = (LPSTR)lpszUrl; /* Relative url */
519 }
520
521 break;
522 }
523
524 /* Parse <params> */
525 lpszParam = strpbrk(lpszap, ";?");
526 if (lpszParam != NULL)
527 {
528 if (!SetUrlComponentValue(&lpUrlComponents->lpszExtraInfo,
529 &lpUrlComponents->dwExtraInfoLength, lpszParam+1, strlen(lpszParam+1)))
530 {
531 return FALSE;
532 }
533 }
534
535 if (bIsAbsolute) /* Parse <protocol>:[//<net_loc>] */
536 {
537 LPSTR lpszNetLoc;
538
539 /* Get scheme first. */
540 lpUrlComponents->nScheme = GetInternetScheme(lpszUrl, lpszcp - lpszUrl);
541 if (!SetUrlComponentValue(&lpUrlComponents->lpszScheme,
542 &lpUrlComponents->dwSchemeLength, lpszUrl, lpszcp - lpszUrl))
543 return FALSE;
544
545 /* Eat ':' in protocol. */
546 lpszcp++;
547
548 /* Skip over slashes. */
549 if (*lpszcp == '/')
550 {
551 lpszcp++;
552 if (*lpszcp == '/')
553 {
554 lpszcp++;
555 if (*lpszcp == '/')
556 lpszcp++;
557 }
558 }
559
560 lpszNetLoc = strpbrk(lpszcp, "/");
561 if (lpszParam)
562 {
563 if (lpszNetLoc)
564 lpszNetLoc = min(lpszNetLoc, lpszParam);
565 else
566 lpszNetLoc = lpszParam;
567 }
568 else if (!lpszNetLoc)
569 lpszNetLoc = lpszcp + strlen(lpszcp);
570
571 /* Parse net-loc */
572 if (lpszNetLoc)
573 {
574 LPSTR lpszHost;
575 LPSTR lpszPort;
576
577 /* [<user>[<:password>]@]<host>[:<port>] */
578 /* First find the user and password if they exist */
579
580 lpszHost = strchr(lpszcp, '@');
581 if (lpszHost == NULL || lpszHost > lpszNetLoc)
582 {
583 /* username and password not specified. */
584 SetUrlComponentValue(&lpUrlComponents->lpszUserName,
585 &lpUrlComponents->dwUserNameLength, NULL, 0);
586 SetUrlComponentValue(&lpUrlComponents->lpszPassword,
587 &lpUrlComponents->dwPasswordLength, NULL, 0);
588 }
589 else /* Parse out username and password */
590 {
591 LPSTR lpszUser = lpszcp;
592 LPSTR lpszPasswd = lpszHost;
593
594 while (lpszcp < lpszHost)
595 {
596 if (*lpszcp == ':')
597 lpszPasswd = lpszcp;
598
599 lpszcp++;
600 }
601
602 SetUrlComponentValue(&lpUrlComponents->lpszUserName,
603 &lpUrlComponents->dwUserNameLength, lpszUser, lpszPasswd - lpszUser);
604
605 SetUrlComponentValue(&lpUrlComponents->lpszPassword,
606 &lpUrlComponents->dwPasswordLength,
607 lpszPasswd == lpszHost ? NULL : ++lpszPasswd,
608 lpszHost - lpszPasswd);
609
610 lpszcp++; /* Advance to beginning of host */
611 }
612
613 /* Parse <host><:port> */
614
615 lpszHost = lpszcp;
616 lpszPort = lpszNetLoc;
617
618 while (lpszcp < lpszNetLoc)
619 {
620 if (*lpszcp == ':')
621 lpszPort = lpszcp;
622
623 lpszcp++;
624 }
625
626 SetUrlComponentValue(&lpUrlComponents->lpszHostName,
627 &lpUrlComponents->dwHostNameLength, lpszHost, lpszPort - lpszHost);
628
629 if (lpszPort != lpszNetLoc)
630 lpUrlComponents->nPort = atoi(++lpszPort);
631 }
632 }
633
634 /* Here lpszcp points to:
635 *
636 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
637 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
638 */
639 if (lpszcp != 0 && *lpszcp != '\0' && (!lpszParam || lpszcp < lpszParam))
640 {
641 INT len;
642
643 /* Only truncate the parameter list if it's already been saved
644 * in lpUrlComponents->lpszExtraInfo.
645 */
646 if (lpszParam && lpUrlComponents->dwExtraInfoLength)
647 len = lpszParam - lpszcp;
648 else
649 {
650 /* Leave the parameter list in lpszUrlPath. Strip off any trailing
651 * newlines if necessary.
652 */
653 LPSTR lpsznewline = strchr (lpszcp, '\n');
654 if (lpsznewline != NULL)
655 len = lpsznewline - lpszcp;
656 else
657 len = strlen(lpszcp);
658 }
659
660 if (!SetUrlComponentValue(&lpUrlComponents->lpszUrlPath,
661 &lpUrlComponents->dwUrlPathLength, lpszcp, len))
662 return FALSE;
663 }
664 else
665 {
666 lpUrlComponents->dwUrlPathLength = 0;
667 }
668
669 TRACE("%s: host(%s) path(%s) extra(%s)\n", lpszUrl, lpUrlComponents->lpszHostName,
670 lpUrlComponents->lpszUrlPath, lpUrlComponents->lpszExtraInfo);
671
672 return TRUE;
673}
674
675
676/***********************************************************************
677 * InternetAttemptConnect (WININET.81)
678 *
679 * Attempt to make a connection to the internet
680 *
681 * RETURNS
682 * ERROR_SUCCESS on success
683 * Error value on failure
684 *
685 */
686INTERNETAPI DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
687{
688 FIXME("Stub\n");
689 return ERROR_SUCCESS;
690}
691
692
693/***********************************************************************
694 * InternetCanonicalizeUrlA (WININET.85)
695 *
696 * Escape unsafe characters and spaces
697 *
698 * RETURNS
699 * TRUE on success
700 * FALSE on failure
701 *
702 */
703BOOLAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
704 LPDWORD lpdwBufferLength, DWORD dwFlags)
705{
706 BOOL bSuccess = FALSE;
707
708 FIXME("Stub\n");
709
710 if(lpszUrl)
711 {
712 strncpy(lpszBuffer, lpszUrl, *lpdwBufferLength);
713 *lpdwBufferLength = strlen(lpszUrl);
714 bSuccess = TRUE;
715 }
716
717 return bSuccess;
718}
719
720/***********************************************************************
721 * InternetSetStatusCallback (WININET.133)
722 *
723 * Sets up a callback function which is called as progress is made
724 * during an operation.
725 *
726 * RETURNS
727 * Previous callback or NULL on success
728 * INTERNET_INVALID_STATUS_CALLBACK on failure
729 *
730 */
731INTERNETAPI INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallback(
732 HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
733{
734 INTERNET_STATUS_CALLBACK retVal;
735 LPWININETAPPINFOA lpwai = (LPWININETAPPINFOA)hInternet;
736
737 TRACE("\n");
738 if (lpwai->hdr.htype != WH_HINIT)
739 return INTERNET_INVALID_STATUS_CALLBACK;
740
741 retVal = lpwai->lpfnStatusCB;
742 lpwai->lpfnStatusCB = lpfnIntCB;
743
744 return retVal;
745}
746
747
748/***********************************************************************
749 * InternetWriteFile (WININET.138)
750 *
751 * Write data to an open internet file
752 *
753 * RETURNS
754 * TRUE on success
755 * FALSE on failure
756 *
757 */
758BOOLAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer ,
759 DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
760{
761 BOOL retval = FALSE;
762 int nSocket = INVALID_SOCKET;
763 int nBytesWritten;
764 LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hFile;
765
766 TRACE("\n");
767 if (NULL == lpwh)
768 return FALSE;
769
770 switch (lpwh->htype)
771 {
772 case WH_HHTTPREQ:
773 nSocket = ((LPWININETHTTPREQA)hFile)->nSocketFD;
774 break;
775
776 case WH_HFILE:
777 nSocket = ((LPWININETFILE)hFile)->nDataSocket;
778 break;
779
780 default:
781 break;
782 }
783
784 if (INVALID_SOCKET != nSocket)
785 {
786 nBytesWritten = INTERNET_WriteDataToStream(nSocket, lpBuffer, dwNumOfBytesToWrite);
787 if (nBytesWritten < 0)
788 *lpdwNumOfBytesWritten = 0;
789 else
790 {
791 *lpdwNumOfBytesWritten = nBytesWritten;
792 retval = TRUE;
793 }
794 }
795
796 return retval;
797}
798
799
800/***********************************************************************
801 * InternetReadFile (WININET.121)
802 *
803 * Read data from an open internet file
804 *
805 * RETURNS
806 * TRUE on success
807 * FALSE on failure
808 *
809 */
810BOOLAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
811 DWORD dwNumOfBytesToRead, LPDWORD dwNumOfBytesRead)
812{
813 BOOL retval = FALSE;
814 int nBytesRead;
815 int nSocket = INVALID_SOCKET;
816 LONG *lpBytesAvailable = 0;
817 LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hFile;
818
819 TRACE("\n");
820 if (NULL == lpwh)
821 return FALSE;
822
823 switch (lpwh->htype)
824 {
825 case WH_HHTTPREQ:
826 nSocket = ((LPWININETHTTPREQA)hFile)->nSocketFD;
827 break;
828
829 case WH_HFILE:
830 nSocket = ((LPWININETFILE)hFile)->nDataSocket;
831 lpBytesAvailable = &(((LPWININETFILE)hFile)->lBytesAvailable);
832 break;
833
834 default:
835 break;
836 }
837
838 if (INVALID_SOCKET != nSocket)
839 {
840 nBytesRead = INTERNET_ReadDataFromStream(nSocket, lpBuffer, dwNumOfBytesToRead);
841 if (nBytesRead < 0)
842 *dwNumOfBytesRead = 0;
843 else
844 {
845 *dwNumOfBytesRead = nBytesRead;
846 retval = TRUE;
847 }
848 }
849
850 if(lpBytesAvailable)
851 *lpBytesAvailable -= *dwNumOfBytesRead;
852
853 return retval;
854}
855
856/***********************************************************************
857 * InternetQueryOptionA
858 *
859 * Queries an options on the specified handle
860 *
861 * RETURNS
862 * TRUE on success
863 * FALSE on failure
864 *
865 */
866BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
867 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
868{
869 LPWININETHANDLEHEADER lpwhh;
870 BOOL bSuccess = FALSE;
871
872 TRACE("0x%08lx\n", dwOption);
873
874 if (NULL == hInternet)
875 {
876 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
877 return FALSE;
878 }
879
880 lpwhh = (LPWININETHANDLEHEADER) hInternet;
881
882 switch (dwOption)
883 {
884 case INTERNET_OPTION_HANDLE_TYPE:
885 {
886 ULONG type = lpwhh->htype;
887 TRACE("INTERNET_OPTION_HANDLE_TYPE: %ld\n", type);
888
889 if (*lpdwBufferLength < sizeof(ULONG))
890 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
891 else
892 {
893 memcpy(lpBuffer, &type, sizeof(ULONG));
894 *lpdwBufferLength = sizeof(ULONG);
895 bSuccess = TRUE;
896 }
897
898 break;
899 }
900
901 default:
902 FIXME("Stub!");
903 break;
904 }
905
906 return bSuccess;
907}
908
909
910/***********************************************************************
911 * GetInternetScheme (internal)
912 *
913 * Get scheme of url
914 *
915 * RETURNS
916 * scheme on success
917 * INTERNET_SCHEME_UNKNOWN on failure
918 *
919 */
920INTERNET_SCHEME GetInternetScheme(LPCSTR lpszScheme, int nMaxCmp)
921{
922 if(lpszScheme==NULL)
923 return INTERNET_SCHEME_UNKNOWN;
924
925 if( (strncasecmp("ftp", lpszScheme, nMaxCmp) == 0))
926 return INTERNET_SCHEME_FTP;
927
928 else if( (strncasecmp("gopher", lpszScheme, nMaxCmp) == 0))
929 return INTERNET_SCHEME_GOPHER;
930
931 else if( (strncasecmp("http", lpszScheme, nMaxCmp) == 0))
932 return INTERNET_SCHEME_HTTP;
933
934 else if( (strncasecmp("https", lpszScheme, nMaxCmp) == 0))
935 return INTERNET_SCHEME_HTTPS;
936
937 else if( (strncasecmp("file", lpszScheme, nMaxCmp) == 0))
938 return INTERNET_SCHEME_FILE;
939
940 else if( (strncasecmp("news", lpszScheme, nMaxCmp) == 0))
941 return INTERNET_SCHEME_NEWS;
942
943 else if( (strncasecmp("mailto", lpszScheme, nMaxCmp) == 0))
944 return INTERNET_SCHEME_MAILTO;
945 else
946 return INTERNET_SCHEME_UNKNOWN;
947}
948
949/***********************************************************************
950 * InternetCheckConnectionA
951 *
952 * Pings a requested host to check internet connection
953 *
954 * RETURNS
955 * TRUE on success and FALSE on failure.
956 * On failure ERROR_NOT_CONNECTED is placed into GetLastError
957 */
958BOOLAPI InternetCheckConnectionA( LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
959{
960 /* Instead of WINE's shelling out and executing a 'ping' we'll use the */
961 /* ICMP.DLL instead. */
962 DWORD rc=0;
963 HANDLE hIcmp;
964 char RequestBuffer[]="Odin - PING request, please reply...";
965 char lpszHost[1024],ReplyBuffer[256];
966 URL_COMPONENTSA UrlComponents;
967 ULONG dest_addr;
968 struct hostent *host;
969
970 if(!lpszUrl)
971 {
972 FIXME("Unimplemented with URL of NULL\n");
973 return TRUE;
974 }
975
976 memset(&UrlComponents, 0, sizeof(URL_COMPONENTSA));
977
978 UrlComponents.lpszHostName = lpszHost;
979 UrlComponents.dwHostNameLength = 1024;
980
981 if(!InternetCrackUrlA(lpszUrl, 0, 0, &UrlComponents))
982 {
983 INTERNET_SetLastError(ERROR_NOT_CONNECTED);
984 return FALSE;
985 }
986
987 hIcmp = IcmpCreateFile();
988
989 if(!hIcmp)
990 {
991 INTERNET_SetLastError(ERROR_NOT_CONNECTED);
992 return FALSE;
993 }
994
995 dest_addr = inet_addr(lpszHost);
996
997 if(dest_addr == 0)
998 host = gethostbyname(lpszHost);
999 else
1000 host = gethostbyaddr(lpszHost, strlen(lpszHost), PF_INET);
1001
1002 if(host->h_addr)
1003 rc=IcmpSendEcho(hIcmp,
1004 (IPAddr)host->h_addr,
1005 RequestBuffer,
1006 strlen(RequestBuffer),
1007 NULL,
1008 ReplyBuffer,
1009 256,
1010 5000);
1011 else
1012 rc = 0;
1013
1014 IcmpCloseHandle(hIcmp);
1015
1016 return rc>0;
1017}
1018
1019/***********************************************************************
1020 * WriteDataToStream (internal)
1021 *
1022 * Send data to server
1023 *
1024 * RETURNS
1025 *
1026 * number of characters sent on success
1027 * -1 on error
1028 */
1029int INTERNET_WriteDataToStream(int nDataSocket, LPCVOID Buffer, DWORD BytesToWrite)
1030{
1031 if (INVALID_SOCKET == nDataSocket)
1032 return SOCKET_ERROR;
1033
1034 return send(nDataSocket, Buffer, BytesToWrite, 0);
1035}
1036
1037
1038/***********************************************************************
1039 * INTERNET_ReadDataFromStream (internal)
1040 *
1041 * Read data from http server
1042 *
1043 * RETURNS
1044 *
1045 * number of characters sent on success
1046 * -1 on error
1047 */
1048int INTERNET_ReadDataFromStream(int nDataSocket, LPVOID Buffer, DWORD BytesToRead)
1049{
1050 if (INVALID_SOCKET == nDataSocket)
1051 return SOCKET_ERROR;
1052
1053 return recv(nDataSocket, Buffer, BytesToRead, 0);
1054}
1055
1056
1057/***********************************************************************
1058 * INTERNET_SetLastError (internal)
1059 *
1060 * Set last thread specific error
1061 *
1062 * RETURNS
1063 *
1064 */
1065void INTERNET_SetLastError(DWORD dwError)
1066{
1067 LPWITHREADERROR lpwite;
1068
1069 lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
1070
1071 SetLastError(dwError);
1072 lpwite->dwError = dwError;
1073}
1074
1075
1076/************************************************************************
1077 * INTERNET_GetLastError (internal)
1078 *
1079 * Get last thread specific error
1080 *
1081 * RETURNS
1082 *
1083 */
1084DWORD INTERNET_GetLastError()
1085{
1086 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
1087 return lpwite->dwError;
1088}
1089
1090
1091/************************************************************************
1092 * INTERNET_WorkerThreadFunc (internal)
1093 *
1094 * Worker thread execution function
1095 *
1096 * RETURNS
1097 *
1098 */
1099DWORD INTERNET_WorkerThreadFunc(LPVOID *lpvParam)
1100{
1101 DWORD dwWaitRes;
1102
1103 while (1)
1104 {
1105 dwWaitRes = WaitForMultipleObjects(2, hEventArray, FALSE, MAX_IDLE_WORKER);
1106
1107 if (dwWaitRes == WAIT_OBJECT_0 + 1)
1108 INTERNET_ExecuteWork();
1109 else
1110 break;
1111
1112 InterlockedIncrement(&dwNumIdleThreads);
1113 }
1114
1115 InterlockedDecrement(&dwNumIdleThreads);
1116 InterlockedDecrement(&dwNumThreads);
1117 TRACE("Worker thread exiting\n");
1118 return TRUE;
1119}
1120
1121
1122/************************************************************************
1123 * INTERNET_InsertWorkRequest (internal)
1124 *
1125 * Insert work request into queue
1126 *
1127 * RETURNS
1128 *
1129 */
1130BOOL INTERNET_InsertWorkRequest(LPWORKREQUEST lpWorkRequest)
1131{
1132 BOOL bSuccess = FALSE;
1133 LPWORKREQUEST lpNewRequest;
1134
1135 TRACE("\n");
1136
1137 lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
1138 if (lpNewRequest)
1139 {
1140 memcpy(lpNewRequest, lpWorkRequest, sizeof(WORKREQUEST));
1141 lpNewRequest->prev = NULL;
1142
1143 EnterCriticalSection(&csQueue);
1144
1145 lpNewRequest->next = lpWorkQueueTail;
1146 if (lpWorkQueueTail)
1147 lpWorkQueueTail->prev = lpNewRequest;
1148 lpWorkQueueTail = lpNewRequest;
1149 if (!lpHeadWorkQueue)
1150 lpHeadWorkQueue = lpWorkQueueTail;
1151
1152 LeaveCriticalSection(&csQueue);
1153
1154 bSuccess = TRUE;
1155 }
1156
1157 return bSuccess;
1158}
1159
1160
1161/************************************************************************
1162 * INTERNET_GetWorkRequest (internal)
1163 *
1164 * Retrieves work request from queue
1165 *
1166 * RETURNS
1167 *
1168 */
1169BOOL INTERNET_GetWorkRequest(LPWORKREQUEST lpWorkRequest)
1170{
1171 BOOL bSuccess = FALSE;
1172 LPWORKREQUEST lpRequest = NULL;
1173
1174 TRACE("\n");
1175
1176 EnterCriticalSection(&csQueue);
1177
1178 if (lpHeadWorkQueue)
1179 {
1180 lpRequest = lpHeadWorkQueue;
1181 lpHeadWorkQueue = lpHeadWorkQueue->prev;
1182 if (lpRequest == lpWorkQueueTail)
1183 lpWorkQueueTail = lpHeadWorkQueue;
1184 }
1185
1186 LeaveCriticalSection(&csQueue);
1187
1188 if (lpRequest)
1189 {
1190 memcpy(lpWorkRequest, lpRequest, sizeof(WORKREQUEST));
1191 HeapFree(GetProcessHeap(), 0, lpRequest);
1192 bSuccess = TRUE;
1193 }
1194
1195 return bSuccess;
1196}
1197
1198
1199/************************************************************************
1200 * INTERNET_AsyncCall (internal)
1201 *
1202 * Retrieves work request from queue
1203 *
1204 * RETURNS
1205 *
1206 */
1207BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
1208{
1209 HANDLE hThread;
1210 DWORD dwTID;
1211 BOOL bSuccess = FALSE;
1212
1213 TRACE("\n");
1214
1215 if (InterlockedDecrement(&dwNumIdleThreads) < 0)
1216 {
1217 InterlockedIncrement(&dwNumIdleThreads);
1218
1219 if (InterlockedIncrement(&dwNumThreads) > MAX_WORKER_THREADS ||
1220 !(hThread = CreateThread(NULL, 0,
1221 (LPTHREAD_START_ROUTINE)INTERNET_WorkerThreadFunc, NULL, 0, &dwTID)))
1222 {
1223 InterlockedDecrement(&dwNumThreads);
1224 INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED);
1225 goto lerror;
1226 }
1227
1228 TRACE("Created new thread\n");
1229 }
1230
1231 bSuccess = TRUE;
1232 INTERNET_InsertWorkRequest(lpWorkRequest);
1233 SetEvent(hWorkEvent);
1234
1235lerror:
1236
1237 return bSuccess;
1238}
1239
1240
1241/************************************************************************
1242 * INTERNET_ExecuteWork (internal)
1243 *
1244 * RETURNS
1245 *
1246 */
1247VOID INTERNET_ExecuteWork()
1248{
1249 WORKREQUEST workRequest;
1250
1251 TRACE("\n");
1252
1253 if (INTERNET_GetWorkRequest(&workRequest))
1254 {
1255 switch (workRequest.asyncall)
1256 {
1257 case FTPPUTFILEA:
1258 FTP_FtpPutFileA((HINTERNET)workRequest.HFTPSESSION, (LPCSTR)workRequest.LPSZLOCALFILE,
1259 (LPCSTR)workRequest.LPSZNEWREMOTEFILE, workRequest.DWFLAGS, workRequest.DWCONTEXT);
1260 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZLOCALFILE);
1261 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZNEWREMOTEFILE);
1262 break;
1263
1264 case FTPSETCURRENTDIRECTORYA:
1265 FTP_FtpSetCurrentDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1266 (LPCSTR)workRequest.LPSZDIRECTORY);
1267 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDIRECTORY);
1268 break;
1269
1270 case FTPCREATEDIRECTORYA:
1271 FTP_FtpCreateDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1272 (LPCSTR)workRequest.LPSZDIRECTORY);
1273 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDIRECTORY);
1274 break;
1275
1276 case FTPFINDFIRSTFILEA:
1277 FTP_FtpFindFirstFileA((HINTERNET)workRequest.HFTPSESSION,
1278 (LPCSTR)workRequest.LPSZSEARCHFILE,
1279 (LPWIN32_FIND_DATAA)workRequest.LPFINDFILEDATA, workRequest.DWFLAGS,
1280 workRequest.DWCONTEXT);
1281 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZSEARCHFILE);
1282 break;
1283
1284 case FTPGETCURRENTDIRECTORYA:
1285 FTP_FtpGetCurrentDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1286 (LPSTR)workRequest.LPSZDIRECTORY, (LPDWORD)workRequest.LPDWDIRECTORY);
1287 break;
1288
1289 case FTPOPENFILEA:
1290 FTP_FtpOpenFileA((HINTERNET)workRequest.HFTPSESSION,
1291 (LPCSTR)workRequest.LPSZFILENAME,
1292 workRequest.FDWACCESS,
1293 workRequest.DWFLAGS,
1294 workRequest.DWCONTEXT);
1295 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZFILENAME);
1296 break;
1297
1298 case FTPGETFILEA:
1299 FTP_FtpGetFileA((HINTERNET)workRequest.HFTPSESSION,
1300 (LPCSTR)workRequest.LPSZREMOTEFILE,
1301 (LPCSTR)workRequest.LPSZNEWFILE,
1302 (BOOL)workRequest.FFAILIFEXISTS,
1303 workRequest.DWLOCALFLAGSATTRIBUTE,
1304 workRequest.DWFLAGS,
1305 workRequest.DWCONTEXT);
1306 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZREMOTEFILE);
1307 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZNEWFILE);
1308 break;
1309
1310 case FTPDELETEFILEA:
1311 FTP_FtpDeleteFileA((HINTERNET)workRequest.HFTPSESSION,
1312 (LPCSTR)workRequest.LPSZFILENAME);
1313 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZFILENAME);
1314 break;
1315
1316 case FTPREMOVEDIRECTORYA:
1317 FTP_FtpRemoveDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1318 (LPCSTR)workRequest.LPSZDIRECTORY);
1319 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDIRECTORY);
1320 break;
1321
1322 case FTPRENAMEFILEA:
1323 FTP_FtpRenameFileA((HINTERNET)workRequest.HFTPSESSION,
1324 (LPCSTR)workRequest.LPSZSRCFILE,
1325 (LPCSTR)workRequest.LPSZDESTFILE);
1326 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZSRCFILE);
1327 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDESTFILE);
1328 break;
1329
1330 case INTERNETFINDNEXTA:
1331 INTERNET_FindNextFileA((HINTERNET)workRequest.HFTPSESSION,
1332 (LPWIN32_FIND_DATAA)workRequest.LPFINDFILEDATA);
1333 break;
1334
1335 case HTTPSENDREQUESTA:
1336 HTTP_HttpSendRequestA((HINTERNET)workRequest.HFTPSESSION,
1337 (LPCSTR)workRequest.LPSZHEADER,
1338 workRequest.DWHEADERLENGTH,
1339 (LPVOID)workRequest.LPOPTIONAL,
1340 workRequest.DWOPTIONALLENGTH);
1341 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZHEADER);
1342 break;
1343
1344 case HTTPOPENREQUESTA:
1345 HTTP_HttpOpenRequestA((HINTERNET)workRequest.HFTPSESSION,
1346 (LPCSTR)workRequest.LPSZVERB,
1347 (LPCSTR)workRequest.LPSZOBJECTNAME,
1348 (LPCSTR)workRequest.LPSZVERSION,
1349 (LPCSTR)workRequest.LPSZREFERRER,
1350 (LPCSTR*)workRequest.LPSZACCEPTTYPES,
1351 workRequest.DWFLAGS,
1352 workRequest.DWCONTEXT);
1353 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZVERB);
1354 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZOBJECTNAME);
1355 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZVERSION);
1356 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZREFERRER);
1357 break;
1358
1359 }
1360 }
1361}
1362
1363
1364/************************************************************************
1365 * INTERNET_GetResponseBuffer
1366 *
1367 * RETURNS
1368 *
1369 */
1370LPSTR INTERNET_GetResponseBuffer()
1371{
1372 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
1373 return lpwite->response;
1374}
1375
1376
1377/************************************************************************
1378 * INTERNET_GetNextLine (internal)
1379 *
1380 * Parse next line in directory string listing
1381 *
1382 * RETURNS
1383 * Pointer to begining of next line
1384 * NULL on failure
1385 *
1386 */
1387LPSTR INTERNET_GetNextLine(INT nSocket, LPSTR lpszBuffer, LPDWORD dwBuffer)
1388{
1389 struct timeval tv;
1390 fd_set infd;
1391 BOOL bSuccess = FALSE;
1392 INT nRecv = 0;
1393
1394 TRACE("\n");
1395
1396 FD_ZERO(&infd);
1397 FD_SET(nSocket, &infd);
1398 tv.tv_sec=RESPONSE_TIMEOUT;
1399 tv.tv_usec=0;
1400
1401 while (nRecv < *dwBuffer)
1402 {
1403 if (select(nSocket+1,&infd,NULL,NULL,&tv) > 0)
1404 {
1405 if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
1406 {
1407 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1408 goto lend;
1409 }
1410
1411 if (lpszBuffer[nRecv] == '\n')
1412 {
1413 bSuccess = TRUE;
1414 break;
1415 }
1416 if (lpszBuffer[nRecv] != '\r')
1417 nRecv++;
1418 }
1419 else
1420 {
1421 INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
1422 goto lend;
1423}
1424 }
1425
1426lend:
1427 if (bSuccess)
1428 {
1429 lpszBuffer[nRecv] = '\0';
1430 *dwBuffer = nRecv - 1;
1431 TRACE(":%d %s\n", nRecv, lpszBuffer);
1432 return lpszBuffer;
1433 }
1434 else
1435 {
1436 return NULL;
1437 }
1438}
1439
1440
1441/************************************************************************
1442 * InternetQueryDataAvailable (WININET.118)
1443 *
1444 * Fetch the amount of data available for retrieval
1445 *
1446 * RETURNS
1447 * TRUE on success
1448 * FALSE on failure
1449 *
1450 */
1451BOOL WINAPI InternetQueryDataAvailable(HINTERNET hFile,LPDWORD lpdwNumberOfBytesAvailable,
1452 DWORD dwFlags, DWORD dwContext)
1453{
1454 LONG lBytesAvailable;
1455 LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hFile;
1456
1457 if (NULL == lpwh)
1458 {
1459 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1460 return FALSE;
1461 }
1462
1463 WriteLog("InternetQueryDataAvailable for hHandle %08x",lpwh);
1464
1465 switch (lpwh->htype)
1466 {
1467 case WH_HHTTPREQ:
1468 *lpdwNumberOfBytesAvailable = -1;
1469 break;
1470
1471 case WH_HFILE:
1472 *lpdwNumberOfBytesAvailable = ((LPWININETFILE)lpwh)->lBytesAvailable;
1473 break;
1474
1475 default:
1476 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1477 return FALSE;
1478 }
1479
1480 if(*lpdwNumberOfBytesAvailable == -1)
1481 return FALSE;
1482
1483 WriteLog("InternetQueryDataAvailable returns %d",*lpdwNumberOfBytesAvailable);
1484
1485 return TRUE;
1486}
Note: See TracBrowser for help on using the repository browser.