mshtml: Wine Gecko 1.3 release.
[wine] / dlls / mshtml / npplugin.c
1 /*
2  * Copyright 2010 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 "shlobj.h"
30
31 #include "mshtml_private.h"
32 #include "pluginhost.h"
33
34 #include "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
37
38 /* Parts of npapi.h */
39
40 #define NPERR_BASE                         0
41 #define NPERR_NO_ERROR                    (NPERR_BASE + 0)
42 #define NPERR_GENERIC_ERROR               (NPERR_BASE + 1)
43 #define NPERR_INVALID_INSTANCE_ERROR      (NPERR_BASE + 2)
44 #define NPERR_INVALID_FUNCTABLE_ERROR     (NPERR_BASE + 3)
45 #define NPERR_MODULE_LOAD_FAILED_ERROR    (NPERR_BASE + 4)
46 #define NPERR_OUT_OF_MEMORY_ERROR         (NPERR_BASE + 5)
47 #define NPERR_INVALID_PLUGIN_ERROR        (NPERR_BASE + 6)
48 #define NPERR_INVALID_PLUGIN_DIR_ERROR    (NPERR_BASE + 7)
49 #define NPERR_INCOMPATIBLE_VERSION_ERROR  (NPERR_BASE + 8)
50 #define NPERR_INVALID_PARAM               (NPERR_BASE + 9)
51 #define NPERR_INVALID_URL                 (NPERR_BASE + 10)
52 #define NPERR_FILE_NOT_FOUND              (NPERR_BASE + 11)
53 #define NPERR_NO_DATA                     (NPERR_BASE + 12)
54 #define NPERR_STREAM_NOT_SEEKABLE         (NPERR_BASE + 13)
55
56 /* Parts of npfunctions.h */
57
58 typedef NPError (CDECL *NPP_NewProcPtr)(NPMIMEType,NPP,UINT16,INT16,char**,char**,NPSavedData*);
59 typedef NPError (CDECL *NPP_DestroyProcPtr)(NPP,NPSavedData**);
60 typedef NPError (CDECL *NPP_SetWindowProcPtr)(NPP,NPWindow*);
61 typedef NPError (CDECL *NPP_NewStreamProcPtr)(NPP,NPMIMEType,NPStream*,NPBool,UINT16*);
62 typedef NPError (CDECL *NPP_DestroyStreamProcPtr)(NPP,NPStream*,NPReason);
63 typedef INT32 (CDECL *NPP_WriteReadyProcPtr)(NPP,NPStream*);
64 typedef INT32 (CDECL *NPP_WriteProcPtr)(NPP,NPStream*,INT32,INT32,void*);
65 typedef void (CDECL *NPP_StreamAsFileProcPtr)(NPP,NPStream*,const char*);
66 typedef void (CDECL *NPP_PrintProcPtr)(NPP,NPPrint*);
67 typedef INT16 (CDECL *NPP_HandleEventProcPtr)(NPP,void*);
68 typedef void (CDECL *NPP_URLNotifyProcPtr)(NPP,const char*,NPReason,void*);
69 typedef NPError (CDECL *NPP_GetValueProcPtr)(NPP,NPPVariable,void*);
70 typedef NPError (CDECL *NPP_SetValueProcPtr)(NPP,NPNVariable,void*);
71 typedef NPBool (CDECL *NPP_GotFocusPtr)(NPP,NPFocusDirection);
72 typedef void (CDECL *NPP_LostFocusPtr)(NPP);
73
74 typedef struct _NPPluginFuncs {
75     UINT16 size;
76     UINT16 version;
77     NPP_NewProcPtr newp;
78     NPP_DestroyProcPtr destroy;
79     NPP_SetWindowProcPtr setwindow;
80     NPP_NewStreamProcPtr newstream;
81     NPP_DestroyStreamProcPtr destroystream;
82     NPP_StreamAsFileProcPtr asfile;
83     NPP_WriteReadyProcPtr writeready;
84     NPP_WriteProcPtr write;
85     NPP_PrintProcPtr print;
86     NPP_HandleEventProcPtr event;
87     NPP_URLNotifyProcPtr urlnotify;
88     void *javaClass;
89     NPP_GetValueProcPtr getvalue;
90     NPP_SetValueProcPtr setvalue;
91     NPP_GotFocusPtr gotfocus;
92     NPP_LostFocusPtr lostfocus;
93 } NPPluginFuncs;
94
95 static nsIDOMElement *get_dom_element(NPP instance)
96 {
97     nsISupports *instance_unk = (nsISupports*)instance->ndata;
98     nsIPluginInstance *plugin_instance;
99     nsIDOMElement *elem;
100     nsresult nsres;
101
102     nsres = nsISupports_QueryInterface(instance_unk, &IID_nsIPluginInstance, (void**)&plugin_instance);
103     if(NS_FAILED(nsres)) {
104         ERR("Could not get nsIPluginInstance interface: %08x\n", nsres);
105         return NULL;
106     }
107
108     nsres = nsIPluginInstance_GetDOMElement(plugin_instance, &elem);
109     nsIPluginInstance_Release(plugin_instance);
110     if(NS_FAILED(nsres)) {
111         ERR("GetDOMElement failed: %08x\n", nsres);
112         return NULL;
113     }
114
115     return elem;
116 }
117
118 static HTMLWindow *get_elem_window(nsIDOMElement *elem)
119 {
120     nsIDOMWindow *nswindow;
121     nsIDOMDocument *nsdoc;
122     HTMLWindow *window;
123     nsresult nsres;
124
125     nsres = nsIDOMElement_GetOwnerDocument(elem, &nsdoc);
126     if(NS_FAILED(nsres))
127         return NULL;
128
129     nswindow = get_nsdoc_window(nsdoc);
130     nsIDOMDocument_Release(nsdoc);
131     if(!nswindow)
132         return NULL;
133
134     window = nswindow_to_window(nswindow);
135     nsIDOMWindow_Release(nswindow);
136
137     return window;
138 }
139
140 static BOOL parse_classid(const PRUnichar *classid, CLSID *clsid)
141 {
142     const WCHAR *ptr;
143     unsigned len;
144     HRESULT hres;
145
146     static const PRUnichar clsidW[] = {'c','l','s','i','d',':'};
147
148     if(strncmpiW(classid, clsidW, sizeof(clsidW)/sizeof(WCHAR)))
149         return FALSE;
150
151     ptr = classid + sizeof(clsidW)/sizeof(WCHAR);
152     len = strlenW(ptr);
153
154     if(len == 38) {
155         hres = CLSIDFromString(ptr, clsid);
156     }else if(len == 36) {
157         WCHAR buf[39];
158
159         buf[0] = '{';
160         memcpy(buf+1, ptr, len*sizeof(WCHAR));
161         buf[37] = '}';
162         buf[38] = 0;
163         hres = CLSIDFromString(buf, clsid);
164     }else {
165         return FALSE;
166     }
167
168     return SUCCEEDED(hres);
169 }
170
171 static BOOL get_elem_clsid(nsIDOMElement *elem, CLSID *clsid)
172 {
173     nsAString attr_str, val_str;
174     nsresult nsres;
175     BOOL ret = FALSE;
176
177     static const PRUnichar classidW[] = {'c','l','a','s','s','i','d',0};
178
179     nsAString_InitDepend(&attr_str, classidW);
180     nsAString_Init(&val_str, NULL);
181     nsres = nsIDOMElement_GetAttribute(elem, &attr_str, &val_str);
182     nsAString_Finish(&attr_str);
183     if(NS_SUCCEEDED(nsres)) {
184         const PRUnichar *val;
185
186         nsAString_GetData(&val_str, &val);
187         if(*val)
188             ret = parse_classid(val, clsid);
189     }else {
190         ERR("GetAttribute failed: %08x\n", nsres);
191     }
192
193     nsAString_Finish(&attr_str);
194     return ret;
195 }
196
197 static IUnknown *create_activex_object(HTMLWindow *window, nsIDOMElement *nselem, CLSID *clsid)
198 {
199     IClassFactoryEx *cfex;
200     IClassFactory *cf;
201     IUnknown *obj;
202     DWORD policy;
203     HRESULT hres;
204
205     if(!get_elem_clsid(nselem, clsid)) {
206         WARN("Could not determine element CLSID\n");
207         return NULL;
208     }
209
210     TRACE("clsid %s\n", debugstr_guid(clsid));
211
212     policy = 0;
213     hres = IInternetHostSecurityManager_ProcessUrlAction(&window->doc->IInternetHostSecurityManager_iface,
214             URLACTION_ACTIVEX_RUN, (BYTE*)&policy, sizeof(policy), (BYTE*)clsid, sizeof(GUID), 0, 0);
215     if(FAILED(hres) || policy != URLPOLICY_ALLOW) {
216         WARN("ProcessUrlAction returned %08x %x\n", hres, policy);
217         return NULL;
218     }
219
220     hres = CoGetClassObject(clsid, CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER, NULL, &IID_IClassFactory, (void**)&cf);
221     if(FAILED(hres))
222         return NULL;
223
224     hres = IClassFactory_QueryInterface(cf, &IID_IClassFactoryEx, (void**)&cfex);
225     if(SUCCEEDED(hres)) {
226         FIXME("Use IClassFactoryEx\n");
227         IClassFactoryEx_Release(cfex);
228     }
229
230     hres = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void**)&obj);
231     if(FAILED(hres))
232         return NULL;
233
234     return obj;
235 }
236
237 static NPError CDECL NPP_New(NPMIMEType pluginType, NPP instance, UINT16 mode, INT16 argc, char **argn,
238         char **argv, NPSavedData *saved)
239 {
240     nsIDOMElement *nselem;
241     HTMLWindow *window;
242     IUnknown *obj;
243     CLSID clsid;
244     NPError err = NPERR_NO_ERROR;
245
246     TRACE("(%s %p %x %d %p %p %p)\n", debugstr_a(pluginType), instance, mode, argc, argn, argv, saved);
247
248     nselem = get_dom_element(instance);
249     if(!nselem) {
250         ERR("Could not get DOM element\n");
251         return NPERR_GENERIC_ERROR;
252     }
253
254     window = get_elem_window(nselem);
255     if(!window) {
256         ERR("Could not get element's window object\n");
257         nsIDOMElement_Release(nselem);
258         return NPERR_GENERIC_ERROR;
259     }
260
261     obj = create_activex_object(window, nselem, &clsid);
262     if(obj) {
263         PluginHost *host;
264         HRESULT hres;
265
266         hres = create_plugin_host(window->doc, nselem, obj, &clsid, &host);
267         nsIDOMElement_Release(nselem);
268         IUnknown_Release(obj);
269         if(SUCCEEDED(hres))
270             instance->pdata = host;
271         else
272             err = NPERR_GENERIC_ERROR;
273     }else {
274         err = NPERR_GENERIC_ERROR;
275     }
276
277     nsIDOMElement_Release(nselem);
278     return err;
279 }
280
281 static NPError CDECL NPP_Destroy(NPP instance, NPSavedData **save)
282 {
283     PluginHost *host = instance->pdata;
284
285     TRACE("(%p %p)\n", instance, save);
286
287     if(!host)
288         return NPERR_GENERIC_ERROR;
289
290     detach_plugin_host(host);
291     IOleClientSite_Release(&host->IOleClientSite_iface);
292     instance->pdata = NULL;
293     return NPERR_NO_ERROR;
294 }
295
296 static NPError CDECL NPP_SetWindow(NPP instance, NPWindow *window)
297 {
298     PluginHost *host = instance->pdata;
299     RECT pos_rect = {0, 0, window->width, window->height};
300
301     TRACE("(%p %p)\n", instance, window);
302
303     if(!host)
304         return NPERR_GENERIC_ERROR;
305
306     update_plugin_window(host, window->window, &pos_rect);
307     return NPERR_NO_ERROR;
308 }
309
310 static NPError CDECL NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream, NPBool seekable, UINT16 *stype)
311 {
312     TRACE("\n");
313     return NPERR_GENERIC_ERROR;
314 }
315
316 static NPError CDECL NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason)
317 {
318     TRACE("\n");
319     return NPERR_GENERIC_ERROR;
320 }
321
322 static INT32 CDECL NPP_WriteReady(NPP instance, NPStream *stream)
323 {
324     TRACE("\n");
325     return NPERR_GENERIC_ERROR;
326 }
327
328 static INT32 CDECL NPP_Write(NPP instance, NPStream *stream, INT32 offset, INT32 len, void *buffer)
329 {
330     TRACE("\n");
331     return NPERR_GENERIC_ERROR;
332 }
333
334 static void CDECL NPP_StreamAsFile(NPP instance, NPStream *stream, const char *fname)
335 {
336     TRACE("\n");
337 }
338
339 static void CDECL NPP_Print(NPP instance, NPPrint *platformPrint)
340 {
341     FIXME("\n");
342 }
343
344 static INT16 CDECL NPP_HandleEvent(NPP instance, void *event)
345 {
346     TRACE("\n");
347     return NPERR_GENERIC_ERROR;
348 }
349
350 static void CDECL NPP_URLNotify(NPP instance, const char *url, NPReason reason, void *notifyData)
351 {
352     TRACE("\n");
353 }
354
355 static NPError CDECL NPP_GetValue(NPP instance, NPPVariable variable, void *ret_value)
356 {
357     TRACE("\n");
358     return NPERR_GENERIC_ERROR;
359 }
360
361 static NPError CDECL NPP_SetValue(NPP instance, NPNVariable variable, void *value)
362 {
363     TRACE("\n");
364     return NPERR_GENERIC_ERROR;
365 }
366
367 static NPBool CDECL NPP_GotFocus(NPP instance, NPFocusDirection direction)
368 {
369     FIXME("\n");
370     return NPERR_GENERIC_ERROR;
371 }
372
373 static void CDECL NPP_LostFocus(NPP instance)
374 {
375     FIXME("\n");
376 }
377
378 /***********************************************************************
379  *          NP_GetEntryPoints (mshtml.@)
380  */
381 NPError WINAPI NP_GetEntryPoints(NPPluginFuncs* funcs)
382 {
383     TRACE("(%p)\n", funcs);
384
385     funcs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
386     funcs->newp = NPP_New;
387     funcs->destroy = NPP_Destroy;
388     funcs->setwindow = NPP_SetWindow;
389     funcs->newstream = NPP_NewStream;
390     funcs->destroystream = NPP_DestroyStream;
391     funcs->asfile = NPP_StreamAsFile;
392     funcs->writeready = NPP_WriteReady;
393     funcs->write = NPP_Write;
394     funcs->print = NPP_Print;
395     funcs->event = NPP_HandleEvent;
396     funcs->urlnotify = NPP_URLNotify;
397     funcs->javaClass = NULL;
398     funcs->getvalue = NPP_GetValue;
399     funcs->setvalue = NPP_SetValue;
400     funcs->gotfocus = NPP_GotFocus;
401     funcs->lostfocus = NPP_LostFocus;
402
403     return NPERR_NO_ERROR;
404 }