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(%ld) 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 DWORD 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 DWORD 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 static INTERNET_SCHEME GetInternetSchemeW(LPCWSTR lpszScheme, DWORD 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 static BOOL SetUrlComponentValueW(LPWSTR* lppszComponent, LPDWORD dwComponentLen, LPCWSTR lpszStart, DWORD len)
1156 TRACE("%s (%ld)\n", debugstr_wn(lpszStart,len), len);
1158 if ( (*dwComponentLen == 0) && (*lppszComponent == NULL) )
1161 if (*dwComponentLen != 0 || *lppszComponent == NULL)
1163 if (*lppszComponent == NULL)
1165 *lppszComponent = (LPWSTR)lpszStart;
1166 *dwComponentLen = len;
1170 DWORD ncpylen = min((*dwComponentLen)-1, len);
1171 strncpyW(*lppszComponent, lpszStart, ncpylen);
1172 (*lppszComponent)[ncpylen] = '\0';
1173 *dwComponentLen = ncpylen;
1180 /***********************************************************************
1181 * InternetCrackUrlW (WININET.@)
1183 BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
1184 LPURL_COMPONENTSW lpUC)
1188 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1191 LPCWSTR lpszParam = NULL;
1192 BOOL bIsAbsolute = FALSE;
1193 LPCWSTR lpszap = lpszUrl;
1194 LPCWSTR lpszcp = NULL;
1195 const WCHAR lpszSeparators[3]={';','?',0};
1196 const WCHAR lpszSlash[2]={'/',0};
1198 dwUrlLength=strlenW(lpszUrl);
1202 /* Determine if the URI is absolute. */
1203 while (*lpszap != '\0')
1205 if (isalnumW(*lpszap))
1210 if ((*lpszap == ':') && (lpszap - lpszUrl >= 2))
1217 lpszcp = lpszUrl; /* Relative url */
1223 /* Parse <params> */
1224 lpszParam = strpbrkW(lpszap, lpszSeparators);
1225 if (lpszParam != NULL)
1227 SetUrlComponentValueW(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength,
1228 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 SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength,
1239 lpszUrl, lpszcp - lpszUrl);
1241 /* Eat ':' in protocol. */
1244 /* if the scheme is "about", there is no host */
1245 if(strncmpW(wszAbout,lpszUrl, lpszcp - lpszUrl)==0)
1247 SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1248 SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1249 SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
1254 /* Skip over slashes. */
1266 lpszNetLoc = strpbrkW(lpszcp, lpszSlash);
1270 lpszNetLoc = min(lpszNetLoc, lpszParam);
1272 lpszNetLoc = lpszParam;
1274 else if (!lpszNetLoc)
1275 lpszNetLoc = lpszcp + dwUrlLength-(lpszcp-lpszUrl);
1283 /* [<user>[<:password>]@]<host>[:<port>] */
1284 /* First find the user and password if they exist */
1286 lpszHost = strchrW(lpszcp, '@');
1287 if (lpszHost == NULL || lpszHost > lpszNetLoc)
1289 /* username and password not specified. */
1290 SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1291 SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1293 else /* Parse out username and password */
1295 LPCWSTR lpszUser = lpszcp;
1296 LPCWSTR lpszPasswd = lpszHost;
1298 while (lpszcp < lpszHost)
1301 lpszPasswd = lpszcp;
1306 SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength,
1307 lpszUser, lpszPasswd - lpszUser);
1309 if (lpszPasswd != lpszHost)
1311 SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength,
1312 lpszPasswd == lpszHost ? NULL : lpszPasswd,
1313 lpszHost - lpszPasswd);
1315 lpszcp++; /* Advance to beginning of host */
1318 /* Parse <host><:port> */
1321 lpszPort = lpszNetLoc;
1323 /* special case for res:// URLs: there is no port here, so the host is the
1324 entire string up to the first '/' */
1325 if(lpUC->nScheme==INTERNET_SCHEME_RES)
1327 SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1328 lpszHost, lpszPort - lpszHost);
1334 while (lpszcp < lpszNetLoc)
1342 /* If the scheme is "file" and the host is just one letter, it's not a host */
1343 if(lpUC->nScheme==INTERNET_SCHEME_FILE && (lpszPort-lpszHost)==1)
1346 SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1352 SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1353 lpszHost, lpszPort - lpszHost);
1354 if (lpszPort != lpszNetLoc)
1355 lpUC->nPort = atoiW(++lpszPort);
1364 /* Here lpszcp points to:
1366 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1367 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1369 if (lpszcp != 0 && *lpszcp != '\0' && (!lpszParam || lpszcp < lpszParam))
1373 /* Only truncate the parameter list if it's already been saved
1374 * in lpUC->lpszExtraInfo.
1376 if (lpszParam && lpUC->dwExtraInfoLength && lpUC->lpszExtraInfo)
1377 len = lpszParam - lpszcp;
1380 /* Leave the parameter list in lpszUrlPath. Strip off any trailing
1381 * newlines if necessary.
1383 LPWSTR lpsznewline = strchrW(lpszcp, '\n');
1384 if (lpsznewline != NULL)
1385 len = lpsznewline - lpszcp;
1387 len = dwUrlLength-(lpszcp-lpszUrl);
1390 SetUrlComponentValueW(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength,
1395 lpUC->dwUrlPathLength = 0;
1398 TRACE("%s: host(%s) path(%s) extra(%s)\n", debugstr_wn(lpszUrl,dwUrlLength),
1399 debugstr_wn(lpUC->lpszHostName,lpUC->dwHostNameLength),
1400 debugstr_wn(lpUC->lpszUrlPath,lpUC->dwUrlPathLength),
1401 debugstr_wn(lpUC->lpszExtraInfo,lpUC->dwExtraInfoLength));
1406 /***********************************************************************
1407 * InternetAttemptConnect (WININET.@)
1409 * Attempt to make a connection to the internet
1412 * ERROR_SUCCESS on success
1413 * Error value on failure
1416 DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
1419 return ERROR_SUCCESS;
1423 /***********************************************************************
1424 * InternetCanonicalizeUrlA (WININET.@)
1426 * Escape unsafe characters and spaces
1433 BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
1434 LPDWORD lpdwBufferLength, DWORD dwFlags)
1437 TRACE("%s %p %p %08lx\n",debugstr_a(lpszUrl), lpszBuffer,
1438 lpdwBufferLength, dwFlags);
1440 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1441 dwFlags ^= ICU_NO_ENCODE;
1443 dwFlags |= 0x80000000; /* Don't know what this means */
1445 hr = UrlCanonicalizeA(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
1447 return (hr == S_OK) ? TRUE : FALSE;
1450 /***********************************************************************
1451 * InternetCanonicalizeUrlW (WININET.@)
1453 * Escape unsafe characters and spaces
1460 BOOL WINAPI InternetCanonicalizeUrlW(LPCWSTR lpszUrl, LPWSTR lpszBuffer,
1461 LPDWORD lpdwBufferLength, DWORD dwFlags)
1464 TRACE("%s %p %p %08lx\n", debugstr_w(lpszUrl), lpszBuffer,
1465 lpdwBufferLength, dwFlags);
1467 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1468 dwFlags ^= ICU_NO_ENCODE;
1470 dwFlags |= 0x80000000; /* Don't know what this means */
1472 hr = UrlCanonicalizeW(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
1474 return (hr == S_OK) ? TRUE : FALSE;
1478 /***********************************************************************
1479 * InternetSetStatusCallbackA (WININET.@)
1481 * Sets up a callback function which is called as progress is made
1482 * during an operation.
1485 * Previous callback or NULL on success
1486 * INTERNET_INVALID_STATUS_CALLBACK on failure
1489 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackA(
1490 HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
1492 INTERNET_STATUS_CALLBACK retVal = INTERNET_INVALID_STATUS_CALLBACK;
1493 LPWININETAPPINFOW lpwai;
1495 TRACE("0x%08lx\n", (ULONG)hInternet);
1497 lpwai = (LPWININETAPPINFOW)WININET_GetObject(hInternet);
1501 if (lpwai->hdr.htype == WH_HINIT)
1503 lpwai->hdr.dwInternalFlags &= ~INET_CALLBACKW;
1504 retVal = lpwai->lpfnStatusCB;
1505 lpwai->lpfnStatusCB = lpfnIntCB;
1507 WININET_Release( &lpwai->hdr );
1512 /***********************************************************************
1513 * InternetSetStatusCallbackW (WININET.@)
1515 * Sets up a callback function which is called as progress is made
1516 * during an operation.
1519 * Previous callback or NULL on success
1520 * INTERNET_INVALID_STATUS_CALLBACK on failure
1523 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackW(
1524 HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
1526 INTERNET_STATUS_CALLBACK retVal = INTERNET_INVALID_STATUS_CALLBACK;
1527 LPWININETAPPINFOW lpwai;
1529 TRACE("0x%08lx\n", (ULONG)hInternet);
1531 lpwai = (LPWININETAPPINFOW)WININET_GetObject(hInternet);
1535 if (lpwai->hdr.htype == WH_HINIT)
1537 lpwai->hdr.dwInternalFlags |= INET_CALLBACKW;
1538 retVal = lpwai->lpfnStatusCB;
1539 lpwai->lpfnStatusCB = lpfnIntCB;
1542 WININET_Release( &lpwai->hdr );
1547 /***********************************************************************
1548 * InternetSetFilePointer (WININET.@)
1550 DWORD WINAPI InternetSetFilePointer(HINTERNET f1, LONG f2, PVOID f3, DWORD f4, DWORD f5)
1556 /***********************************************************************
1557 * InternetWriteFile (WININET.@)
1559 * Write data to an open internet file
1566 BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer ,
1567 DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
1569 BOOL retval = FALSE;
1571 LPWININETHANDLEHEADER lpwh;
1574 lpwh = (LPWININETHANDLEHEADER) WININET_GetObject( hFile );
1578 switch (lpwh->htype)
1581 FIXME("This shouldn't be here! We don't support this kind"
1582 " of connection anymore. Must use NETCON functions,"
1583 " especially if using SSL\n");
1584 nSocket = ((LPWININETHTTPREQW)lpwh)->netConnection.socketFD;
1588 nSocket = ((LPWININETFILE)lpwh)->nDataSocket;
1597 int res = send(nSocket, lpBuffer, dwNumOfBytesToWrite, 0);
1598 retval = (res >= 0);
1599 *lpdwNumOfBytesWritten = retval ? res : 0;
1601 WININET_Release( lpwh );
1607 /***********************************************************************
1608 * InternetReadFile (WININET.@)
1610 * Read data from an open internet file
1617 BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
1618 DWORD dwNumOfBytesToRead, LPDWORD dwNumOfBytesRead)
1620 BOOL retval = FALSE;
1622 LPWININETHANDLEHEADER lpwh;
1624 TRACE("%p %p %ld %p\n", hFile, lpBuffer, dwNumOfBytesToRead, dwNumOfBytesRead);
1626 lpwh = (LPWININETHANDLEHEADER) WININET_GetObject( hFile );
1630 /* FIXME: this should use NETCON functions! */
1631 switch (lpwh->htype)
1634 if (!NETCON_recv(&((LPWININETHTTPREQW)lpwh)->netConnection, lpBuffer,
1635 dwNumOfBytesToRead, 0, (int *)dwNumOfBytesRead))
1637 *dwNumOfBytesRead = 0;
1638 retval = TRUE; /* Under windows, it seems to return 0 even if nothing was read... */
1645 /* FIXME: FTP should use NETCON_ stuff */
1646 nSocket = ((LPWININETFILE)lpwh)->nDataSocket;
1649 int res = recv(nSocket, lpBuffer, dwNumOfBytesToRead, 0);
1650 retval = (res >= 0);
1651 *dwNumOfBytesRead = retval ? res : 0;
1658 WININET_Release( lpwh );
1663 /***********************************************************************
1664 * InternetReadFileExA (WININET.@)
1666 * Read data from an open internet file
1673 BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffer,
1674 DWORD dwFlags, DWORD dwContext)
1680 /***********************************************************************
1681 * InternetReadFileExW (WININET.@)
1683 * Read data from an open internet file
1690 BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer,
1691 DWORD dwFlags, DWORD dwContext)
1695 INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1699 /***********************************************************************
1700 * INET_QueryOptionHelper (internal)
1702 static BOOL INET_QueryOptionHelper(BOOL bIsUnicode, HINTERNET hInternet, DWORD dwOption,
1703 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1705 LPWININETHANDLEHEADER lpwhh;
1706 BOOL bSuccess = FALSE;
1708 TRACE("(%p, 0x%08lx, %p, %p)\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
1710 lpwhh = (LPWININETHANDLEHEADER) WININET_GetObject( hInternet );
1714 case INTERNET_OPTION_HANDLE_TYPE:
1720 WARN("Invalid hInternet handle\n");
1721 SetLastError(ERROR_INVALID_HANDLE);
1725 type = lpwhh->htype;
1727 TRACE("INTERNET_OPTION_HANDLE_TYPE: %ld\n", type);
1729 if (*lpdwBufferLength < sizeof(ULONG))
1730 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1733 memcpy(lpBuffer, &type, sizeof(ULONG));
1734 *lpdwBufferLength = sizeof(ULONG);
1740 case INTERNET_OPTION_REQUEST_FLAGS:
1743 TRACE("INTERNET_OPTION_REQUEST_FLAGS: %ld\n", flags);
1744 if (*lpdwBufferLength < sizeof(ULONG))
1745 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1748 memcpy(lpBuffer, &flags, sizeof(ULONG));
1749 *lpdwBufferLength = sizeof(ULONG);
1755 case INTERNET_OPTION_URL:
1756 case INTERNET_OPTION_DATAFILE_NAME:
1760 WARN("Invalid hInternet handle\n");
1761 SetLastError(ERROR_INVALID_HANDLE);
1764 if (lpwhh->htype == WH_HHTTPREQ)
1766 LPWININETHTTPREQW lpreq = (LPWININETHTTPREQW) lpwhh;
1768 static const WCHAR szFmt[] = {'h','t','t','p',':','/','/','%','s','%','s',0};
1770 sprintfW(url,szFmt,lpreq->lpszHostName,lpreq->lpszPath);
1771 TRACE("INTERNET_OPTION_URL: %s\n",debugstr_w(url));
1772 if (*lpdwBufferLength < strlenW(url)+1)
1773 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1778 *lpdwBufferLength=WideCharToMultiByte(CP_ACP,0,url,-1,lpBuffer,*lpdwBufferLength,NULL,NULL);
1782 strcpyW(lpBuffer, url);
1783 *lpdwBufferLength = strlenW(url)+1;
1790 case INTERNET_OPTION_HTTP_VERSION:
1793 * Presently hardcoded to 1.1
1795 ((HTTP_VERSION_INFO*)lpBuffer)->dwMajorVersion = 1;
1796 ((HTTP_VERSION_INFO*)lpBuffer)->dwMinorVersion = 1;
1800 case INTERNET_OPTION_CONNECTED_STATE:
1802 INTERNET_CONNECTED_INFO * pCi = (INTERNET_CONNECTED_INFO *)lpBuffer;
1803 FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n");
1804 pCi->dwConnectedState = INTERNET_STATE_CONNECTED;
1809 case INTERNET_OPTION_SECURITY_FLAGS:
1810 FIXME("INTERNET_OPTION_SECURITY_FLAGS: Stub\n");
1814 FIXME("Stub! %ld \n",dwOption);
1818 WININET_Release( lpwhh );
1823 /***********************************************************************
1824 * InternetQueryOptionW (WININET.@)
1826 * Queries an options on the specified handle
1833 BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption,
1834 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1836 return INET_QueryOptionHelper(TRUE, hInternet, dwOption, lpBuffer, lpdwBufferLength);
1839 /***********************************************************************
1840 * InternetQueryOptionA (WININET.@)
1842 * Queries an options on the specified handle
1849 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
1850 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1852 return INET_QueryOptionHelper(FALSE, hInternet, dwOption, lpBuffer, lpdwBufferLength);
1856 /***********************************************************************
1857 * InternetSetOptionW (WININET.@)
1859 * Sets an options on the specified handle
1866 BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
1867 LPVOID lpBuffer, DWORD dwBufferLength)
1869 LPWININETHANDLEHEADER lpwhh;
1872 TRACE("0x%08lx\n", dwOption);
1874 lpwhh = (LPWININETHANDLEHEADER) WININET_GetObject( hInternet );
1880 case INTERNET_OPTION_HTTP_VERSION:
1882 HTTP_VERSION_INFO* pVersion=(HTTP_VERSION_INFO*)lpBuffer;
1883 FIXME("Option INTERNET_OPTION_HTTP_VERSION(%ld,%ld): STUB\n",pVersion->dwMajorVersion,pVersion->dwMinorVersion);
1886 case INTERNET_OPTION_ERROR_MASK:
1888 unsigned long flags=*(unsigned long*)lpBuffer;
1889 FIXME("Option INTERNET_OPTION_ERROR_MASK(%ld): STUB\n",flags);
1892 case INTERNET_OPTION_CODEPAGE:
1894 unsigned long codepage=*(unsigned long*)lpBuffer;
1895 FIXME("Option INTERNET_OPTION_CODEPAGE (%ld): STUB\n",codepage);
1898 case INTERNET_OPTION_REQUEST_PRIORITY:
1900 unsigned long priority=*(unsigned long*)lpBuffer;
1901 FIXME("Option INTERNET_OPTION_REQUEST_PRIORITY (%ld): STUB\n",priority);
1904 case INTERNET_OPTION_CONNECT_TIMEOUT:
1906 unsigned long connecttimeout=*(unsigned long*)lpBuffer;
1907 FIXME("Option INTERNET_OPTION_CONNECT_TIMEOUT (%ld): STUB\n",connecttimeout);
1910 case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT:
1912 unsigned long receivetimeout=*(unsigned long*)lpBuffer;
1913 FIXME("Option INTERNET_OPTION_DATA_RECEIVE_TIMEOUT (%ld): STUB\n",receivetimeout);
1916 case INTERNET_OPTION_RESET_URLCACHE_SESSION:
1917 FIXME("Option INTERNET_OPTION_RESET_URLCACHE_SESSION: STUB\n");
1919 case INTERNET_OPTION_END_BROWSER_SESSION:
1920 FIXME("Option INTERNET_OPTION_END_BROWSER_SESSION: STUB\n");
1922 case INTERNET_OPTION_CONNECTED_STATE:
1923 FIXME("Option INTERNET_OPTION_CONNECTED_STATE: STUB\n");
1926 FIXME("Option %ld STUB\n",dwOption);
1927 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1931 WININET_Release( lpwhh );
1937 /***********************************************************************
1938 * InternetSetOptionA (WININET.@)
1940 * Sets an options on the specified handle.
1947 BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
1948 LPVOID lpBuffer, DWORD dwBufferLength)
1956 case INTERNET_OPTION_PROXY:
1958 LPINTERNET_PROXY_INFOA pi = (LPINTERNET_PROXY_INFOA) lpBuffer;
1959 LPINTERNET_PROXY_INFOW piw;
1960 DWORD proxlen, prbylen;
1963 proxlen = MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, NULL, 0);
1964 prbylen= MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, NULL, 0);
1965 wlen = sizeof(*piw) + proxlen + prbylen;
1966 wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
1967 piw = (LPINTERNET_PROXY_INFOW) wbuffer;
1968 piw->dwAccessType = pi->dwAccessType;
1969 prox = (LPWSTR) &piw[1];
1970 prby = &prox[proxlen+1];
1971 MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, prox, proxlen);
1972 MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, prby, prbylen);
1973 piw->lpszProxy = prox;
1974 piw->lpszProxyBypass = prby;
1977 case INTERNET_OPTION_USER_AGENT:
1978 case INTERNET_OPTION_USERNAME:
1979 case INTERNET_OPTION_PASSWORD:
1980 wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
1982 wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
1983 MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
1988 wlen = dwBufferLength;
1991 r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen);
1993 if( lpBuffer != wbuffer )
1994 HeapFree( GetProcessHeap(), 0, wbuffer );
2000 /***********************************************************************
2001 * InternetSetOptionExA (WININET.@)
2003 BOOL WINAPI InternetSetOptionExA(HINTERNET hInternet, DWORD dwOption,
2004 LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2006 FIXME("Flags %08lx ignored\n", dwFlags);
2007 return InternetSetOptionA( hInternet, dwOption, lpBuffer, dwBufferLength );
2010 /***********************************************************************
2011 * InternetSetOptionExW (WININET.@)
2013 BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption,
2014 LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2016 FIXME("Flags %08lx ignored\n", dwFlags);
2017 if( dwFlags & ~ISO_VALID_FLAGS )
2019 SetLastError( ERROR_INVALID_PARAMETER );
2022 return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength );
2026 /***********************************************************************
2027 * InternetCheckConnectionA (WININET.@)
2029 * Pings a requested host to check internet connection
2032 * TRUE on success and FALSE on failure. If a failure then
2033 * ERROR_NOT_CONNECTED is placesd into GetLastError
2036 BOOL WINAPI InternetCheckConnectionA( LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
2039 * this is a kludge which runs the resident ping program and reads the output.
2041 * Anyone have a better idea?
2052 * Crack or set the Address
2054 if (lpszUrl == NULL)
2057 * According to the doc we are supost to use the ip for the next
2058 * server in the WnInet internal server database. I have
2059 * no idea what that is or how to get it.
2061 * So someone needs to implement this.
2063 FIXME("Unimplemented with URL of NULL\n");
2068 URL_COMPONENTSA componets;
2070 ZeroMemory(&componets,sizeof(URL_COMPONENTSA));
2071 componets.lpszHostName = (LPSTR)&host;
2072 componets.dwHostNameLength = 1024;
2074 if (!InternetCrackUrlA(lpszUrl,0,0,&componets))
2077 TRACE("host name : %s\n",componets.lpszHostName);
2081 * Build our ping command
2083 strcpy(command,"ping -w 1 ");
2084 strcat(command,host);
2085 strcat(command," >/dev/null 2>/dev/null");
2087 TRACE("Ping command is : %s\n",command);
2089 status = system(command);
2091 TRACE("Ping returned a code of %i \n",status);
2093 /* Ping return code of 0 indicates success */
2100 SetLastError(ERROR_NOT_CONNECTED);
2106 /***********************************************************************
2107 * InternetCheckConnectionW (WININET.@)
2109 * Pings a requested host to check internet connection
2112 * TRUE on success and FALSE on failure. If a failure then
2113 * ERROR_NOT_CONNECTED is placed into GetLastError
2116 BOOL WINAPI InternetCheckConnectionW(LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
2122 len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
2123 if (!(szUrl = (CHAR *)HeapAlloc(GetProcessHeap(), 0, len*sizeof(CHAR))))
2125 WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, szUrl, len, NULL, NULL);
2126 rc = InternetCheckConnectionA((LPCSTR)szUrl, dwFlags, dwReserved);
2127 HeapFree(GetProcessHeap(), 0, szUrl);
2133 /**********************************************************
2134 * INTERNET_InternetOpenUrlW (internal)
2139 * handle of connection or NULL on failure
2141 HINTERNET WINAPI INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUrl,
2142 LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
2144 URL_COMPONENTSW urlComponents;
2145 WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024];
2146 WCHAR password[1024], path[2048], extra[1024];
2147 HINTERNET client = NULL, client1 = NULL;
2149 TRACE("(%p, %s, %s, %08lx, %08lx, %08lx\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
2150 dwHeadersLength, dwFlags, dwContext);
2152 urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
2153 urlComponents.lpszScheme = protocol;
2154 urlComponents.dwSchemeLength = 32;
2155 urlComponents.lpszHostName = hostName;
2156 urlComponents.dwHostNameLength = MAXHOSTNAME;
2157 urlComponents.lpszUserName = userName;
2158 urlComponents.dwUserNameLength = 1024;
2159 urlComponents.lpszPassword = password;
2160 urlComponents.dwPasswordLength = 1024;
2161 urlComponents.lpszUrlPath = path;
2162 urlComponents.dwUrlPathLength = 2048;
2163 urlComponents.lpszExtraInfo = extra;
2164 urlComponents.dwExtraInfoLength = 1024;
2165 if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
2167 switch(urlComponents.nScheme) {
2168 case INTERNET_SCHEME_FTP:
2169 if(urlComponents.nPort == 0)
2170 urlComponents.nPort = INTERNET_DEFAULT_FTP_PORT;
2171 client = FTP_Connect(hIC, hostName, urlComponents.nPort,
2172 userName, password, dwFlags, dwContext, INET_OPENURL);
2175 client1 = FtpOpenFileW(client, path, GENERIC_READ, dwFlags, dwContext);
2176 if(client1 == NULL) {
2177 InternetCloseHandle(client);
2182 case INTERNET_SCHEME_HTTP:
2183 case INTERNET_SCHEME_HTTPS: {
2184 static const WCHAR szStars[] = { '*','/','*', 0 };
2185 LPCWSTR accept[2] = { szStars, NULL };
2186 if(urlComponents.nPort == 0) {
2187 if(urlComponents.nScheme == INTERNET_SCHEME_HTTP)
2188 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
2190 urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
2192 /* FIXME: should use pointers, not handles, as handles are not thread-safe */
2193 client = HTTP_Connect(hIC, hostName, urlComponents.nPort,
2194 userName, password, dwFlags, dwContext, INET_OPENURL);
2197 client1 = HttpOpenRequestW(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
2198 if(client1 == NULL) {
2199 InternetCloseHandle(client);
2202 HttpAddRequestHeadersW(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
2203 if (!HttpSendRequestW(client1, NULL, 0, NULL, 0)) {
2204 InternetCloseHandle(client1);
2209 case INTERNET_SCHEME_GOPHER:
2210 /* gopher doesn't seem to be implemented in wine, but it's supposed
2211 * to be supported by InternetOpenUrlA. */
2216 TRACE(" %p <--\n", client1);
2221 /**********************************************************
2222 * InternetOpenUrlW (WININET.@)
2227 * handle of connection or NULL on failure
2229 HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
2230 LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
2232 HINTERNET ret = NULL;
2233 LPWININETAPPINFOW hIC = NULL;
2235 TRACE("(%p, %s, %s, %08lx, %08lx, %08lx\n", hInternet, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
2236 dwHeadersLength, dwFlags, dwContext);
2238 hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
2239 if (NULL == hIC || hIC->hdr.htype != WH_HINIT) {
2240 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2244 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) {
2245 WORKREQUEST workRequest;
2246 struct WORKREQ_INTERNETOPENURLW *req;
2248 workRequest.asyncall = INTERNETOPENURLW;
2249 workRequest.hdr = WININET_AddRef( &hIC->hdr );
2250 req = &workRequest.u.InternetOpenUrlW;
2252 req->lpszUrl = WININET_strdupW(lpszUrl);
2256 req->lpszHeaders = WININET_strdupW(lpszHeaders);
2258 req->lpszHeaders = 0;
2259 req->dwHeadersLength = dwHeadersLength;
2260 req->dwFlags = dwFlags;
2261 req->dwContext = dwContext;
2263 INTERNET_AsyncCall(&workRequest);
2265 * This is from windows.
2267 SetLastError(ERROR_IO_PENDING);
2269 ret = INTERNET_InternetOpenUrlW(hIC, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext);
2274 WININET_Release( &hIC->hdr );
2275 TRACE(" %p <--\n", ret);
2280 /**********************************************************
2281 * InternetOpenUrlA (WININET.@)
2286 * handle of connection or NULL on failure
2288 HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
2289 LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
2291 HINTERNET rc = (HINTERNET)NULL;
2295 LPWSTR szUrl = NULL;
2296 LPWSTR szHeaders = NULL;
2301 lenUrl = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0 );
2302 szUrl = HeapAlloc(GetProcessHeap(), 0, lenUrl*sizeof(WCHAR));
2304 return (HINTERNET)NULL;
2305 MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, szUrl, lenUrl);
2309 lenHeaders = MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, NULL, 0 );
2310 szHeaders = HeapAlloc(GetProcessHeap(), 0, lenHeaders*sizeof(WCHAR));
2312 if(szUrl) HeapFree(GetProcessHeap(), 0, szUrl);
2313 return (HINTERNET)NULL;
2315 MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, szHeaders, lenHeaders);
2318 rc = InternetOpenUrlW(hInternet, szUrl, szHeaders,
2319 lenHeaders, dwFlags, dwContext);
2321 if(szUrl) HeapFree(GetProcessHeap(), 0, szUrl);
2322 if(szHeaders) HeapFree(GetProcessHeap(), 0, szHeaders);
2328 /***********************************************************************
2329 * INTERNET_SetLastError (internal)
2331 * Set last thread specific error
2336 void INTERNET_SetLastError(DWORD dwError)
2338 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
2340 SetLastError(dwError);
2342 lpwite->dwError = dwError;
2346 /***********************************************************************
2347 * INTERNET_GetLastError (internal)
2349 * Get last thread specific error
2354 DWORD INTERNET_GetLastError()
2356 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
2357 return lpwite->dwError;
2361 /***********************************************************************
2362 * INTERNET_WorkerThreadFunc (internal)
2364 * Worker thread execution function
2369 DWORD INTERNET_WorkerThreadFunc(LPVOID *lpvParam)
2376 INTERNET_ExecuteWork();
2379 dwWaitRes = WaitForMultipleObjects(2, hEventArray, FALSE, MAX_IDLE_WORKER);
2381 if (dwWaitRes == WAIT_OBJECT_0 + 1)
2382 INTERNET_ExecuteWork();
2386 InterlockedIncrement(&dwNumIdleThreads);
2389 InterlockedDecrement(&dwNumIdleThreads);
2390 InterlockedDecrement(&dwNumThreads);
2391 TRACE("Worker thread exiting\n");
2396 /***********************************************************************
2397 * INTERNET_InsertWorkRequest (internal)
2399 * Insert work request into queue
2404 BOOL INTERNET_InsertWorkRequest(LPWORKREQUEST lpWorkRequest)
2406 BOOL bSuccess = FALSE;
2407 LPWORKREQUEST lpNewRequest;
2411 lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
2414 memcpy(lpNewRequest, lpWorkRequest, sizeof(WORKREQUEST));
2415 lpNewRequest->prev = NULL;
2417 EnterCriticalSection(&csQueue);
2419 lpNewRequest->next = lpWorkQueueTail;
2420 if (lpWorkQueueTail)
2421 lpWorkQueueTail->prev = lpNewRequest;
2422 lpWorkQueueTail = lpNewRequest;
2423 if (!lpHeadWorkQueue)
2424 lpHeadWorkQueue = lpWorkQueueTail;
2426 LeaveCriticalSection(&csQueue);
2429 InterlockedIncrement(&dwNumJobs);
2436 /***********************************************************************
2437 * INTERNET_GetWorkRequest (internal)
2439 * Retrieves work request from queue
2444 BOOL INTERNET_GetWorkRequest(LPWORKREQUEST lpWorkRequest)
2446 BOOL bSuccess = FALSE;
2447 LPWORKREQUEST lpRequest = NULL;
2451 EnterCriticalSection(&csQueue);
2453 if (lpHeadWorkQueue)
2455 lpRequest = lpHeadWorkQueue;
2456 lpHeadWorkQueue = lpHeadWorkQueue->prev;
2457 if (lpRequest == lpWorkQueueTail)
2458 lpWorkQueueTail = lpHeadWorkQueue;
2461 LeaveCriticalSection(&csQueue);
2465 memcpy(lpWorkRequest, lpRequest, sizeof(WORKREQUEST));
2466 HeapFree(GetProcessHeap(), 0, lpRequest);
2468 InterlockedDecrement(&dwNumJobs);
2475 /***********************************************************************
2476 * INTERNET_AsyncCall (internal)
2478 * Retrieves work request from queue
2483 BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
2487 BOOL bSuccess = FALSE;
2491 if (InterlockedDecrement(&dwNumIdleThreads) < 0)
2493 InterlockedIncrement(&dwNumIdleThreads);
2495 if (InterlockedIncrement(&dwNumThreads) > MAX_WORKER_THREADS ||
2496 !(hThread = CreateThread(NULL, 0,
2497 (LPTHREAD_START_ROUTINE)INTERNET_WorkerThreadFunc, NULL, 0, &dwTID)))
2499 InterlockedDecrement(&dwNumThreads);
2500 INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED);
2504 TRACE("Created new thread\n");
2508 INTERNET_InsertWorkRequest(lpWorkRequest);
2509 SetEvent(hWorkEvent);
2517 /***********************************************************************
2518 * INTERNET_ExecuteWork (internal)
2523 static VOID INTERNET_ExecuteWork()
2525 WORKREQUEST workRequest;
2529 if (!INTERNET_GetWorkRequest(&workRequest))
2532 switch (workRequest.asyncall)
2536 struct WORKREQ_FTPPUTFILEW *req = &workRequest.u.FtpPutFileW;
2537 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2539 TRACE("FTPPUTFILEW %p\n", lpwfs);
2541 FTP_FtpPutFileW(lpwfs, req->lpszLocalFile,
2542 req->lpszNewRemoteFile, req->dwFlags, req->dwContext);
2544 HeapFree(GetProcessHeap(), 0, req->lpszLocalFile);
2545 HeapFree(GetProcessHeap(), 0, req->lpszNewRemoteFile);
2549 case FTPSETCURRENTDIRECTORYW:
2551 struct WORKREQ_FTPSETCURRENTDIRECTORYW *req;
2552 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2554 TRACE("FTPSETCURRENTDIRECTORYW %p\n", lpwfs);
2556 req = &workRequest.u.FtpSetCurrentDirectoryW;
2557 FTP_FtpSetCurrentDirectoryW(lpwfs, req->lpszDirectory);
2558 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2562 case FTPCREATEDIRECTORYW:
2564 struct WORKREQ_FTPCREATEDIRECTORYW *req;
2565 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2567 TRACE("FTPCREATEDIRECTORYW %p\n", lpwfs);
2569 req = &workRequest.u.FtpCreateDirectoryW;
2570 FTP_FtpCreateDirectoryW(lpwfs, req->lpszDirectory);
2571 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2575 case FTPFINDFIRSTFILEW:
2577 struct WORKREQ_FTPFINDFIRSTFILEW *req;
2578 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2580 TRACE("FTPFINDFIRSTFILEW %p\n", lpwfs);
2582 req = &workRequest.u.FtpFindFirstFileW;
2583 FTP_FtpFindFirstFileW(lpwfs, req->lpszSearchFile,
2584 req->lpFindFileData, req->dwFlags, req->dwContext);
2585 if (req->lpszSearchFile != NULL)
2586 HeapFree(GetProcessHeap(), 0, req->lpszSearchFile);
2590 case FTPGETCURRENTDIRECTORYW:
2592 struct WORKREQ_FTPGETCURRENTDIRECTORYW *req;
2593 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2595 TRACE("FTPGETCURRENTDIRECTORYW %p\n", lpwfs);
2597 req = &workRequest.u.FtpGetCurrentDirectoryW;
2598 FTP_FtpGetCurrentDirectoryW(lpwfs,
2599 req->lpszDirectory, req->lpdwDirectory);
2605 struct WORKREQ_FTPOPENFILEW *req = &workRequest.u.FtpOpenFileW;
2606 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2608 TRACE("FTPOPENFILEW %p\n", lpwfs);
2610 FTP_FtpOpenFileW(lpwfs, req->lpszFilename,
2611 req->dwAccess, req->dwFlags, req->dwContext);
2612 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
2618 struct WORKREQ_FTPGETFILEW *req = &workRequest.u.FtpGetFileW;
2619 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2621 TRACE("FTPGETFILEW %p\n", lpwfs);
2623 FTP_FtpGetFileW(lpwfs, req->lpszRemoteFile,
2624 req->lpszNewFile, req->fFailIfExists,
2625 req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext);
2626 HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile);
2627 HeapFree(GetProcessHeap(), 0, req->lpszNewFile);
2631 case FTPDELETEFILEW:
2633 struct WORKREQ_FTPDELETEFILEW *req = &workRequest.u.FtpDeleteFileW;
2634 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2636 TRACE("FTPDELETEFILEW %p\n", lpwfs);
2638 FTP_FtpDeleteFileW(lpwfs, req->lpszFilename);
2639 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
2643 case FTPREMOVEDIRECTORYW:
2645 struct WORKREQ_FTPREMOVEDIRECTORYW *req;
2646 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2648 TRACE("FTPREMOVEDIRECTORYW %p\n", lpwfs);
2650 req = &workRequest.u.FtpRemoveDirectoryW;
2651 FTP_FtpRemoveDirectoryW(lpwfs, req->lpszDirectory);
2652 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2656 case FTPRENAMEFILEW:
2658 struct WORKREQ_FTPRENAMEFILEW *req = &workRequest.u.FtpRenameFileW;
2659 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2661 TRACE("FTPRENAMEFILEW %p\n", lpwfs);
2663 FTP_FtpRenameFileW(lpwfs, req->lpszSrcFile, req->lpszDestFile);
2664 HeapFree(GetProcessHeap(), 0, req->lpszSrcFile);
2665 HeapFree(GetProcessHeap(), 0, req->lpszDestFile);
2669 case INTERNETFINDNEXTW:
2671 struct WORKREQ_INTERNETFINDNEXTW *req;
2672 LPWININETFINDNEXTW lpwh = (LPWININETFINDNEXTW) workRequest.hdr;
2674 TRACE("INTERNETFINDNEXTW %p\n", lpwh);
2676 req = &workRequest.u.InternetFindNextW;
2677 INTERNET_FindNextFileW(lpwh, req->lpFindFileData);
2681 case HTTPSENDREQUESTW:
2683 struct WORKREQ_HTTPSENDREQUESTW *req = &workRequest.u.HttpSendRequestW;
2684 LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) workRequest.hdr;
2686 TRACE("HTTPSENDREQUESTW %p\n", lpwhr);
2688 HTTP_HttpSendRequestW(lpwhr, req->lpszHeader,
2689 req->dwHeaderLength, req->lpOptional, req->dwOptionalLength);
2691 HeapFree(GetProcessHeap(), 0, req->lpszHeader);
2695 case HTTPOPENREQUESTW:
2697 struct WORKREQ_HTTPOPENREQUESTW *req = &workRequest.u.HttpOpenRequestW;
2698 LPWININETHTTPSESSIONW lpwhs = (LPWININETHTTPSESSIONW) workRequest.hdr;
2700 TRACE("HTTPOPENREQUESTW %p\n", lpwhs);
2702 HTTP_HttpOpenRequestW(lpwhs, req->lpszVerb,
2703 req->lpszObjectName, req->lpszVersion, req->lpszReferrer,
2704 req->lpszAcceptTypes, req->dwFlags, req->dwContext);
2706 HeapFree(GetProcessHeap(), 0, req->lpszVerb);
2707 HeapFree(GetProcessHeap(), 0, req->lpszObjectName);
2708 HeapFree(GetProcessHeap(), 0, req->lpszVersion);
2709 HeapFree(GetProcessHeap(), 0, req->lpszReferrer);
2715 struct WORKREQ_SENDCALLBACK *req = &workRequest.u.SendCallback;
2716 LPWININETAPPINFOW hIC = (LPWININETAPPINFOW) workRequest.hdr;
2718 TRACE("SENDCALLBACK %p\n", hIC);
2720 SendAsyncCallbackInt(hIC, req->hdr,
2721 req->dwContext, req->dwInternetStatus, req->lpvStatusInfo,
2722 req->dwStatusInfoLength);
2726 case INTERNETOPENURLW:
2728 struct WORKREQ_INTERNETOPENURLW *req = &workRequest.u.InternetOpenUrlW;
2729 LPWININETAPPINFOW hIC = (LPWININETAPPINFOW) workRequest.hdr;
2731 TRACE("INTERNETOPENURLW %p\n", hIC);
2733 INTERNET_InternetOpenUrlW(hIC, req->lpszUrl,
2734 req->lpszHeaders, req->dwHeadersLength, req->dwFlags, req->dwContext);
2735 HeapFree(GetProcessHeap(), 0, req->lpszUrl);
2736 HeapFree(GetProcessHeap(), 0, req->lpszHeaders);
2740 WININET_Release( workRequest.hdr );
2744 /***********************************************************************
2745 * INTERNET_GetResponseBuffer
2750 LPSTR INTERNET_GetResponseBuffer()
2752 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
2754 return lpwite->response;
2757 /***********************************************************************
2758 * INTERNET_GetNextLine (internal)
2760 * Parse next line in directory string listing
2763 * Pointer to beginning of next line
2768 LPSTR INTERNET_GetNextLine(INT nSocket, LPDWORD dwLen)
2772 BOOL bSuccess = FALSE;
2774 LPSTR lpszBuffer = INTERNET_GetResponseBuffer();
2779 FD_SET(nSocket, &infd);
2780 tv.tv_sec=RESPONSE_TIMEOUT;
2783 while (nRecv < MAX_REPLY_LEN)
2785 if (select(nSocket+1,&infd,NULL,NULL,&tv) > 0)
2787 if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
2789 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
2793 if (lpszBuffer[nRecv] == '\n')
2798 if (lpszBuffer[nRecv] != '\r')
2803 INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
2811 lpszBuffer[nRecv] = '\0';
2813 TRACE(":%d %s\n", nRecv, lpszBuffer);
2822 /***********************************************************************
2825 BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile,
2826 LPDWORD lpdwNumberOfBytesAvailble,
2827 DWORD dwFlags, DWORD dwConext)
2829 LPWININETHTTPREQW lpwhr;
2833 lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hFile );
2836 SetLastError(ERROR_NO_MORE_FILES);
2840 TRACE("--> %p %i\n",lpwhr,lpwhr->hdr.htype);
2842 switch (lpwhr->hdr.htype)
2845 if (!NETCON_recv(&lpwhr->netConnection, buffer,
2846 4048, MSG_PEEK, (int *)lpdwNumberOfBytesAvailble))
2848 SetLastError(ERROR_NO_MORE_FILES);
2856 FIXME("unsupported file type\n");
2859 WININET_Release( &lpwhr->hdr );
2861 TRACE("<-- %i\n",retval);
2866 /***********************************************************************
2869 BOOL WINAPI InternetLockRequestFile( HINTERNET hInternet, HANDLE
2876 BOOL WINAPI InternetUnlockRequestFile( HANDLE hLockHandle)
2883 /***********************************************************************
2886 * On windows this function is supposed to dial the default internet
2887 * connection. We don't want to have Wine dial out to the internet so
2888 * we return TRUE by default. It might be nice to check if we are connected.
2895 BOOL WINAPI InternetAutodial(DWORD dwFlags, HWND hwndParent)
2899 /* Tell that we are connected to the internet. */
2903 /***********************************************************************
2904 * InternetAutodialHangup
2906 * Hangs up an connection made with InternetAutodial
2915 BOOL WINAPI InternetAutodialHangup(DWORD dwReserved)
2919 /* we didn't dial, we don't disconnect */
2923 /***********************************************************************
2925 * InternetCombineUrlA
2927 * Combine a base URL with a relative URL
2935 BOOL WINAPI InternetCombineUrlA(LPCSTR lpszBaseUrl, LPCSTR lpszRelativeUrl,
2936 LPSTR lpszBuffer, LPDWORD lpdwBufferLength,
2941 TRACE("(%s, %s, %p, %p, 0x%08lx)\n", debugstr_a(lpszBaseUrl), debugstr_a(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
2943 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
2944 dwFlags ^= ICU_NO_ENCODE;
2945 hr=UrlCombineA(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
2950 /***********************************************************************
2952 * InternetCombineUrlW
2954 * Combine a base URL with a relative URL
2962 BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
2963 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength,
2968 TRACE("(%s, %s, %p, %p, 0x%08lx)\n", debugstr_w(lpszBaseUrl), debugstr_w(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
2970 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
2971 dwFlags ^= ICU_NO_ENCODE;
2972 hr=UrlCombineW(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
2977 /***********************************************************************
2979 * InternetCreateUrlA
2986 BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
2987 LPSTR lpszUrl, LPDWORD lpdwUrlLength)
2993 /***********************************************************************
2995 * InternetCreateUrlW
3002 BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
3003 LPWSTR lpszUrl, LPDWORD lpdwUrlLength)