crypt32: NULL ptr could leak into function (Coverity).
[wine] / dlls / mshtml / script.c
1 /*
2  * Copyright 2008 Jacek Caban for CodeWeavers
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #include "config.h"
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "ole2.h"
29 #include "activscp.h"
30 #include "activdbg.h"
31 #include "objsafe.h"
32
33 #include "wine/debug.h"
34
35 #include "mshtml_private.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
38
39 #ifdef _WIN64
40 #define CTXARG_T DWORDLONG
41 #define IActiveScriptSiteDebugVtbl IActiveScriptSiteDebug64Vtbl
42 #else
43 #define CTXARG_T DWORD
44 #define IActiveScriptSiteDebugVtbl IActiveScriptSiteDebug32Vtbl
45 #endif
46
47 static const WCHAR windowW[] = {'w','i','n','d','o','w',0};
48 static const WCHAR emptyW[] = {0};
49
50 static const CLSID CLSID_JScript =
51     {0xf414c260,0x6ac0,0x11cf,{0xb6,0xd1,0x00,0xaa,0x00,0xbb,0xbb,0x58}};
52
53 struct ScriptHost {
54     const IActiveScriptSiteVtbl               *lpIActiveScriptSiteVtbl;
55     const IActiveScriptSiteInterruptPollVtbl  *lpIActiveScriptSiteInterruptPollVtbl;
56     const IActiveScriptSiteWindowVtbl         *lpIActiveScriptSiteWindowVtbl;
57     const IActiveScriptSiteDebugVtbl          *lpIActiveScriptSiteDebugVtbl;
58     IServiceProvider               IServiceProvider_iface;
59
60     LONG ref;
61
62     IActiveScript *script;
63     IActiveScriptParse *parse;
64     IActiveScriptParseProcedure *parse_proc;
65
66     SCRIPTSTATE script_state;
67
68     HTMLWindow *window;
69
70     GUID guid;
71     struct list entry;
72 };
73
74 #define ACTSCPSITE(x)  ((IActiveScriptSite*)               &(x)->lpIActiveScriptSiteVtbl)
75 #define ACTSCPPOLL(x)  (&(x)->lpIActiveScriptSiteInterruptPollVtbl)
76 #define ACTSCPWIN(x)   (&(x)->lpIActiveScriptSiteWindowVtbl)
77 #define ACTSCPDBG(x)   (&(x)->lpIActiveScriptSiteDebugVtbl)
78
79 static void set_script_prop(ScriptHost *script_host, DWORD property, VARIANT *val)
80 {
81     IActiveScriptProperty *script_prop;
82     HRESULT hres;
83
84     hres = IActiveScript_QueryInterface(script_host->script, &IID_IActiveScriptProperty,
85             (void**)&script_prop);
86     if(FAILED(hres)) {
87         WARN("Could not get IActiveScriptProperty iface: %08x\n", hres);
88         return;
89     }
90
91     hres = IActiveScriptProperty_SetProperty(script_prop, property, NULL, val);
92     IActiveScriptProperty_Release(script_prop);
93     if(FAILED(hres))
94         WARN("SetProperty(%x) failed: %08x\n", property, hres);
95 }
96
97 static BOOL init_script_engine(ScriptHost *script_host)
98 {
99     IObjectSafety *safety;
100     SCRIPTSTATE state;
101     DWORD supported_opts=0, enabled_opts=0;
102     VARIANT var;
103     HRESULT hres;
104
105     hres = IActiveScript_QueryInterface(script_host->script, &IID_IActiveScriptParse, (void**)&script_host->parse);
106     if(FAILED(hres)) {
107         WARN("Could not get IActiveScriptHost: %08x\n", hres);
108         return FALSE;
109     }
110
111     hres = IActiveScript_QueryInterface(script_host->script, &IID_IObjectSafety, (void**)&safety);
112     if(FAILED(hres)) {
113         FIXME("Could not get IObjectSafety: %08x\n", hres);
114         return FALSE;
115     }
116
117     hres = IObjectSafety_GetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse, &supported_opts, &enabled_opts);
118     if(FAILED(hres)) {
119         FIXME("GetInterfaceSafetyOptions failed: %08x\n", hres);
120     }else if(!(supported_opts & INTERFACE_USES_DISPEX)) {
121         FIXME("INTERFACE_USES_DISPEX is not supported\n");
122     }else {
123         hres = IObjectSafety_SetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse,
124                 INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER,
125                 INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER);
126         if(FAILED(hres))
127             FIXME("SetInterfaceSafetyOptions failed: %08x\n", hres);
128     }
129
130     IObjectSafety_Release(safety);
131     if(FAILED(hres))
132         return FALSE;
133
134     V_VT(&var) = VT_I4;
135     V_I4(&var) = 1;
136     set_script_prop(script_host, SCRIPTPROP_INVOKEVERSIONING, &var);
137
138     V_VT(&var) = VT_BOOL;
139     V_BOOL(&var) = VARIANT_TRUE;
140     set_script_prop(script_host, SCRIPTPROP_HACK_TRIDENTEVENTSINK, &var);
141
142     hres = IActiveScriptParse64_InitNew(script_host->parse);
143     if(FAILED(hres)) {
144         WARN("InitNew failed: %08x\n", hres);
145         return FALSE;
146     }
147
148     hres = IActiveScript_SetScriptSite(script_host->script, ACTSCPSITE(script_host));
149     if(FAILED(hres)) {
150         WARN("SetScriptSite failed: %08x\n", hres);
151         IActiveScript_Close(script_host->script);
152         return FALSE;
153     }
154
155     hres = IActiveScript_GetScriptState(script_host->script, &state);
156     if(FAILED(hres))
157         WARN("GetScriptState failed: %08x\n", hres);
158     else if(state != SCRIPTSTATE_INITIALIZED)
159         FIXME("state = %x\n", state);
160
161     hres = IActiveScript_SetScriptState(script_host->script, SCRIPTSTATE_STARTED);
162     if(FAILED(hres)) {
163         WARN("Starting script failed: %08x\n", hres);
164         return FALSE;
165     }
166
167     hres = IActiveScript_AddNamedItem(script_host->script, windowW,
168             SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|SCRIPTITEM_GLOBALMEMBERS);
169     if(SUCCEEDED(hres)) {
170         V_VT(&var) = VT_BOOL;
171         V_BOOL(&var) = VARIANT_TRUE;
172         set_script_prop(script_host, SCRIPTPROP_ABBREVIATE_GLOBALNAME_RESOLUTION, &var);
173     }else {
174        WARN("AddNamedItem failed: %08x\n", hres);
175     }
176
177     hres = IActiveScript_QueryInterface(script_host->script, &IID_IActiveScriptParseProcedure2,
178                                         (void**)&script_host->parse_proc);
179     if(FAILED(hres)) {
180         /* FIXME: QI for IActiveScriptParseProcedure */
181         WARN("Could not get IActiveScriptParseProcedure iface: %08x\n", hres);
182     }
183
184     return TRUE;
185 }
186
187 static void release_script_engine(ScriptHost *This)
188 {
189     if(!This->script)
190         return;
191
192     switch(This->script_state) {
193     case SCRIPTSTATE_CONNECTED:
194         IActiveScript_SetScriptState(This->script, SCRIPTSTATE_DISCONNECTED);
195
196     case SCRIPTSTATE_STARTED:
197     case SCRIPTSTATE_DISCONNECTED:
198     case SCRIPTSTATE_INITIALIZED:
199         IActiveScript_Close(This->script);
200
201     default:
202         if(This->parse_proc) {
203             IUnknown_Release(This->parse_proc);
204             This->parse_proc = NULL;
205         }
206
207         if(This->parse) {
208             IUnknown_Release(This->parse);
209             This->parse = NULL;
210         }
211     }
212
213     IActiveScript_Release(This->script);
214     This->script = NULL;
215     This->script_state = SCRIPTSTATE_UNINITIALIZED;
216 }
217
218 void connect_scripts(HTMLWindow *window)
219 {
220     ScriptHost *iter;
221
222     LIST_FOR_EACH_ENTRY(iter, &window->script_hosts, ScriptHost, entry) {
223         if(iter->script_state == SCRIPTSTATE_STARTED)
224             IActiveScript_SetScriptState(iter->script, SCRIPTSTATE_CONNECTED);
225     }
226 }
227
228 #define ACTSCPSITE_THIS(iface) DEFINE_THIS(ScriptHost, IActiveScriptSite, iface)
229
230 static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, REFIID riid, void **ppv)
231 {
232     ScriptHost *This = ACTSCPSITE_THIS(iface);
233
234     *ppv = NULL;
235
236     if(IsEqualGUID(&IID_IUnknown, riid)) {
237         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
238         *ppv = ACTSCPSITE(This);
239     }else if(IsEqualGUID(&IID_IActiveScriptSite, riid)) {
240         TRACE("(%p)->(IID_IActiveScriptSite %p)\n", This, ppv);
241         *ppv = ACTSCPSITE(This);
242     }else if(IsEqualGUID(&IID_IActiveScriptSiteInterruptPoll, riid)) {
243         TRACE("(%p)->(IID_IActiveScriptSiteInterruprtPoll %p)\n", This, ppv);
244         *ppv = ACTSCPPOLL(This);
245     }else if(IsEqualGUID(&IID_IActiveScriptSiteWindow, riid)) {
246         TRACE("(%p)->(IID_IActiveScriptSiteWindow %p)\n", This, ppv);
247         *ppv = ACTSCPWIN(This);
248     }else if(IsEqualGUID(&IID_IActiveScriptSiteDebug, riid)) {
249         TRACE("(%p)->(IID_IActiveScriptSiteDebug %p)\n", This, ppv);
250         *ppv = ACTSCPDBG(This);
251     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
252         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
253         *ppv = &This->IServiceProvider_iface;
254     }else if(IsEqualGUID(&IID_ICanHandleException, riid)) {
255         TRACE("(%p)->(IID_ICanHandleException not supported %p)\n", This, ppv);
256         return E_NOINTERFACE;
257     }else {
258         FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
259         return E_NOINTERFACE;
260     }
261
262     IUnknown_AddRef((IUnknown*)*ppv);
263     return S_OK;
264 }
265
266 static ULONG WINAPI ActiveScriptSite_AddRef(IActiveScriptSite *iface)
267 {
268     ScriptHost *This = ACTSCPSITE_THIS(iface);
269     LONG ref = InterlockedIncrement(&This->ref);
270
271     TRACE("(%p) ref=%d\n", This, ref);
272
273     return ref;
274 }
275
276 static ULONG WINAPI ActiveScriptSite_Release(IActiveScriptSite *iface)
277 {
278     ScriptHost *This = ACTSCPSITE_THIS(iface);
279     LONG ref = InterlockedDecrement(&This->ref);
280
281     TRACE("(%p) ref=%d\n", This, ref);
282
283     if(!ref) {
284         release_script_engine(This);
285         if(This->window)
286             list_remove(&This->entry);
287         heap_free(This);
288     }
289
290     return ref;
291 }
292
293 static HRESULT WINAPI ActiveScriptSite_GetLCID(IActiveScriptSite *iface, LCID *plcid)
294 {
295     ScriptHost *This = ACTSCPSITE_THIS(iface);
296
297     TRACE("(%p)->(%p)\n", This, plcid);
298
299     *plcid = GetUserDefaultLCID();
300     return S_OK;
301 }
302
303 static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPCOLESTR pstrName,
304         DWORD dwReturnMask, IUnknown **ppiunkItem, ITypeInfo **ppti)
305 {
306     ScriptHost *This = ACTSCPSITE_THIS(iface);
307
308     TRACE("(%p)->(%s %x %p %p)\n", This, debugstr_w(pstrName), dwReturnMask, ppiunkItem, ppti);
309
310     if(dwReturnMask != SCRIPTINFO_IUNKNOWN) {
311         FIXME("Unsupported mask %x\n", dwReturnMask);
312         return E_NOTIMPL;
313     }
314
315     *ppiunkItem = NULL;
316
317     if(strcmpW(pstrName, windowW))
318         return DISP_E_MEMBERNOTFOUND;
319
320     if(!This->window)
321         return E_FAIL;
322
323     /* FIXME: Return proxy object */
324     *ppiunkItem = (IUnknown*)&This->window->IHTMLWindow2_iface;
325     IUnknown_AddRef(*ppiunkItem);
326
327     return S_OK;
328 }
329
330 static HRESULT WINAPI ActiveScriptSite_GetDocVersionString(IActiveScriptSite *iface, BSTR *pbstrVersion)
331 {
332     ScriptHost *This = ACTSCPSITE_THIS(iface);
333     FIXME("(%p)->(%p)\n", This, pbstrVersion);
334     return E_NOTIMPL;
335 }
336
337 static HRESULT WINAPI ActiveScriptSite_OnScriptTerminate(IActiveScriptSite *iface,
338         const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo)
339 {
340     ScriptHost *This = ACTSCPSITE_THIS(iface);
341     FIXME("(%p)->(%p %p)\n", This, pvarResult, pexcepinfo);
342     return E_NOTIMPL;
343 }
344
345 static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface, SCRIPTSTATE ssScriptState)
346 {
347     ScriptHost *This = ACTSCPSITE_THIS(iface);
348
349     TRACE("(%p)->(%x)\n", This, ssScriptState);
350
351     This->script_state = ssScriptState;
352     return S_OK;
353 }
354
355 static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, IActiveScriptError *pscripterror)
356 {
357     ScriptHost *This = ACTSCPSITE_THIS(iface);
358     FIXME("(%p)->(%p)\n", This, pscripterror);
359     return E_NOTIMPL;
360 }
361
362 static HRESULT WINAPI ActiveScriptSite_OnEnterScript(IActiveScriptSite *iface)
363 {
364     ScriptHost *This = ACTSCPSITE_THIS(iface);
365
366     TRACE("(%p)->()\n", This);
367
368     return S_OK;
369 }
370
371 static HRESULT WINAPI ActiveScriptSite_OnLeaveScript(IActiveScriptSite *iface)
372 {
373     ScriptHost *This = ACTSCPSITE_THIS(iface);
374
375     TRACE("(%p)->()\n", This);
376
377     return S_OK;
378 }
379
380 #undef ACTSCPSITE_THIS
381
382 static const IActiveScriptSiteVtbl ActiveScriptSiteVtbl = {
383     ActiveScriptSite_QueryInterface,
384     ActiveScriptSite_AddRef,
385     ActiveScriptSite_Release,
386     ActiveScriptSite_GetLCID,
387     ActiveScriptSite_GetItemInfo,
388     ActiveScriptSite_GetDocVersionString,
389     ActiveScriptSite_OnScriptTerminate,
390     ActiveScriptSite_OnStateChange,
391     ActiveScriptSite_OnScriptError,
392     ActiveScriptSite_OnEnterScript,
393     ActiveScriptSite_OnLeaveScript
394 };
395
396 #define ACTSCPPOLL_THIS(iface) DEFINE_THIS(ScriptHost, IActiveScriptSiteInterruptPoll, iface)
397
398 static HRESULT WINAPI ActiveScriptSiteInterruptPoll_QueryInterface(IActiveScriptSiteInterruptPoll *iface,
399         REFIID riid, void **ppv)
400 {
401     ScriptHost *This = ACTSCPPOLL_THIS(iface);
402     return IActiveScriptSite_QueryInterface(ACTSCPSITE(This), riid, ppv);
403 }
404
405 static ULONG WINAPI ActiveScriptSiteInterruptPoll_AddRef(IActiveScriptSiteInterruptPoll *iface)
406 {
407     ScriptHost *This = ACTSCPPOLL_THIS(iface);
408     return IActiveScriptSite_AddRef(ACTSCPSITE(This));
409 }
410
411 static ULONG WINAPI ActiveScriptSiteInterruptPoll_Release(IActiveScriptSiteInterruptPoll *iface)
412 {
413     ScriptHost *This = ACTSCPPOLL_THIS(iface);
414     return IActiveScriptSite_Release(ACTSCPSITE(This));
415 }
416
417 static HRESULT WINAPI ActiveScriptSiteInterruptPoll_QueryContinue(IActiveScriptSiteInterruptPoll *iface)
418 {
419     ScriptHost *This = ACTSCPPOLL_THIS(iface);
420
421     TRACE("(%p)\n", This);
422
423     return S_OK;
424 }
425
426 #undef ACTSCPPOLL_THIS
427
428 static const IActiveScriptSiteInterruptPollVtbl ActiveScriptSiteInterruptPollVtbl = {
429     ActiveScriptSiteInterruptPoll_QueryInterface,
430     ActiveScriptSiteInterruptPoll_AddRef,
431     ActiveScriptSiteInterruptPoll_Release,
432     ActiveScriptSiteInterruptPoll_QueryContinue
433 };
434
435 #define ACTSCPWIN_THIS(iface) DEFINE_THIS(ScriptHost, IActiveScriptSiteWindow, iface)
436
437 static HRESULT WINAPI ActiveScriptSiteWindow_QueryInterface(IActiveScriptSiteWindow *iface,
438         REFIID riid, void **ppv)
439 {
440     ScriptHost *This = ACTSCPWIN_THIS(iface);
441     return IActiveScriptSite_QueryInterface(ACTSCPSITE(This), riid, ppv);
442 }
443
444 static ULONG WINAPI ActiveScriptSiteWindow_AddRef(IActiveScriptSiteWindow *iface)
445 {
446     ScriptHost *This = ACTSCPWIN_THIS(iface);
447     return IActiveScriptSite_AddRef(ACTSCPSITE(This));
448 }
449
450 static ULONG WINAPI ActiveScriptSiteWindow_Release(IActiveScriptSiteWindow *iface)
451 {
452     ScriptHost *This = ACTSCPWIN_THIS(iface);
453     return IActiveScriptSite_Release(ACTSCPSITE(This));
454 }
455
456 static HRESULT WINAPI ActiveScriptSiteWindow_GetWindow(IActiveScriptSiteWindow *iface, HWND *phwnd)
457 {
458     ScriptHost *This = ACTSCPWIN_THIS(iface);
459     FIXME("(%p)->(%p)\n", This, phwnd);
460     return E_NOTIMPL;
461 }
462
463 static HRESULT WINAPI ActiveScriptSiteWindow_EnableModeless(IActiveScriptSiteWindow *iface, BOOL fEnable)
464 {
465     ScriptHost *This = ACTSCPWIN_THIS(iface);
466     FIXME("(%p)->(%x)\n", This, fEnable);
467     return E_NOTIMPL;
468 }
469
470 #undef ACTSCPWIN_THIS
471
472 static const IActiveScriptSiteWindowVtbl ActiveScriptSiteWindowVtbl = {
473     ActiveScriptSiteWindow_QueryInterface,
474     ActiveScriptSiteWindow_AddRef,
475     ActiveScriptSiteWindow_Release,
476     ActiveScriptSiteWindow_GetWindow,
477     ActiveScriptSiteWindow_EnableModeless
478 };
479
480 #define ACTSCPDBG_THIS(iface) DEFINE_THIS(ScriptHost, IActiveScriptSiteDebug, iface)
481
482 static HRESULT WINAPI ActiveScriptSiteDebug_QueryInterface(IActiveScriptSiteDebug *iface,
483         REFIID riid, void **ppv)
484 {
485     ScriptHost *This = ACTSCPDBG_THIS(iface);
486     return IActiveScriptSite_QueryInterface(ACTSCPSITE(This), riid, ppv);
487 }
488
489 static ULONG WINAPI ActiveScriptSiteDebug_AddRef(IActiveScriptSiteDebug *iface)
490 {
491     ScriptHost *This = ACTSCPDBG_THIS(iface);
492     return IActiveScriptSite_AddRef(ACTSCPSITE(This));
493 }
494
495 static ULONG WINAPI ActiveScriptSiteDebug_Release(IActiveScriptSiteDebug *iface)
496 {
497     ScriptHost *This = ACTSCPDBG_THIS(iface);
498     return IActiveScriptSite_Release(ACTSCPSITE(This));
499 }
500
501 static HRESULT WINAPI ActiveScriptSiteDebug_GetDocumentContextFromPosition(IActiveScriptSiteDebug *iface,
502             CTXARG_T dwSourceContext, ULONG uCharacterOffset, ULONG uNumChars, IDebugDocumentContext **ppsc)
503 {
504     ScriptHost *This = ACTSCPDBG_THIS(iface);
505     FIXME("(%p)->(%s %u %u %p)\n", This, wine_dbgstr_longlong(dwSourceContext), uCharacterOffset,
506           uNumChars, ppsc);
507     return E_NOTIMPL;
508 }
509
510 static HRESULT WINAPI ActiveScriptSiteDebug_GetApplication(IActiveScriptSiteDebug *iface, IDebugApplication **ppda)
511 {
512     ScriptHost *This = ACTSCPDBG_THIS(iface);
513     FIXME("(%p)->(%p)\n", This, ppda);
514     return E_NOTIMPL;
515 }
516
517 static HRESULT WINAPI ActiveScriptSiteDebug_GetRootApplicationNode(IActiveScriptSiteDebug *iface,
518             IDebugApplicationNode **ppdanRoot)
519 {
520     ScriptHost *This = ACTSCPDBG_THIS(iface);
521     FIXME("(%p)->(%p)\n", This, ppdanRoot);
522     return E_NOTIMPL;
523 }
524
525 static HRESULT WINAPI ActiveScriptSiteDebug_OnScriptErrorDebug(IActiveScriptSiteDebug *iface,
526             IActiveScriptErrorDebug *pErrorDebug, BOOL *pfEnterDebugger, BOOL *pfCallOnScriptErrorWhenContinuing)
527 {
528     ScriptHost *This = ACTSCPDBG_THIS(iface);
529     FIXME("(%p)->(%p %p %p)\n", This, pErrorDebug, pfEnterDebugger, pfCallOnScriptErrorWhenContinuing);
530     return E_NOTIMPL;
531 }
532
533 #undef ACTSCPDBG_THIS
534
535 static const IActiveScriptSiteDebugVtbl ActiveScriptSiteDebugVtbl = {
536     ActiveScriptSiteDebug_QueryInterface,
537     ActiveScriptSiteDebug_AddRef,
538     ActiveScriptSiteDebug_Release,
539     ActiveScriptSiteDebug_GetDocumentContextFromPosition,
540     ActiveScriptSiteDebug_GetApplication,
541     ActiveScriptSiteDebug_GetRootApplicationNode,
542     ActiveScriptSiteDebug_OnScriptErrorDebug
543 };
544
545 static inline ScriptHost *impl_from_IServiceProvider(IServiceProvider *iface)
546 {
547     return CONTAINING_RECORD(iface, ScriptHost, IServiceProvider_iface);
548 }
549
550 static HRESULT WINAPI ASServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
551 {
552     ScriptHost *This = impl_from_IServiceProvider(iface);
553     return IActiveScriptSite_QueryInterface(ACTSCPSITE(This), riid, ppv);
554 }
555
556 static ULONG WINAPI ASServiceProvider_AddRef(IServiceProvider *iface)
557 {
558     ScriptHost *This = impl_from_IServiceProvider(iface);
559     return IActiveScriptSite_AddRef(ACTSCPSITE(This));
560 }
561
562 static ULONG WINAPI ASServiceProvider_Release(IServiceProvider *iface)
563 {
564     ScriptHost *This = impl_from_IServiceProvider(iface);
565     return IActiveScriptSite_Release(ACTSCPSITE(This));
566 }
567
568 static HRESULT WINAPI ASServiceProvider_QueryService(IServiceProvider *iface, REFGUID guidService,
569         REFIID riid, void **ppv)
570 {
571     ScriptHost *This = impl_from_IServiceProvider(iface);
572
573     if(IsEqualGUID(&SID_SInternetHostSecurityManager, guidService)) {
574         TRACE("(%p)->(SID_SInternetHostSecurityManager)\n", This);
575
576         if(!This->window || !This->window->doc)
577             return E_NOINTERFACE;
578
579         return IInternetHostSecurityManager_QueryInterface(HOSTSECMGR(This->window->doc), riid, ppv);
580     }
581
582     FIXME("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
583     return E_NOINTERFACE;
584 }
585
586 static const IServiceProviderVtbl ASServiceProviderVtbl = {
587     ASServiceProvider_QueryInterface,
588     ASServiceProvider_AddRef,
589     ASServiceProvider_Release,
590     ASServiceProvider_QueryService
591 };
592
593 static ScriptHost *create_script_host(HTMLWindow *window, const GUID *guid)
594 {
595     ScriptHost *ret;
596     HRESULT hres;
597
598     ret = heap_alloc_zero(sizeof(*ret));
599     ret->lpIActiveScriptSiteVtbl               = &ActiveScriptSiteVtbl;
600     ret->lpIActiveScriptSiteInterruptPollVtbl  = &ActiveScriptSiteInterruptPollVtbl;
601     ret->lpIActiveScriptSiteWindowVtbl         = &ActiveScriptSiteWindowVtbl;
602     ret->lpIActiveScriptSiteDebugVtbl          = &ActiveScriptSiteDebugVtbl;
603     ret->IServiceProvider_iface.lpVtbl         = &ASServiceProviderVtbl;
604     ret->ref = 1;
605     ret->window = window;
606     ret->script_state = SCRIPTSTATE_UNINITIALIZED;
607
608     ret->guid = *guid;
609     list_add_tail(&window->script_hosts, &ret->entry);
610
611     hres = CoCreateInstance(&ret->guid, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
612             &IID_IActiveScript, (void**)&ret->script);
613     if(FAILED(hres))
614         WARN("Could not load script engine: %08x\n", hres);
615     else if(!init_script_engine(ret))
616         release_script_engine(ret);
617
618     return ret;
619 }
620
621 static void parse_text(ScriptHost *script_host, LPCWSTR text)
622 {
623     EXCEPINFO excepinfo;
624     VARIANT var;
625     HRESULT hres;
626
627     static const WCHAR script_endW[] = {'<','/','S','C','R','I','P','T','>',0};
628
629     TRACE("%s\n", debugstr_w(text));
630
631     VariantInit(&var);
632     memset(&excepinfo, 0, sizeof(excepinfo));
633     TRACE(">>>\n");
634     hres = IActiveScriptParse64_ParseScriptText(script_host->parse, text, windowW, NULL, script_endW,
635                                               0, 0, SCRIPTTEXT_ISVISIBLE|SCRIPTTEXT_HOSTMANAGESSOURCE,
636                                               &var, &excepinfo);
637     if(SUCCEEDED(hres))
638         TRACE("<<<\n");
639     else
640         WARN("<<< %08x\n", hres);
641
642 }
643
644 static void parse_extern_script(ScriptHost *script_host, LPCWSTR src)
645 {
646     IMoniker *mon;
647     char *buf;
648     WCHAR *text;
649     DWORD len, size=0;
650     HRESULT hres;
651
652     static const WCHAR wine_schemaW[] = {'w','i','n','e',':'};
653
654     if(strlenW(src) > sizeof(wine_schemaW)/sizeof(WCHAR) && !memcmp(src, wine_schemaW, sizeof(wine_schemaW)))
655         src += sizeof(wine_schemaW)/sizeof(WCHAR);
656
657     hres = CreateURLMoniker(NULL, src, &mon);
658     if(FAILED(hres))
659         return;
660
661     hres = bind_mon_to_buffer(script_host->window->doc, mon, (void**)&buf, &size);
662     IMoniker_Release(mon);
663     if(FAILED(hres))
664         return;
665
666     len = MultiByteToWideChar(CP_ACP, 0, buf, size, NULL, 0);
667     text = heap_alloc((len+1)*sizeof(WCHAR));
668     MultiByteToWideChar(CP_ACP, 0, buf, size, text, len);
669     heap_free(buf);
670     text[len] = 0;
671
672     parse_text(script_host, text);
673
674     heap_free(text);
675 }
676
677 static void parse_inline_script(ScriptHost *script_host, nsIDOMHTMLScriptElement *nsscript)
678 {
679     const PRUnichar *text;
680     nsAString text_str;
681     nsresult nsres;
682
683     nsAString_Init(&text_str, NULL);
684
685     nsres = nsIDOMHTMLScriptElement_GetText(nsscript, &text_str);
686
687     if(NS_SUCCEEDED(nsres)) {
688         nsAString_GetData(&text_str, &text);
689         parse_text(script_host, text);
690     }else {
691         ERR("GetText failed: %08x\n", nsres);
692     }
693
694     nsAString_Finish(&text_str);
695 }
696
697 static void parse_script_elem(ScriptHost *script_host, nsIDOMHTMLScriptElement *nsscript)
698 {
699     const PRUnichar *src;
700     nsAString src_str;
701     nsresult nsres;
702
703     nsAString_Init(&src_str, NULL);
704
705     nsres = nsIDOMHTMLScriptElement_GetSrc(nsscript, &src_str);
706     nsAString_GetData(&src_str, &src);
707
708     if(NS_FAILED(nsres))
709         ERR("GetSrc failed: %08x\n", nsres);
710     else if(*src)
711         parse_extern_script(script_host, src);
712     else
713         parse_inline_script(script_host, nsscript);
714
715     nsAString_Finish(&src_str);
716 }
717
718 static BOOL get_guid_from_type(LPCWSTR type, GUID *guid)
719 {
720     const WCHAR text_javascriptW[] =
721         {'t','e','x','t','/','j','a','v','a','s','c','r','i','p','t',0};
722
723     /* FIXME: Handle more types */
724     if(!strcmpiW(type, text_javascriptW)) {
725         *guid = CLSID_JScript;
726     }else {
727         FIXME("Unknown type %s\n", debugstr_w(type));
728         return FALSE;
729     }
730
731     return TRUE;
732 }
733
734 static BOOL get_guid_from_language(LPCWSTR type, GUID *guid)
735 {
736     HRESULT hres;
737
738     hres = CLSIDFromProgID(type, guid);
739     if(FAILED(hres))
740         return FALSE;
741
742     /* FIXME: Check CATID_ActiveScriptParse */
743
744     return TRUE;
745 }
746
747 static BOOL get_script_guid(nsIDOMHTMLScriptElement *nsscript, GUID *guid)
748 {
749     nsAString attr_str, val_str;
750     BOOL ret = FALSE;
751     nsresult nsres;
752
753     static const PRUnichar languageW[] = {'l','a','n','g','u','a','g','e',0};
754
755     nsAString_Init(&val_str, NULL);
756
757     nsres = nsIDOMHTMLScriptElement_GetType(nsscript, &val_str);
758     if(NS_SUCCEEDED(nsres)) {
759         const PRUnichar *type;
760
761         nsAString_GetData(&val_str, &type);
762         if(*type) {
763             ret = get_guid_from_type(type, guid);
764             nsAString_Finish(&val_str);
765             return ret;
766         }
767     }else {
768         ERR("GetType failed: %08x\n", nsres);
769     }
770
771     nsAString_InitDepend(&attr_str, languageW);
772     nsres = nsIDOMHTMLScriptElement_GetAttribute(nsscript, &attr_str, &val_str);
773     nsAString_Finish(&attr_str);
774     if(NS_SUCCEEDED(nsres)) {
775         const PRUnichar *language;
776
777         nsAString_GetData(&val_str, &language);
778
779         if(*language) {
780             ret = get_guid_from_language(language, guid);
781         }else {
782             *guid = CLSID_JScript;
783             ret = TRUE;
784         }
785     }else {
786         ERR("GetAttribute(language) failed: %08x\n", nsres);
787     }
788
789     nsAString_Finish(&val_str);
790
791     return ret;
792 }
793
794 static ScriptHost *get_script_host(HTMLWindow *window, const GUID *guid)
795 {
796     ScriptHost *iter;
797
798     if(IsEqualGUID(&CLSID_JScript, guid) && window->scriptmode != SCRIPTMODE_ACTIVESCRIPT) {
799         TRACE("Ignoring JScript\n");
800         return NULL;
801     }
802
803     LIST_FOR_EACH_ENTRY(iter, &window->script_hosts, ScriptHost, entry) {
804         if(IsEqualGUID(guid, &iter->guid))
805             return iter;
806     }
807
808     return create_script_host(window, guid);
809 }
810
811 void doc_insert_script(HTMLWindow *window, nsIDOMHTMLScriptElement *nsscript)
812 {
813     ScriptHost *script_host;
814     GUID guid;
815
816     if(!get_script_guid(nsscript, &guid)) {
817         WARN("Could not find script GUID\n");
818         return;
819     }
820
821     script_host = get_script_host(window, &guid);
822     if(!script_host)
823         return;
824
825     if(script_host->parse)
826         parse_script_elem(script_host, nsscript);
827 }
828
829 IDispatch *script_parse_event(HTMLWindow *window, LPCWSTR text)
830 {
831     ScriptHost *script_host;
832     GUID guid = CLSID_JScript;
833     const WCHAR *ptr;
834     IDispatch *disp;
835     HRESULT hres;
836
837     static const WCHAR delimiterW[] = {'\"',0};
838
839     for(ptr = text; isalnumW(*ptr); ptr++);
840     if(*ptr == ':') {
841         LPWSTR language;
842         BOOL b;
843
844         language = heap_alloc((ptr-text+1)*sizeof(WCHAR));
845         memcpy(language, text, (ptr-text)*sizeof(WCHAR));
846         language[ptr-text] = 0;
847
848         b = get_guid_from_language(language, &guid);
849
850         heap_free(language);
851
852         if(!b) {
853             WARN("Could not find language\n");
854             return NULL;
855         }
856
857         ptr++;
858     }else {
859         ptr = text;
860     }
861
862     script_host = get_script_host(window, &guid);
863     if(!script_host || !script_host->parse_proc)
864         return NULL;
865
866     hres = IActiveScriptParseProcedure64_ParseProcedureText(script_host->parse_proc, ptr, NULL, emptyW,
867             NULL, NULL, delimiterW, 0 /* FIXME */, 0,
868             SCRIPTPROC_HOSTMANAGESSOURCE|SCRIPTPROC_IMPLICIT_THIS|SCRIPTPROC_IMPLICIT_PARENTS, &disp);
869     if(FAILED(hres)) {
870         WARN("ParseProcedureText failed: %08x\n", hres);
871         return NULL;
872     }
873
874     TRACE("ret %p\n", disp);
875     return disp;
876 }
877
878 HRESULT exec_script(HTMLWindow *window, const WCHAR *code, const WCHAR *lang, VARIANT *ret)
879 {
880     ScriptHost *script_host;
881     EXCEPINFO ei;
882     GUID guid;
883     HRESULT hres;
884
885     static const WCHAR delimW[] = {'"',0};
886
887     if(!get_guid_from_language(lang, &guid)) {
888         WARN("Could not find script GUID\n");
889         return CO_E_CLASSSTRING;
890     }
891
892     script_host = get_script_host(window, &guid);
893     if(!script_host) {
894         FIXME("No script host\n");
895         return E_FAIL;
896     }
897
898     if(!script_host->parse) {
899         FIXME("script_host->parse == NULL\n");
900         return E_FAIL;
901     }
902
903     memset(&ei, 0, sizeof(ei));
904     TRACE(">>>\n");
905     hres = IActiveScriptParse64_ParseScriptText(script_host->parse, code, NULL, NULL, delimW, 0, 0, SCRIPTTEXT_ISVISIBLE, ret, &ei);
906     if(SUCCEEDED(hres))
907         TRACE("<<<\n");
908     else
909         WARN("<<< %08x\n", hres);
910
911     return hres;
912 }
913
914 IDispatch *get_script_disp(ScriptHost *script_host)
915 {
916     IDispatch *disp;
917     HRESULT hres;
918
919     if(!script_host->script)
920         return NULL;
921
922     hres = IActiveScript_GetScriptDispatch(script_host->script, windowW, &disp);
923     if(FAILED(hres))
924         return NULL;
925
926     return disp;
927 }
928
929 BOOL find_global_prop(HTMLWindow *window, BSTR name, DWORD flags, ScriptHost **ret_host, DISPID *ret_id)
930 {
931     IDispatchEx *dispex;
932     IDispatch *disp;
933     ScriptHost *iter;
934     HRESULT hres;
935
936     LIST_FOR_EACH_ENTRY(iter, &window->script_hosts, ScriptHost, entry) {
937         disp = get_script_disp(iter);
938         if(!disp)
939             continue;
940
941         hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
942         if(SUCCEEDED(hres)) {
943             hres = IDispatchEx_GetDispID(dispex, name, flags & (~fdexNameEnsure), ret_id);
944             IDispatchEx_Release(dispex);
945         }else {
946             FIXME("No IDispatchEx\n");
947             hres = E_NOTIMPL;
948         }
949
950         IDispatch_Release(disp);
951         if(SUCCEEDED(hres)) {
952             *ret_host = iter;
953             return TRUE;
954         }
955     }
956
957     return FALSE;
958 }
959
960 static BOOL is_jscript_available(void)
961 {
962     static BOOL available, checked;
963
964     if(!checked) {
965         IUnknown *unk;
966         HRESULT hres = CoGetClassObject(&CLSID_JScript, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void**)&unk);
967
968         if(SUCCEEDED(hres)) {
969             available = TRUE;
970             IUnknown_Release(unk);
971         }else {
972             available = FALSE;
973         }
974         checked = TRUE;
975     }
976
977     return available;
978 }
979
980 void set_script_mode(HTMLWindow *window, SCRIPTMODE mode)
981 {
982     nsIWebBrowserSetup *setup;
983     nsresult nsres;
984
985     if(mode == SCRIPTMODE_ACTIVESCRIPT && !is_jscript_available()) {
986         TRACE("jscript.dll not available\n");
987         window->scriptmode = SCRIPTMODE_GECKO;
988         return;
989     }
990
991     window->scriptmode = mode;
992
993     if(!window->doc_obj->nscontainer || !window->doc_obj->nscontainer->webbrowser)
994         return;
995
996     nsres = nsIWebBrowser_QueryInterface(window->doc_obj->nscontainer->webbrowser,
997             &IID_nsIWebBrowserSetup, (void**)&setup);
998     if(NS_SUCCEEDED(nsres)) {
999         nsres = nsIWebBrowserSetup_SetProperty(setup, SETUP_ALLOW_JAVASCRIPT,
1000                 window->scriptmode == SCRIPTMODE_GECKO);
1001         nsIWebBrowserSetup_Release(setup);
1002     }
1003
1004     if(NS_FAILED(nsres))
1005         ERR("JavaScript setup failed: %08x\n", nsres);
1006 }
1007
1008 void release_script_hosts(HTMLWindow *window)
1009 {
1010     ScriptHost *iter;
1011
1012     while(!list_empty(&window->script_hosts)) {
1013         iter = LIST_ENTRY(list_head(&window->script_hosts), ScriptHost, entry);
1014
1015         release_script_engine(iter);
1016         list_remove(&iter->entry);
1017         iter->window = NULL;
1018         IActiveScript_Release(ACTSCPSITE(iter));
1019     }
1020 }