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

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

JH: Resync with latest Wine + fixes/additions

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