4 * Copyright 1999 Corel Corporation
5 * Copyright 2002 CodeWeavers Inc.
6 * Copyright 2002 Jaco Greeff
7 * Copyright 2002 TransGaming Technologies Inc.
8 * Copyright 2004 Mike McCormack for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include "wine/port.h"
32 #define MAXHOSTNAME 100 /* from http.c */
37 #include <sys/types.h>
38 #ifdef HAVE_SYS_SOCKET_H
39 # include <sys/socket.h>
41 #ifdef HAVE_SYS_TIME_H
42 # include <sys/time.h>
57 #include "wine/debug.h"
59 #define NO_SHLWAPI_STREAM
62 #include "wine/exception.h"
67 #include "wine/unicode.h"
69 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
71 #define MAX_IDLE_WORKER 1000*60*1
72 #define MAX_WORKER_THREADS 10
73 #define RESPONSE_TIMEOUT 30
75 #define GET_HWININET_FROM_LPWININETFINDNEXT(lpwh) \
76 (LPWININETAPPINFOW)(((LPWININETFTPSESSIONW)(lpwh->hdr.lpwhparent))->hdr.lpwhparent)
82 CHAR response[MAX_REPLY_LEN];
83 } WITHREADERROR, *LPWITHREADERROR;
85 static VOID INTERNET_CloseHandle(LPWININETHANDLEHEADER hdr);
86 BOOL WINAPI INTERNET_FindNextFileW(LPWININETFINDNEXTW lpwh, LPVOID lpvFindData);
87 HINTERNET WINAPI INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUrl,
88 LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext);
89 static VOID INTERNET_ExecuteWork();
91 DWORD g_dwTlsErrIndex = TLS_OUT_OF_INDEXES;
93 DWORD dwNumIdleThreads;
95 HANDLE hEventArray[2];
96 #define hQuitEvent hEventArray[0]
97 #define hWorkEvent hEventArray[1]
98 CRITICAL_SECTION csQueue;
99 LPWORKREQUEST lpHeadWorkQueue;
100 LPWORKREQUEST lpWorkQueueTail;
102 extern void URLCacheContainers_CreateDefaults();
103 extern void URLCacheContainers_DeleteAll();
105 #define HANDLE_CHUNK_SIZE 0x10
107 static CRITICAL_SECTION WININET_cs;
108 static CRITICAL_SECTION_DEBUG WININET_cs_debug =
111 { &WININET_cs_debug.ProcessLocksList, &WININET_cs_debug.ProcessLocksList },
112 0, 0, { 0, (DWORD)(__FILE__ ": WININET_cs") }
114 static CRITICAL_SECTION WININET_cs = { &WININET_cs_debug, -1, 0, 0, 0, 0 };
116 static LPWININETHANDLEHEADER *WININET_Handles;
117 static UINT WININET_dwNextHandle;
118 static UINT WININET_dwMaxHandles;
120 HINTERNET WININET_AllocHandle( LPWININETHANDLEHEADER info )
122 LPWININETHANDLEHEADER *p;
123 UINT handle = 0, num;
125 EnterCriticalSection( &WININET_cs );
126 if( !WININET_dwMaxHandles )
128 num = HANDLE_CHUNK_SIZE;
129 p = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
134 WININET_dwMaxHandles = num;
136 if( WININET_dwMaxHandles == WININET_dwNextHandle )
138 num = WININET_dwMaxHandles + HANDLE_CHUNK_SIZE;
139 p = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
140 WININET_Handles, sizeof (UINT)* num);
144 WININET_dwMaxHandles = num;
147 handle = WININET_dwNextHandle;
148 if( WININET_Handles[handle] )
149 ERR("handle isn't free but should be\n");
150 WININET_Handles[handle] = WININET_AddRef( info );
152 while( WININET_Handles[WININET_dwNextHandle] &&
153 (WININET_dwNextHandle < WININET_dwMaxHandles ) )
154 WININET_dwNextHandle++;
157 LeaveCriticalSection( &WININET_cs );
159 return (HINTERNET) (handle+1);
162 HINTERNET WININET_FindHandle( LPWININETHANDLEHEADER info )
166 EnterCriticalSection( &WININET_cs );
167 for( i=0; i<WININET_dwMaxHandles; i++ )
169 if( info == WININET_Handles[i] )
171 WININET_AddRef( info );
176 LeaveCriticalSection( &WININET_cs );
178 return (HINTERNET) handle;
181 LPWININETHANDLEHEADER WININET_AddRef( LPWININETHANDLEHEADER info )
184 TRACE("%p -> refcount = %ld\n", info, info->dwRefCount );
188 LPWININETHANDLEHEADER WININET_GetObject( HINTERNET hinternet )
190 LPWININETHANDLEHEADER info = NULL;
191 UINT handle = (UINT) hinternet;
193 EnterCriticalSection( &WININET_cs );
195 if( (handle > 0) && ( handle <= WININET_dwMaxHandles ) )
196 info = WININET_AddRef( WININET_Handles[handle-1] );
198 LeaveCriticalSection( &WININET_cs );
200 TRACE("handle %d -> %p\n", handle, info);
205 BOOL WININET_Release( LPWININETHANDLEHEADER info )
208 TRACE( "object %p refcount = %ld\n", info, info->dwRefCount );
209 if( !info->dwRefCount )
211 TRACE( "destroying object %p\n", info);
212 info->destroy( info );
217 BOOL WININET_FreeHandle( HINTERNET hinternet )
220 UINT handle = (UINT) hinternet;
221 LPWININETHANDLEHEADER info = NULL;
223 EnterCriticalSection( &WININET_cs );
225 if( (handle > 0) && ( handle <= WININET_dwMaxHandles ) )
228 if( WININET_Handles[handle] )
230 info = WININET_Handles[handle];
231 TRACE( "destroying handle %d for object %p\n", handle+1, info);
232 WININET_Handles[handle] = NULL;
234 if( WININET_dwNextHandle > handle )
235 WININET_dwNextHandle = handle;
239 LeaveCriticalSection( &WININET_cs );
242 WININET_Release( info );
247 /***********************************************************************
248 * DllMain [Internal] Initializes the internal 'WININET.DLL'.
251 * hinstDLL [I] handle to the DLL's instance
253 * lpvReserved [I] reserved, must be NULL
260 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
262 TRACE("%p,%lx,%p\n", hinstDLL, fdwReason, lpvReserved);
265 case DLL_PROCESS_ATTACH:
267 g_dwTlsErrIndex = TlsAlloc();
269 if (g_dwTlsErrIndex == TLS_OUT_OF_INDEXES)
272 hQuitEvent = CreateEventA(0, TRUE, FALSE, NULL);
273 hWorkEvent = CreateEventA(0, FALSE, FALSE, NULL);
274 InitializeCriticalSection(&csQueue);
276 URLCacheContainers_CreateDefaults();
279 dwNumIdleThreads = 0;
282 case DLL_THREAD_ATTACH:
284 LPWITHREADERROR lpwite = HeapAlloc(GetProcessHeap(), 0, sizeof(WITHREADERROR));
288 TlsSetValue(g_dwTlsErrIndex, (LPVOID)lpwite);
292 case DLL_THREAD_DETACH:
293 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
295 LPVOID lpwite = TlsGetValue(g_dwTlsErrIndex);
297 HeapFree(GetProcessHeap(), 0, lpwite);
301 case DLL_PROCESS_DETACH:
303 URLCacheContainers_DeleteAll();
305 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
307 HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex));
308 TlsFree(g_dwTlsErrIndex);
311 SetEvent(hQuitEvent);
313 CloseHandle(hQuitEvent);
314 CloseHandle(hWorkEvent);
315 DeleteCriticalSection(&csQueue);
323 /***********************************************************************
324 * InternetInitializeAutoProxyDll (WININET.@)
326 * Setup the internal proxy
335 BOOL WINAPI InternetInitializeAutoProxyDll(DWORD dwReserved)
338 INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
342 /***********************************************************************
343 * DetectAutoProxyUrl (WININET.@)
345 * Auto detect the proxy url
351 BOOL WINAPI DetectAutoProxyUrl(LPSTR lpszAutoProxyUrl,
352 DWORD dwAutoProxyUrlLength, DWORD dwDetectFlags)
355 INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
360 /***********************************************************************
361 * INTERNET_ConfigureProxyFromReg
364 * The proxy may be specified in the form 'http=proxy.my.org'
365 * Presumably that means there can be ftp=ftpproxy.my.org too.
367 static BOOL INTERNET_ConfigureProxyFromReg( LPWININETAPPINFOW lpwai )
370 DWORD r, keytype, len, enabled;
371 LPSTR lpszInternetSettings =
372 "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
373 static const WCHAR szProxyServer[] = { 'P','r','o','x','y','S','e','r','v','e','r', 0 };
375 r = RegOpenKeyA(HKEY_CURRENT_USER, lpszInternetSettings, &key);
376 if ( r != ERROR_SUCCESS )
379 len = sizeof enabled;
380 r = RegQueryValueExA( key, "ProxyEnable", NULL, &keytype,
381 (BYTE*)&enabled, &len);
382 if( (r == ERROR_SUCCESS) && enabled )
384 TRACE("Proxy is enabled.\n");
386 /* figure out how much memory the proxy setting takes */
387 r = RegQueryValueExW( key, szProxyServer, NULL, &keytype,
389 if( (r == ERROR_SUCCESS) && len && (keytype == REG_SZ) )
392 static const WCHAR szHttp[] = {'h','t','t','p','=',0};
394 szProxy=HeapAlloc( GetProcessHeap(), 0, len );
395 RegQueryValueExW( key, szProxyServer, NULL, &keytype,
396 (BYTE*)szProxy, &len);
398 /* find the http proxy, and strip away everything else */
399 p = strstrW( szProxy, szHttp );
402 p += lstrlenW(szHttp);
403 lstrcpyW( szProxy, p );
405 p = strchrW( szProxy, ' ' );
409 lpwai->dwAccessType = INTERNET_OPEN_TYPE_PROXY;
410 lpwai->lpszProxy = szProxy;
412 TRACE("http proxy = %s\n", debugstr_w(lpwai->lpszProxy));
415 ERR("Couldn't read proxy server settings.\n");
418 TRACE("Proxy is not enabled.\n");
424 /***********************************************************************
425 * InternetOpenW (WININET.@)
427 * Per-application initialization of wininet
430 * HINTERNET on success
434 HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType,
435 LPCWSTR lpszProxy, LPCWSTR lpszProxyBypass, DWORD dwFlags)
437 LPWININETAPPINFOW lpwai = NULL;
438 HINTERNET handle = NULL;
440 if (TRACE_ON(wininet)) {
441 #define FE(x) { x, #x }
442 static const wininet_flag_info access_type[] = {
443 FE(INTERNET_OPEN_TYPE_PRECONFIG),
444 FE(INTERNET_OPEN_TYPE_DIRECT),
445 FE(INTERNET_OPEN_TYPE_PROXY),
446 FE(INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY)
448 static const wininet_flag_info flag[] = {
449 FE(INTERNET_FLAG_ASYNC),
450 FE(INTERNET_FLAG_FROM_CACHE),
451 FE(INTERNET_FLAG_OFFLINE)
455 const char *access_type_str = "Unknown";
456 DWORD flag_val = dwFlags;
458 TRACE("(%s, %li, %s, %s, %li)\n", debugstr_w(lpszAgent), dwAccessType,
459 debugstr_w(lpszProxy), debugstr_w(lpszProxyBypass), dwFlags);
460 for (i = 0; i < (sizeof(access_type) / sizeof(access_type[0])); i++) {
461 if (access_type[i].val == dwAccessType) {
462 access_type_str = access_type[i].name;
466 TRACE(" access type : %s\n", access_type_str);
468 for (i = 0; i < (sizeof(flag) / sizeof(flag[0])); i++) {
469 if (flag[i].val & flag_val) {
470 DPRINTF(" %s", flag[i].name);
471 flag_val &= ~flag[i].val;
474 if (flag_val) DPRINTF(" Unknown flags (%08lx)", flag_val);
478 /* Clear any error information */
479 INTERNET_SetLastError(0);
481 lpwai = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETAPPINFOW));
484 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
488 memset(lpwai, 0, sizeof(WININETAPPINFOW));
489 lpwai->hdr.htype = WH_HINIT;
490 lpwai->hdr.lpwhparent = NULL;
491 lpwai->hdr.dwFlags = dwFlags;
492 lpwai->hdr.dwRefCount = 1;
493 lpwai->hdr.destroy = INTERNET_CloseHandle;
494 lpwai->dwAccessType = dwAccessType;
495 lpwai->lpszProxyUsername = NULL;
496 lpwai->lpszProxyPassword = NULL;
498 handle = WININET_AllocHandle( &lpwai->hdr );
501 HeapFree( GetProcessHeap(), 0, lpwai );
502 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
506 if (NULL != lpszAgent)
508 lpwai->lpszAgent = HeapAlloc( GetProcessHeap(),0,
509 (strlenW(lpszAgent)+1)*sizeof(WCHAR));
510 if (lpwai->lpszAgent)
511 lstrcpyW( lpwai->lpszAgent, lpszAgent );
513 if(dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG)
514 INTERNET_ConfigureProxyFromReg( lpwai );
515 else if (NULL != lpszProxy)
517 lpwai->lpszProxy = HeapAlloc( GetProcessHeap(), 0,
518 (strlenW(lpszProxy)+1)*sizeof(WCHAR));
519 if (lpwai->lpszProxy)
520 lstrcpyW( lpwai->lpszProxy, lpszProxy );
523 if (NULL != lpszProxyBypass)
525 lpwai->lpszProxyBypass = HeapAlloc( GetProcessHeap(), 0,
526 (strlenW(lpszProxyBypass)+1)*sizeof(WCHAR));
527 if (lpwai->lpszProxyBypass)
528 lstrcpyW( lpwai->lpszProxyBypass, lpszProxyBypass );
533 WININET_Release( &lpwai->hdr );
535 TRACE("returning %p\n", lpwai);
541 /***********************************************************************
542 * InternetOpenA (WININET.@)
544 * Per-application initialization of wininet
547 * HINTERNET on success
551 HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType,
552 LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags)
554 HINTERNET rc = (HINTERNET)NULL;
556 WCHAR *szAgent = NULL, *szProxy = NULL, *szBypass = NULL;
558 TRACE("(%s, 0x%08lx, %s, %s, 0x%08lx)\n", debugstr_a(lpszAgent),
559 dwAccessType, debugstr_a(lpszProxy), debugstr_a(lpszProxyBypass), dwFlags);
563 len = MultiByteToWideChar(CP_ACP, 0, lpszAgent, -1, NULL, 0);
564 szAgent = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
565 MultiByteToWideChar(CP_ACP, 0, lpszAgent, -1, szAgent, len);
570 len = MultiByteToWideChar(CP_ACP, 0, lpszProxy, -1, NULL, 0);
571 szProxy = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
572 MultiByteToWideChar(CP_ACP, 0, lpszProxy, -1, szProxy, len);
575 if( lpszProxyBypass )
577 len = MultiByteToWideChar(CP_ACP, 0, lpszProxyBypass, -1, NULL, 0);
578 szBypass = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
579 MultiByteToWideChar(CP_ACP, 0, lpszProxyBypass, -1, szBypass, len);
582 rc = InternetOpenW(szAgent, dwAccessType, szProxy, szBypass, dwFlags);
585 HeapFree(GetProcessHeap(), 0, szAgent);
587 HeapFree(GetProcessHeap(), 0, szProxy);
589 HeapFree(GetProcessHeap(), 0, szBypass);
594 /***********************************************************************
595 * InternetGetLastResponseInfoA (WININET.@)
597 * Return last wininet error description on the calling thread
600 * TRUE on success of writing to buffer
604 BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError,
605 LPSTR lpszBuffer, LPDWORD lpdwBufferLength)
607 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
611 *lpdwError = lpwite->dwError;
614 strncpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
615 *lpdwBufferLength = strlen(lpszBuffer);
618 *lpdwBufferLength = 0;
624 /***********************************************************************
625 * InternetGetConnectedState (WININET.@)
627 * Return connected state
631 * if lpdwStatus is not null, return the status (off line,
632 * modem, lan...) in it.
633 * FALSE if not connected
635 BOOL WINAPI InternetGetConnectedState(LPDWORD lpdwStatus, DWORD dwReserved)
637 TRACE("(%p, 0x%08lx)\n", lpdwStatus, dwReserved);
640 FIXME("always returning LAN connection.\n");
641 *lpdwStatus = INTERNET_CONNECTION_LAN;
646 /***********************************************************************
647 * InternetGetConnectedStateEx (WININET.@)
649 * Return connected state
653 * if lpdwStatus is not null, return the status (off line,
654 * modem, lan...) in it.
655 * FALSE if not connected
657 BOOL WINAPI InternetGetConnectedStateExW(LPDWORD lpdwStatus, LPWSTR lpszConnectionName,
658 DWORD dwNameLen, DWORD dwReserved)
660 TRACE("(%p, %s, %ld, 0x%08lx)\n", lpdwStatus, debugstr_w(lpszConnectionName), dwNameLen, dwReserved);
667 FIXME("always returning LAN connection.\n");
668 *lpdwStatus = INTERNET_CONNECTION_LAN;
673 /***********************************************************************
674 * InternetConnectW (WININET.@)
676 * Open a ftp, gopher or http session
679 * HINTERNET a session handle on success
683 HINTERNET WINAPI InternetConnectW(HINTERNET hInternet,
684 LPCWSTR lpszServerName, INTERNET_PORT nServerPort,
685 LPCWSTR lpszUserName, LPCWSTR lpszPassword,
686 DWORD dwService, DWORD dwFlags, DWORD dwContext)
688 LPWININETAPPINFOW hIC;
689 HINTERNET rc = (HINTERNET) NULL;
691 TRACE("(%p, %s, %i, %s, %s, %li, %li, %li)\n", hInternet, debugstr_w(lpszServerName),
692 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword),
693 dwService, dwFlags, dwContext);
695 /* Clear any error information */
696 INTERNET_SetLastError(0);
697 hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
698 if ( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) )
703 case INTERNET_SERVICE_FTP:
704 rc = FTP_Connect(hIC, lpszServerName, nServerPort,
705 lpszUserName, lpszPassword, dwFlags, dwContext, 0);
708 case INTERNET_SERVICE_HTTP:
709 rc = HTTP_Connect(hIC, lpszServerName, nServerPort,
710 lpszUserName, lpszPassword, dwFlags, dwContext, 0);
713 case INTERNET_SERVICE_GOPHER:
719 WININET_Release( &hIC->hdr );
721 TRACE("returning %p\n", rc);
726 /***********************************************************************
727 * InternetConnectA (WININET.@)
729 * Open a ftp, gopher or http session
732 * HINTERNET a session handle on success
736 HINTERNET WINAPI InternetConnectA(HINTERNET hInternet,
737 LPCSTR lpszServerName, INTERNET_PORT nServerPort,
738 LPCSTR lpszUserName, LPCSTR lpszPassword,
739 DWORD dwService, DWORD dwFlags, DWORD dwContext)
741 HINTERNET rc = (HINTERNET)NULL;
743 LPWSTR szServerName = NULL;
744 LPWSTR szUserName = NULL;
745 LPWSTR szPassword = NULL;
749 len = MultiByteToWideChar(CP_ACP, 0, lpszServerName, -1, NULL, 0);
750 szServerName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
751 MultiByteToWideChar(CP_ACP, 0, lpszServerName, -1, szServerName, len);
755 len = MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, NULL, 0);
756 szUserName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
757 MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, szUserName, len);
761 len = MultiByteToWideChar(CP_ACP, 0, lpszPassword, -1, NULL, 0);
762 szPassword = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
763 MultiByteToWideChar(CP_ACP, 0, lpszPassword, -1, szPassword, len);
767 rc = InternetConnectW(hInternet, szServerName, nServerPort,
768 szUserName, szPassword, dwService, dwFlags, dwContext);
770 if (szServerName) HeapFree(GetProcessHeap(), 0, szServerName);
771 if (szUserName) HeapFree(GetProcessHeap(), 0, szUserName);
772 if (szPassword) HeapFree(GetProcessHeap(), 0, szPassword);
777 /***********************************************************************
778 * InternetFindNextFileA (WININET.@)
780 * Continues a file search from a previous call to FindFirstFile
787 BOOL WINAPI InternetFindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
792 ret = InternetFindNextFileW(hFind, lpvFindData?&fd:NULL);
794 WININET_find_data_WtoA(&fd, (LPWIN32_FIND_DATAA)lpvFindData);
798 /***********************************************************************
799 * InternetFindNextFileW (WININET.@)
801 * Continues a file search from a previous call to FindFirstFile
808 BOOL WINAPI InternetFindNextFileW(HINTERNET hFind, LPVOID lpvFindData)
810 LPWININETAPPINFOW hIC = NULL;
811 LPWININETFINDNEXTW lpwh;
812 BOOL bSuccess = FALSE;
816 lpwh = (LPWININETFINDNEXTW) WININET_GetObject( hFind );
817 if (NULL == lpwh || lpwh->hdr.htype != WH_HFINDNEXT)
819 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
823 hIC = GET_HWININET_FROM_LPWININETFINDNEXT(lpwh);
824 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
826 WORKREQUEST workRequest;
827 struct WORKREQ_INTERNETFINDNEXTW *req;
829 workRequest.asyncall = INTERNETFINDNEXTW;
830 workRequest.hdr = WININET_AddRef( &lpwh->hdr );
831 req = &workRequest.u.InternetFindNextW;
832 req->lpFindFileData = lpvFindData;
834 bSuccess = INTERNET_AsyncCall(&workRequest);
838 bSuccess = INTERNET_FindNextFileW(lpwh, lpvFindData);
842 WININET_Release( &lpwh->hdr );
846 /***********************************************************************
847 * INTERNET_FindNextFileW (Internal)
849 * Continues a file search from a previous call to FindFirstFile
856 BOOL WINAPI INTERNET_FindNextFileW(LPWININETFINDNEXTW lpwh, LPVOID lpvFindData)
858 BOOL bSuccess = TRUE;
859 LPWININETAPPINFOW hIC = NULL;
860 LPWIN32_FIND_DATAW lpFindFileData;
864 assert (lpwh->hdr.htype == WH_HFINDNEXT);
866 /* Clear any error information */
867 INTERNET_SetLastError(0);
869 if (lpwh->hdr.lpwhparent->htype != WH_HFTPSESSION)
871 FIXME("Only FTP find next supported\n");
872 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
876 TRACE("index(%d) size(%ld)\n", lpwh->index, lpwh->size);
878 lpFindFileData = (LPWIN32_FIND_DATAW) lpvFindData;
879 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
881 if (lpwh->index >= lpwh->size)
883 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
888 FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
891 TRACE("\nName: %s\nSize: %ld\n", debugstr_w(lpFindFileData->cFileName), lpFindFileData->nFileSizeLow);
895 hIC = GET_HWININET_FROM_LPWININETFINDNEXT(lpwh);
896 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
898 INTERNET_ASYNC_RESULT iar;
900 iar.dwResult = (DWORD)bSuccess;
901 iar.dwError = iar.dwError = bSuccess ? ERROR_SUCCESS :
902 INTERNET_GetLastError();
904 SendAsyncCallback(hIC, &lpwh->hdr, lpwh->hdr.dwContext,
905 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
906 sizeof(INTERNET_ASYNC_RESULT));
913 /***********************************************************************
914 * INTERNET_CloseHandle (internal)
916 * Close internet handle
922 static VOID INTERNET_CloseHandle(LPWININETHANDLEHEADER hdr)
924 LPWININETAPPINFOW lpwai = (LPWININETAPPINFOW) hdr;
928 if (lpwai->lpszAgent)
929 HeapFree(GetProcessHeap(), 0, lpwai->lpszAgent);
931 if (lpwai->lpszProxy)
932 HeapFree(GetProcessHeap(), 0, lpwai->lpszProxy);
934 if (lpwai->lpszProxyBypass)
935 HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyBypass);
937 if (lpwai->lpszProxyUsername)
938 HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyUsername);
940 if (lpwai->lpszProxyPassword)
941 HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyPassword);
943 HeapFree(GetProcessHeap(), 0, lpwai);
947 /***********************************************************************
948 * InternetCloseHandle (WININET.@)
950 * Generic close handle function
957 BOOL WINAPI InternetCloseHandle(HINTERNET hInternet)
959 LPWININETHANDLEHEADER lpwh, parent;
960 LPWININETAPPINFOW hIC;
962 TRACE("%p\n",hInternet);
964 lpwh = WININET_GetObject( hInternet );
967 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
972 while( parent && (parent->htype != WH_HINIT ) )
973 parent = parent->lpwhparent;
975 hIC = (LPWININETAPPINFOW) parent;
976 SendAsyncCallback(hIC, lpwh, lpwh->dwContext,
977 INTERNET_STATUS_HANDLE_CLOSING, hInternet,
980 if( lpwh->lpwhparent )
981 WININET_Release( lpwh->lpwhparent );
982 WININET_FreeHandle( hInternet );
983 WININET_Release( lpwh );
989 /***********************************************************************
990 * ConvertUrlComponentValue (Internal)
992 * Helper function for InternetCrackUrlW
995 void ConvertUrlComponentValue(LPSTR* lppszComponent, LPDWORD dwComponentLen,
996 LPWSTR lpwszComponent, DWORD dwwComponentLen,
1000 if (*dwComponentLen != 0)
1002 int nASCIILength=WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,NULL,0,NULL,NULL);
1003 if (*lppszComponent == NULL)
1005 int nASCIIOffset=WideCharToMultiByte(CP_ACP,0,lpwszStart,lpwszComponent-lpwszStart,NULL,0,NULL,NULL);
1006 *lppszComponent = (LPSTR)lpszStart+nASCIIOffset;
1007 *dwComponentLen = nASCIILength;
1011 INT ncpylen = min((*dwComponentLen)-1, nASCIILength);
1012 WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,*lppszComponent,ncpylen+1,NULL,NULL);
1013 (*lppszComponent)[ncpylen]=0;
1014 *dwComponentLen = ncpylen;
1020 /***********************************************************************
1021 * InternetCrackUrlA (WININET.@)
1023 * Break up URL into its components
1025 * TODO: Handle dwFlags
1032 BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
1033 LPURL_COMPONENTSA lpUrlComponents)
1036 URL_COMPONENTSW UCW;
1041 nLength=MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,NULL,0);
1042 lpwszUrl=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR)*nLength);
1043 MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,lpwszUrl,nLength);
1045 memset(&UCW,0,sizeof(UCW));
1046 if(lpUrlComponents->dwHostNameLength!=0)
1047 UCW.dwHostNameLength=1;
1048 if(lpUrlComponents->dwUserNameLength!=0)
1049 UCW.dwUserNameLength=1;
1050 if(lpUrlComponents->dwPasswordLength!=0)
1051 UCW.dwPasswordLength=1;
1052 if(lpUrlComponents->dwUrlPathLength!=0)
1053 UCW.dwUrlPathLength=1;
1054 if(lpUrlComponents->dwSchemeLength!=0)
1055 UCW.dwSchemeLength=1;
1056 if(lpUrlComponents->dwExtraInfoLength!=0)
1057 UCW.dwExtraInfoLength=1;
1058 if(!InternetCrackUrlW(lpwszUrl,nLength,dwFlags,&UCW))
1060 HeapFree(GetProcessHeap(), 0, lpwszUrl);
1063 ConvertUrlComponentValue(&lpUrlComponents->lpszHostName, &lpUrlComponents->dwHostNameLength,
1064 UCW.lpszHostName, UCW.dwHostNameLength,
1066 ConvertUrlComponentValue(&lpUrlComponents->lpszUserName, &lpUrlComponents->dwUserNameLength,
1067 UCW.lpszUserName, UCW.dwUserNameLength,
1069 ConvertUrlComponentValue(&lpUrlComponents->lpszPassword, &lpUrlComponents->dwPasswordLength,
1070 UCW.lpszPassword, UCW.dwPasswordLength,
1072 ConvertUrlComponentValue(&lpUrlComponents->lpszUrlPath, &lpUrlComponents->dwUrlPathLength,
1073 UCW.lpszUrlPath, UCW.dwUrlPathLength,
1075 ConvertUrlComponentValue(&lpUrlComponents->lpszScheme, &lpUrlComponents->dwSchemeLength,
1076 UCW.lpszScheme, UCW.dwSchemeLength,
1078 ConvertUrlComponentValue(&lpUrlComponents->lpszExtraInfo, &lpUrlComponents->dwExtraInfoLength,
1079 UCW.lpszExtraInfo, UCW.dwExtraInfoLength,
1081 lpUrlComponents->nScheme=UCW.nScheme;
1082 lpUrlComponents->nPort=UCW.nPort;
1083 HeapFree(GetProcessHeap(), 0, lpwszUrl);
1085 TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", lpszUrl,
1086 debugstr_an(lpUrlComponents->lpszScheme,lpUrlComponents->dwSchemeLength),
1087 debugstr_an(lpUrlComponents->lpszHostName,lpUrlComponents->dwHostNameLength),
1088 debugstr_an(lpUrlComponents->lpszUrlPath,lpUrlComponents->dwUrlPathLength),
1089 debugstr_an(lpUrlComponents->lpszExtraInfo,lpUrlComponents->dwExtraInfoLength));
1094 /***********************************************************************
1095 * GetInternetSchemeW (internal)
1101 * INTERNET_SCHEME_UNKNOWN on failure
1104 INTERNET_SCHEME GetInternetSchemeW(LPCWSTR lpszScheme, INT nMaxCmp)
1106 INTERNET_SCHEME iScheme=INTERNET_SCHEME_UNKNOWN;
1107 static const WCHAR lpszFtp[]={'f','t','p',0};
1108 static const WCHAR lpszGopher[]={'g','o','p','h','e','r',0};
1109 static const WCHAR lpszHttp[]={'h','t','t','p',0};
1110 static const WCHAR lpszHttps[]={'h','t','t','p','s',0};
1111 static const WCHAR lpszFile[]={'f','i','l','e',0};
1112 static const WCHAR lpszNews[]={'n','e','w','s',0};
1113 static const WCHAR lpszMailto[]={'m','a','i','l','t','o',0};
1114 static const WCHAR lpszRes[]={'r','e','s',0};
1115 WCHAR* tempBuffer=NULL;
1117 if(lpszScheme==NULL)
1118 return INTERNET_SCHEME_UNKNOWN;
1120 tempBuffer=HeapAlloc(GetProcessHeap(),0,(nMaxCmp+1)*sizeof(WCHAR));
1121 strncpyW(tempBuffer,lpszScheme,nMaxCmp);
1122 tempBuffer[nMaxCmp]=0;
1123 strlwrW(tempBuffer);
1124 if (nMaxCmp==strlenW(lpszFtp) && !strncmpW(lpszFtp, tempBuffer, nMaxCmp))
1125 iScheme=INTERNET_SCHEME_FTP;
1126 else if (nMaxCmp==strlenW(lpszGopher) && !strncmpW(lpszGopher, tempBuffer, nMaxCmp))
1127 iScheme=INTERNET_SCHEME_GOPHER;
1128 else if (nMaxCmp==strlenW(lpszHttp) && !strncmpW(lpszHttp, tempBuffer, nMaxCmp))
1129 iScheme=INTERNET_SCHEME_HTTP;
1130 else if (nMaxCmp==strlenW(lpszHttps) && !strncmpW(lpszHttps, tempBuffer, nMaxCmp))
1131 iScheme=INTERNET_SCHEME_HTTPS;
1132 else if (nMaxCmp==strlenW(lpszFile) && !strncmpW(lpszFile, tempBuffer, nMaxCmp))
1133 iScheme=INTERNET_SCHEME_FILE;
1134 else if (nMaxCmp==strlenW(lpszNews) && !strncmpW(lpszNews, tempBuffer, nMaxCmp))
1135 iScheme=INTERNET_SCHEME_NEWS;
1136 else if (nMaxCmp==strlenW(lpszMailto) && !strncmpW(lpszMailto, tempBuffer, nMaxCmp))
1137 iScheme=INTERNET_SCHEME_MAILTO;
1138 else if (nMaxCmp==strlenW(lpszRes) && !strncmpW(lpszRes, tempBuffer, nMaxCmp))
1139 iScheme=INTERNET_SCHEME_RES;
1140 HeapFree(GetProcessHeap(),0,tempBuffer);
1144 /***********************************************************************
1145 * SetUrlComponentValueW (Internal)
1147 * Helper function for InternetCrackUrlW
1154 BOOL SetUrlComponentValueW(LPWSTR* lppszComponent, LPDWORD dwComponentLen, LPCWSTR lpszStart, INT len)
1156 TRACE("%s (%d)\n", debugstr_wn(lpszStart,len), len);
1158 if (*dwComponentLen != 0 || *lppszComponent == NULL)
1160 if (*lppszComponent == NULL)
1162 *lppszComponent = (LPWSTR)lpszStart;
1163 *dwComponentLen = len;
1167 INT ncpylen = min((*dwComponentLen)-1, len);
1168 strncpyW(*lppszComponent, lpszStart, ncpylen);
1169 (*lppszComponent)[ncpylen] = '\0';
1170 *dwComponentLen = ncpylen;
1177 /***********************************************************************
1178 * InternetCrackUrlW (WININET.@)
1180 BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
1181 LPURL_COMPONENTSW lpUC)
1185 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1188 LPCWSTR lpszParam = NULL;
1189 BOOL bIsAbsolute = FALSE;
1190 LPCWSTR lpszap = lpszUrl;
1191 LPCWSTR lpszcp = NULL;
1192 const WCHAR lpszSeparators[3]={';','?',0};
1193 const WCHAR lpszSlash[2]={'/',0};
1195 dwUrlLength=strlenW(lpszUrl);
1199 /* Determine if the URI is absolute. */
1200 while (*lpszap != '\0')
1202 if (isalnumW(*lpszap))
1207 if ((*lpszap == ':') && (lpszap - lpszUrl >= 2))
1214 lpszcp = lpszUrl; /* Relative url */
1220 /* Parse <params> */
1221 lpszParam = strpbrkW(lpszap, lpszSeparators);
1222 if (lpszParam != NULL)
1224 if (!SetUrlComponentValueW(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength,
1225 lpszParam, dwUrlLength-(lpszParam-lpszUrl)))
1231 if (bIsAbsolute) /* Parse <protocol>:[//<net_loc>] */
1234 static const WCHAR wszAbout[]={'a','b','o','u','t',':',0};
1236 /* Get scheme first. */
1237 lpUC->nScheme = GetInternetSchemeW(lpszUrl, lpszcp - lpszUrl);
1238 if (!SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength,
1239 lpszUrl, lpszcp - lpszUrl))
1242 /* Eat ':' in protocol. */
1245 /* if the scheme is "about", there is no host */
1246 if(strncmpW(wszAbout,lpszUrl, lpszcp - lpszUrl)==0)
1248 SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1249 SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1250 SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
1255 /* Skip over slashes. */
1267 lpszNetLoc = strpbrkW(lpszcp, lpszSlash);
1271 lpszNetLoc = min(lpszNetLoc, lpszParam);
1273 lpszNetLoc = lpszParam;
1275 else if (!lpszNetLoc)
1276 lpszNetLoc = lpszcp + dwUrlLength-(lpszcp-lpszUrl);
1284 /* [<user>[<:password>]@]<host>[:<port>] */
1285 /* First find the user and password if they exist */
1287 lpszHost = strchrW(lpszcp, '@');
1288 if (lpszHost == NULL || lpszHost > lpszNetLoc)
1290 /* username and password not specified. */
1291 SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1292 SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1294 else /* Parse out username and password */
1296 LPCWSTR lpszUser = lpszcp;
1297 LPCWSTR lpszPasswd = lpszHost;
1299 while (lpszcp < lpszHost)
1302 lpszPasswd = lpszcp;
1307 SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength,
1308 lpszUser, lpszPasswd - lpszUser);
1310 if (lpszPasswd != lpszHost)
1312 SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength,
1313 lpszPasswd == lpszHost ? NULL : lpszPasswd,
1314 lpszHost - lpszPasswd);
1316 lpszcp++; /* Advance to beginning of host */
1319 /* Parse <host><:port> */
1322 lpszPort = lpszNetLoc;
1324 /* special case for res:// URLs: there is no port here, so the host is the
1325 entire string up to the first '/' */
1326 if(lpUC->nScheme==INTERNET_SCHEME_RES)
1328 SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1329 lpszHost, lpszPort - lpszHost);
1335 while (lpszcp < lpszNetLoc)
1343 /* If the scheme is "file" and the host is just one letter, it's not a host */
1344 if(lpUC->nScheme==INTERNET_SCHEME_FILE && (lpszPort-lpszHost)==1)
1347 SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1353 SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1354 lpszHost, lpszPort - lpszHost);
1355 if (lpszPort != lpszNetLoc)
1356 lpUC->nPort = atoiW(++lpszPort);
1365 /* Here lpszcp points to:
1367 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1368 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1370 if (lpszcp != 0 && *lpszcp != '\0' && (!lpszParam || lpszcp < lpszParam))
1374 /* Only truncate the parameter list if it's already been saved
1375 * in lpUC->lpszExtraInfo.
1377 if (lpszParam && lpUC->dwExtraInfoLength)
1378 len = lpszParam - lpszcp;
1381 /* Leave the parameter list in lpszUrlPath. Strip off any trailing
1382 * newlines if necessary.
1384 LPWSTR lpsznewline = strchrW(lpszcp, '\n');
1385 if (lpsznewline != NULL)
1386 len = lpsznewline - lpszcp;
1388 len = dwUrlLength-(lpszcp-lpszUrl);
1391 if (!SetUrlComponentValueW(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength,
1397 lpUC->dwUrlPathLength = 0;
1400 TRACE("%s: host(%s) path(%s) extra(%s)\n", debugstr_wn(lpszUrl,dwUrlLength),
1401 debugstr_wn(lpUC->lpszHostName,lpUC->dwHostNameLength),
1402 debugstr_wn(lpUC->lpszUrlPath,lpUC->dwUrlPathLength),
1403 debugstr_wn(lpUC->lpszExtraInfo,lpUC->dwExtraInfoLength));
1408 /***********************************************************************
1409 * InternetAttemptConnect (WININET.@)
1411 * Attempt to make a connection to the internet
1414 * ERROR_SUCCESS on success
1415 * Error value on failure
1418 DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
1421 return ERROR_SUCCESS;
1425 /***********************************************************************
1426 * InternetCanonicalizeUrlA (WININET.@)
1428 * Escape unsafe characters and spaces
1435 BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
1436 LPDWORD lpdwBufferLength, DWORD dwFlags)
1439 TRACE("%s %p %p %08lx\n",debugstr_a(lpszUrl), lpszBuffer,
1440 lpdwBufferLength, dwFlags);
1442 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1443 dwFlags ^= ICU_NO_ENCODE;
1445 dwFlags |= 0x80000000; /* Don't know what this means */
1447 hr = UrlCanonicalizeA(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
1449 return (hr == S_OK) ? TRUE : FALSE;
1452 /***********************************************************************
1453 * InternetCanonicalizeUrlW (WININET.@)
1455 * Escape unsafe characters and spaces
1462 BOOL WINAPI InternetCanonicalizeUrlW(LPCWSTR lpszUrl, LPWSTR lpszBuffer,
1463 LPDWORD lpdwBufferLength, DWORD dwFlags)
1466 TRACE("%s %p %p %08lx\n", debugstr_w(lpszUrl), lpszBuffer,
1467 lpdwBufferLength, dwFlags);
1469 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1470 dwFlags ^= ICU_NO_ENCODE;
1472 dwFlags |= 0x80000000; /* Don't know what this means */
1474 hr = UrlCanonicalizeW(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
1476 return (hr == S_OK) ? TRUE : FALSE;
1480 /***********************************************************************
1481 * InternetSetStatusCallbackA (WININET.@)
1483 * Sets up a callback function which is called as progress is made
1484 * during an operation.
1487 * Previous callback or NULL on success
1488 * INTERNET_INVALID_STATUS_CALLBACK on failure
1491 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackA(
1492 HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
1494 INTERNET_STATUS_CALLBACK retVal = INTERNET_INVALID_STATUS_CALLBACK;
1495 LPWININETAPPINFOW lpwai;
1497 TRACE("0x%08lx\n", (ULONG)hInternet);
1499 lpwai = (LPWININETAPPINFOW)WININET_GetObject(hInternet);
1503 if (lpwai->hdr.htype == WH_HINIT)
1505 lpwai->hdr.dwInternalFlags &= ~INET_CALLBACKW;
1506 retVal = lpwai->lpfnStatusCB;
1507 lpwai->lpfnStatusCB = lpfnIntCB;
1509 WININET_Release( &lpwai->hdr );
1514 /***********************************************************************
1515 * InternetSetStatusCallbackW (WININET.@)
1517 * Sets up a callback function which is called as progress is made
1518 * during an operation.
1521 * Previous callback or NULL on success
1522 * INTERNET_INVALID_STATUS_CALLBACK on failure
1525 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackW(
1526 HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
1528 INTERNET_STATUS_CALLBACK retVal = INTERNET_INVALID_STATUS_CALLBACK;
1529 LPWININETAPPINFOW lpwai;
1531 TRACE("0x%08lx\n", (ULONG)hInternet);
1533 lpwai = (LPWININETAPPINFOW)WININET_GetObject(hInternet);
1537 if (lpwai->hdr.htype == WH_HINIT)
1539 lpwai->hdr.dwInternalFlags |= INET_CALLBACKW;
1540 retVal = lpwai->lpfnStatusCB;
1541 lpwai->lpfnStatusCB = lpfnIntCB;
1544 WININET_Release( &lpwai->hdr );
1549 /***********************************************************************
1550 * InternetSetFilePointer (WININET.@)
1552 DWORD WINAPI InternetSetFilePointer(HINTERNET f1, LONG f2, PVOID f3, DWORD f4, DWORD f5)
1558 /***********************************************************************
1559 * InternetWriteFile (WININET.@)
1561 * Write data to an open internet file
1568 BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer ,
1569 DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
1571 BOOL retval = FALSE;
1573 LPWININETHANDLEHEADER lpwh;
1576 lpwh = (LPWININETHANDLEHEADER) WININET_GetObject( hFile );
1580 switch (lpwh->htype)
1583 FIXME("This shouldn't be here! We don't support this kind"
1584 " of connection anymore. Must use NETCON functions,"
1585 " especially if using SSL\n");
1586 nSocket = ((LPWININETHTTPREQW)lpwh)->netConnection.socketFD;
1590 nSocket = ((LPWININETFILE)lpwh)->nDataSocket;
1599 int res = send(nSocket, lpBuffer, dwNumOfBytesToWrite, 0);
1600 retval = (res >= 0);
1601 *lpdwNumOfBytesWritten = retval ? res : 0;
1603 WININET_Release( lpwh );
1609 /***********************************************************************
1610 * InternetReadFile (WININET.@)
1612 * Read data from an open internet file
1619 BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
1620 DWORD dwNumOfBytesToRead, LPDWORD dwNumOfBytesRead)
1622 BOOL retval = FALSE;
1624 LPWININETHANDLEHEADER lpwh;
1626 TRACE("%p %p %ld %p\n", hFile, lpBuffer, dwNumOfBytesToRead, dwNumOfBytesRead);
1628 lpwh = (LPWININETHANDLEHEADER) WININET_GetObject( hFile );
1632 /* FIXME: this should use NETCON functions! */
1633 switch (lpwh->htype)
1636 if (!NETCON_recv(&((LPWININETHTTPREQW)lpwh)->netConnection, lpBuffer,
1637 dwNumOfBytesToRead, 0, (int *)dwNumOfBytesRead))
1639 *dwNumOfBytesRead = 0;
1640 retval = TRUE; /* Under windows, it seems to return 0 even if nothing was read... */
1647 /* FIXME: FTP should use NETCON_ stuff */
1648 nSocket = ((LPWININETFILE)lpwh)->nDataSocket;
1651 int res = recv(nSocket, lpBuffer, dwNumOfBytesToRead, 0);
1652 retval = (res >= 0);
1653 *dwNumOfBytesRead = retval ? res : 0;
1660 WININET_Release( lpwh );
1665 /***********************************************************************
1666 * InternetReadFileExA (WININET.@)
1668 * Read data from an open internet file
1675 BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffer,
1676 DWORD dwFlags, DWORD dwContext)
1682 /***********************************************************************
1683 * InternetReadFileExW (WININET.@)
1685 * Read data from an open internet file
1692 BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer,
1693 DWORD dwFlags, DWORD dwContext)
1697 INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1701 /***********************************************************************
1702 * INET_QueryOptionHelper (internal)
1704 static BOOL INET_QueryOptionHelper(BOOL bIsUnicode, HINTERNET hInternet, DWORD dwOption,
1705 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1707 LPWININETHANDLEHEADER lpwhh;
1708 BOOL bSuccess = FALSE;
1710 TRACE("(%p, 0x%08lx, %p, %p)\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
1712 lpwhh = (LPWININETHANDLEHEADER) WININET_GetObject( hInternet );
1716 case INTERNET_OPTION_HANDLE_TYPE:
1722 WARN("Invalid hInternet handle\n");
1723 SetLastError(ERROR_INVALID_HANDLE);
1727 type = lpwhh->htype;
1729 TRACE("INTERNET_OPTION_HANDLE_TYPE: %ld\n", type);
1731 if (*lpdwBufferLength < sizeof(ULONG))
1732 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1735 memcpy(lpBuffer, &type, sizeof(ULONG));
1736 *lpdwBufferLength = sizeof(ULONG);
1742 case INTERNET_OPTION_REQUEST_FLAGS:
1745 TRACE("INTERNET_OPTION_REQUEST_FLAGS: %ld\n", flags);
1746 if (*lpdwBufferLength < sizeof(ULONG))
1747 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1750 memcpy(lpBuffer, &flags, sizeof(ULONG));
1751 *lpdwBufferLength = sizeof(ULONG);
1757 case INTERNET_OPTION_URL:
1758 case INTERNET_OPTION_DATAFILE_NAME:
1762 WARN("Invalid hInternet handle\n");
1763 SetLastError(ERROR_INVALID_HANDLE);
1766 if (lpwhh->htype == WH_HHTTPREQ)
1768 LPWININETHTTPREQW lpreq = (LPWININETHTTPREQW) lpwhh;
1770 static const WCHAR szFmt[] = {'h','t','t','p',':','/','/','%','s','%','s',0};
1772 sprintfW(url,szFmt,lpreq->lpszHostName,lpreq->lpszPath);
1773 TRACE("INTERNET_OPTION_URL: %s\n",debugstr_w(url));
1774 if (*lpdwBufferLength < strlenW(url)+1)
1775 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1780 *lpdwBufferLength=WideCharToMultiByte(CP_ACP,0,url,-1,lpBuffer,*lpdwBufferLength,NULL,NULL);
1784 strcpyW(lpBuffer, url);
1785 *lpdwBufferLength = strlenW(url)+1;
1792 case INTERNET_OPTION_HTTP_VERSION:
1795 * Presently hardcoded to 1.1
1797 ((HTTP_VERSION_INFO*)lpBuffer)->dwMajorVersion = 1;
1798 ((HTTP_VERSION_INFO*)lpBuffer)->dwMinorVersion = 1;
1802 case INTERNET_OPTION_CONNECTED_STATE:
1804 INTERNET_CONNECTED_INFO * pCi = (INTERNET_CONNECTED_INFO *)lpBuffer;
1805 FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n");
1806 pCi->dwConnectedState = INTERNET_STATE_CONNECTED;
1811 case INTERNET_OPTION_SECURITY_FLAGS:
1812 FIXME("INTERNET_OPTION_SECURITY_FLAGS: Stub\n");
1816 FIXME("Stub! %ld \n",dwOption);
1820 WININET_Release( lpwhh );
1825 /***********************************************************************
1826 * InternetQueryOptionW (WININET.@)
1828 * Queries an options on the specified handle
1835 BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption,
1836 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1838 return INET_QueryOptionHelper(TRUE, hInternet, dwOption, lpBuffer, lpdwBufferLength);
1841 /***********************************************************************
1842 * InternetQueryOptionA (WININET.@)
1844 * Queries an options on the specified handle
1851 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
1852 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1854 return INET_QueryOptionHelper(FALSE, hInternet, dwOption, lpBuffer, lpdwBufferLength);
1858 /***********************************************************************
1859 * InternetSetOptionW (WININET.@)
1861 * Sets an options on the specified handle
1868 BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
1869 LPVOID lpBuffer, DWORD dwBufferLength)
1871 LPWININETHANDLEHEADER lpwhh;
1874 TRACE("0x%08lx\n", dwOption);
1876 lpwhh = (LPWININETHANDLEHEADER) WININET_GetObject( hInternet );
1882 case INTERNET_OPTION_HTTP_VERSION:
1884 HTTP_VERSION_INFO* pVersion=(HTTP_VERSION_INFO*)lpBuffer;
1885 FIXME("Option INTERNET_OPTION_HTTP_VERSION(%ld,%ld): STUB\n",pVersion->dwMajorVersion,pVersion->dwMinorVersion);
1888 case INTERNET_OPTION_ERROR_MASK:
1890 unsigned long flags=*(unsigned long*)lpBuffer;
1891 FIXME("Option INTERNET_OPTION_ERROR_MASK(%ld): STUB\n",flags);
1894 case INTERNET_OPTION_CODEPAGE:
1896 unsigned long codepage=*(unsigned long*)lpBuffer;
1897 FIXME("Option INTERNET_OPTION_CODEPAGE (%ld): STUB\n",codepage);
1900 case INTERNET_OPTION_REQUEST_PRIORITY:
1902 unsigned long priority=*(unsigned long*)lpBuffer;
1903 FIXME("Option INTERNET_OPTION_REQUEST_PRIORITY (%ld): STUB\n",priority);
1906 case INTERNET_OPTION_CONNECT_TIMEOUT:
1908 unsigned long connecttimeout=*(unsigned long*)lpBuffer;
1909 FIXME("Option INTERNET_OPTION_CONNECT_TIMEOUT (%ld): STUB\n",connecttimeout);
1912 case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT:
1914 unsigned long receivetimeout=*(unsigned long*)lpBuffer;
1915 FIXME("Option INTERNET_OPTION_DATA_RECEIVE_TIMEOUT (%ld): STUB\n",receivetimeout);
1918 case INTERNET_OPTION_RESET_URLCACHE_SESSION:
1919 FIXME("Option INTERNET_OPTION_RESET_URLCACHE_SESSION: STUB\n");
1921 case INTERNET_OPTION_END_BROWSER_SESSION:
1922 FIXME("Option INTERNET_OPTION_END_BROWSER_SESSION: STUB\n");
1924 case INTERNET_OPTION_CONNECTED_STATE:
1925 FIXME("Option INTERNET_OPTION_CONNECTED_STATE: STUB\n");
1928 FIXME("Option %ld STUB\n",dwOption);
1929 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1933 WININET_Release( lpwhh );
1939 /***********************************************************************
1940 * InternetSetOptionA (WININET.@)
1942 * Sets an options on the specified handle.
1949 BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
1950 LPVOID lpBuffer, DWORD dwBufferLength)
1958 case INTERNET_OPTION_PROXY:
1960 LPINTERNET_PROXY_INFOA pi = (LPINTERNET_PROXY_INFOA) lpBuffer;
1961 LPINTERNET_PROXY_INFOW piw;
1962 DWORD proxlen, prbylen;
1965 proxlen = MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, NULL, 0);
1966 prbylen= MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, NULL, 0);
1967 wlen = sizeof(*piw) + proxlen + prbylen;
1968 wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
1969 piw = (LPINTERNET_PROXY_INFOW) wbuffer;
1970 piw->dwAccessType = pi->dwAccessType;
1971 prox = (LPWSTR) &piw[1];
1972 prby = &prox[proxlen+1];
1973 MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, prox, proxlen);
1974 MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, prby, prbylen);
1975 piw->lpszProxy = prox;
1976 piw->lpszProxyBypass = prby;
1979 case INTERNET_OPTION_USER_AGENT:
1980 case INTERNET_OPTION_USERNAME:
1981 case INTERNET_OPTION_PASSWORD:
1982 wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
1984 wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
1985 MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
1990 wlen = dwBufferLength;
1993 r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen);
1995 if( lpBuffer != wbuffer )
1996 HeapFree( GetProcessHeap(), 0, wbuffer );
2002 /***********************************************************************
2003 * InternetSetOptionExA (WININET.@)
2005 BOOL WINAPI InternetSetOptionExA(HINTERNET hInternet, DWORD dwOption,
2006 LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2008 FIXME("Flags %08lx ignored\n", dwFlags);
2009 return InternetSetOptionA( hInternet, dwOption, lpBuffer, dwBufferLength );
2012 /***********************************************************************
2013 * InternetSetOptionExW (WININET.@)
2015 BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption,
2016 LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2018 FIXME("Flags %08lx ignored\n", dwFlags);
2019 if( dwFlags & ~ISO_VALID_FLAGS )
2021 SetLastError( ERROR_INVALID_PARAMETER );
2024 return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength );
2028 /***********************************************************************
2029 * InternetCheckConnectionA (WININET.@)
2031 * Pings a requested host to check internet connection
2034 * TRUE on success and FALSE on failure. If a failure then
2035 * ERROR_NOT_CONNECTED is placesd into GetLastError
2038 BOOL WINAPI InternetCheckConnectionA( LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
2041 * this is a kludge which runs the resident ping program and reads the output.
2043 * Anyone have a better idea?
2054 * Crack or set the Address
2056 if (lpszUrl == NULL)
2059 * According to the doc we are supost to use the ip for the next
2060 * server in the WnInet internal server database. I have
2061 * no idea what that is or how to get it.
2063 * So someone needs to implement this.
2065 FIXME("Unimplemented with URL of NULL\n");
2070 URL_COMPONENTSA componets;
2072 ZeroMemory(&componets,sizeof(URL_COMPONENTSA));
2073 componets.lpszHostName = (LPSTR)&host;
2074 componets.dwHostNameLength = 1024;
2076 if (!InternetCrackUrlA(lpszUrl,0,0,&componets))
2079 TRACE("host name : %s\n",componets.lpszHostName);
2083 * Build our ping command
2085 strcpy(command,"ping -w 1 ");
2086 strcat(command,host);
2087 strcat(command," >/dev/null 2>/dev/null");
2089 TRACE("Ping command is : %s\n",command);
2091 status = system(command);
2093 TRACE("Ping returned a code of %i \n",status);
2095 /* Ping return code of 0 indicates success */
2102 SetLastError(ERROR_NOT_CONNECTED);
2108 /***********************************************************************
2109 * InternetCheckConnectionW (WININET.@)
2111 * Pings a requested host to check internet connection
2114 * TRUE on success and FALSE on failure. If a failure then
2115 * ERROR_NOT_CONNECTED is placed into GetLastError
2118 BOOL WINAPI InternetCheckConnectionW(LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
2124 len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
2125 if (!(szUrl = (CHAR *)HeapAlloc(GetProcessHeap(), 0, len*sizeof(CHAR))))
2127 WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, szUrl, len, NULL, NULL);
2128 rc = InternetCheckConnectionA((LPCSTR)szUrl, dwFlags, dwReserved);
2129 HeapFree(GetProcessHeap(), 0, szUrl);
2135 /**********************************************************
2136 * INTERNET_InternetOpenUrlW (internal)
2141 * handle of connection or NULL on failure
2143 HINTERNET WINAPI INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUrl,
2144 LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
2146 URL_COMPONENTSW urlComponents;
2147 WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024];
2148 WCHAR password[1024], path[2048], extra[1024];
2149 HINTERNET client = NULL, client1 = NULL;
2151 TRACE("(%p, %s, %s, %08lx, %08lx, %08lx\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
2152 dwHeadersLength, dwFlags, dwContext);
2154 urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
2155 urlComponents.lpszScheme = protocol;
2156 urlComponents.dwSchemeLength = 32;
2157 urlComponents.lpszHostName = hostName;
2158 urlComponents.dwHostNameLength = MAXHOSTNAME;
2159 urlComponents.lpszUserName = userName;
2160 urlComponents.dwUserNameLength = 1024;
2161 urlComponents.lpszPassword = password;
2162 urlComponents.dwPasswordLength = 1024;
2163 urlComponents.lpszUrlPath = path;
2164 urlComponents.dwUrlPathLength = 2048;
2165 urlComponents.lpszExtraInfo = extra;
2166 urlComponents.dwExtraInfoLength = 1024;
2167 if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
2169 switch(urlComponents.nScheme) {
2170 case INTERNET_SCHEME_FTP:
2171 if(urlComponents.nPort == 0)
2172 urlComponents.nPort = INTERNET_DEFAULT_FTP_PORT;
2173 client = FTP_Connect(hIC, hostName, urlComponents.nPort,
2174 userName, password, dwFlags, dwContext, INET_OPENURL);
2177 client1 = FtpOpenFileW(client, path, GENERIC_READ, dwFlags, dwContext);
2178 if(client1 == NULL) {
2179 InternetCloseHandle(client);
2184 case INTERNET_SCHEME_HTTP:
2185 case INTERNET_SCHEME_HTTPS: {
2186 static const WCHAR szStars[] = { '*','/','*', 0 };
2187 LPCWSTR accept[2] = { szStars, NULL };
2188 if(urlComponents.nPort == 0) {
2189 if(urlComponents.nScheme == INTERNET_SCHEME_HTTP)
2190 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
2192 urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
2194 /* FIXME: should use pointers, not handles, as handles are not thread-safe */
2195 client = HTTP_Connect(hIC, hostName, urlComponents.nPort,
2196 userName, password, dwFlags, dwContext, INET_OPENURL);
2199 client1 = HttpOpenRequestW(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
2200 if(client1 == NULL) {
2201 InternetCloseHandle(client);
2204 HttpAddRequestHeadersW(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
2205 if (!HttpSendRequestW(client1, NULL, 0, NULL, 0)) {
2206 InternetCloseHandle(client1);
2211 case INTERNET_SCHEME_GOPHER:
2212 /* gopher doesn't seem to be implemented in wine, but it's supposed
2213 * to be supported by InternetOpenUrlA. */
2218 TRACE(" %p <--\n", client1);
2223 /**********************************************************
2224 * InternetOpenUrlW (WININET.@)
2229 * handle of connection or NULL on failure
2231 HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
2232 LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
2234 HINTERNET ret = NULL;
2235 LPWININETAPPINFOW hIC = NULL;
2237 TRACE("(%p, %s, %s, %08lx, %08lx, %08lx\n", hInternet, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
2238 dwHeadersLength, dwFlags, dwContext);
2240 hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
2241 if (NULL == hIC || hIC->hdr.htype != WH_HINIT) {
2242 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2246 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) {
2247 WORKREQUEST workRequest;
2248 struct WORKREQ_INTERNETOPENURLW *req;
2250 workRequest.asyncall = INTERNETOPENURLW;
2251 workRequest.hdr = WININET_AddRef( &hIC->hdr );
2252 req = &workRequest.u.InternetOpenUrlW;
2254 req->lpszUrl = WININET_strdupW(lpszUrl);
2258 req->lpszHeaders = WININET_strdupW(lpszHeaders);
2260 req->lpszHeaders = 0;
2261 req->dwHeadersLength = dwHeadersLength;
2262 req->dwFlags = dwFlags;
2263 req->dwContext = dwContext;
2265 INTERNET_AsyncCall(&workRequest);
2267 * This is from windows.
2269 SetLastError(ERROR_IO_PENDING);
2271 ret = INTERNET_InternetOpenUrlW(hIC, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext);
2276 WININET_Release( &hIC->hdr );
2277 TRACE(" %p <--\n", ret);
2282 /**********************************************************
2283 * InternetOpenUrlA (WININET.@)
2288 * handle of connection or NULL on failure
2290 HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
2291 LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
2293 HINTERNET rc = (HINTERNET)NULL;
2297 LPWSTR szUrl = NULL;
2298 LPWSTR szHeaders = NULL;
2303 lenUrl = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0 );
2304 szUrl = HeapAlloc(GetProcessHeap(), 0, lenUrl*sizeof(WCHAR));
2306 return (HINTERNET)NULL;
2307 MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, szUrl, lenUrl);
2311 lenHeaders = MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, NULL, 0 );
2312 szHeaders = HeapAlloc(GetProcessHeap(), 0, lenHeaders*sizeof(WCHAR));
2314 if(szUrl) HeapFree(GetProcessHeap(), 0, szUrl);
2315 return (HINTERNET)NULL;
2317 MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, szHeaders, lenHeaders);
2320 rc = InternetOpenUrlW(hInternet, szUrl, szHeaders,
2321 lenHeaders, dwFlags, dwContext);
2323 if(szUrl) HeapFree(GetProcessHeap(), 0, szUrl);
2324 if(szHeaders) HeapFree(GetProcessHeap(), 0, szHeaders);
2330 /***********************************************************************
2331 * INTERNET_SetLastError (internal)
2333 * Set last thread specific error
2338 void INTERNET_SetLastError(DWORD dwError)
2340 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
2342 SetLastError(dwError);
2344 lpwite->dwError = dwError;
2348 /***********************************************************************
2349 * INTERNET_GetLastError (internal)
2351 * Get last thread specific error
2356 DWORD INTERNET_GetLastError()
2358 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
2359 return lpwite->dwError;
2363 /***********************************************************************
2364 * INTERNET_WorkerThreadFunc (internal)
2366 * Worker thread execution function
2371 DWORD INTERNET_WorkerThreadFunc(LPVOID *lpvParam)
2378 INTERNET_ExecuteWork();
2381 dwWaitRes = WaitForMultipleObjects(2, hEventArray, FALSE, MAX_IDLE_WORKER);
2383 if (dwWaitRes == WAIT_OBJECT_0 + 1)
2384 INTERNET_ExecuteWork();
2388 InterlockedIncrement(&dwNumIdleThreads);
2391 InterlockedDecrement(&dwNumIdleThreads);
2392 InterlockedDecrement(&dwNumThreads);
2393 TRACE("Worker thread exiting\n");
2398 /***********************************************************************
2399 * INTERNET_InsertWorkRequest (internal)
2401 * Insert work request into queue
2406 BOOL INTERNET_InsertWorkRequest(LPWORKREQUEST lpWorkRequest)
2408 BOOL bSuccess = FALSE;
2409 LPWORKREQUEST lpNewRequest;
2413 lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
2416 memcpy(lpNewRequest, lpWorkRequest, sizeof(WORKREQUEST));
2417 lpNewRequest->prev = NULL;
2419 EnterCriticalSection(&csQueue);
2421 lpNewRequest->next = lpWorkQueueTail;
2422 if (lpWorkQueueTail)
2423 lpWorkQueueTail->prev = lpNewRequest;
2424 lpWorkQueueTail = lpNewRequest;
2425 if (!lpHeadWorkQueue)
2426 lpHeadWorkQueue = lpWorkQueueTail;
2428 LeaveCriticalSection(&csQueue);
2431 InterlockedIncrement(&dwNumJobs);
2438 /***********************************************************************
2439 * INTERNET_GetWorkRequest (internal)
2441 * Retrieves work request from queue
2446 BOOL INTERNET_GetWorkRequest(LPWORKREQUEST lpWorkRequest)
2448 BOOL bSuccess = FALSE;
2449 LPWORKREQUEST lpRequest = NULL;
2453 EnterCriticalSection(&csQueue);
2455 if (lpHeadWorkQueue)
2457 lpRequest = lpHeadWorkQueue;
2458 lpHeadWorkQueue = lpHeadWorkQueue->prev;
2459 if (lpRequest == lpWorkQueueTail)
2460 lpWorkQueueTail = lpHeadWorkQueue;
2463 LeaveCriticalSection(&csQueue);
2467 memcpy(lpWorkRequest, lpRequest, sizeof(WORKREQUEST));
2468 HeapFree(GetProcessHeap(), 0, lpRequest);
2470 InterlockedDecrement(&dwNumJobs);
2477 /***********************************************************************
2478 * INTERNET_AsyncCall (internal)
2480 * Retrieves work request from queue
2485 BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
2489 BOOL bSuccess = FALSE;
2493 if (InterlockedDecrement(&dwNumIdleThreads) < 0)
2495 InterlockedIncrement(&dwNumIdleThreads);
2497 if (InterlockedIncrement(&dwNumThreads) > MAX_WORKER_THREADS ||
2498 !(hThread = CreateThread(NULL, 0,
2499 (LPTHREAD_START_ROUTINE)INTERNET_WorkerThreadFunc, NULL, 0, &dwTID)))
2501 InterlockedDecrement(&dwNumThreads);
2502 INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED);
2506 TRACE("Created new thread\n");
2510 INTERNET_InsertWorkRequest(lpWorkRequest);
2511 SetEvent(hWorkEvent);
2519 /***********************************************************************
2520 * INTERNET_ExecuteWork (internal)
2525 static VOID INTERNET_ExecuteWork()
2527 WORKREQUEST workRequest;
2531 if (!INTERNET_GetWorkRequest(&workRequest))
2534 switch (workRequest.asyncall)
2538 struct WORKREQ_FTPPUTFILEW *req = &workRequest.u.FtpPutFileW;
2539 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2541 TRACE("FTPPUTFILEW %p\n", lpwfs);
2543 FTP_FtpPutFileW(lpwfs, req->lpszLocalFile,
2544 req->lpszNewRemoteFile, req->dwFlags, req->dwContext);
2546 HeapFree(GetProcessHeap(), 0, req->lpszLocalFile);
2547 HeapFree(GetProcessHeap(), 0, req->lpszNewRemoteFile);
2551 case FTPSETCURRENTDIRECTORYW:
2553 struct WORKREQ_FTPSETCURRENTDIRECTORYW *req;
2554 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2556 TRACE("FTPSETCURRENTDIRECTORYW %p\n", lpwfs);
2558 req = &workRequest.u.FtpSetCurrentDirectoryW;
2559 FTP_FtpSetCurrentDirectoryW(lpwfs, req->lpszDirectory);
2560 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2564 case FTPCREATEDIRECTORYW:
2566 struct WORKREQ_FTPCREATEDIRECTORYW *req;
2567 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2569 TRACE("FTPCREATEDIRECTORYW %p\n", lpwfs);
2571 req = &workRequest.u.FtpCreateDirectoryW;
2572 FTP_FtpCreateDirectoryW(lpwfs, req->lpszDirectory);
2573 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2577 case FTPFINDFIRSTFILEW:
2579 struct WORKREQ_FTPFINDFIRSTFILEW *req;
2580 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2582 TRACE("FTPFINDFIRSTFILEW %p\n", lpwfs);
2584 req = &workRequest.u.FtpFindFirstFileW;
2585 FTP_FtpFindFirstFileW(lpwfs, req->lpszSearchFile,
2586 req->lpFindFileData, req->dwFlags, req->dwContext);
2587 if (req->lpszSearchFile != NULL)
2588 HeapFree(GetProcessHeap(), 0, req->lpszSearchFile);
2592 case FTPGETCURRENTDIRECTORYW:
2594 struct WORKREQ_FTPGETCURRENTDIRECTORYW *req;
2595 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2597 TRACE("FTPGETCURRENTDIRECTORYW %p\n", lpwfs);
2599 req = &workRequest.u.FtpGetCurrentDirectoryW;
2600 FTP_FtpGetCurrentDirectoryW(lpwfs,
2601 req->lpszDirectory, req->lpdwDirectory);
2607 struct WORKREQ_FTPOPENFILEW *req = &workRequest.u.FtpOpenFileW;
2608 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2610 TRACE("FTPOPENFILEW %p\n", lpwfs);
2612 FTP_FtpOpenFileW(lpwfs, req->lpszFilename,
2613 req->dwAccess, req->dwFlags, req->dwContext);
2614 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
2620 struct WORKREQ_FTPGETFILEW *req = &workRequest.u.FtpGetFileW;
2621 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2623 TRACE("FTPGETFILEW %p\n", lpwfs);
2625 FTP_FtpGetFileW(lpwfs, req->lpszRemoteFile,
2626 req->lpszNewFile, req->fFailIfExists,
2627 req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext);
2628 HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile);
2629 HeapFree(GetProcessHeap(), 0, req->lpszNewFile);
2633 case FTPDELETEFILEW:
2635 struct WORKREQ_FTPDELETEFILEW *req = &workRequest.u.FtpDeleteFileW;
2636 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2638 TRACE("FTPDELETEFILEW %p\n", lpwfs);
2640 FTP_FtpDeleteFileW(lpwfs, req->lpszFilename);
2641 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
2645 case FTPREMOVEDIRECTORYW:
2647 struct WORKREQ_FTPREMOVEDIRECTORYW *req;
2648 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2650 TRACE("FTPREMOVEDIRECTORYW %p\n", lpwfs);
2652 req = &workRequest.u.FtpRemoveDirectoryW;
2653 FTP_FtpRemoveDirectoryW(lpwfs, req->lpszDirectory);
2654 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2658 case FTPRENAMEFILEW:
2660 struct WORKREQ_FTPRENAMEFILEW *req = &workRequest.u.FtpRenameFileW;
2661 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2663 TRACE("FTPRENAMEFILEW %p\n", lpwfs);
2665 FTP_FtpRenameFileW(lpwfs, req->lpszSrcFile, req->lpszDestFile);
2666 HeapFree(GetProcessHeap(), 0, req->lpszSrcFile);
2667 HeapFree(GetProcessHeap(), 0, req->lpszDestFile);
2671 case INTERNETFINDNEXTW:
2673 struct WORKREQ_INTERNETFINDNEXTW *req;
2674 LPWININETFINDNEXTW lpwh = (LPWININETFINDNEXTW) workRequest.hdr;
2676 TRACE("INTERNETFINDNEXTW %p\n", lpwh);
2678 req = &workRequest.u.InternetFindNextW;
2679 INTERNET_FindNextFileW(lpwh, req->lpFindFileData);
2683 case HTTPSENDREQUESTW:
2685 struct WORKREQ_HTTPSENDREQUESTW *req = &workRequest.u.HttpSendRequestW;
2686 LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) workRequest.hdr;
2688 TRACE("HTTPSENDREQUESTW %p\n", lpwhr);
2690 HTTP_HttpSendRequestW(lpwhr, req->lpszHeader,
2691 req->dwHeaderLength, req->lpOptional, req->dwOptionalLength);
2693 HeapFree(GetProcessHeap(), 0, req->lpszHeader);
2697 case HTTPOPENREQUESTW:
2699 struct WORKREQ_HTTPOPENREQUESTW *req = &workRequest.u.HttpOpenRequestW;
2700 LPWININETHTTPSESSIONW lpwhs = (LPWININETHTTPSESSIONW) workRequest.hdr;
2702 TRACE("HTTPOPENREQUESTW %p\n", lpwhs);
2704 HTTP_HttpOpenRequestW(lpwhs, req->lpszVerb,
2705 req->lpszObjectName, req->lpszVersion, req->lpszReferrer,
2706 req->lpszAcceptTypes, req->dwFlags, req->dwContext);
2708 HeapFree(GetProcessHeap(), 0, req->lpszVerb);
2709 HeapFree(GetProcessHeap(), 0, req->lpszObjectName);
2710 HeapFree(GetProcessHeap(), 0, req->lpszVersion);
2711 HeapFree(GetProcessHeap(), 0, req->lpszReferrer);
2717 struct WORKREQ_SENDCALLBACK *req = &workRequest.u.SendCallback;
2718 LPWININETAPPINFOW hIC = (LPWININETAPPINFOW) workRequest.hdr;
2720 TRACE("SENDCALLBACK %p\n", hIC);
2722 SendAsyncCallbackInt(hIC, req->hdr,
2723 req->dwContext, req->dwInternetStatus, req->lpvStatusInfo,
2724 req->dwStatusInfoLength);
2728 case INTERNETOPENURLW:
2730 struct WORKREQ_INTERNETOPENURLW *req = &workRequest.u.InternetOpenUrlW;
2731 LPWININETAPPINFOW hIC = (LPWININETAPPINFOW) workRequest.hdr;
2733 TRACE("INTERNETOPENURLW %p\n", hIC);
2735 INTERNET_InternetOpenUrlW(hIC, req->lpszUrl,
2736 req->lpszHeaders, req->dwHeadersLength, req->dwFlags, req->dwContext);
2737 HeapFree(GetProcessHeap(), 0, req->lpszUrl);
2738 HeapFree(GetProcessHeap(), 0, req->lpszHeaders);
2742 WININET_Release( workRequest.hdr );
2746 /***********************************************************************
2747 * INTERNET_GetResponseBuffer
2752 LPSTR INTERNET_GetResponseBuffer()
2754 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
2756 return lpwite->response;
2759 /***********************************************************************
2760 * INTERNET_GetNextLine (internal)
2762 * Parse next line in directory string listing
2765 * Pointer to beginning of next line
2770 LPSTR INTERNET_GetNextLine(INT nSocket, LPDWORD dwLen)
2774 BOOL bSuccess = FALSE;
2776 LPSTR lpszBuffer = INTERNET_GetResponseBuffer();
2781 FD_SET(nSocket, &infd);
2782 tv.tv_sec=RESPONSE_TIMEOUT;
2785 while (nRecv < MAX_REPLY_LEN)
2787 if (select(nSocket+1,&infd,NULL,NULL,&tv) > 0)
2789 if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
2791 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
2795 if (lpszBuffer[nRecv] == '\n')
2800 if (lpszBuffer[nRecv] != '\r')
2805 INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
2813 lpszBuffer[nRecv] = '\0';
2815 TRACE(":%d %s\n", nRecv, lpszBuffer);
2824 /***********************************************************************
2827 BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile,
2828 LPDWORD lpdwNumberOfBytesAvailble,
2829 DWORD dwFlags, DWORD dwConext)
2831 LPWININETHTTPREQW lpwhr;
2835 lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hFile );
2838 SetLastError(ERROR_NO_MORE_FILES);
2842 TRACE("--> %p %i\n",lpwhr,lpwhr->hdr.htype);
2844 switch (lpwhr->hdr.htype)
2847 if (!NETCON_recv(&lpwhr->netConnection, buffer,
2848 4048, MSG_PEEK, (int *)lpdwNumberOfBytesAvailble))
2850 SetLastError(ERROR_NO_MORE_FILES);
2858 FIXME("unsupported file type\n");
2861 WININET_Release( &lpwhr->hdr );
2863 TRACE("<-- %i\n",retval);
2868 /***********************************************************************
2871 BOOL WINAPI InternetLockRequestFile( HINTERNET hInternet, HANDLE
2878 BOOL WINAPI InternetUnlockRequestFile( HANDLE hLockHandle)
2885 /***********************************************************************
2888 * On windows this function is supposed to dial the default internet
2889 * connection. We don't want to have Wine dial out to the internet so
2890 * we return TRUE by default. It might be nice to check if we are connected.
2897 BOOL WINAPI InternetAutodial(DWORD dwFlags, HWND hwndParent)
2901 /* Tell that we are connected to the internet. */
2905 /***********************************************************************
2906 * InternetAutodialHangup
2908 * Hangs up an connection made with InternetAutodial
2917 BOOL WINAPI InternetAutodialHangup(DWORD dwReserved)
2921 /* we didn't dial, we don't disconnect */
2925 /***********************************************************************
2927 * InternetCombineUrlA
2929 * Combine a base URL with a relative URL
2937 BOOL WINAPI InternetCombineUrlA(LPCSTR lpszBaseUrl, LPCSTR lpszRelativeUrl,
2938 LPSTR lpszBuffer, LPDWORD lpdwBufferLength,
2943 TRACE("(%s, %s, %p, %p, 0x%08lx)\n", debugstr_a(lpszBaseUrl), debugstr_a(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
2945 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
2946 dwFlags ^= ICU_NO_ENCODE;
2947 hr=UrlCombineA(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
2952 /***********************************************************************
2954 * InternetCombineUrlW
2956 * Combine a base URL with a relative URL
2964 BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
2965 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength,
2970 TRACE("(%s, %s, %p, %p, 0x%08lx)\n", debugstr_w(lpszBaseUrl), debugstr_w(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
2972 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
2973 dwFlags ^= ICU_NO_ENCODE;
2974 hr=UrlCombineW(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
2979 /***********************************************************************
2981 * InternetCreateUrlA
2988 BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
2989 LPSTR lpszUrl, LPDWORD lpdwUrlLength)
2995 /***********************************************************************
2997 * InternetCreateUrlW
3004 BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
3005 LPWSTR lpszUrl, LPDWORD lpdwUrlLength)