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

Last change on this file since 8706 was 7291, checked in by phaller, 24 years ago

.

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