Replaced HEAP_strdup* and lstrcpynAtoW calls by exported functions.
[wine/multimedia.git] / dlls / wininet / internet.c
blob0a0c669cb45555a44234f295cc300ca4b52511c6
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 <sys/time.h>
18 #include <stdlib.h>
19 #include <ctype.h>
20 #include <unistd.h>
22 #include "windows.h"
23 #include "wininet.h"
24 #include "debugtools.h"
25 #include "winerror.h"
26 #include "winsock.h"
28 #include "internet.h"
30 DEFAULT_DEBUG_CHANNEL(wininet);
32 #define MAX_IDLE_WORKER 1000*60*1
33 #define MAX_WORKER_THREADS 10
34 #define RESPONSE_TIMEOUT 30
36 #define GET_HWININET_FROM_LPWININETFINDNEXT(lpwh) \
37 (LPWININETAPPINFOA)(((LPWININETFTPSESSIONA)(lpwh->hdr.lpwhparent))->hdr.lpwhparent)
39 typedef struct
41 DWORD dwError;
42 CHAR response[MAX_REPLY_LEN];
43 } WITHREADERROR, *LPWITHREADERROR;
45 INTERNET_SCHEME GetInternetScheme(LPCSTR lpszScheme, INT nMaxCmp);
46 BOOL WINAPI INTERNET_FindNextFileA(HINTERNET hFind, LPVOID lpvFindData);
47 VOID INTERNET_ExecuteWork();
49 DWORD g_dwTlsErrIndex = TLS_OUT_OF_INDEXES;
50 DWORD dwNumThreads;
51 DWORD dwNumIdleThreads;
52 HANDLE hEventArray[2];
53 #define hQuitEvent hEventArray[0]
54 #define hWorkEvent hEventArray[1]
55 CRITICAL_SECTION csQueue;
56 LPWORKREQUEST lpHeadWorkQueue;
57 LPWORKREQUEST lpWorkQueueTail;
59 /***********************************************************************
60 * WININET_LibMain [Internal] Initializes the internal 'WININET.DLL'.
62 * PARAMS
63 * hinstDLL [I] handle to the DLL's instance
64 * fdwReason [I]
65 * lpvReserved [I] reserved, must be NULL
67 * RETURNS
68 * Success: TRUE
69 * Failure: FALSE
72 BOOL WINAPI
73 WININET_LibMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
75 TRACE("%x,%lx,%p\n", hinstDLL, fdwReason, lpvReserved);
77 switch (fdwReason) {
78 case DLL_PROCESS_ATTACH:
80 g_dwTlsErrIndex = TlsAlloc();
82 if (g_dwTlsErrIndex == TLS_OUT_OF_INDEXES)
83 return FALSE;
85 hQuitEvent = CreateEventA(0, TRUE, FALSE, NULL);
86 hWorkEvent = CreateEventA(0, FALSE, FALSE, NULL);
87 InitializeCriticalSection(&csQueue);
89 dwNumThreads = 0;
90 dwNumIdleThreads = 0;
92 case DLL_THREAD_ATTACH:
94 LPWITHREADERROR lpwite = HeapAlloc(GetProcessHeap(), 0, sizeof(WITHREADERROR));
95 if (NULL == lpwite)
96 return FALSE;
98 TlsSetValue(g_dwTlsErrIndex, (LPVOID)lpwite);
100 break;
102 case DLL_THREAD_DETACH:
103 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
105 LPVOID lpwite = TlsGetValue(g_dwTlsErrIndex);
106 if (lpwite)
107 HeapFree(GetProcessHeap(), 0, lpwite);
109 break;
111 case DLL_PROCESS_DETACH:
113 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
115 HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex));
116 TlsFree(g_dwTlsErrIndex);
119 SetEvent(hQuitEvent);
121 CloseHandle(hQuitEvent);
122 CloseHandle(hWorkEvent);
123 DeleteCriticalSection(&csQueue);
124 break;
127 return TRUE;
131 /***********************************************************************
132 * InternetOpenA (WININET.113)
134 * Per-application initialization of wininet
136 * RETURNS
137 * HINTERNET on success
138 * NULL on failure
141 INTERNETAPI HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent,
142 DWORD dwAccessType, LPCSTR lpszProxy,
143 LPCSTR lpszProxyBypass, DWORD dwFlags)
145 LPWININETAPPINFOA lpwai = NULL;
147 TRACE("\n");
149 /* Clear any error information */
150 INTERNET_SetLastError(0);
152 lpwai = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETAPPINFOA));
153 if (NULL == lpwai)
154 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
155 else
157 memset(lpwai, 0, sizeof(WININETAPPINFOA));
158 lpwai->hdr.htype = WH_HINIT;
159 lpwai->hdr.lpwhparent = NULL;
160 lpwai->hdr.dwFlags = dwFlags;
161 if (NULL != lpszAgent)
163 if ((lpwai->lpszAgent = HeapAlloc( GetProcessHeap(),0,strlen(lpszAgent)+1)))
164 strcpy( lpwai->lpszAgent, lpszAgent );
166 if (NULL != lpszProxy)
168 if ((lpwai->lpszProxy = HeapAlloc( GetProcessHeap(), 0, strlen(lpszProxy)+1 )))
169 strcpy( lpwai->lpszProxy, lpszProxy );
171 if (NULL != lpszProxyBypass)
173 if ((lpwai->lpszProxyBypass = HeapAlloc( GetProcessHeap(), 0, strlen(lpszProxyBypass)+1)))
174 strcpy( lpwai->lpszProxyBypass, lpszProxyBypass );
176 lpwai->dwAccessType = dwAccessType;
179 return (HINTERNET)lpwai;
183 /***********************************************************************
184 * InternetGetLastResponseInfoA (WININET.108)
186 * Return last wininet error description on the calling thread
188 * RETURNS
189 * TRUE on success of writting to buffer
190 * FALSE on failure
193 BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError,
194 LPSTR lpszBuffer, LPDWORD lpdwBufferLength)
196 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
198 TRACE("\n");
200 *lpdwError = lpwite->dwError;
201 if (lpwite->dwError)
203 strncpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
204 *lpdwBufferLength = strlen(lpszBuffer);
206 else
207 *lpdwBufferLength = 0;
209 return TRUE;
213 /***********************************************************************
214 * InternetGetConnectedState (WININET.103)
216 * Return connected state
218 * RETURNS
219 * TRUE if connected
220 * if lpdwStatus is not null, return the status (off line,
221 * modem, lan...) in it.
222 * FALSE if not connected
224 BOOL WINAPI InternetGetConnectedState(LPDWORD lpdwStatus, DWORD dwReserved)
226 FIXME("Stub\n");
227 return FALSE;
231 /***********************************************************************
232 * InternetConnectA (WININET.93)
234 * Open a ftp, gopher or http session
236 * RETURNS
237 * HINTERNET a session handle on success
238 * NULL on failure
241 INTERNETAPI HINTERNET WINAPI InternetConnectA(HINTERNET hInternet,
242 LPCSTR lpszServerName, INTERNET_PORT nServerPort,
243 LPCSTR lpszUserName, LPCSTR lpszPassword,
244 DWORD dwService, DWORD dwFlags, DWORD dwContext)
246 HINTERNET rc = (HINTERNET) NULL;
248 TRACE("\n");
250 /* Clear any error information */
251 INTERNET_SetLastError(0);
253 switch (dwService)
255 case INTERNET_SERVICE_FTP:
256 rc = FTP_Connect(hInternet, lpszServerName, nServerPort,
257 lpszUserName, lpszPassword, dwFlags, dwContext);
258 break;
260 case INTERNET_SERVICE_HTTP:
261 rc = HTTP_Connect(hInternet, lpszServerName, nServerPort,
262 lpszUserName, lpszPassword, dwFlags, dwContext);
263 break;
265 case INTERNET_SERVICE_GOPHER:
266 default:
267 break;
270 return rc;
273 /***********************************************************************
274 * InternetFindNextFileA (WININET.102)
276 * Continues a file search from a previous call to FindFirstFile
278 * RETURNS
279 * TRUE on success
280 * FALSE on failure
283 BOOL WINAPI InternetFindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
285 LPWININETAPPINFOA hIC = NULL;
286 LPWININETFINDNEXTA lpwh = (LPWININETFINDNEXTA) hFind;
288 TRACE("\n");
290 if (NULL == lpwh || lpwh->hdr.htype != WH_HFINDNEXT)
292 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
293 return FALSE;
296 hIC = GET_HWININET_FROM_LPWININETFINDNEXT(lpwh);
297 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
299 WORKREQUEST workRequest;
301 workRequest.asyncall = INTERNETFINDNEXTA;
302 workRequest.HFTPSESSION = (DWORD)hFind;
303 workRequest.LPFINDFILEDATA = (DWORD)lpvFindData;
305 return INTERNET_AsyncCall(&workRequest);
307 else
309 return INTERNET_FindNextFileA(hFind, lpvFindData);
313 /***********************************************************************
314 * INTERNET_FindNextFileA (Internal)
316 * Continues a file search from a previous call to FindFirstFile
318 * RETURNS
319 * TRUE on success
320 * FALSE on failure
323 BOOL WINAPI INTERNET_FindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
325 BOOL bSuccess = TRUE;
326 LPWININETAPPINFOA hIC = NULL;
327 LPWIN32_FIND_DATAA lpFindFileData;
328 LPWININETFINDNEXTA lpwh = (LPWININETFINDNEXTA) hFind;
330 TRACE("\n");
332 if (NULL == lpwh || lpwh->hdr.htype != WH_HFINDNEXT)
334 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
335 return FALSE;
338 /* Clear any error information */
339 INTERNET_SetLastError(0);
341 if (lpwh->hdr.lpwhparent->htype != WH_HFTPSESSION)
343 FIXME("Only FTP find next supported\n");
344 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
345 return FALSE;
348 TRACE("index(%d) size(%ld)\n", lpwh->index, lpwh->size);
350 lpFindFileData = (LPWIN32_FIND_DATAA) lpvFindData;
351 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
353 if (lpwh->index >= lpwh->size)
355 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
356 bSuccess = FALSE;
357 goto lend;
360 FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
361 lpwh->index++;
363 TRACE("\nName: %s\nSize: %ld\n", lpFindFileData->cFileName, lpFindFileData->nFileSizeLow);
365 lend:
367 hIC = GET_HWININET_FROM_LPWININETFINDNEXT(lpwh);
368 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
370 INTERNET_ASYNC_RESULT iar;
372 iar.dwResult = (DWORD)bSuccess;
373 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
375 hIC->lpfnStatusCB(hFind, lpwh->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
376 &iar, sizeof(INTERNET_ASYNC_RESULT));
379 return bSuccess;
383 /***********************************************************************
384 * INTERNET_CloseHandle (internal)
386 * Close internet handle
388 * RETURNS
389 * Void
392 VOID INTERNET_CloseHandle(LPWININETAPPINFOA lpwai)
394 if (lpwai->lpszAgent)
395 HeapFree(GetProcessHeap(), 0, lpwai->lpszAgent);
397 if (lpwai->lpszProxy)
398 HeapFree(GetProcessHeap(), 0, lpwai->lpszProxy);
400 if (lpwai->lpszProxyBypass)
401 HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyBypass);
403 HeapFree(GetProcessHeap(), 0, lpwai);
407 /***********************************************************************
408 * InternetCloseHandle (WININET.89)
410 * Generic close handle function
412 * RETURNS
413 * TRUE on success
414 * FALSE on failure
417 BOOL WINAPI InternetCloseHandle(HINTERNET hInternet)
419 BOOL retval = FALSE;
420 LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hInternet;
422 TRACE("\n");
423 if (NULL == lpwh)
424 return FALSE;
426 /* Clear any error information */
427 INTERNET_SetLastError(0);
429 switch (lpwh->htype)
431 case WH_HINIT:
432 INTERNET_CloseHandle((LPWININETAPPINFOA) lpwh);
433 break;
435 case WH_HHTTPSESSION:
436 HTTP_CloseHTTPSessionHandle((LPWININETHTTPSESSIONA) lpwh);
437 break;
439 case WH_HHTTPREQ:
440 HTTP_CloseHTTPRequestHandle((LPWININETHTTPREQA) lpwh);
441 break;
443 case WH_HFTPSESSION:
444 retval = FTP_CloseSessionHandle((LPWININETFTPSESSIONA) lpwh);
445 break;
447 case WH_HFINDNEXT:
448 retval = FTP_CloseFindNextHandle((LPWININETFINDNEXTA) lpwh);
449 break;
451 default:
452 break;
455 return retval;
459 /***********************************************************************
460 * SetUrlComponentValue (Internal)
462 * Helper function for InternetCrackUrlA
464 * RETURNS
465 * TRUE on success
466 * FALSE on failure
469 BOOL SetUrlComponentValue(LPSTR* lppszComponent, LPDWORD dwComponentLen, LPCSTR lpszStart, INT len)
471 TRACE("%s (%d)\n", lpszStart, len);
473 if (*dwComponentLen != 0)
475 if (*lppszComponent == NULL)
477 *lppszComponent = (LPSTR)lpszStart;
478 *dwComponentLen = len;
480 else
482 INT ncpylen = min((*dwComponentLen)-1, len);
483 strncpy(*lppszComponent, lpszStart, ncpylen);
484 (*lppszComponent)[ncpylen] = '\0';
485 *dwComponentLen = ncpylen;
489 return TRUE;
493 /***********************************************************************
494 * InternetCrackUrlA (WININET.95)
496 * Break up URL into its components
498 * TODO: Hadnle dwFlags
500 * RETURNS
501 * TRUE on success
502 * FALSE on failure
505 BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
506 LPURL_COMPONENTSA lpUrlComponents)
509 * RFC 1808
510 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
513 LPSTR lpszParam = NULL;
514 BOOL bIsAbsolute = FALSE;
515 LPSTR lpszap = (char*)lpszUrl;
516 LPSTR lpszcp = NULL;
518 TRACE("\n");
520 /* Determine if the URI is absolute. */
521 while (*lpszap != '\0')
523 if (isalnum(*lpszap))
525 lpszap++;
526 continue;
528 if ((*lpszap == ':') && (lpszap - lpszUrl >= 2))
530 bIsAbsolute = TRUE;
531 lpszcp = lpszap;
533 else
535 lpszcp = (LPSTR)lpszUrl; /* Relative url */
538 break;
541 /* Parse <params> */
542 lpszParam = strpbrk(lpszap, ";?");
543 if (lpszParam != NULL)
545 if (!SetUrlComponentValue(&lpUrlComponents->lpszExtraInfo,
546 &lpUrlComponents->dwExtraInfoLength, lpszParam+1, strlen(lpszParam+1)))
548 return FALSE;
552 if (bIsAbsolute) /* Parse <protocol>:[//<net_loc>] */
554 LPSTR lpszNetLoc;
556 /* Get scheme first. */
557 lpUrlComponents->nScheme = GetInternetScheme(lpszUrl, lpszcp - lpszUrl);
558 if (!SetUrlComponentValue(&lpUrlComponents->lpszScheme,
559 &lpUrlComponents->dwSchemeLength, lpszUrl, lpszcp - lpszUrl))
560 return FALSE;
562 /* Eat ':' in protocol. */
563 lpszcp++;
565 /* Skip over slashes. */
566 if (*lpszcp == '/')
568 lpszcp++;
569 if (*lpszcp == '/')
571 lpszcp++;
572 if (*lpszcp == '/')
573 lpszcp++;
577 lpszNetLoc = strpbrk(lpszcp, "/");
578 if (lpszParam)
580 if (lpszNetLoc)
581 lpszNetLoc = min(lpszNetLoc, lpszParam);
582 else
583 lpszNetLoc = lpszParam;
585 else if (!lpszNetLoc)
586 lpszNetLoc = lpszcp + strlen(lpszcp);
588 /* Parse net-loc */
589 if (lpszNetLoc)
591 LPSTR lpszHost;
592 LPSTR lpszPort;
594 /* [<user>[<:password>]@]<host>[:<port>] */
595 /* First find the user and password if they exist */
597 lpszHost = strchr(lpszcp, '@');
598 if (lpszHost == NULL || lpszHost > lpszNetLoc)
600 /* username and password not specified. */
601 SetUrlComponentValue(&lpUrlComponents->lpszUserName,
602 &lpUrlComponents->dwUserNameLength, NULL, 0);
603 SetUrlComponentValue(&lpUrlComponents->lpszPassword,
604 &lpUrlComponents->dwPasswordLength, NULL, 0);
606 else /* Parse out username and password */
608 LPSTR lpszUser = lpszcp;
609 LPSTR lpszPasswd = lpszHost;
611 while (lpszcp < lpszHost)
613 if (*lpszcp == ':')
614 lpszPasswd = lpszcp;
616 lpszcp++;
619 SetUrlComponentValue(&lpUrlComponents->lpszUserName,
620 &lpUrlComponents->dwUserNameLength, lpszUser, lpszPasswd - lpszUser);
622 SetUrlComponentValue(&lpUrlComponents->lpszPassword,
623 &lpUrlComponents->dwPasswordLength,
624 lpszPasswd == lpszHost ? NULL : ++lpszPasswd,
625 lpszHost - lpszPasswd);
627 lpszcp++; /* Advance to beginning of host */
630 /* Parse <host><:port> */
632 lpszHost = lpszcp;
633 lpszPort = lpszNetLoc;
635 while (lpszcp < lpszNetLoc)
637 if (*lpszcp == ':')
638 lpszPort = lpszcp;
640 lpszcp++;
643 SetUrlComponentValue(&lpUrlComponents->lpszHostName,
644 &lpUrlComponents->dwHostNameLength, lpszHost, lpszPort - lpszHost);
646 if (lpszPort != lpszNetLoc)
647 lpUrlComponents->nPort = atoi(++lpszPort);
651 /* Here lpszcp points to:
653 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
654 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
656 if (lpszcp != 0 && *lpszcp != '\0' && (!lpszParam || lpszcp < lpszParam))
658 INT len;
660 /* Only truncate the parameter list if it's already been saved
661 * in lpUrlComponents->lpszExtraInfo.
663 if (lpszParam && lpUrlComponents->dwExtraInfoLength)
664 len = lpszParam - lpszcp;
665 else
667 /* Leave the parameter list in lpszUrlPath. Strip off any trailing
668 * newlines if necessary.
670 LPSTR lpsznewline = strchr (lpszcp, '\n');
671 if (lpsznewline != NULL)
672 len = lpsznewline - lpszcp;
673 else
674 len = strlen(lpszcp);
677 if (!SetUrlComponentValue(&lpUrlComponents->lpszUrlPath,
678 &lpUrlComponents->dwUrlPathLength, lpszcp, len))
679 return FALSE;
681 else
683 lpUrlComponents->dwUrlPathLength = 0;
686 TRACE("%s: host(%s) path(%s) extra(%s)\n", lpszUrl, lpUrlComponents->lpszHostName,
687 lpUrlComponents->lpszUrlPath, lpUrlComponents->lpszExtraInfo);
689 return TRUE;
693 /***********************************************************************
694 * InternetAttemptConnect (WININET.81)
696 * Attempt to make a connection to the internet
698 * RETURNS
699 * ERROR_SUCCESS on success
700 * Error value on failure
703 INTERNETAPI DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
705 FIXME("Stub\n");
706 return ERROR_SUCCESS;
710 /***********************************************************************
711 * InternetCanonicalizeUrlA (WININET.85)
713 * Escape unsafe characters and spaces
715 * RETURNS
716 * TRUE on success
717 * FALSE on failure
720 BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
721 LPDWORD lpdwBufferLength, DWORD dwFlags)
723 BOOL bSuccess = FALSE;
725 FIXME("Stub!\n");
727 if (lpszUrl)
729 strncpy(lpszBuffer, lpszUrl, *lpdwBufferLength);
730 *lpdwBufferLength = strlen(lpszBuffer);
731 bSuccess = TRUE;
734 return bSuccess;
738 /***********************************************************************
739 * InternetSetStatusCallback (WININET.133)
741 * Sets up a callback function which is called as progress is made
742 * during an operation.
744 * RETURNS
745 * Previous callback or NULL on success
746 * INTERNET_INVALID_STATUS_CALLBACK on failure
749 INTERNETAPI INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallback(
750 HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
752 INTERNET_STATUS_CALLBACK retVal;
753 LPWININETAPPINFOA lpwai = (LPWININETAPPINFOA)hInternet;
755 TRACE("0x%08lx\n", (ULONG)hInternet);
756 if (lpwai->hdr.htype != WH_HINIT)
757 return INTERNET_INVALID_STATUS_CALLBACK;
759 retVal = lpwai->lpfnStatusCB;
760 lpwai->lpfnStatusCB = lpfnIntCB;
762 return retVal;
766 /***********************************************************************
767 * InternetWriteFile (WININET.138)
769 * Write data to an open internet file
771 * RETURNS
772 * TRUE on success
773 * FALSE on failure
776 BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer ,
777 DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
779 BOOL retval = FALSE;
780 int nSocket = INVALID_SOCKET;
781 LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hFile;
783 TRACE("\n");
784 if (NULL == lpwh)
785 return FALSE;
787 switch (lpwh->htype)
789 case WH_HHTTPREQ:
790 nSocket = ((LPWININETHTTPREQA)hFile)->nSocketFD;
791 break;
793 case WH_HFILE:
794 nSocket = ((LPWININETFILE)hFile)->nDataSocket;
795 break;
797 default:
798 break;
801 if (INVALID_SOCKET != nSocket)
803 *lpdwNumOfBytesWritten = INTERNET_WriteDataToStream(nSocket, lpBuffer, dwNumOfBytesToWrite);
804 if (*lpdwNumOfBytesWritten < 0)
805 *lpdwNumOfBytesWritten = 0;
806 else
807 retval = TRUE;
810 return retval;
814 /***********************************************************************
815 * InternetReadFile (WININET.121)
817 * Read data from an open internet file
819 * RETURNS
820 * TRUE on success
821 * FALSE on failure
824 BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
825 DWORD dwNumOfBytesToRead, LPDWORD dwNumOfBytesRead)
827 BOOL retval = FALSE;
828 int nSocket = INVALID_SOCKET;
829 LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hFile;
831 TRACE("\n");
832 if (NULL == lpwh)
833 return FALSE;
835 switch (lpwh->htype)
837 case WH_HHTTPREQ:
838 nSocket = ((LPWININETHTTPREQA)hFile)->nSocketFD;
839 break;
841 case WH_HFILE:
842 nSocket = ((LPWININETFILE)hFile)->nDataSocket;
843 break;
845 default:
846 break;
849 if (INVALID_SOCKET != nSocket)
851 *dwNumOfBytesRead = INTERNET_ReadDataFromStream(nSocket, lpBuffer, dwNumOfBytesToRead);
852 if (*dwNumOfBytesRead < 0)
853 *dwNumOfBytesRead = 0;
854 else
855 retval = TRUE;
858 return retval;
862 /***********************************************************************
863 * InternetQueryOptionA
865 * Queries an options on the specified handle
867 * RETURNS
868 * TRUE on success
869 * FALSE on failure
872 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
873 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
875 LPWININETHANDLEHEADER lpwhh;
876 BOOL bSuccess = FALSE;
878 TRACE("0x%08lx\n", dwOption);
880 if (NULL == hInternet)
882 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
883 return FALSE;
886 lpwhh = (LPWININETHANDLEHEADER) hInternet;
888 switch (dwOption)
890 case INTERNET_OPTION_HANDLE_TYPE:
892 ULONG type = lpwhh->htype;
893 TRACE("INTERNET_OPTION_HANDLE_TYPE: %ld\n", type);
895 if (*lpdwBufferLength < sizeof(ULONG))
896 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
897 else
899 memcpy(lpBuffer, &type, sizeof(ULONG));
900 *lpdwBufferLength = sizeof(ULONG);
901 bSuccess = TRUE;
904 break;
907 default:
908 FIXME("Stub!");
909 break;
912 return bSuccess;
916 /***********************************************************************
917 * GetInternetScheme (internal)
919 * Get scheme of url
921 * RETURNS
922 * scheme on success
923 * INTERNET_SCHEME_UNKNOWN on failure
926 INTERNET_SCHEME GetInternetScheme(LPCSTR lpszScheme, INT nMaxCmp)
928 if(lpszScheme==NULL)
929 return INTERNET_SCHEME_UNKNOWN;
931 if (!strncasecmp("ftp", lpszScheme, nMaxCmp))
932 return INTERNET_SCHEME_FTP;
933 else if (!strncasecmp("gopher", lpszScheme, nMaxCmp))
934 return INTERNET_SCHEME_GOPHER;
935 else if (!strncasecmp("http", lpszScheme, nMaxCmp))
936 return INTERNET_SCHEME_HTTP;
937 else if (!strncasecmp("https", lpszScheme, nMaxCmp))
938 return INTERNET_SCHEME_HTTPS;
939 else if (!strncasecmp("file", lpszScheme, nMaxCmp))
940 return INTERNET_SCHEME_FILE;
941 else if (!strncasecmp("news", lpszScheme, nMaxCmp))
942 return INTERNET_SCHEME_NEWS;
943 else if (!strncasecmp("mailto", lpszScheme, nMaxCmp))
944 return INTERNET_SCHEME_MAILTO;
945 else
946 return INTERNET_SCHEME_UNKNOWN;
949 /***********************************************************************
950 * InternetCheckConnectionA
952 * Pings a requested host to check internet connection
954 * RETURNS
956 * TRUE on success and FALSE on failure. if a failures then
957 * ERROR_NOT_CONNECTED is places into GetLastError
960 BOOL WINAPI InternetCheckConnectionA( LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
963 * this is a kludge which runs the resident ping program and reads the output.
965 * Anyone have a better idea?
968 BOOL rc = FALSE;
969 char command[1024];
970 char host[1024];
971 int status = -1;
974 * Crack or set the Address
976 if (lpszUrl == NULL)
979 * According to the doc we are supost to use the ip for the next
980 * server in the WnInet internal server database. I have
981 * no idea what that is or how to get it.
983 * So someone needs to implement this.
985 FIXME("Unimplemented with URL of NULL");
986 return TRUE;
988 else
990 URL_COMPONENTSA componets;
992 ZeroMemory(&componets,sizeof(URL_COMPONENTSA));
993 componets.lpszHostName = (LPSTR)&host;
994 componets.dwHostNameLength = 1024;
996 if (!InternetCrackUrlA(lpszUrl,0,0,&componets))
997 goto End;
999 TRACE("host name : %s\n",componets.lpszHostName);
1003 * Build our ping command
1005 strcpy(command,"ping -w 1 ");
1006 strcat(command,host);
1007 strcat(command," >/dev/null 2>/dev/null");
1009 TRACE("Ping command is : %s\n",command);
1011 status = system(command);
1013 TRACE("Ping returned a code of %i \n",status);
1015 /* Ping return code of 0 indicates success */
1016 if (status == 0)
1017 rc = TRUE;
1019 End:
1021 if (rc == FALSE)
1022 SetLastError(ERROR_NOT_CONNECTED);
1024 return rc;
1029 /***********************************************************************
1030 * INTERNET_WriteDataToStream (internal)
1032 * Send data to server
1034 * RETURNS
1036 * number of characters sent on success
1037 * -1 on error
1039 int INTERNET_WriteDataToStream(int nDataSocket, LPCVOID Buffer, DWORD BytesToWrite)
1041 if (INVALID_SOCKET == nDataSocket)
1042 return SOCKET_ERROR;
1044 return send(nDataSocket, Buffer, BytesToWrite, 0);
1048 /***********************************************************************
1049 * INTERNET_ReadDataFromStream (internal)
1051 * Read data from http server
1053 * RETURNS
1055 * number of characters sent on success
1056 * -1 on error
1058 int INTERNET_ReadDataFromStream(int nDataSocket, LPVOID Buffer, DWORD BytesToRead)
1060 if (INVALID_SOCKET == nDataSocket)
1061 return SOCKET_ERROR;
1063 return recv(nDataSocket, Buffer, BytesToRead, 0);
1067 /***********************************************************************
1068 * INTERNET_SetLastError (internal)
1070 * Set last thread specific error
1072 * RETURNS
1075 void INTERNET_SetLastError(DWORD dwError)
1077 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
1079 SetLastError(dwError);
1080 lpwite->dwError = dwError;
1084 /***********************************************************************
1085 * INTERNET_GetLastError (internal)
1087 * Get last thread specific error
1089 * RETURNS
1092 DWORD INTERNET_GetLastError()
1094 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
1095 return lpwite->dwError;
1099 /***********************************************************************
1100 * INTERNET_WorkerThreadFunc (internal)
1102 * Worker thread execution function
1104 * RETURNS
1107 DWORD INTERNET_WorkerThreadFunc(LPVOID *lpvParam)
1109 DWORD dwWaitRes;
1111 while (1)
1113 dwWaitRes = WaitForMultipleObjects(2, hEventArray, FALSE, MAX_IDLE_WORKER);
1115 if (dwWaitRes == WAIT_OBJECT_0 + 1)
1116 INTERNET_ExecuteWork();
1117 else
1118 break;
1120 InterlockedIncrement(&dwNumIdleThreads);
1123 InterlockedDecrement(&dwNumIdleThreads);
1124 InterlockedDecrement(&dwNumThreads);
1125 TRACE("Worker thread exiting\n");
1126 return TRUE;
1130 /***********************************************************************
1131 * INTERNET_InsertWorkRequest (internal)
1133 * Insert work request into queue
1135 * RETURNS
1138 BOOL INTERNET_InsertWorkRequest(LPWORKREQUEST lpWorkRequest)
1140 BOOL bSuccess = FALSE;
1141 LPWORKREQUEST lpNewRequest;
1143 TRACE("\n");
1145 lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
1146 if (lpNewRequest)
1148 memcpy(lpNewRequest, lpWorkRequest, sizeof(WORKREQUEST));
1149 lpNewRequest->prev = NULL;
1151 EnterCriticalSection(&csQueue);
1153 lpNewRequest->next = lpWorkQueueTail;
1154 if (lpWorkQueueTail)
1155 lpWorkQueueTail->prev = lpNewRequest;
1156 lpWorkQueueTail = lpNewRequest;
1157 if (!lpHeadWorkQueue)
1158 lpHeadWorkQueue = lpWorkQueueTail;
1160 LeaveCriticalSection(&csQueue);
1162 bSuccess = TRUE;
1165 return bSuccess;
1169 /***********************************************************************
1170 * INTERNET_GetWorkRequest (internal)
1172 * Retrieves work request from queue
1174 * RETURNS
1177 BOOL INTERNET_GetWorkRequest(LPWORKREQUEST lpWorkRequest)
1179 BOOL bSuccess = FALSE;
1180 LPWORKREQUEST lpRequest = NULL;
1182 TRACE("\n");
1184 EnterCriticalSection(&csQueue);
1186 if (lpHeadWorkQueue)
1188 lpRequest = lpHeadWorkQueue;
1189 lpHeadWorkQueue = lpHeadWorkQueue->prev;
1190 if (lpRequest == lpWorkQueueTail)
1191 lpWorkQueueTail = lpHeadWorkQueue;
1194 LeaveCriticalSection(&csQueue);
1196 if (lpRequest)
1198 memcpy(lpWorkRequest, lpRequest, sizeof(WORKREQUEST));
1199 HeapFree(GetProcessHeap(), 0, lpRequest);
1200 bSuccess = TRUE;
1203 return bSuccess;
1207 /***********************************************************************
1208 * INTERNET_AsyncCall (internal)
1210 * Retrieves work request from queue
1212 * RETURNS
1215 BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
1217 HANDLE hThread;
1218 DWORD dwTID;
1219 BOOL bSuccess = FALSE;
1221 TRACE("\n");
1223 if (InterlockedDecrement(&dwNumIdleThreads) < 0)
1225 InterlockedIncrement(&dwNumIdleThreads);
1227 if (InterlockedIncrement(&dwNumThreads) > MAX_WORKER_THREADS ||
1228 !(hThread = CreateThread(NULL, 0,
1229 (LPTHREAD_START_ROUTINE)INTERNET_WorkerThreadFunc, NULL, 0, &dwTID)))
1231 InterlockedDecrement(&dwNumThreads);
1232 INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED);
1233 goto lerror;
1236 TRACE("Created new thread\n");
1239 bSuccess = TRUE;
1240 INTERNET_InsertWorkRequest(lpWorkRequest);
1241 SetEvent(hWorkEvent);
1243 lerror:
1245 return bSuccess;
1249 /***********************************************************************
1250 * INTERNET_ExecuteWork (internal)
1252 * RETURNS
1255 VOID INTERNET_ExecuteWork()
1257 WORKREQUEST workRequest;
1259 TRACE("\n");
1261 if (INTERNET_GetWorkRequest(&workRequest))
1263 switch (workRequest.asyncall)
1265 case FTPPUTFILEA:
1266 FTP_FtpPutFileA((HINTERNET)workRequest.HFTPSESSION, (LPCSTR)workRequest.LPSZLOCALFILE,
1267 (LPCSTR)workRequest.LPSZNEWREMOTEFILE, workRequest.DWFLAGS, workRequest.DWCONTEXT);
1268 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZLOCALFILE);
1269 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZNEWREMOTEFILE);
1270 break;
1272 case FTPSETCURRENTDIRECTORYA:
1273 FTP_FtpSetCurrentDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1274 (LPCSTR)workRequest.LPSZDIRECTORY);
1275 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDIRECTORY);
1276 break;
1278 case FTPCREATEDIRECTORYA:
1279 FTP_FtpCreateDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1280 (LPCSTR)workRequest.LPSZDIRECTORY);
1281 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDIRECTORY);
1282 break;
1284 case FTPFINDFIRSTFILEA:
1285 FTP_FtpFindFirstFileA((HINTERNET)workRequest.HFTPSESSION,
1286 (LPCSTR)workRequest.LPSZSEARCHFILE,
1287 (LPWIN32_FIND_DATAA)workRequest.LPFINDFILEDATA, workRequest.DWFLAGS,
1288 workRequest.DWCONTEXT);
1289 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZSEARCHFILE);
1290 break;
1292 case FTPGETCURRENTDIRECTORYA:
1293 FTP_FtpGetCurrentDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1294 (LPSTR)workRequest.LPSZDIRECTORY, (LPDWORD)workRequest.LPDWDIRECTORY);
1295 break;
1297 case FTPOPENFILEA:
1298 FTP_FtpOpenFileA((HINTERNET)workRequest.HFTPSESSION,
1299 (LPCSTR)workRequest.LPSZFILENAME,
1300 workRequest.FDWACCESS,
1301 workRequest.DWFLAGS,
1302 workRequest.DWCONTEXT);
1303 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZFILENAME);
1304 break;
1306 case FTPGETFILEA:
1307 FTP_FtpGetFileA((HINTERNET)workRequest.HFTPSESSION,
1308 (LPCSTR)workRequest.LPSZREMOTEFILE,
1309 (LPCSTR)workRequest.LPSZNEWFILE,
1310 (BOOL)workRequest.FFAILIFEXISTS,
1311 workRequest.DWLOCALFLAGSATTRIBUTE,
1312 workRequest.DWFLAGS,
1313 workRequest.DWCONTEXT);
1314 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZREMOTEFILE);
1315 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZNEWFILE);
1316 break;
1318 case FTPDELETEFILEA:
1319 FTP_FtpDeleteFileA((HINTERNET)workRequest.HFTPSESSION,
1320 (LPCSTR)workRequest.LPSZFILENAME);
1321 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZFILENAME);
1322 break;
1324 case FTPREMOVEDIRECTORYA:
1325 FTP_FtpRemoveDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1326 (LPCSTR)workRequest.LPSZDIRECTORY);
1327 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDIRECTORY);
1328 break;
1330 case FTPRENAMEFILEA:
1331 FTP_FtpRenameFileA((HINTERNET)workRequest.HFTPSESSION,
1332 (LPCSTR)workRequest.LPSZSRCFILE,
1333 (LPCSTR)workRequest.LPSZDESTFILE);
1334 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZSRCFILE);
1335 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDESTFILE);
1336 break;
1338 case INTERNETFINDNEXTA:
1339 INTERNET_FindNextFileA((HINTERNET)workRequest.HFTPSESSION,
1340 (LPWIN32_FIND_DATAA)workRequest.LPFINDFILEDATA);
1341 break;
1343 case HTTPSENDREQUESTA:
1344 HTTP_HttpSendRequestA((HINTERNET)workRequest.HFTPSESSION,
1345 (LPCSTR)workRequest.LPSZHEADER,
1346 workRequest.DWHEADERLENGTH,
1347 (LPVOID)workRequest.LPOPTIONAL,
1348 workRequest.DWOPTIONALLENGTH);
1349 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZHEADER);
1350 break;
1352 case HTTPOPENREQUESTA:
1353 HTTP_HttpOpenRequestA((HINTERNET)workRequest.HFTPSESSION,
1354 (LPCSTR)workRequest.LPSZVERB,
1355 (LPCSTR)workRequest.LPSZOBJECTNAME,
1356 (LPCSTR)workRequest.LPSZVERSION,
1357 (LPCSTR)workRequest.LPSZREFERRER,
1358 (LPCSTR*)workRequest.LPSZACCEPTTYPES,
1359 workRequest.DWFLAGS,
1360 workRequest.DWCONTEXT);
1361 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZVERB);
1362 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZOBJECTNAME);
1363 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZVERSION);
1364 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZREFERRER);
1365 break;
1372 /***********************************************************************
1373 * INTERNET_GetResponseBuffer
1375 * RETURNS
1378 LPSTR INTERNET_GetResponseBuffer()
1380 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
1381 return lpwite->response;
1385 /***********************************************************************
1386 * INTERNET_GetNextLine (internal)
1388 * Parse next line in directory string listing
1390 * RETURNS
1391 * Pointer to begining of next line
1392 * NULL on failure
1396 LPSTR INTERNET_GetNextLine(INT nSocket, LPSTR lpszBuffer, LPDWORD dwBuffer)
1398 struct timeval tv;
1399 fd_set infd;
1400 BOOL bSuccess = FALSE;
1401 INT nRecv = 0;
1403 TRACE("\n");
1405 FD_ZERO(&infd);
1406 FD_SET(nSocket, &infd);
1407 tv.tv_sec=RESPONSE_TIMEOUT;
1408 tv.tv_usec=0;
1410 while (nRecv < *dwBuffer)
1412 if (select(nSocket+1,&infd,NULL,NULL,&tv) > 0)
1414 if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
1416 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1417 goto lend;
1420 if (lpszBuffer[nRecv] == '\n')
1422 bSuccess = TRUE;
1423 break;
1425 if (lpszBuffer[nRecv] != '\r')
1426 nRecv++;
1428 else
1430 INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
1431 goto lend;
1435 lend:
1436 if (bSuccess)
1438 lpszBuffer[nRecv] = '\0';
1439 *dwBuffer = nRecv - 1;
1440 TRACE(":%d %s\n", nRecv, lpszBuffer);
1441 return lpszBuffer;
1443 else
1445 return NULL;