2 * Copyright 2014 Hans Leidekker for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "wine/port.h"
23 #include <sys/types.h>
24 #ifdef HAVE_SYS_SOCKET_H
25 # include <sys/socket.h>
27 #ifdef HAVE_NETINET_IN_H
28 # include <netinet/in.h>
33 #if defined(__MINGW32__) || defined (_MSC_VER)
34 # include <ws2tcpip.h>
36 # define closesocket close
37 # define ioctlsocket ioctl
53 #include "wine/debug.h"
54 #include "wine/heap.h"
55 #include "wine/unicode.h"
57 static HINSTANCE instance
;
59 WINE_DEFAULT_DEBUG_CHANNEL(jsproxy
);
61 static CRITICAL_SECTION cs_jsproxy
;
62 static CRITICAL_SECTION_DEBUG critsect_debug
=
65 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
66 0, 0, { (DWORD_PTR
)(__FILE__
": cs_jsproxy") }
68 static CRITICAL_SECTION cs_jsproxy
= { &critsect_debug
, -1, 0, 0, 0, 0 };
70 static const WCHAR global_funcsW
[] = {'g','l','o','b','a','l','_','f','u','n','c','s',0};
71 static const WCHAR dns_resolveW
[] = {'d','n','s','_','r','e','s','o','l','v','e',0};
73 /******************************************************************
76 BOOL WINAPI
DllMain( HINSTANCE hinst
, DWORD reason
, LPVOID reserved
)
80 case DLL_PROCESS_ATTACH
:
82 DisableThreadLibraryCalls( hinst
);
85 case DLL_PROCESS_DETACH
:
91 static inline WCHAR
*strdupAW( const char *src
, int len
)
96 int dst_len
= MultiByteToWideChar( CP_ACP
, 0, src
, len
, NULL
, 0 );
97 if ((dst
= heap_alloc( (dst_len
+ 1) * sizeof(WCHAR
) )))
99 len
= MultiByteToWideChar( CP_ACP
, 0, src
, len
, dst
, dst_len
);
106 static inline char *strdupWA( const WCHAR
*src
)
111 int len
= WideCharToMultiByte( CP_ACP
, 0, src
, -1, NULL
, 0, NULL
, NULL
);
112 if ((dst
= heap_alloc( len
))) WideCharToMultiByte( CP_ACP
, 0, src
, -1, dst
, len
, NULL
, NULL
);
117 static struct pac_script
121 static struct pac_script
*global_script
= &pac_script
;
123 /******************************************************************
124 * InternetDeInitializeAutoProxyDll (jsproxy.@)
126 BOOL WINAPI
InternetDeInitializeAutoProxyDll( LPSTR mime
, DWORD reserved
)
128 TRACE( "%s, %u\n", debugstr_a(mime
), reserved
);
130 EnterCriticalSection( &cs_jsproxy
);
132 heap_free( global_script
->text
);
133 global_script
->text
= NULL
;
135 LeaveCriticalSection( &cs_jsproxy
);
139 static WCHAR
*load_script( const char *filename
)
142 DWORD size
, bytes_read
;
145 WCHAR
*script
= NULL
;
147 handle
= CreateFileA( filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0 );
148 if (handle
== INVALID_HANDLE_VALUE
) return NULL
;
150 size
= GetFileSize( handle
, NULL
);
151 if (!(buffer
= heap_alloc( size
))) goto done
;
152 if (!ReadFile( handle
, buffer
, size
, &bytes_read
, NULL
) || bytes_read
!= size
) goto done
;
154 len
= MultiByteToWideChar( CP_ACP
, 0, buffer
, size
, NULL
, 0 );
155 if (!(script
= heap_alloc( (len
+ 1) * sizeof(WCHAR
) ))) goto done
;
156 MultiByteToWideChar( CP_ACP
, 0, buffer
, size
, script
, len
);
160 CloseHandle( handle
);
165 /******************************************************************
166 * InternetInitializeAutoProxyDll (jsproxy.@)
168 BOOL WINAPI
JSPROXY_InternetInitializeAutoProxyDll( DWORD version
, LPSTR tmpfile
, LPSTR mime
,
169 AutoProxyHelperFunctions
*callbacks
,
170 LPAUTO_PROXY_SCRIPT_BUFFER buffer
)
174 TRACE( "%u, %s, %s, %p, %p\n", version
, debugstr_a(tmpfile
), debugstr_a(mime
), callbacks
, buffer
);
176 if (callbacks
) FIXME( "callbacks not supported\n" );
178 EnterCriticalSection( &cs_jsproxy
);
180 if (buffer
&& buffer
->dwStructSize
== sizeof(*buffer
) && buffer
->lpszScriptBuffer
)
183 for (i
= 0; i
< buffer
->dwScriptBufferSize
; i
++)
185 if (!buffer
->lpszScriptBuffer
[i
]) break;
188 if (len
== buffer
->dwScriptBufferSize
)
190 SetLastError( ERROR_INVALID_PARAMETER
);
191 LeaveCriticalSection( &cs_jsproxy
);
194 heap_free( global_script
->text
);
195 if ((global_script
->text
= strdupAW( buffer
->lpszScriptBuffer
, len
))) ret
= TRUE
;
199 heap_free( global_script
->text
);
200 if ((global_script
->text
= load_script( tmpfile
))) ret
= TRUE
;
203 LeaveCriticalSection( &cs_jsproxy
);
207 static HRESULT WINAPI
dispex_QueryInterface(
208 IDispatchEx
*iface
, REFIID riid
, void **ppv
)
212 if (IsEqualGUID( riid
, &IID_IUnknown
) ||
213 IsEqualGUID( riid
, &IID_IDispatch
) ||
214 IsEqualGUID( riid
, &IID_IDispatchEx
))
217 return E_NOINTERFACE
;
222 static ULONG WINAPI
dispex_AddRef(
228 static ULONG WINAPI
dispex_Release(
234 static HRESULT WINAPI
dispex_GetTypeInfoCount(
235 IDispatchEx
*iface
, UINT
*info
)
240 static HRESULT WINAPI
dispex_GetTypeInfo(
241 IDispatchEx
*iface
, UINT info
, LCID lcid
, ITypeInfo
**type_info
)
246 static HRESULT WINAPI
dispex_GetIDsOfNames(
247 IDispatchEx
*iface
, REFIID riid
, LPOLESTR
*names
, UINT count
, LCID lcid
, DISPID
*id
)
252 static HRESULT WINAPI
dispex_Invoke(
253 IDispatchEx
*iface
, DISPID member
, REFIID riid
, LCID lcid
, WORD flags
,
254 DISPPARAMS
*params
, VARIANT
*result
, EXCEPINFO
*excep
, UINT
*err
)
259 static HRESULT WINAPI
dispex_DeleteMemberByName(
260 IDispatchEx
*iface
, BSTR name
, DWORD flags
)
265 static HRESULT WINAPI
dispex_DeleteMemberByDispID(
266 IDispatchEx
*iface
, DISPID id
)
271 static HRESULT WINAPI
dispex_GetMemberProperties(
272 IDispatchEx
*iface
, DISPID id
, DWORD flags_fetch
, DWORD
*flags
)
277 static HRESULT WINAPI
dispex_GetMemberName(
278 IDispatchEx
*iface
, DISPID id
, BSTR
*name
)
283 static HRESULT WINAPI
dispex_GetNextDispID(
284 IDispatchEx
*iface
, DWORD flags
, DISPID id
, DISPID
*next
)
289 static HRESULT WINAPI
dispex_GetNameSpaceParent(
290 IDispatchEx
*iface
, IUnknown
**unk
)
295 #define DISPID_GLOBAL_DNSRESOLVE 0x1000
297 static HRESULT WINAPI
dispex_GetDispID(
298 IDispatchEx
*iface
, BSTR name
, DWORD flags
, DISPID
*id
)
300 if (!strcmpW( name
, dns_resolveW
))
302 *id
= DISPID_GLOBAL_DNSRESOLVE
;
305 return DISP_E_UNKNOWNNAME
;
308 static char *get_computer_name( COMPUTER_NAME_FORMAT format
)
313 GetComputerNameExA( format
, NULL
, &size
);
314 if (GetLastError() != ERROR_MORE_DATA
) return NULL
;
315 if (!(ret
= heap_alloc( size
))) return NULL
;
316 if (!GetComputerNameExA( format
, ret
, &size
))
324 static void printf_addr( const WCHAR
*fmt
, WCHAR
*buf
, struct sockaddr_in
*addr
)
327 (unsigned int)(ntohl( addr
->sin_addr
.s_addr
) >> 24 & 0xff),
328 (unsigned int)(ntohl( addr
->sin_addr
.s_addr
) >> 16 & 0xff),
329 (unsigned int)(ntohl( addr
->sin_addr
.s_addr
) >> 8 & 0xff),
330 (unsigned int)(ntohl( addr
->sin_addr
.s_addr
) & 0xff) );
333 static HRESULT
dns_resolve( const WCHAR
*hostname
, VARIANT
*result
)
335 #ifdef HAVE_GETADDRINFO
336 static const WCHAR fmtW
[] = {'%','u','.','%','u','.','%','u','.','%','u',0};
338 struct addrinfo
*ai
, *elem
;
343 hostnameA
= strdupWA( hostname
);
345 hostnameA
= get_computer_name( ComputerNamePhysicalDnsFullyQualified
);
347 if (!hostnameA
) return E_OUTOFMEMORY
;
348 res
= getaddrinfo( hostnameA
, NULL
, NULL
, &ai
);
349 heap_free( hostnameA
);
350 if (res
) return S_FALSE
;
353 while (elem
&& elem
->ai_family
!= AF_INET
) elem
= elem
->ai_next
;
359 printf_addr( fmtW
, addr
, (struct sockaddr_in
*)elem
->ai_addr
);
361 V_VT( result
) = VT_BSTR
;
362 V_BSTR( result
) = SysAllocString( addr
);
365 FIXME("getaddrinfo not found at build time\n");
370 static HRESULT WINAPI
dispex_InvokeEx(
371 IDispatchEx
*iface
, DISPID id
, LCID lcid
, WORD flags
, DISPPARAMS
*params
,
372 VARIANT
*result
, EXCEPINFO
*exep
, IServiceProvider
*caller
)
374 if (id
== DISPID_GLOBAL_DNSRESOLVE
)
376 if (params
->cArgs
!= 1) return DISP_E_BADPARAMCOUNT
;
377 if (V_VT(¶ms
->rgvarg
[0]) != VT_BSTR
) return DISP_E_BADVARTYPE
;
378 return dns_resolve( V_BSTR(¶ms
->rgvarg
[0]), result
);
380 return DISP_E_MEMBERNOTFOUND
;
383 static const IDispatchExVtbl dispex_vtbl
=
385 dispex_QueryInterface
,
388 dispex_GetTypeInfoCount
,
390 dispex_GetIDsOfNames
,
394 dispex_DeleteMemberByName
,
395 dispex_DeleteMemberByDispID
,
396 dispex_GetMemberProperties
,
397 dispex_GetMemberName
,
398 dispex_GetNextDispID
,
399 dispex_GetNameSpaceParent
402 static IDispatchEx global_dispex
= { &dispex_vtbl
};
404 static HRESULT WINAPI
site_QueryInterface(
405 IActiveScriptSite
*iface
, REFIID riid
, void **ppv
)
409 if (IsEqualGUID( &IID_IUnknown
, riid
))
411 else if (IsEqualGUID( &IID_IActiveScriptSite
, riid
))
414 return E_NOINTERFACE
;
416 IUnknown_AddRef( (IUnknown
*)*ppv
);
420 static ULONG WINAPI
site_AddRef(
421 IActiveScriptSite
*iface
)
426 static ULONG WINAPI
site_Release(
427 IActiveScriptSite
*iface
)
432 static HRESULT WINAPI
site_GetLCID(
433 IActiveScriptSite
*iface
, LCID
*lcid
)
438 static HRESULT WINAPI
site_GetItemInfo(
439 IActiveScriptSite
*iface
, LPCOLESTR name
, DWORD mask
,
440 IUnknown
**item
, ITypeInfo
**type_info
)
442 if (!strcmpW( name
, global_funcsW
) && mask
== SCRIPTINFO_IUNKNOWN
)
444 *item
= (IUnknown
*)&global_dispex
;
450 static HRESULT WINAPI
site_GetDocVersionString(
451 IActiveScriptSite
*iface
, BSTR
*version
)
456 static HRESULT WINAPI
site_OnScriptTerminate(
457 IActiveScriptSite
*iface
, const VARIANT
*result
, const EXCEPINFO
*info
)
462 static HRESULT WINAPI
site_OnStateChange(
463 IActiveScriptSite
*iface
, SCRIPTSTATE state
)
468 static HRESULT WINAPI
site_OnScriptError(
469 IActiveScriptSite
*iface
, IActiveScriptError
*error
)
474 static HRESULT WINAPI
site_OnEnterScript(
475 IActiveScriptSite
*iface
)
480 static HRESULT WINAPI
site_OnLeaveScript(
481 IActiveScriptSite
*iface
)
486 static const IActiveScriptSiteVtbl site_vtbl
=
493 site_GetDocVersionString
,
494 site_OnScriptTerminate
,
501 static IActiveScriptSite script_site
= { &site_vtbl
};
503 static BSTR
include_pac_utils( const WCHAR
*script
)
505 static const WCHAR pacjsW
[] = {'p','a','c','.','j','s',0};
506 HMODULE hmod
= GetModuleHandleA( "jsproxy.dll" );
513 if (!(rsrc
= FindResourceW( hmod
, pacjsW
, (LPCWSTR
)40 ))) return NULL
;
514 size
= SizeofResource( hmod
, rsrc
);
515 data
= LoadResource( hmod
, rsrc
);
517 len
= MultiByteToWideChar( CP_ACP
, 0, data
, size
, NULL
, 0 );
518 if (!(ret
= SysAllocStringLen( NULL
, len
+ strlenW( script
) + 1 ))) return NULL
;
519 MultiByteToWideChar( CP_ACP
, 0, data
, size
, ret
, len
);
520 strcpyW( ret
+ len
, script
);
525 #define IActiveScriptParse_Release IActiveScriptParse64_Release
526 #define IActiveScriptParse_InitNew IActiveScriptParse64_InitNew
527 #define IActiveScriptParse_ParseScriptText IActiveScriptParse64_ParseScriptText
529 #define IActiveScriptParse_Release IActiveScriptParse32_Release
530 #define IActiveScriptParse_InitNew IActiveScriptParse32_InitNew
531 #define IActiveScriptParse_ParseScriptText IActiveScriptParse32_ParseScriptText
534 static BOOL
run_script( const WCHAR
*script
, const WCHAR
*url
, const WCHAR
*hostname
, char **result_str
, DWORD
*result_len
)
536 static const WCHAR jscriptW
[] = {'J','S','c','r','i','p','t',0};
537 static const WCHAR findproxyW
[] = {'F','i','n','d','P','r','o','x','y','F','o','r','U','R','L',0};
538 IActiveScriptParse
*parser
= NULL
;
539 IActiveScript
*engine
= NULL
;
540 IDispatch
*dispatch
= NULL
;
544 BSTR func
= NULL
, full_script
= NULL
;
545 VARIANT args
[2], retval
;
549 init
= CoInitialize( NULL
);
550 hr
= CLSIDFromProgID( jscriptW
, &clsid
);
551 if (hr
!= S_OK
) goto done
;
553 hr
= CoCreateInstance( &clsid
, NULL
, CLSCTX_INPROC_SERVER
|CLSCTX_INPROC_HANDLER
,
554 &IID_IActiveScript
, (void **)&engine
);
555 if (hr
!= S_OK
) goto done
;
557 hr
= IActiveScript_QueryInterface( engine
, &IID_IActiveScriptParse
, (void **)&parser
);
558 if (hr
!= S_OK
) goto done
;
560 hr
= IActiveScriptParse_InitNew( parser
);
561 if (hr
!= S_OK
) goto done
;
563 hr
= IActiveScript_SetScriptSite( engine
, &script_site
);
564 if (hr
!= S_OK
) goto done
;
566 hr
= IActiveScript_AddNamedItem( engine
, global_funcsW
, SCRIPTITEM_GLOBALMEMBERS
);
567 if (hr
!= S_OK
) goto done
;
569 if (!(full_script
= include_pac_utils( script
))) goto done
;
571 hr
= IActiveScriptParse_ParseScriptText( parser
, full_script
, NULL
, NULL
, NULL
, 0, 0, 0, NULL
, NULL
);
572 if (hr
!= S_OK
) goto done
;
574 hr
= IActiveScript_SetScriptState( engine
, SCRIPTSTATE_STARTED
);
575 if (hr
!= S_OK
) goto done
;
577 hr
= IActiveScript_GetScriptDispatch( engine
, NULL
, &dispatch
);
578 if (hr
!= S_OK
) goto done
;
580 if (!(func
= SysAllocString( findproxyW
))) goto done
;
581 hr
= IDispatch_GetIDsOfNames( dispatch
, &IID_NULL
, &func
, 1, LOCALE_SYSTEM_DEFAULT
, &dispid
);
582 if (hr
!= S_OK
) goto done
;
584 V_VT( &args
[0] ) = VT_BSTR
;
585 V_BSTR( &args
[0] ) = SysAllocString( hostname
);
586 V_VT( &args
[1] ) = VT_BSTR
;
587 V_BSTR( &args
[1] ) = SysAllocString( url
);
589 params
.rgvarg
= args
;
590 params
.rgdispidNamedArgs
= NULL
;
592 params
.cNamedArgs
= 0;
593 hr
= IDispatch_Invoke( dispatch
, dispid
, &IID_NULL
, LOCALE_SYSTEM_DEFAULT
, DISPATCH_METHOD
,
594 ¶ms
, &retval
, NULL
, NULL
);
595 VariantClear( &args
[0] );
596 VariantClear( &args
[1] );
599 WARN("script failed 0x%08x\n", hr
);
602 if ((*result_str
= strdupWA( V_BSTR( &retval
) )))
604 TRACE( "result: %s\n", debugstr_a(*result_str
) );
605 *result_len
= strlen( *result_str
) + 1;
608 VariantClear( &retval
);
611 SysFreeString( full_script
);
612 SysFreeString( func
);
613 if (dispatch
) IDispatch_Release( dispatch
);
614 if (parser
) IActiveScriptParse_Release( parser
);
615 if (engine
) IActiveScript_Release( engine
);
616 if (SUCCEEDED( init
)) CoUninitialize();
620 /******************************************************************
621 * InternetGetProxyInfo (jsproxy.@)
623 BOOL WINAPI
InternetGetProxyInfo( LPCSTR url
, DWORD len_url
, LPCSTR hostname
, DWORD len_hostname
, LPSTR
*proxy
,
626 WCHAR
*urlW
= NULL
, *hostnameW
= NULL
;
629 TRACE( "%s, %u, %s, %u, %p, %p\n", debugstr_a(url
), len_url
, hostname
, len_hostname
, proxy
, len_proxy
);
631 EnterCriticalSection( &cs_jsproxy
);
633 if (!global_script
->text
)
635 SetLastError( ERROR_CAN_NOT_COMPLETE
);
638 if (hostname
&& len_hostname
< strlen( hostname
))
640 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
643 if (!(urlW
= strdupAW( url
, -1 ))) goto done
;
644 if (hostname
&& !(hostnameW
= strdupAW( hostname
, -1 ))) goto done
;
646 TRACE( "%s\n", debugstr_w(global_script
->text
) );
647 ret
= run_script( global_script
->text
, urlW
, hostnameW
, proxy
, len_proxy
);
650 heap_free( hostnameW
);
652 LeaveCriticalSection( &cs_jsproxy
);