Removed some unnecessary #includes and dll dependencies.
[wine/multimedia.git] / dlls / wininet / internet.c
blobae5ce189b5cc4a1973a7641508eb28b38a4788f3
1 /*
2 * Wininet
4 * Copyright 1999 Corel Corporation
6 * Ulrich Czekalla
8 */
10 #include "config.h"
12 #include <string.h>
13 #include <sys/types.h>
14 #ifdef HAVE_SYS_SOCKET_H
15 # include <sys/socket.h>
16 #endif
17 #include <stdlib.h>
18 #include <ctype.h>
20 #include "windows.h"
21 #include "wininet.h"
22 #include "debugtools.h"
23 #include "winerror.h"
24 #include "winsock.h"
25 #include "heap.h"
27 #include "internet.h"
29 DEFAULT_DEBUG_CHANNEL(wininet);
31 #define MAX_IDLE_WORKER 1000*60*1
32 #define MAX_WORKER_THREADS 10
33 #define RESPONSE_TIMEOUT 30
35 #define GET_HWININET_FROM_LPWININETFINDNEXT(lpwh) \
36 (LPWININETAPPINFOA)(((LPWININETFTPSESSIONA)(lpwh->hdr.lpwhparent))->hdr.lpwhparent)
38 typedef struct
40 DWORD dwError;
41 CHAR response[MAX_REPLY_LEN];
42 } WITHREADERROR, *LPWITHREADERROR;
44 INTERNET_SCHEME GetInternetScheme(LPCSTR lpszScheme, INT nMaxCmp);
45 BOOL WINAPI INTERNET_FindNextFileA(HINTERNET hFind, LPVOID lpvFindData);
46 VOID INTERNET_ExecuteWork();
48 DWORD g_dwTlsErrIndex = TLS_OUT_OF_INDEXES;
49 DWORD dwNumThreads;
50 DWORD dwNumIdleThreads;
51 HANDLE hEventArray[2];
52 #define hQuitEvent hEventArray[0]
53 #define hWorkEvent hEventArray[1]
54 CRITICAL_SECTION csQueue;
55 LPWORKREQUEST lpHeadWorkQueue;
56 LPWORKREQUEST lpWorkQueueTail;
58 /***********************************************************************
59 * WININET_LibMain [Internal] Initializes the internal 'WININET.DLL'.
61 * PARAMS
62 * hinstDLL [I] handle to the DLL's instance
63 * fdwReason [I]
64 * lpvReserved [I] reserved, must be NULL
66 * RETURNS
67 * Success: TRUE
68 * Failure: FALSE
71 BOOL WINAPI
72 WININET_LibMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
74 TRACE("%x,%lx,%p\n", hinstDLL, fdwReason, lpvReserved);
76 switch (fdwReason) {
77 case DLL_PROCESS_ATTACH:
79 g_dwTlsErrIndex = TlsAlloc();
81 if (g_dwTlsErrIndex == TLS_OUT_OF_INDEXES)
82 return FALSE;
84 hQuitEvent = CreateEventA(0, TRUE, FALSE, NULL);
85 hWorkEvent = CreateEventA(0, FALSE, FALSE, NULL);
86 InitializeCriticalSection(&csQueue);
88 dwNumThreads = 0;
89 dwNumIdleThreads = 0;
91 case DLL_THREAD_ATTACH:
93 LPWITHREADERROR lpwite = HeapAlloc(GetProcessHeap(), 0, sizeof(WITHREADERROR));
94 if (NULL == lpwite)
95 return FALSE;
97 TlsSetValue(g_dwTlsErrIndex, (LPVOID)lpwite);
99 break;
101 case DLL_THREAD_DETACH:
102 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
104 LPVOID lpwite = TlsGetValue(g_dwTlsErrIndex);
105 if (lpwite)
106 HeapFree(GetProcessHeap(), 0, lpwite);
108 break;
110 case DLL_PROCESS_DETACH:
112 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
114 HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex));
115 TlsFree(g_dwTlsErrIndex);
118 SetEvent(hQuitEvent);
120 CloseHandle(hQuitEvent);
121 CloseHandle(hWorkEvent);
122 DeleteCriticalSection(&csQueue);
123 break;
126 return TRUE;
130 /***********************************************************************
131 * InternetOpenA (WININET.113)
133 * Per-application initialization of wininet
135 * RETURNS
136 * HINTERNET on success
137 * NULL on failure
140 INTERNETAPI HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent,
141 DWORD dwAccessType, LPCSTR lpszProxy,
142 LPCSTR lpszProxyBypass, DWORD dwFlags)
144 LPWININETAPPINFOA lpwai = NULL;
146 TRACE("\n");
148 /* Clear any error information */
149 INTERNET_SetLastError(0);
151 lpwai = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETAPPINFOA));
152 if (NULL == lpwai)
153 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
154 else
156 memset(lpwai, 0, sizeof(WININETAPPINFOA));
157 lpwai->hdr.htype = WH_HINIT;
158 lpwai->hdr.lpwhparent = NULL;
159 lpwai->hdr.dwFlags = dwFlags;
160 if (NULL != lpszAgent)
161 lpwai->lpszAgent = HEAP_strdupA(GetProcessHeap(),0,lpszAgent);
162 if (NULL != lpszProxy)
163 lpwai->lpszProxy = HEAP_strdupA(GetProcessHeap(),0,lpszProxy);
164 if (NULL != lpszProxyBypass)
165 lpwai->lpszProxyBypass = HEAP_strdupA(GetProcessHeap(),0,lpszProxyBypass);
166 lpwai->dwAccessType = dwAccessType;
169 return (HINTERNET)lpwai;
173 /***********************************************************************
174 * InternetGetLastResponseInfoA (WININET.108)
176 * Return last wininet error description on the calling thread
178 * RETURNS
179 * TRUE on success of writting to buffer
180 * FALSE on failure
183 BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError,
184 LPSTR lpszBuffer, LPDWORD lpdwBufferLength)
186 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
188 TRACE("\n");
190 *lpdwError = lpwite->dwError;
191 if (lpwite->dwError)
193 strncpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
194 *lpdwBufferLength = strlen(lpszBuffer);
196 else
197 *lpdwBufferLength = 0;
199 return TRUE;
203 /***********************************************************************
204 * InternetGetConnectedState (WININET.103)
206 * Return connected state
208 * RETURNS
209 * TRUE if connected
210 * if lpdwStatus is not null, return the status (off line,
211 * modem, lan...) in it.
212 * FALSE if not connected
214 BOOL WINAPI InternetGetConnectedState(LPDWORD lpdwStatus, DWORD dwReserved)
216 FIXME("Stub\n");
217 return FALSE;
221 /***********************************************************************
222 * InternetConnectA (WININET.93)
224 * Open a ftp, gopher or http session
226 * RETURNS
227 * HINTERNET a session handle on success
228 * NULL on failure
231 INTERNETAPI HINTERNET WINAPI InternetConnectA(HINTERNET hInternet,
232 LPCSTR lpszServerName, INTERNET_PORT nServerPort,
233 LPCSTR lpszUserName, LPCSTR lpszPassword,
234 DWORD dwService, DWORD dwFlags, DWORD dwContext)
236 HINTERNET rc = (HINTERNET) NULL;
238 TRACE("\n");
240 /* Clear any error information */
241 INTERNET_SetLastError(0);
243 switch (dwService)
245 case INTERNET_SERVICE_FTP:
246 rc = FTP_Connect(hInternet, lpszServerName, nServerPort,
247 lpszUserName, lpszPassword, dwFlags, dwContext);
248 break;
250 case INTERNET_SERVICE_HTTP:
251 rc = HTTP_Connect(hInternet, lpszServerName, nServerPort,
252 lpszUserName, lpszPassword, dwFlags, dwContext);
253 break;
255 case INTERNET_SERVICE_GOPHER:
256 default:
257 break;
260 return rc;
263 /***********************************************************************
264 * InternetFindNextFileA (WININET.102)
266 * Continues a file search from a previous call to FindFirstFile
268 * RETURNS
269 * TRUE on success
270 * FALSE on failure
273 BOOL WINAPI InternetFindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
275 LPWININETAPPINFOA hIC = NULL;
276 LPWININETFINDNEXTA lpwh = (LPWININETFINDNEXTA) hFind;
278 TRACE("\n");
280 if (NULL == lpwh || lpwh->hdr.htype != WH_HFINDNEXT)
282 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
283 return FALSE;
286 hIC = GET_HWININET_FROM_LPWININETFINDNEXT(lpwh);
287 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
289 WORKREQUEST workRequest;
291 workRequest.asyncall = INTERNETFINDNEXTA;
292 workRequest.HFTPSESSION = (DWORD)hFind;
293 workRequest.LPFINDFILEDATA = (DWORD)lpvFindData;
295 return INTERNET_AsyncCall(&workRequest);
297 else
299 return INTERNET_FindNextFileA(hFind, lpvFindData);
303 /***********************************************************************
304 * INTERNET_FindNextFileA (Internal)
306 * Continues a file search from a previous call to FindFirstFile
308 * RETURNS
309 * TRUE on success
310 * FALSE on failure
313 BOOL WINAPI INTERNET_FindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
315 BOOL bSuccess = TRUE;
316 LPWININETAPPINFOA hIC = NULL;
317 LPWIN32_FIND_DATAA lpFindFileData;
318 LPWININETFINDNEXTA lpwh = (LPWININETFINDNEXTA) hFind;
320 TRACE("\n");
322 if (NULL == lpwh || lpwh->hdr.htype != WH_HFINDNEXT)
324 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
325 return FALSE;
328 /* Clear any error information */
329 INTERNET_SetLastError(0);
331 if (lpwh->hdr.lpwhparent->htype != WH_HFTPSESSION)
333 FIXME("Only FTP find next supported\n");
334 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
335 return FALSE;
338 TRACE("index(%d) size(%ld)\n", lpwh->index, lpwh->size);
340 lpFindFileData = (LPWIN32_FIND_DATAA) lpvFindData;
341 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
343 if (lpwh->index >= lpwh->size)
345 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
346 bSuccess = FALSE;
347 goto lend;
350 FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
351 lpwh->index++;
353 TRACE("\nName: %s\nSize: %ld\n", lpFindFileData->cFileName, lpFindFileData->nFileSizeLow);
355 lend:
357 hIC = GET_HWININET_FROM_LPWININETFINDNEXT(lpwh);
358 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
360 INTERNET_ASYNC_RESULT iar;
362 iar.dwResult = (DWORD)bSuccess;
363 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
365 hIC->lpfnStatusCB(hFind, lpwh->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
366 &iar, sizeof(INTERNET_ASYNC_RESULT));
369 return bSuccess;
373 /***********************************************************************
374 * INTERNET_CloseHandle (internal)
376 * Close internet handle
378 * RETURNS
379 * Void
382 VOID INTERNET_CloseHandle(LPWININETAPPINFOA lpwai)
384 if (lpwai->lpszAgent)
385 HeapFree(GetProcessHeap(), 0, lpwai->lpszAgent);
387 if (lpwai->lpszProxy)
388 HeapFree(GetProcessHeap(), 0, lpwai->lpszProxy);
390 if (lpwai->lpszProxyBypass)
391 HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyBypass);
393 HeapFree(GetProcessHeap(), 0, lpwai);
397 /***********************************************************************
398 * InternetCloseHandle (WININET.89)
400 * Generic close handle function
402 * RETURNS
403 * TRUE on success
404 * FALSE on failure
407 BOOL WINAPI InternetCloseHandle(HINTERNET hInternet)
409 BOOL retval = FALSE;
410 LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hInternet;
412 TRACE("\n");
413 if (NULL == lpwh)
414 return FALSE;
416 /* Clear any error information */
417 INTERNET_SetLastError(0);
419 switch (lpwh->htype)
421 case WH_HINIT:
422 INTERNET_CloseHandle((LPWININETAPPINFOA) lpwh);
423 break;
425 case WH_HHTTPSESSION:
426 HTTP_CloseHTTPSessionHandle((LPWININETHTTPSESSIONA) lpwh);
427 break;
429 case WH_HHTTPREQ:
430 HTTP_CloseHTTPRequestHandle((LPWININETHTTPREQA) lpwh);
431 break;
433 case WH_HFTPSESSION:
434 retval = FTP_CloseSessionHandle((LPWININETFTPSESSIONA) lpwh);
435 break;
437 case WH_HFINDNEXT:
438 retval = FTP_CloseFindNextHandle((LPWININETFINDNEXTA) lpwh);
439 break;
441 default:
442 break;
445 return retval;
449 /***********************************************************************
450 * SetUrlComponentValue (Internal)
452 * Helper function for InternetCrackUrlA
454 * RETURNS
455 * TRUE on success
456 * FALSE on failure
459 BOOL SetUrlComponentValue(LPSTR* lppszComponent, LPDWORD dwComponentLen, LPCSTR lpszStart, INT len)
461 TRACE("%s (%d)\n", lpszStart, len);
463 if (*dwComponentLen != 0)
465 if (*lppszComponent == NULL)
467 *lppszComponent = (LPSTR)lpszStart;
468 *dwComponentLen = len;
470 else
472 INT ncpylen = min((*dwComponentLen)-1, len);
473 strncpy(*lppszComponent, lpszStart, ncpylen);
474 (*lppszComponent)[ncpylen] = '\0';
475 *dwComponentLen = ncpylen;
479 return TRUE;
483 /***********************************************************************
484 * InternetCrackUrlA (WININET.95)
486 * Break up URL into its components
488 * TODO: Hadnle dwFlags
490 * RETURNS
491 * TRUE on success
492 * FALSE on failure
495 BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
496 LPURL_COMPONENTSA lpUrlComponents)
499 * RFC 1808
500 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
503 LPSTR lpszParam = NULL;
504 BOOL bIsAbsolute = FALSE;
505 LPSTR lpszap = (char*)lpszUrl;
506 LPSTR lpszcp = NULL;
508 TRACE("\n");
510 /* Determine if the URI is absolute. */
511 while (*lpszap != '\0')
513 if (isalnum(*lpszap))
515 lpszap++;
516 continue;
518 if ((*lpszap == ':') && (lpszap - lpszUrl >= 2))
520 bIsAbsolute = TRUE;
521 lpszcp = lpszap;
523 else
525 lpszcp = (LPSTR)lpszUrl; /* Relative url */
528 break;
531 /* Parse <params> */
532 lpszParam = strpbrk(lpszap, ";?");
533 if (lpszParam != NULL)
535 if (!SetUrlComponentValue(&lpUrlComponents->lpszExtraInfo,
536 &lpUrlComponents->dwExtraInfoLength, lpszParam+1, strlen(lpszParam+1)))
538 return FALSE;
542 if (bIsAbsolute) /* Parse <protocol>:[//<net_loc>] */
544 LPSTR lpszNetLoc;
546 /* Get scheme first. */
547 lpUrlComponents->nScheme = GetInternetScheme(lpszUrl, lpszcp - lpszUrl);
548 if (!SetUrlComponentValue(&lpUrlComponents->lpszScheme,
549 &lpUrlComponents->dwSchemeLength, lpszUrl, lpszcp - lpszUrl))
550 return FALSE;
552 /* Eat ':' in protocol. */
553 lpszcp++;
555 /* Skip over slashes. */
556 if (*lpszcp == '/')
558 lpszcp++;
559 if (*lpszcp == '/')
561 lpszcp++;
562 if (*lpszcp == '/')
563 lpszcp++;
567 lpszNetLoc = strpbrk(lpszcp, "/");
568 if (lpszParam)
570 if (lpszNetLoc)
571 lpszNetLoc = min(lpszNetLoc, lpszParam);
572 else
573 lpszNetLoc = lpszParam;
575 else if (!lpszNetLoc)
576 lpszNetLoc = lpszcp + strlen(lpszcp);
578 /* Parse net-loc */
579 if (lpszNetLoc)
581 LPSTR lpszHost;
582 LPSTR lpszPort;
584 /* [<user>[<:password>]@]<host>[:<port>] */
585 /* First find the user and password if they exist */
587 lpszHost = strchr(lpszcp, '@');
588 if (lpszHost == NULL || lpszHost > lpszNetLoc)
590 /* username and password not specified. */
591 SetUrlComponentValue(&lpUrlComponents->lpszUserName,
592 &lpUrlComponents->dwUserNameLength, NULL, 0);
593 SetUrlComponentValue(&lpUrlComponents->lpszPassword,
594 &lpUrlComponents->dwPasswordLength, NULL, 0);
596 else /* Parse out username and password */
598 LPSTR lpszUser = lpszcp;
599 LPSTR lpszPasswd = lpszHost;
601 while (lpszcp < lpszHost)
603 if (*lpszcp == ':')
604 lpszPasswd = lpszcp;
606 lpszcp++;
609 SetUrlComponentValue(&lpUrlComponents->lpszUserName,
610 &lpUrlComponents->dwUserNameLength, lpszUser, lpszPasswd - lpszUser);
612 SetUrlComponentValue(&lpUrlComponents->lpszPassword,
613 &lpUrlComponents->dwPasswordLength,
614 lpszPasswd == lpszHost ? NULL : ++lpszPasswd,
615 lpszHost - lpszPasswd);
617 lpszcp++; /* Advance to beginning of host */
620 /* Parse <host><:port> */
622 lpszHost = lpszcp;
623 lpszPort = lpszNetLoc;
625 while (lpszcp < lpszNetLoc)
627 if (*lpszcp == ':')
628 lpszPort = lpszcp;
630 lpszcp++;
633 SetUrlComponentValue(&lpUrlComponents->lpszHostName,
634 &lpUrlComponents->dwHostNameLength, lpszHost, lpszPort - lpszHost);
636 if (lpszPort != lpszNetLoc)
637 lpUrlComponents->nPort = atoi(++lpszPort);
641 /* Here lpszcp points to:
643 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
644 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
646 if (lpszcp != 0 && *lpszcp != '\0' && (!lpszParam || lpszcp < lpszParam))
648 INT len;
650 /* Only truncate the parameter list if it's already been saved
651 * in lpUrlComponents->lpszExtraInfo.
653 if (lpszParam && lpUrlComponents->dwExtraInfoLength)
654 len = lpszParam - lpszcp;
655 else
657 /* Leave the parameter list in lpszUrlPath. Strip off any trailing
658 * newlines if necessary.
660 LPSTR lpsznewline = strchr (lpszcp, '\n');
661 if (lpsznewline != NULL)
662 len = lpsznewline - lpszcp;
663 else
664 len = strlen(lpszcp);
667 if (!SetUrlComponentValue(&lpUrlComponents->lpszUrlPath,
668 &lpUrlComponents->dwUrlPathLength, lpszcp, len))
669 return FALSE;
671 else
673 lpUrlComponents->dwUrlPathLength = 0;
676 TRACE("%s: host(%s) path(%s) extra(%s)\n", lpszUrl, lpUrlComponents->lpszHostName,
677 lpUrlComponents->lpszUrlPath, lpUrlComponents->lpszExtraInfo);
679 return TRUE;
683 /***********************************************************************
684 * InternetAttemptConnect (WININET.81)
686 * Attempt to make a connection to the internet
688 * RETURNS
689 * ERROR_SUCCESS on success
690 * Error value on failure
693 INTERNETAPI DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
695 FIXME("Stub\n");
696 return ERROR_SUCCESS;
700 /***********************************************************************
701 * InternetCanonicalizeUrlA (WININET.85)
703 * Escape unsafe characters and spaces
705 * RETURNS
706 * TRUE on success
707 * FALSE on failure
710 BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
711 LPDWORD lpdwBufferLength, DWORD dwFlags)
713 BOOL bSuccess = FALSE;
715 FIXME("Stub!\n");
717 if (lpszUrl)
719 strncpy(lpszBuffer, lpszUrl, *lpdwBufferLength);
720 *lpdwBufferLength = strlen(lpszBuffer);
721 bSuccess = TRUE;
724 return bSuccess;
728 /***********************************************************************
729 * InternetSetStatusCallback (WININET.133)
731 * Sets up a callback function which is called as progress is made
732 * during an operation.
734 * RETURNS
735 * Previous callback or NULL on success
736 * INTERNET_INVALID_STATUS_CALLBACK on failure
739 INTERNETAPI INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallback(
740 HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
742 INTERNET_STATUS_CALLBACK retVal;
743 LPWININETAPPINFOA lpwai = (LPWININETAPPINFOA)hInternet;
745 TRACE("0x%08lx\n", (ULONG)hInternet);
746 if (lpwai->hdr.htype != WH_HINIT)
747 return INTERNET_INVALID_STATUS_CALLBACK;
749 retVal = lpwai->lpfnStatusCB;
750 lpwai->lpfnStatusCB = lpfnIntCB;
752 return retVal;
756 /***********************************************************************
757 * InternetWriteFile (WININET.138)
759 * Write data to an open internet file
761 * RETURNS
762 * TRUE on success
763 * FALSE on failure
766 BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer ,
767 DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
769 BOOL retval = FALSE;
770 int nSocket = INVALID_SOCKET;
771 LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hFile;
773 TRACE("\n");
774 if (NULL == lpwh)
775 return FALSE;
777 switch (lpwh->htype)
779 case WH_HHTTPREQ:
780 nSocket = ((LPWININETHTTPREQA)hFile)->nSocketFD;
781 break;
783 case WH_HFILE:
784 nSocket = ((LPWININETFILE)hFile)->nDataSocket;
785 break;
787 default:
788 break;
791 if (INVALID_SOCKET != nSocket)
793 *lpdwNumOfBytesWritten = INTERNET_WriteDataToStream(nSocket, lpBuffer, dwNumOfBytesToWrite);
794 if (*lpdwNumOfBytesWritten < 0)
795 *lpdwNumOfBytesWritten = 0;
796 else
797 retval = TRUE;
800 return retval;
804 /***********************************************************************
805 * InternetReadFile (WININET.121)
807 * Read data from an open internet file
809 * RETURNS
810 * TRUE on success
811 * FALSE on failure
814 BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
815 DWORD dwNumOfBytesToRead, LPDWORD dwNumOfBytesRead)
817 BOOL retval = FALSE;
818 int nSocket = INVALID_SOCKET;
819 LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hFile;
821 TRACE("\n");
822 if (NULL == lpwh)
823 return FALSE;
825 switch (lpwh->htype)
827 case WH_HHTTPREQ:
828 nSocket = ((LPWININETHTTPREQA)hFile)->nSocketFD;
829 break;
831 case WH_HFILE:
832 nSocket = ((LPWININETFILE)hFile)->nDataSocket;
833 break;
835 default:
836 break;
839 if (INVALID_SOCKET != nSocket)
841 *dwNumOfBytesRead = INTERNET_ReadDataFromStream(nSocket, lpBuffer, dwNumOfBytesToRead);
842 if (*dwNumOfBytesRead < 0)
843 *dwNumOfBytesRead = 0;
844 else
845 retval = TRUE;
848 return retval;
852 /***********************************************************************
853 * InternetQueryOptionA
855 * Queries an options on the specified handle
857 * RETURNS
858 * TRUE on success
859 * FALSE on failure
862 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
863 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
865 LPWININETHANDLEHEADER lpwhh;
866 BOOL bSuccess = FALSE;
868 TRACE("0x%08lx\n", dwOption);
870 if (NULL == hInternet)
872 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
873 return FALSE;
876 lpwhh = (LPWININETHANDLEHEADER) hInternet;
878 switch (dwOption)
880 case INTERNET_OPTION_HANDLE_TYPE:
882 ULONG type = lpwhh->htype;
883 TRACE("INTERNET_OPTION_HANDLE_TYPE: %ld\n", type);
885 if (*lpdwBufferLength < sizeof(ULONG))
886 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
887 else
889 memcpy(lpBuffer, &type, sizeof(ULONG));
890 *lpdwBufferLength = sizeof(ULONG);
891 bSuccess = TRUE;
894 break;
897 default:
898 FIXME("Stub!");
899 break;
902 return bSuccess;
906 /***********************************************************************
907 * GetInternetScheme (internal)
909 * Get scheme of url
911 * RETURNS
912 * scheme on success
913 * INTERNET_SCHEME_UNKNOWN on failure
916 INTERNET_SCHEME GetInternetScheme(LPCSTR lpszScheme, INT nMaxCmp)
918 if(lpszScheme==NULL)
919 return INTERNET_SCHEME_UNKNOWN;
921 if (!strncasecmp("ftp", lpszScheme, nMaxCmp))
922 return INTERNET_SCHEME_FTP;
923 else if (!strncasecmp("gopher", lpszScheme, nMaxCmp))
924 return INTERNET_SCHEME_GOPHER;
925 else if (!strncasecmp("http", lpszScheme, nMaxCmp))
926 return INTERNET_SCHEME_HTTP;
927 else if (!strncasecmp("https", lpszScheme, nMaxCmp))
928 return INTERNET_SCHEME_HTTPS;
929 else if (!strncasecmp("file", lpszScheme, nMaxCmp))
930 return INTERNET_SCHEME_FILE;
931 else if (!strncasecmp("news", lpszScheme, nMaxCmp))
932 return INTERNET_SCHEME_NEWS;
933 else if (!strncasecmp("mailto", lpszScheme, nMaxCmp))
934 return INTERNET_SCHEME_MAILTO;
935 else
936 return INTERNET_SCHEME_UNKNOWN;
939 /***********************************************************************
940 * InternetCheckConnectionA
942 * Pings a requested host to check internet connection
944 * RETURNS
946 * TRUE on success and FALSE on failure. if a failures then
947 * ERROR_NOT_CONNECTED is places into GetLastError
950 BOOL WINAPI InternetCheckConnectionA( LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
953 * this is a kludge which runs the resident ping program and reads the output.
955 * Anyone have a better idea?
958 BOOL rc = FALSE;
959 char command[1024];
960 char host[1024];
961 int status = -1;
964 * Crack or set the Address
966 if (lpszUrl == NULL)
969 * According to the doc we are supost to use the ip for the next
970 * server in the WnInet internal server database. I have
971 * no idea what that is or how to get it.
973 * So someone needs to implement this.
975 FIXME("Unimplemented with URL of NULL");
976 return TRUE;
978 else
980 URL_COMPONENTSA componets;
982 ZeroMemory(&componets,sizeof(URL_COMPONENTSA));
983 componets.lpszHostName = (LPSTR)&host;
984 componets.dwHostNameLength = 1024;
986 if (!InternetCrackUrlA(lpszUrl,0,0,&componets))
987 goto End;
989 TRACE("host name : %s\n",componets.lpszHostName);
993 * Build our ping command
995 strcpy(command,"ping -w 1 ");
996 strcat(command,host);
997 strcat(command," >/dev/null 2>/dev/null");
999 TRACE("Ping command is : %s\n",command);
1001 status = system(command);
1003 TRACE("Ping returned a code of %i \n",status);
1005 /* Ping return code of 0 indicates success */
1006 if (status == 0)
1007 rc = TRUE;
1009 End:
1011 if (rc == FALSE)
1012 SetLastError(ERROR_NOT_CONNECTED);
1014 return rc;
1019 /***********************************************************************
1020 * INTERNET_WriteDataToStream (internal)
1022 * Send data to server
1024 * RETURNS
1026 * number of characters sent on success
1027 * -1 on error
1029 int INTERNET_WriteDataToStream(int nDataSocket, LPCVOID Buffer, DWORD BytesToWrite)
1031 if (INVALID_SOCKET == nDataSocket)
1032 return SOCKET_ERROR;
1034 return send(nDataSocket, Buffer, BytesToWrite, 0);
1038 /***********************************************************************
1039 * INTERNET_ReadDataFromStream (internal)
1041 * Read data from http server
1043 * RETURNS
1045 * number of characters sent on success
1046 * -1 on error
1048 int INTERNET_ReadDataFromStream(int nDataSocket, LPVOID Buffer, DWORD BytesToRead)
1050 if (INVALID_SOCKET == nDataSocket)
1051 return SOCKET_ERROR;
1053 return recv(nDataSocket, Buffer, BytesToRead, 0);
1057 /***********************************************************************
1058 * INTERNET_SetLastError (internal)
1060 * Set last thread specific error
1062 * RETURNS
1065 void INTERNET_SetLastError(DWORD dwError)
1067 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
1069 SetLastError(dwError);
1070 lpwite->dwError = dwError;
1074 /***********************************************************************
1075 * INTERNET_GetLastError (internal)
1077 * Get last thread specific error
1079 * RETURNS
1082 DWORD INTERNET_GetLastError()
1084 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
1085 return lpwite->dwError;
1089 /***********************************************************************
1090 * INTERNET_WorkerThreadFunc (internal)
1092 * Worker thread execution function
1094 * RETURNS
1097 DWORD INTERNET_WorkerThreadFunc(LPVOID *lpvParam)
1099 DWORD dwWaitRes;
1101 while (1)
1103 dwWaitRes = WaitForMultipleObjects(2, hEventArray, FALSE, MAX_IDLE_WORKER);
1105 if (dwWaitRes == WAIT_OBJECT_0 + 1)
1106 INTERNET_ExecuteWork();
1107 else
1108 break;
1110 InterlockedIncrement(&dwNumIdleThreads);
1113 InterlockedDecrement(&dwNumIdleThreads);
1114 InterlockedDecrement(&dwNumThreads);
1115 TRACE("Worker thread exiting\n");
1116 return TRUE;
1120 /***********************************************************************
1121 * INTERNET_InsertWorkRequest (internal)
1123 * Insert work request into queue
1125 * RETURNS
1128 BOOL INTERNET_InsertWorkRequest(LPWORKREQUEST lpWorkRequest)
1130 BOOL bSuccess = FALSE;
1131 LPWORKREQUEST lpNewRequest;
1133 TRACE("\n");
1135 lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
1136 if (lpNewRequest)
1138 memcpy(lpNewRequest, lpWorkRequest, sizeof(WORKREQUEST));
1139 lpNewRequest->prev = NULL;
1141 EnterCriticalSection(&csQueue);
1143 lpNewRequest->next = lpWorkQueueTail;
1144 if (lpWorkQueueTail)
1145 lpWorkQueueTail->prev = lpNewRequest;
1146 lpWorkQueueTail = lpNewRequest;
1147 if (!lpHeadWorkQueue)
1148 lpHeadWorkQueue = lpWorkQueueTail;
1150 LeaveCriticalSection(&csQueue);
1152 bSuccess = TRUE;
1155 return bSuccess;
1159 /***********************************************************************
1160 * INTERNET_GetWorkRequest (internal)
1162 * Retrieves work request from queue
1164 * RETURNS
1167 BOOL INTERNET_GetWorkRequest(LPWORKREQUEST lpWorkRequest)
1169 BOOL bSuccess = FALSE;
1170 LPWORKREQUEST lpRequest = NULL;
1172 TRACE("\n");
1174 EnterCriticalSection(&csQueue);
1176 if (lpHeadWorkQueue)
1178 lpRequest = lpHeadWorkQueue;
1179 lpHeadWorkQueue = lpHeadWorkQueue->prev;
1180 if (lpRequest == lpWorkQueueTail)
1181 lpWorkQueueTail = lpHeadWorkQueue;
1184 LeaveCriticalSection(&csQueue);
1186 if (lpRequest)
1188 memcpy(lpWorkRequest, lpRequest, sizeof(WORKREQUEST));
1189 HeapFree(GetProcessHeap(), 0, lpRequest);
1190 bSuccess = TRUE;
1193 return bSuccess;
1197 /***********************************************************************
1198 * INTERNET_AsyncCall (internal)
1200 * Retrieves work request from queue
1202 * RETURNS
1205 BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
1207 HANDLE hThread;
1208 DWORD dwTID;
1209 BOOL bSuccess = FALSE;
1211 TRACE("\n");
1213 if (InterlockedDecrement(&dwNumIdleThreads) < 0)
1215 InterlockedIncrement(&dwNumIdleThreads);
1217 if (InterlockedIncrement(&dwNumThreads) > MAX_WORKER_THREADS ||
1218 !(hThread = CreateThread(NULL, 0,
1219 (LPTHREAD_START_ROUTINE)INTERNET_WorkerThreadFunc, NULL, 0, &dwTID)))
1221 InterlockedDecrement(&dwNumThreads);
1222 INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED);
1223 goto lerror;
1226 TRACE("Created new thread\n");
1229 bSuccess = TRUE;
1230 INTERNET_InsertWorkRequest(lpWorkRequest);
1231 SetEvent(hWorkEvent);
1233 lerror:
1235 return bSuccess;
1239 /***********************************************************************
1240 * INTERNET_ExecuteWork (internal)
1242 * RETURNS
1245 VOID INTERNET_ExecuteWork()
1247 WORKREQUEST workRequest;
1249 TRACE("\n");
1251 if (INTERNET_GetWorkRequest(&workRequest))
1253 switch (workRequest.asyncall)
1255 case FTPPUTFILEA:
1256 FTP_FtpPutFileA((HINTERNET)workRequest.HFTPSESSION, (LPCSTR)workRequest.LPSZLOCALFILE,
1257 (LPCSTR)workRequest.LPSZNEWREMOTEFILE, workRequest.DWFLAGS, workRequest.DWCONTEXT);
1258 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZLOCALFILE);
1259 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZNEWREMOTEFILE);
1260 break;
1262 case FTPSETCURRENTDIRECTORYA:
1263 FTP_FtpSetCurrentDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1264 (LPCSTR)workRequest.LPSZDIRECTORY);
1265 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDIRECTORY);
1266 break;
1268 case FTPCREATEDIRECTORYA:
1269 FTP_FtpCreateDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1270 (LPCSTR)workRequest.LPSZDIRECTORY);
1271 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDIRECTORY);
1272 break;
1274 case FTPFINDFIRSTFILEA:
1275 FTP_FtpFindFirstFileA((HINTERNET)workRequest.HFTPSESSION,
1276 (LPCSTR)workRequest.LPSZSEARCHFILE,
1277 (LPWIN32_FIND_DATAA)workRequest.LPFINDFILEDATA, workRequest.DWFLAGS,
1278 workRequest.DWCONTEXT);
1279 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZSEARCHFILE);
1280 break;
1282 case FTPGETCURRENTDIRECTORYA:
1283 FTP_FtpGetCurrentDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1284 (LPSTR)workRequest.LPSZDIRECTORY, (LPDWORD)workRequest.LPDWDIRECTORY);
1285 break;
1287 case FTPOPENFILEA:
1288 FTP_FtpOpenFileA((HINTERNET)workRequest.HFTPSESSION,
1289 (LPCSTR)workRequest.LPSZFILENAME,
1290 workRequest.FDWACCESS,
1291 workRequest.DWFLAGS,
1292 workRequest.DWCONTEXT);
1293 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZFILENAME);
1294 break;
1296 case FTPGETFILEA:
1297 FTP_FtpGetFileA((HINTERNET)workRequest.HFTPSESSION,
1298 (LPCSTR)workRequest.LPSZREMOTEFILE,
1299 (LPCSTR)workRequest.LPSZNEWFILE,
1300 (BOOL)workRequest.FFAILIFEXISTS,
1301 workRequest.DWLOCALFLAGSATTRIBUTE,
1302 workRequest.DWFLAGS,
1303 workRequest.DWCONTEXT);
1304 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZREMOTEFILE);
1305 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZNEWFILE);
1306 break;
1308 case FTPDELETEFILEA:
1309 FTP_FtpDeleteFileA((HINTERNET)workRequest.HFTPSESSION,
1310 (LPCSTR)workRequest.LPSZFILENAME);
1311 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZFILENAME);
1312 break;
1314 case FTPREMOVEDIRECTORYA:
1315 FTP_FtpRemoveDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1316 (LPCSTR)workRequest.LPSZDIRECTORY);
1317 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDIRECTORY);
1318 break;
1320 case FTPRENAMEFILEA:
1321 FTP_FtpRenameFileA((HINTERNET)workRequest.HFTPSESSION,
1322 (LPCSTR)workRequest.LPSZSRCFILE,
1323 (LPCSTR)workRequest.LPSZDESTFILE);
1324 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZSRCFILE);
1325 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDESTFILE);
1326 break;
1328 case INTERNETFINDNEXTA:
1329 INTERNET_FindNextFileA((HINTERNET)workRequest.HFTPSESSION,
1330 (LPWIN32_FIND_DATAA)workRequest.LPFINDFILEDATA);
1331 break;
1333 case HTTPSENDREQUESTA:
1334 HTTP_HttpSendRequestA((HINTERNET)workRequest.HFTPSESSION,
1335 (LPCSTR)workRequest.LPSZHEADER,
1336 workRequest.DWHEADERLENGTH,
1337 (LPVOID)workRequest.LPOPTIONAL,
1338 workRequest.DWOPTIONALLENGTH);
1339 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZHEADER);
1340 break;
1342 case HTTPOPENREQUESTA:
1343 HTTP_HttpOpenRequestA((HINTERNET)workRequest.HFTPSESSION,
1344 (LPCSTR)workRequest.LPSZVERB,
1345 (LPCSTR)workRequest.LPSZOBJECTNAME,
1346 (LPCSTR)workRequest.LPSZVERSION,
1347 (LPCSTR)workRequest.LPSZREFERRER,
1348 (LPCSTR*)workRequest.LPSZACCEPTTYPES,
1349 workRequest.DWFLAGS,
1350 workRequest.DWCONTEXT);
1351 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZVERB);
1352 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZOBJECTNAME);
1353 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZVERSION);
1354 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZREFERRER);
1355 break;
1362 /***********************************************************************
1363 * INTERNET_GetResponseBuffer
1365 * RETURNS
1368 LPSTR INTERNET_GetResponseBuffer()
1370 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
1371 return lpwite->response;
1375 /***********************************************************************
1376 * INTERNET_GetNextLine (internal)
1378 * Parse next line in directory string listing
1380 * RETURNS
1381 * Pointer to begining of next line
1382 * NULL on failure
1386 LPSTR INTERNET_GetNextLine(INT nSocket, LPSTR lpszBuffer, LPDWORD dwBuffer)
1388 struct timeval tv;
1389 fd_set infd;
1390 BOOL bSuccess = FALSE;
1391 INT nRecv = 0;
1393 TRACE("\n");
1395 FD_ZERO(&infd);
1396 FD_SET(nSocket, &infd);
1397 tv.tv_sec=RESPONSE_TIMEOUT;
1398 tv.tv_usec=0;
1400 while (nRecv < *dwBuffer)
1402 if (select(nSocket+1,&infd,NULL,NULL,&tv) > 0)
1404 if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
1406 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1407 goto lend;
1410 if (lpszBuffer[nRecv] == '\n')
1412 bSuccess = TRUE;
1413 break;
1415 if (lpszBuffer[nRecv] != '\r')
1416 nRecv++;
1418 else
1420 INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
1421 goto lend;
1425 lend:
1426 if (bSuccess)
1428 lpszBuffer[nRecv] = '\0';
1429 *dwBuffer = nRecv - 1;
1430 TRACE(":%d %s\n", nRecv, lpszBuffer);
1431 return lpszBuffer;
1433 else
1435 return NULL;