1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Pierre Phaneuf <pp@ludusdesign.com>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "nsPluginArray.h"
40 : #include "nsMimeTypeArray.h"
41 : #include "Navigator.h"
42 : #include "nsIScriptGlobalObject.h"
43 : #include "nsIDOMNavigator.h"
44 : #include "nsIDOMMimeType.h"
45 : #include "nsIPluginHost.h"
46 : #include "nsIDocShell.h"
47 : #include "nsIWebNavigation.h"
48 : #include "nsDOMClassInfoID.h"
49 : #include "nsPluginError.h"
50 : #include "nsContentUtils.h"
51 : #include "nsPluginHost.h"
52 :
53 : using namespace mozilla;
54 : using namespace mozilla::dom;
55 :
56 0 : nsPluginArray::nsPluginArray(Navigator* navigator,
57 : nsIDocShell *aDocShell)
58 : : mNavigator(navigator),
59 : mPluginHost(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID)),
60 : mPluginCount(0),
61 : mPluginArray(nsnull),
62 0 : mDocShell(do_GetWeakReference(aDocShell))
63 : {
64 0 : }
65 :
66 0 : nsPluginArray::~nsPluginArray()
67 : {
68 0 : if (mPluginArray != nsnull) {
69 0 : for (PRUint32 i = 0; i < mPluginCount; i++) {
70 0 : NS_IF_RELEASE(mPluginArray[i]);
71 : }
72 0 : delete[] mPluginArray;
73 : }
74 0 : }
75 :
76 : DOMCI_DATA(PluginArray, nsPluginArray)
77 :
78 : // QueryInterface implementation for nsPluginArray
79 0 : NS_INTERFACE_MAP_BEGIN(nsPluginArray)
80 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMPluginArray)
81 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMPluginArray)
82 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(PluginArray)
83 0 : NS_INTERFACE_MAP_END
84 :
85 0 : NS_IMPL_ADDREF(nsPluginArray)
86 0 : NS_IMPL_RELEASE(nsPluginArray)
87 :
88 : NS_IMETHODIMP
89 0 : nsPluginArray::GetLength(PRUint32* aLength)
90 : {
91 0 : nsPluginHost *pluginHost = static_cast<nsPluginHost*>(mPluginHost.get());
92 0 : if (AllowPlugins() && pluginHost)
93 0 : return pluginHost->GetPluginCount(aLength);
94 :
95 0 : *aLength = 0;
96 0 : return NS_OK;
97 : }
98 :
99 : bool
100 0 : nsPluginArray::AllowPlugins()
101 : {
102 0 : bool allowPlugins = false;
103 0 : nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocShell);
104 :
105 0 : if (docShell)
106 0 : if (NS_FAILED(docShell->GetAllowPlugins(&allowPlugins)))
107 0 : allowPlugins = false;
108 :
109 0 : return allowPlugins;
110 : }
111 :
112 : nsIDOMPlugin*
113 0 : nsPluginArray::GetItemAt(PRUint32 aIndex, nsresult* aResult)
114 : {
115 0 : *aResult = NS_OK;
116 :
117 0 : if (!AllowPlugins())
118 0 : return nsnull;
119 :
120 0 : if (mPluginArray == nsnull) {
121 0 : *aResult = GetPlugins();
122 0 : if (*aResult != NS_OK)
123 0 : return nsnull;
124 : }
125 :
126 0 : return aIndex < mPluginCount ? mPluginArray[aIndex] : nsnull;
127 : }
128 :
129 : NS_IMETHODIMP
130 0 : nsPluginArray::Item(PRUint32 aIndex, nsIDOMPlugin** aReturn)
131 : {
132 : nsresult rv;
133 :
134 0 : NS_IF_ADDREF(*aReturn = GetItemAt(aIndex, &rv));
135 :
136 0 : return rv;
137 : }
138 :
139 : nsIDOMPlugin*
140 0 : nsPluginArray::GetNamedItem(const nsAString& aName, nsresult* aResult)
141 : {
142 0 : *aResult = NS_OK;
143 :
144 0 : if (!AllowPlugins())
145 0 : return nsnull;
146 :
147 0 : if (mPluginArray == nsnull) {
148 0 : *aResult = GetPlugins();
149 0 : if (*aResult != NS_OK)
150 0 : return nsnull;
151 : }
152 :
153 0 : for (PRUint32 i = 0; i < mPluginCount; i++) {
154 0 : nsAutoString pluginName;
155 0 : nsIDOMPlugin* plugin = mPluginArray[i];
156 0 : if (plugin->GetName(pluginName) == NS_OK && pluginName.Equals(aName)) {
157 0 : return plugin;
158 : }
159 : }
160 :
161 0 : return nsnull;
162 : }
163 :
164 : NS_IMETHODIMP
165 0 : nsPluginArray::NamedItem(const nsAString& aName, nsIDOMPlugin** aReturn)
166 : {
167 0 : NS_PRECONDITION(nsnull != aReturn, "null arg");
168 :
169 : nsresult rv;
170 :
171 0 : NS_IF_ADDREF(*aReturn = GetNamedItem(aName, &rv));
172 :
173 0 : return rv;
174 : }
175 :
176 : nsresult
177 0 : nsPluginArray::GetPluginHost(nsIPluginHost** aPluginHost)
178 : {
179 0 : NS_ENSURE_ARG_POINTER(aPluginHost);
180 :
181 0 : nsresult rv = NS_OK;
182 :
183 0 : if (!mPluginHost) {
184 0 : mPluginHost = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID, &rv);
185 :
186 0 : if (NS_FAILED(rv)) {
187 0 : return rv;
188 : }
189 : }
190 :
191 0 : *aPluginHost = mPluginHost;
192 0 : NS_IF_ADDREF(*aPluginHost);
193 :
194 0 : return rv;
195 : }
196 :
197 : void
198 0 : nsPluginArray::Invalidate()
199 : {
200 0 : mDocShell = nsnull;
201 0 : mNavigator = nsnull;
202 0 : }
203 :
204 : NS_IMETHODIMP
205 0 : nsPluginArray::Refresh(bool aReloadDocuments)
206 : {
207 0 : nsresult res = NS_OK;
208 0 : if (!AllowPlugins())
209 0 : return NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA;
210 :
211 0 : if (!mPluginHost) {
212 0 : mPluginHost = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID, &res);
213 : }
214 :
215 0 : if(NS_FAILED(res)) {
216 0 : return res;
217 : }
218 :
219 : // NS_ERROR_PLUGINS_PLUGINSNOTCHANGED on reloading plugins indicates
220 : // that plugins did not change and was not reloaded
221 0 : bool pluginsNotChanged = false;
222 0 : if(mPluginHost)
223 0 : pluginsNotChanged = (NS_ERROR_PLUGINS_PLUGINSNOTCHANGED == mPluginHost->ReloadPlugins(aReloadDocuments));
224 :
225 : // no need to reload the page if plugins have not been changed
226 : // in fact, if we do reload we can hit recursive load problem, see bug 93351
227 0 : if(pluginsNotChanged)
228 0 : return res;
229 :
230 0 : nsCOMPtr<nsIWebNavigation> webNav = do_QueryReferent(mDocShell);
231 :
232 0 : if (mPluginArray != nsnull) {
233 0 : for (PRUint32 i = 0; i < mPluginCount; i++)
234 0 : NS_IF_RELEASE(mPluginArray[i]);
235 :
236 0 : delete[] mPluginArray;
237 : }
238 :
239 0 : mPluginCount = 0;
240 0 : mPluginArray = nsnull;
241 :
242 0 : if (mNavigator)
243 0 : mNavigator->RefreshMIMEArray();
244 :
245 0 : if (aReloadDocuments && webNav)
246 0 : webNav->Reload(nsIWebNavigation::LOAD_FLAGS_NONE);
247 :
248 0 : return res;
249 : }
250 :
251 : nsresult
252 0 : nsPluginArray::GetPlugins()
253 : {
254 0 : nsresult rv = GetLength(&mPluginCount);
255 0 : if (NS_SUCCEEDED(rv)) {
256 0 : mPluginArray = new nsIDOMPlugin*[mPluginCount];
257 0 : if (!mPluginArray)
258 0 : return NS_ERROR_OUT_OF_MEMORY;
259 :
260 0 : if (!mPluginCount)
261 0 : return NS_OK;
262 :
263 0 : nsPluginHost *pluginHost = static_cast<nsPluginHost*>(mPluginHost.get());
264 0 : rv = pluginHost->GetPlugins(mPluginCount, mPluginArray);
265 0 : if (NS_SUCCEEDED(rv)) {
266 : // need to wrap each of these with a nsPluginElement, which
267 : // is scriptable.
268 0 : for (PRUint32 i = 0; i < mPluginCount; i++) {
269 0 : nsIDOMPlugin* wrapper = new nsPluginElement(mPluginArray[i]);
270 0 : NS_IF_ADDREF(wrapper);
271 0 : mPluginArray[i] = wrapper;
272 : }
273 : } else {
274 : /* XXX this code is all broken. If GetPlugins fails, there's no contract
275 : * explaining what should happen. Instead of deleting elements in an
276 : * array of random pointers, we mark the array as 0 length.
277 : */
278 0 : mPluginCount = 0;
279 : }
280 : }
281 0 : return rv;
282 : }
283 :
284 : //
285 :
286 0 : nsPluginElement::nsPluginElement(nsIDOMPlugin* plugin)
287 : {
288 0 : mPlugin = plugin; // don't AddRef, see nsPluginArray::Item.
289 0 : mMimeTypeCount = 0;
290 0 : mMimeTypeArray = nsnull;
291 0 : }
292 :
293 0 : nsPluginElement::~nsPluginElement()
294 : {
295 0 : NS_IF_RELEASE(mPlugin);
296 :
297 0 : if (mMimeTypeArray != nsnull) {
298 0 : for (PRUint32 i = 0; i < mMimeTypeCount; i++) {
299 0 : nsMimeType* mt = static_cast<nsMimeType*>(mMimeTypeArray[i]);
300 0 : if (mt) {
301 0 : mt->DetachPlugin();
302 0 : NS_RELEASE(mt);
303 : }
304 : }
305 0 : delete[] mMimeTypeArray;
306 : }
307 0 : }
308 :
309 :
310 : DOMCI_DATA(Plugin, nsPluginElement)
311 :
312 : // QueryInterface implementation for nsPluginElement
313 0 : NS_INTERFACE_MAP_BEGIN(nsPluginElement)
314 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
315 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMPlugin)
316 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Plugin)
317 0 : NS_INTERFACE_MAP_END
318 :
319 :
320 0 : NS_IMPL_ADDREF(nsPluginElement)
321 0 : NS_IMPL_RELEASE(nsPluginElement)
322 :
323 :
324 : NS_IMETHODIMP
325 0 : nsPluginElement::GetDescription(nsAString& aDescription)
326 : {
327 0 : return mPlugin->GetDescription(aDescription);
328 : }
329 :
330 : NS_IMETHODIMP
331 0 : nsPluginElement::GetFilename(nsAString& aFilename)
332 : {
333 0 : return mPlugin->GetFilename(aFilename);
334 : }
335 :
336 : NS_IMETHODIMP
337 0 : nsPluginElement::GetVersion(nsAString& aVersion)
338 : {
339 0 : return mPlugin->GetVersion(aVersion);
340 : }
341 :
342 : NS_IMETHODIMP
343 0 : nsPluginElement::GetName(nsAString& aName)
344 : {
345 0 : return mPlugin->GetName(aName);
346 : }
347 :
348 : NS_IMETHODIMP
349 0 : nsPluginElement::GetLength(PRUint32* aLength)
350 : {
351 0 : return mPlugin->GetLength(aLength);
352 : }
353 :
354 : nsIDOMMimeType*
355 0 : nsPluginElement::GetItemAt(PRUint32 aIndex, nsresult *aResult)
356 : {
357 0 : if (mMimeTypeArray == nsnull) {
358 0 : *aResult = GetMimeTypes();
359 0 : if (*aResult != NS_OK)
360 0 : return nsnull;
361 : }
362 :
363 0 : if (aIndex >= mMimeTypeCount) {
364 0 : *aResult = NS_ERROR_FAILURE;
365 :
366 0 : return nsnull;
367 : }
368 :
369 0 : *aResult = NS_OK;
370 :
371 0 : return mMimeTypeArray[aIndex];
372 : }
373 :
374 : NS_IMETHODIMP
375 0 : nsPluginElement::Item(PRUint32 aIndex, nsIDOMMimeType** aReturn)
376 : {
377 : nsresult rv;
378 :
379 0 : NS_IF_ADDREF(*aReturn = GetItemAt(aIndex, &rv));
380 :
381 0 : return rv;
382 : }
383 :
384 : nsIDOMMimeType*
385 0 : nsPluginElement::GetNamedItem(const nsAString& aName, nsresult *aResult)
386 : {
387 0 : if (mMimeTypeArray == nsnull) {
388 0 : *aResult = GetMimeTypes();
389 0 : if (*aResult != NS_OK)
390 0 : return nsnull;
391 : }
392 :
393 0 : *aResult = NS_OK;
394 0 : for (PRUint32 i = 0; i < mMimeTypeCount; i++) {
395 0 : nsAutoString type;
396 0 : nsIDOMMimeType* mimeType = mMimeTypeArray[i];
397 0 : if (mimeType->GetType(type) == NS_OK && type.Equals(aName)) {
398 0 : return mimeType;
399 : }
400 : }
401 :
402 0 : return nsnull;
403 : }
404 :
405 : NS_IMETHODIMP
406 0 : nsPluginElement::NamedItem(const nsAString& aName, nsIDOMMimeType** aReturn)
407 : {
408 : nsresult rv;
409 :
410 0 : NS_IF_ADDREF(*aReturn = GetNamedItem(aName, &rv));
411 :
412 0 : return rv;
413 : }
414 :
415 : nsresult
416 0 : nsPluginElement::GetMimeTypes()
417 : {
418 0 : nsresult rv = mPlugin->GetLength(&mMimeTypeCount);
419 0 : if (rv == NS_OK) {
420 0 : mMimeTypeArray = new nsIDOMMimeType*[mMimeTypeCount];
421 0 : if (mMimeTypeArray == nsnull)
422 0 : return NS_ERROR_OUT_OF_MEMORY;
423 0 : for (PRUint32 i = 0; i < mMimeTypeCount; i++) {
424 0 : nsCOMPtr<nsIDOMMimeType> mimeType;
425 0 : rv = mPlugin->Item(i, getter_AddRefs(mimeType));
426 0 : if (rv != NS_OK)
427 : break;
428 0 : mimeType = new nsMimeType(this, mimeType);
429 0 : NS_IF_ADDREF(mMimeTypeArray[i] = mimeType);
430 : }
431 : }
432 0 : return rv;
433 : }
|