forked from mirrors/gecko-dev
1289 lines
39 KiB
C++
1289 lines
39 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Adam Lock <adamlock@netscape.com>
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
#include "stdafx.h"
|
|
|
|
#include "npapi.h"
|
|
|
|
#include "jsapi.h"
|
|
#include "jscntxt.h"
|
|
|
|
#include "nsISupports.h"
|
|
|
|
#ifdef MOZ_ACTIVEX_PLUGIN_XPCONNECT
|
|
#include "XPConnect.h"
|
|
#endif
|
|
|
|
#include "LegacyPlugin.h"
|
|
|
|
#ifdef XPC_IDISPATCH_SUPPORT
|
|
#include "nsCOMPtr.h"
|
|
#include "nsStringAPI.h"
|
|
#include "nsIDocument.h"
|
|
#include "nsIDOMElement.h"
|
|
#include "nsIDOMDocument.h"
|
|
#include "nsIDOMWindow.h"
|
|
#include "nsIScriptGlobalObject.h"
|
|
#include "nsIScriptContext.h"
|
|
#include "nsIURI.h"
|
|
#include "nsIJSContextStack.h"
|
|
#include "nsIScriptSecurityManager.h"
|
|
#endif
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// These are constants to control certain default behaviours
|
|
|
|
#ifndef MOZ_ACTIVEX_PLUGIN_XPCONNECT
|
|
// Flag determines if controls should be created if they are not marked
|
|
// safe for scripting.
|
|
const BOOL kHostSafeControlsOnly = FALSE;
|
|
// Flag determines if controls should be downloaded and installed if there is a
|
|
// codebase specified
|
|
const BOOL kDownloadControlsIfMissing = FALSE;
|
|
#endif
|
|
|
|
// Flag determines whether the plugin will complain to the user if a page
|
|
// contains a control it cannot load
|
|
const BOOL kDisplayErrorMessages = FALSE;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// CInstallControlProgress
|
|
|
|
class CInstallControlProgress :
|
|
public CComObjectRootEx<CComSingleThreadModel>,
|
|
public IBindStatusCallback,
|
|
public IWindowForBindingUI
|
|
{
|
|
public:
|
|
CInstallControlProgress()
|
|
{
|
|
}
|
|
|
|
BOOL mBindingInProgress;
|
|
HRESULT mResult;
|
|
NPP mNPP;
|
|
|
|
protected:
|
|
virtual ~CInstallControlProgress()
|
|
{
|
|
}
|
|
public:
|
|
BEGIN_COM_MAP(CInstallControlProgress)
|
|
COM_INTERFACE_ENTRY(IBindStatusCallback)
|
|
COM_INTERFACE_ENTRY(IWindowForBindingUI)
|
|
END_COM_MAP()
|
|
|
|
// IBindStatusCallback
|
|
HRESULT STDMETHODCALLTYPE OnStartBinding(DWORD dwReserved,
|
|
IBinding __RPC_FAR *pib)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE GetPriority(LONG __RPC_FAR *pnPriority)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE OnLowResource(DWORD reserved)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE OnProgress(ULONG ulProgress,
|
|
ULONG ulProgressMax,
|
|
ULONG ulStatusCode,
|
|
LPCWSTR szStatusText)
|
|
{
|
|
switch (ulStatusCode)
|
|
{
|
|
case BINDSTATUS_BEGINDOWNLOADDATA:
|
|
case BINDSTATUS_DOWNLOADINGDATA:
|
|
case BINDSTATUS_ENDDOWNLOADDATA:
|
|
{
|
|
char szMsg[100];
|
|
_snprintf(szMsg, sizeof(szMsg) - 1, "Downloading control (%lu of %lu)", ulProgress, ulProgressMax);
|
|
szMsg[sizeof(szMsg) - 1] = '\0';
|
|
NPN_Status(mNPP, szMsg);
|
|
}
|
|
break;
|
|
case BINDSTATUS_FINDINGRESOURCE:
|
|
case BINDSTATUS_CONNECTING:
|
|
case BINDSTATUS_REDIRECTING:
|
|
case BINDSTATUS_BEGINDOWNLOADCOMPONENTS:
|
|
case BINDSTATUS_INSTALLINGCOMPONENTS:
|
|
case BINDSTATUS_ENDDOWNLOADCOMPONENTS:
|
|
case BINDSTATUS_USINGCACHEDCOPY:
|
|
case BINDSTATUS_SENDINGREQUEST:
|
|
case BINDSTATUS_CLASSIDAVAILABLE:
|
|
case BINDSTATUS_MIMETYPEAVAILABLE:
|
|
case BINDSTATUS_CACHEFILENAMEAVAILABLE:
|
|
case BINDSTATUS_BEGINSYNCOPERATION:
|
|
case BINDSTATUS_ENDSYNCOPERATION:
|
|
case BINDSTATUS_BEGINUPLOADDATA:
|
|
case BINDSTATUS_UPLOADINGDATA:
|
|
case BINDSTATUS_ENDUPLOADDATA:
|
|
case BINDSTATUS_PROTOCOLCLASSID:
|
|
case BINDSTATUS_ENCODING:
|
|
case BINDSTATUS_CLASSINSTALLLOCATION:
|
|
case BINDSTATUS_DECODING:
|
|
case BINDSTATUS_LOADINGMIMEHANDLER:
|
|
default:
|
|
/* do nothing */
|
|
break;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE OnStopBinding(HRESULT hresult, LPCWSTR szError)
|
|
{
|
|
mBindingInProgress = FALSE;
|
|
mResult = hresult;
|
|
NPN_Status(mNPP, "");
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE GetBindInfo(DWORD __RPC_FAR *pgrfBINDF,
|
|
BINDINFO __RPC_FAR *pbindInfo)
|
|
{
|
|
*pgrfBINDF = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE |
|
|
BINDF_GETNEWESTVERSION | BINDF_NOWRITECACHE;
|
|
pbindInfo->cbSize = sizeof(BINDINFO);
|
|
pbindInfo->szExtraInfo = NULL;
|
|
memset(&pbindInfo->stgmedData, 0, sizeof(STGMEDIUM));
|
|
pbindInfo->grfBindInfoF = 0;
|
|
pbindInfo->dwBindVerb = 0;
|
|
pbindInfo->szCustomVerb = NULL;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE OnDataAvailable(DWORD grfBSCF,
|
|
DWORD dwSize,
|
|
FORMATETC __RPC_FAR *pformatetc,
|
|
STGMEDIUM __RPC_FAR *pstgmed)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE OnObjectAvailable(REFIID riid,
|
|
IUnknown __RPC_FAR *punk)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
// IWindowForBindingUI
|
|
virtual HRESULT STDMETHODCALLTYPE GetWindow(
|
|
/* [in] */ REFGUID rguidReason,
|
|
/* [out] */ HWND *phwnd)
|
|
{
|
|
HWND hwnd = NULL;
|
|
NPN_GetValue(mNPP, NPNVnetscapeWindow, &hwnd);
|
|
*phwnd = hwnd;
|
|
return S_OK;
|
|
}
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
// NPP_Initialize
|
|
//
|
|
// Initialize the plugin library. Your DLL global initialization
|
|
// should be here
|
|
//
|
|
NPError NPP_Initialize(void)
|
|
{
|
|
ATLTRACE(_T("NPP_Initialize()\n"));
|
|
_Module.Lock();
|
|
return NPERR_NO_ERROR;
|
|
}
|
|
|
|
|
|
// NPP_Shutdown
|
|
//
|
|
// shutdown the plugin library. Revert initializition
|
|
//
|
|
void NPP_Shutdown(void)
|
|
{
|
|
ATLTRACE(_T("NPP_Shutdown()\n"));
|
|
_Module.Unlock();
|
|
}
|
|
|
|
|
|
#define MIME_OLEOBJECT1 "application/x-oleobject"
|
|
#define MIME_OLEOBJECT2 "application/oleobject"
|
|
|
|
enum MozAxPluginErrors
|
|
{
|
|
MozAxErrorControlIsNotSafeForScripting,
|
|
MozAxErrorCouldNotCreateControl,
|
|
};
|
|
|
|
static void
|
|
ShowError(MozAxPluginErrors errorCode, const CLSID &clsid)
|
|
{
|
|
if (!kDisplayErrorMessages)
|
|
return;
|
|
|
|
const TCHAR *szMsg = NULL;
|
|
const unsigned long kBufSize = 256;
|
|
TCHAR szBuffer[kBufSize];
|
|
|
|
// TODO errors are hardcoded for now
|
|
switch (errorCode)
|
|
{
|
|
case MozAxErrorControlIsNotSafeForScripting:
|
|
{
|
|
USES_CONVERSION;
|
|
LPOLESTR szClsid;
|
|
StringFromCLSID(clsid, &szClsid);
|
|
_sntprintf(szBuffer, kBufSize - 1,
|
|
_T("Could not create the control %s because it is not marked safe for scripting."), OLE2T(szClsid));
|
|
CoTaskMemFree(szClsid);
|
|
szMsg = szBuffer;
|
|
}
|
|
break;
|
|
case MozAxErrorCouldNotCreateControl:
|
|
{
|
|
USES_CONVERSION;
|
|
LPOLESTR szClsid;
|
|
StringFromCLSID(clsid, &szClsid);
|
|
_sntprintf(szBuffer, kBufSize - 1,
|
|
_T("Could not create the control %s. Check that it has been installed on your computer and that this page correctly references it."), OLE2T(szClsid));
|
|
CoTaskMemFree(szClsid);
|
|
szMsg = szBuffer;
|
|
}
|
|
break;
|
|
}
|
|
szBuffer[kBufSize - 1] = TCHAR('\0');
|
|
if (szMsg)
|
|
MessageBox(NULL, szMsg, _T("ActiveX Error"), MB_OK | MB_ICONWARNING);
|
|
}
|
|
|
|
#if defined(MOZ_ACTIVEX_PLUGIN_XPCONNECT) && defined(XPC_IDISPATCH_SUPPORT)
|
|
|
|
static nsresult
|
|
CreatePrincipal(nsIURI * origin,
|
|
nsIPrincipal ** outPrincipal)
|
|
{
|
|
nsresult rv;
|
|
nsCOMPtr<nsIScriptSecurityManager> secMan(
|
|
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
return secMan->GetCodebasePrincipal(origin, outPrincipal);
|
|
}
|
|
|
|
/***************************************************************************/
|
|
// A class to put on the stack to manage JS contexts when we are entering JS.
|
|
// This pushes and pops the given context
|
|
// with the nsThreadJSContextStack service as this object goes into and out
|
|
// of scope. It is optimized to not push/pop the cx if it is already on top
|
|
// of the stack. We need to push the JSContext when we enter JS because the
|
|
// JS security manager looks on the context stack for permissions information.
|
|
|
|
class MozAxAutoPushJSContext
|
|
{
|
|
public:
|
|
MozAxAutoPushJSContext(JSContext *cx, nsIURI * aURI);
|
|
|
|
~MozAxAutoPushJSContext();
|
|
|
|
nsresult ResultOfPush() { return mPushResult; };
|
|
|
|
private:
|
|
nsCOMPtr<nsIJSContextStack> mContextStack;
|
|
JSContext* mContext;
|
|
JSStackFrame mFrame;
|
|
nsresult mPushResult;
|
|
};
|
|
|
|
|
|
MozAxAutoPushJSContext::MozAxAutoPushJSContext(JSContext *cx,
|
|
nsIURI * aURI)
|
|
: mContext(cx), mPushResult(NS_OK)
|
|
{
|
|
nsCOMPtr<nsIJSContextStack> contextStack =
|
|
do_GetService("@mozilla.org/js/xpc/ContextStack;1");
|
|
|
|
JSContext* currentCX;
|
|
if(contextStack &&
|
|
// Don't push if the current context is already on the stack.
|
|
(NS_FAILED(contextStack->Peek(¤tCX)) ||
|
|
cx != currentCX) )
|
|
{
|
|
if (NS_SUCCEEDED(contextStack->Push(cx)))
|
|
{
|
|
// Leave the reference in mContextStack to
|
|
// indicate that we need to pop it in our dtor.
|
|
mContextStack.swap(contextStack);
|
|
}
|
|
}
|
|
|
|
memset(&mFrame, 0, sizeof(mFrame));
|
|
|
|
// See if there are any scripts on the stack.
|
|
// If not, we need to add a dummy frame with a principal.
|
|
PRBool hasScript = PR_FALSE;
|
|
JSStackFrame* tempFP = cx->fp;
|
|
while (tempFP)
|
|
{
|
|
if (tempFP->script)
|
|
{
|
|
hasScript = PR_TRUE;
|
|
break;
|
|
}
|
|
tempFP = tempFP->down;
|
|
};
|
|
|
|
if (!hasScript)
|
|
{
|
|
nsCOMPtr<nsIPrincipal> principal;
|
|
mPushResult = CreatePrincipal(aURI, getter_AddRefs(principal));
|
|
|
|
if (NS_SUCCEEDED(mPushResult))
|
|
{
|
|
JSPrincipals* jsprinc;
|
|
principal->GetJSPrincipals(cx, &jsprinc);
|
|
|
|
mFrame.script = JS_CompileScriptForPrincipals(cx, JS_GetGlobalObject(cx),
|
|
jsprinc, "", 0, "", 1);
|
|
JSPRINCIPALS_DROP(cx, jsprinc);
|
|
|
|
if (mFrame.script)
|
|
{
|
|
mFrame.down = cx->fp;
|
|
cx->fp = &mFrame;
|
|
}
|
|
else
|
|
mPushResult = NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
}
|
|
|
|
MozAxAutoPushJSContext::~MozAxAutoPushJSContext()
|
|
{
|
|
if (mContextStack)
|
|
mContextStack->Pop(nsnull);
|
|
|
|
if (mFrame.script)
|
|
mContext->fp = mFrame.down;
|
|
|
|
}
|
|
|
|
|
|
static JSContext*
|
|
GetPluginsContext(PluginInstanceData *pData)
|
|
{
|
|
nsCOMPtr<nsIDOMWindow> window;
|
|
NPN_GetValue(pData->pPluginInstance, NPNVDOMWindow,
|
|
static_cast<nsIDOMWindow **>(getter_AddRefs(window)));
|
|
|
|
nsCOMPtr<nsIScriptGlobalObject> globalObject(do_QueryInterface(window));
|
|
if (!globalObject)
|
|
return nsnull;
|
|
|
|
nsIScriptContext *scriptContext = globalObject->GetContext();
|
|
|
|
if (!scriptContext)
|
|
return nsnull;
|
|
|
|
return reinterpret_cast<JSContext*>(scriptContext->GetNativeContext());
|
|
}
|
|
|
|
#endif
|
|
|
|
static BOOL
|
|
WillHandleCLSID(const CLSID &clsid, PluginInstanceData *pData)
|
|
{
|
|
#if defined(MOZ_ACTIVEX_PLUGIN_XPCONNECT) && defined(XPC_IDISPATCH_SUPPORT)
|
|
// Ensure the control is safe for scripting
|
|
nsCOMPtr<nsIDispatchSupport> dispSupport = do_GetService(NS_IDISPATCH_SUPPORT_CONTRACTID);
|
|
if (!dispSupport)
|
|
return FALSE;
|
|
JSContext * cx = GetPluginsContext(pData);
|
|
if (!cx)
|
|
return FALSE;
|
|
nsCID cid;
|
|
memcpy(&cid, &clsid, sizeof(nsCID));
|
|
PRBool isSafe = PR_FALSE;
|
|
PRBool classExists = PR_FALSE;
|
|
nsCOMPtr<nsIURI> uri;
|
|
MozAxPlugin::GetCurrentLocation(pData->pPluginInstance, getter_AddRefs(uri));
|
|
|
|
JSAutoRequest req(cx);
|
|
MozAxAutoPushJSContext autoContext(cx, uri);
|
|
dispSupport->IsClassSafeToHost(cx, cid, PR_TRUE, &classExists, &isSafe);
|
|
if (classExists && !isSafe)
|
|
return FALSE;
|
|
return TRUE;
|
|
#else
|
|
if (::IsEqualCLSID(clsid, CLSID_NULL))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Check the Internet Explorer list of vulnerable controls
|
|
CRegKey keyExplorer;
|
|
if (keyExplorer.Open(HKEY_LOCAL_MACHINE,
|
|
_T("SOFTWARE\\Microsoft\\Internet Explorer\\ActiveX Compatibility"), KEY_READ) == ERROR_SUCCESS)
|
|
{
|
|
LPOLESTR szCLSID = NULL;
|
|
::StringFromCLSID(clsid, &szCLSID);
|
|
if (szCLSID)
|
|
{
|
|
CRegKey keyCLSID;
|
|
USES_CONVERSION;
|
|
if (keyCLSID.Open(keyExplorer, W2T(szCLSID), KEY_READ) == ERROR_SUCCESS)
|
|
{
|
|
DWORD dwType = REG_DWORD;
|
|
DWORD dwFlags = 0;
|
|
DWORD dwBufSize = sizeof(dwFlags);
|
|
if (::RegQueryValueEx(keyCLSID, _T("Compatibility Flags"),
|
|
NULL, &dwType, (LPBYTE) &dwFlags, &dwBufSize) == ERROR_SUCCESS)
|
|
{
|
|
// Flags for this reg key
|
|
const DWORD kKillBit = 0x00000400;
|
|
if (dwFlags & kKillBit)
|
|
{
|
|
::CoTaskMemFree(szCLSID);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
::CoTaskMemFree(szCLSID);
|
|
}
|
|
}
|
|
|
|
// Check if the CLSID belongs to a list that the plugin does not support
|
|
CRegKey keyDeny;
|
|
if (keyDeny.Open(HKEY_LOCAL_MACHINE, kControlsToDenyKey, KEY_READ) == ERROR_SUCCESS)
|
|
{
|
|
// Enumerate CLSIDs looking for this one
|
|
int i = 0;
|
|
do {
|
|
USES_CONVERSION;
|
|
TCHAR szCLSID[64];
|
|
const DWORD nLength = sizeof(szCLSID) / sizeof(szCLSID[0]);
|
|
if (::RegEnumKey(keyDeny, i++, szCLSID, nLength) != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
szCLSID[nLength - 1] = TCHAR('\0');
|
|
CLSID clsidToCompare = GUID_NULL;
|
|
if (SUCCEEDED(::CLSIDFromString(T2OLE(szCLSID), &clsidToCompare)) &&
|
|
::IsEqualCLSID(clsid, clsidToCompare))
|
|
{
|
|
return FALSE;
|
|
}
|
|
} while (1);
|
|
keyDeny.Close();
|
|
}
|
|
|
|
// Check if the CLSID belongs to a list that the plugin only supports
|
|
CRegKey keyAllow;
|
|
if (keyAllow.Open(HKEY_LOCAL_MACHINE, kControlsToAllowKey, KEY_READ) == ERROR_SUCCESS)
|
|
{
|
|
// Enumerate CLSIDs looking for this one
|
|
int i = 0;
|
|
do {
|
|
USES_CONVERSION;
|
|
TCHAR szCLSID[64];
|
|
const DWORD nLength = sizeof(szCLSID) / sizeof(szCLSID[0]);
|
|
if (::RegEnumKey(keyAllow, i, szCLSID, nLength) != ERROR_SUCCESS)
|
|
{
|
|
// An empty list means all controls are allowed.
|
|
return (i == 0) ? TRUE : FALSE;
|
|
}
|
|
++i;
|
|
szCLSID[nLength - 1] = TCHAR('\0');
|
|
CLSID clsidToCompare = GUID_NULL;
|
|
if (SUCCEEDED(::CLSIDFromString(T2OLE(szCLSID), &clsidToCompare)) &&
|
|
::IsEqualCLSID(clsid, clsidToCompare))
|
|
{
|
|
return TRUE;
|
|
}
|
|
} while (1);
|
|
}
|
|
|
|
return TRUE;
|
|
#endif
|
|
}
|
|
|
|
static NPError
|
|
CreateControl(const CLSID &clsid, PluginInstanceData *pData, PropertyList &pl, LPCOLESTR szCodebase)
|
|
{
|
|
// Make sure we got a CLSID we can handle
|
|
if (!WillHandleCLSID(clsid, pData))
|
|
{
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
|
|
pData->clsid = clsid;
|
|
|
|
// Set flags to specify if it is allowed to host safe or unsafe controls
|
|
// and download them.
|
|
PRBool hostSafeControlsOnly;
|
|
PRBool downloadControlsIfMissing;
|
|
#if defined(MOZ_ACTIVEX_PLUGIN_XPCONNECT) && defined(XPC_IDISPATCH_SUPPORT)
|
|
#ifdef MOZ_FLASH_ACTIVEX_PATCH
|
|
GUID flashGUID;
|
|
::CLSIDFromString(_T("{D27CDB6E-AE6D-11CF-96B8-444553540000}"), &flashGUID);
|
|
|
|
// HACK: Allow anything but downloading for the wrapped Flash control.
|
|
PRUint32 hostingFlags;
|
|
if (clsid == flashGUID)
|
|
{
|
|
hostingFlags = (nsIActiveXSecurityPolicy::HOSTING_FLAGS_HOST_SAFE_OBJECTS |
|
|
nsIActiveXSecurityPolicy::HOSTING_FLAGS_SCRIPT_SAFE_OBJECTS |
|
|
nsIActiveXSecurityPolicy::HOSTING_FLAGS_SCRIPT_ALL_OBJECTS |
|
|
nsIActiveXSecurityPolicy::HOSTING_FLAGS_HOST_ALL_OBJECTS);
|
|
}
|
|
else
|
|
{
|
|
hostingFlags = MozAxPlugin::PrefGetHostingFlags();
|
|
}
|
|
#else
|
|
PRUint32 hostingFlags = MozAxPlugin::PrefGetHostingFlags();
|
|
#endif
|
|
if (hostingFlags & nsIActiveXSecurityPolicy::HOSTING_FLAGS_HOST_SAFE_OBJECTS &&
|
|
!(hostingFlags & nsIActiveXSecurityPolicy::HOSTING_FLAGS_HOST_ALL_OBJECTS))
|
|
{
|
|
hostSafeControlsOnly = TRUE;
|
|
}
|
|
else if (hostingFlags & nsIActiveXSecurityPolicy::HOSTING_FLAGS_HOST_ALL_OBJECTS)
|
|
{
|
|
hostSafeControlsOnly = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// Plugin can host neither safe nor unsafe controls, so just return
|
|
// without creating anything.
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
if (hostingFlags & nsIActiveXSecurityPolicy::HOSTING_FLAGS_DOWNLOAD_CONTROLS)
|
|
{
|
|
downloadControlsIfMissing = PR_TRUE;
|
|
}
|
|
else
|
|
{
|
|
downloadControlsIfMissing = PR_FALSE;
|
|
}
|
|
// Ensure we can obtain the nsIDispatchSupport service
|
|
nsCOMPtr<nsIDispatchSupport> dispSupport = do_GetService(NS_IDISPATCH_SUPPORT_CONTRACTID);
|
|
if (!dispSupport)
|
|
{
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
// Now test if the CLSID is safe for scripting
|
|
PRBool classIsMarkedSafeForScripting = PR_FALSE;
|
|
if (hostSafeControlsOnly)
|
|
{
|
|
PRBool classExists = PR_FALSE;
|
|
PRBool isClassSafeForScripting = PR_FALSE;
|
|
nsCID cid;
|
|
memcpy(&cid, &clsid, sizeof(cid));
|
|
if (NS_SUCCEEDED(dispSupport->IsClassMarkedSafeForScripting(cid, &classExists, &isClassSafeForScripting)) &&
|
|
classExists && isClassSafeForScripting)
|
|
{
|
|
classIsMarkedSafeForScripting = PR_TRUE;
|
|
}
|
|
}
|
|
#else
|
|
hostSafeControlsOnly = kHostSafeControlsOnly;
|
|
downloadControlsIfMissing = kDownloadControlsIfMissing;
|
|
#endif
|
|
|
|
// Create the control site
|
|
CControlSiteInstance *pSite = NULL;
|
|
CControlSiteInstance::CreateInstance(&pSite);
|
|
if (pSite == NULL)
|
|
{
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
|
|
pSite->m_bSupportWindowlessActivation = FALSE;
|
|
#if defined(MOZ_ACTIVEX_PLUGIN_XPCONNECT) && defined(XPC_IDISPATCH_SUPPORT)
|
|
// We handle our own security further down
|
|
pSite->SetSecurityPolicy(NULL);
|
|
pSite->m_bSafeForScriptingObjectsOnly = FALSE;
|
|
#else
|
|
pSite->m_bSafeForScriptingObjectsOnly = hostSafeControlsOnly;
|
|
#endif
|
|
|
|
pSite->AddRef();
|
|
|
|
#ifdef MOZ_ACTIVEX_PLUGIN_XPCONNECT
|
|
// Set up the service provider and container so the control can get hold
|
|
// of the IE DOM and other interfaces
|
|
CComPtr<IServiceProvider> sp;
|
|
MozAxPlugin::GetServiceProvider(pData, &sp);
|
|
if (sp)
|
|
pSite->SetServiceProvider(sp);
|
|
CComQIPtr<IOleContainer> container = sp;
|
|
if (container)
|
|
pSite->SetContainer(container);
|
|
#endif
|
|
|
|
// TODO check the object is installed and at least as recent as
|
|
// that specified in szCodebase
|
|
|
|
// Create the object
|
|
HRESULT hr;
|
|
if (!downloadControlsIfMissing || !szCodebase)
|
|
{
|
|
hr = pSite->Create(clsid, pl);
|
|
}
|
|
else if (szCodebase)
|
|
{
|
|
CComObject<CInstallControlProgress> *pProgress = NULL;
|
|
CComPtr<IBindCtx> spBindCtx;
|
|
CComPtr<IBindStatusCallback> spOldBSC;
|
|
CComObject<CInstallControlProgress>::CreateInstance(&pProgress);
|
|
pProgress->AddRef();
|
|
CreateBindCtx(0, &spBindCtx);
|
|
RegisterBindStatusCallback(spBindCtx, dynamic_cast<IBindStatusCallback *>(pProgress), &spOldBSC, 0);
|
|
|
|
hr = pSite->Create(clsid, pl, szCodebase, spBindCtx);
|
|
if (hr == MK_S_ASYNCHRONOUS)
|
|
{
|
|
pProgress->mNPP = pData->pPluginInstance;
|
|
pProgress->mBindingInProgress = TRUE;
|
|
pProgress->mResult = E_FAIL;
|
|
|
|
// Spin around waiting for binding to complete
|
|
HANDLE hFakeEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
while (pProgress->mBindingInProgress)
|
|
{
|
|
MSG msg;
|
|
// Process pending messages
|
|
while (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
|
|
{
|
|
if (!::GetMessage(&msg, NULL, 0, 0))
|
|
{
|
|
pProgress->mBindingInProgress = FALSE;
|
|
break;
|
|
}
|
|
::TranslateMessage(&msg);
|
|
::DispatchMessage(&msg);
|
|
}
|
|
if (!pProgress->mBindingInProgress)
|
|
break;
|
|
// Sleep for a bit or the next msg to appear
|
|
::MsgWaitForMultipleObjects(1, &hFakeEvent, FALSE, 500, QS_ALLEVENTS);
|
|
}
|
|
::CloseHandle(hFakeEvent);
|
|
|
|
hr = pProgress->mResult;
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pSite->Create(clsid, pl);
|
|
}
|
|
}
|
|
if (pProgress)
|
|
{
|
|
RevokeBindStatusCallback(spBindCtx, dynamic_cast<IBindStatusCallback *>(pProgress));
|
|
pProgress->Release();
|
|
}
|
|
}
|
|
if (FAILED(hr))
|
|
{
|
|
ShowError(MozAxErrorCouldNotCreateControl, clsid);
|
|
}
|
|
#if defined(MOZ_ACTIVEX_PLUGIN_XPCONNECT) && defined(XPC_IDISPATCH_SUPPORT)
|
|
if (SUCCEEDED(hr) && hostSafeControlsOnly && !classIsMarkedSafeForScripting)
|
|
{
|
|
CComPtr<IUnknown> cpUnk;
|
|
pSite->GetControlUnknown(&cpUnk);
|
|
nsIID iidDispatch;
|
|
memcpy(&iidDispatch, &__uuidof(IDispatch), sizeof(nsIID));
|
|
PRBool isObjectSafe = PR_FALSE;
|
|
if (!cpUnk ||
|
|
NS_FAILED(dispSupport->IsObjectSafeForScripting(
|
|
reinterpret_cast<void *>(cpUnk.p), iidDispatch, &isObjectSafe)) ||
|
|
!isObjectSafe)
|
|
{
|
|
pSite->Detach();
|
|
hr = E_FAIL;
|
|
ShowError(MozAxErrorControlIsNotSafeForScripting, clsid);
|
|
// DROP THROUGH
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Clean up if the control could not be created
|
|
if (FAILED(hr))
|
|
{
|
|
pSite->Release();
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
|
|
#if defined(MOZ_ACTIVEX_PLUGIN_XPCONNECT) && defined(XPC_IDISPATCH_SUPPORT)
|
|
// Hook up the event sink
|
|
nsEventSinkInstance *pSink = NULL;
|
|
nsEventSinkInstance::CreateInstance(&pSink);
|
|
if (pSink)
|
|
{
|
|
pSink->AddRef();
|
|
pSink->mPlugin = pData;
|
|
CComPtr<IUnknown> control;
|
|
pSite->GetControlUnknown(&control);
|
|
pSink->SubscribeToEvents(control);
|
|
}
|
|
pData->pControlEventSink = pSink;
|
|
#endif
|
|
pData->nType = itControl;
|
|
pData->pControlSite = pSite;
|
|
|
|
return NPERR_NO_ERROR;
|
|
}
|
|
|
|
static NPError
|
|
NewControl(const char *pluginType,
|
|
PluginInstanceData *pData,
|
|
uint16_t mode,
|
|
int16_t argc,
|
|
char *argn[],
|
|
char *argv[])
|
|
{
|
|
// Read the parameters
|
|
CLSID clsid = CLSID_NULL;
|
|
CComBSTR codebase;
|
|
PropertyList pl;
|
|
|
|
if (strcmp(pluginType, MIME_OLEOBJECT1) != 0 &&
|
|
strcmp(pluginType, MIME_OLEOBJECT2) != 0)
|
|
{
|
|
clsid = MozAxPlugin::GetCLSIDForType(pluginType);
|
|
}
|
|
|
|
for (int16_t i = 0; i < argc; i++)
|
|
{
|
|
if (stricmp(argn[i], "CLSID") == 0 ||
|
|
stricmp(argn[i], "CLASSID") == 0)
|
|
{
|
|
// Accept CLSIDs specified in various ways
|
|
// e.g:
|
|
// "CLSID:C16DF970-D1BA-11d2-A252-000000000000"
|
|
// "C16DF970-D1BA-11d2-A252-000000000000"
|
|
// "{C16DF970-D1BA-11d2-A252-000000000000}"
|
|
//
|
|
// The first example is the proper way
|
|
|
|
const int kCLSIDLen = 256;
|
|
char szCLSID[kCLSIDLen];
|
|
if (strlen(argv[i]) < sizeof(szCLSID))
|
|
{
|
|
if (_strnicmp(argv[i], "CLSID:", 6) == 0)
|
|
{
|
|
_snprintf(szCLSID, kCLSIDLen - 1, "{%s}", argv[i]+6);
|
|
}
|
|
else if(argv[i][0] != '{')
|
|
{
|
|
_snprintf(szCLSID, kCLSIDLen - 1, "{%s}", argv[i]);
|
|
}
|
|
else
|
|
{
|
|
strncpy(szCLSID, argv[i], kCLSIDLen - 1);
|
|
}
|
|
szCLSID[kCLSIDLen - 1] = '\0';
|
|
USES_CONVERSION;
|
|
CLSIDFromString(A2OLE(szCLSID), &clsid);
|
|
}
|
|
}
|
|
else if (stricmp(argn[i], "CODEBASE") == 0)
|
|
{
|
|
codebase = argv[i];
|
|
|
|
#ifdef XPC_IDISPATCH_SUPPORT
|
|
// resolve relative URLs on CODEBASE
|
|
if (argv[i])
|
|
{
|
|
nsCOMPtr<nsIDOMElement> element;
|
|
NPN_GetValue(pData->pPluginInstance, NPNVDOMElement,
|
|
static_cast<nsIDOMElement **>(getter_AddRefs(element)));
|
|
if (element)
|
|
{
|
|
nsCOMPtr<nsIDOMNode> tagAsNode (do_QueryInterface(element));
|
|
if (tagAsNode)
|
|
{
|
|
nsCOMPtr<nsIDOMDocument> DOMdocument;
|
|
tagAsNode->GetOwnerDocument(getter_AddRefs(DOMdocument));
|
|
// XXX nsIDocument is not frozen!!!
|
|
nsCOMPtr<nsIDocument> doc(do_QueryInterface(DOMdocument));
|
|
if (doc)
|
|
{
|
|
nsIURI *baseURI = doc->GetBaseURI();
|
|
if (baseURI)
|
|
{
|
|
nsCAutoString newURL;
|
|
if (NS_SUCCEEDED(baseURI->Resolve(nsDependentCString(argv[i]), newURL)))
|
|
{
|
|
codebase = newURL.get();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
}
|
|
else
|
|
{
|
|
CComBSTR paramName;
|
|
if (_strnicmp(argn[i], "PARAM_", 6) == 0)
|
|
{
|
|
paramName = argn[i] + 6;
|
|
}
|
|
else if (stricmp(argn[i], "PARAM") == 0)
|
|
{
|
|
// The next argn and argv values after this symbol
|
|
// will be <param> tag names and values
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
paramName = argn[i];
|
|
}
|
|
|
|
// Empty parameters are ignored
|
|
if (!paramName.m_str || paramName.Length() == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
USES_CONVERSION;
|
|
CComBSTR paramValue(A2W(argv[i]));
|
|
|
|
// Check for existing params with the same name
|
|
BOOL bFound = FALSE;
|
|
for (unsigned long j = 0; j < pl.GetSize(); j++)
|
|
{
|
|
if (wcscmp(pl.GetNameOf(j), (BSTR) paramName) == 0)
|
|
{
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
// If the parameter already exists, don't add it to the
|
|
// list again.
|
|
if (bFound)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Add named parameter to list
|
|
CComVariant v(paramValue);
|
|
pl.AddNamedProperty(paramName, v);
|
|
}
|
|
}
|
|
|
|
return CreateControl(clsid, pData, pl, codebase.m_str);
|
|
}
|
|
|
|
|
|
// NPP_New
|
|
//
|
|
// create a new plugin instance
|
|
// handle any instance specific code initialization here
|
|
//
|
|
NPError NPP_New(NPMIMEType pluginType,
|
|
NPP instance,
|
|
uint16_t mode,
|
|
int16_t argc,
|
|
char* argn[],
|
|
char* argv[],
|
|
NPSavedData* saved)
|
|
{
|
|
ATLTRACE(_T("NPP_New()\n"));
|
|
|
|
// trap duff args
|
|
if (instance == NULL)
|
|
{
|
|
return NPERR_INVALID_INSTANCE_ERROR;
|
|
}
|
|
|
|
PluginInstanceData *pData = new PluginInstanceData;
|
|
if (pData == NULL)
|
|
{
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
pData->pPluginInstance = instance;
|
|
pData->szUrl = NULL;
|
|
pData->szContentType = (pluginType) ? strdup(pluginType) : NULL;
|
|
#ifdef MOZ_ACTIVEX_PLUGIN_XPCONNECT
|
|
pData->pScriptingPeer = NULL;
|
|
#endif
|
|
|
|
// Create a plugin according to the mime type
|
|
#ifdef MOZ_ACTIVEX_PLUGIN_XPCONNECT
|
|
MozAxPlugin::AddRef();
|
|
#endif
|
|
|
|
CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
|
|
|
NPError rv = NPERR_GENERIC_ERROR;
|
|
/* if (strcmp(pluginType, MIME_OLEOBJECT1) == 0 ||
|
|
strcmp(pluginType, MIME_OLEOBJECT2) == 0) */
|
|
{
|
|
rv = NewControl(pluginType, pData, mode, argc, argn, argv);
|
|
}
|
|
|
|
// Test if plugin creation has succeeded and cleanup if it hasn't
|
|
if (rv != NPERR_NO_ERROR)
|
|
{
|
|
if (pData->szContentType)
|
|
free(pData->szContentType);
|
|
if (pData->szUrl)
|
|
free(pData->szUrl);
|
|
delete pData;
|
|
#ifdef MOZ_ACTIVEX_PLUGIN_XPCONNECT
|
|
MozAxPlugin::Release();
|
|
#endif
|
|
CoUninitialize();
|
|
return rv;
|
|
}
|
|
|
|
instance->pdata = pData;
|
|
|
|
return NPERR_NO_ERROR;
|
|
}
|
|
|
|
|
|
// NPP_Destroy
|
|
//
|
|
// Deletes a plug-in instance and releases all of its resources.
|
|
//
|
|
NPError
|
|
NPP_Destroy(NPP instance, NPSavedData** save)
|
|
{
|
|
ATLTRACE(_T("NPP_Destroy()\n"));
|
|
|
|
PluginInstanceData *pData = (PluginInstanceData *) instance->pdata;
|
|
if (pData == NULL)
|
|
{
|
|
return NPERR_INVALID_INSTANCE_ERROR;
|
|
}
|
|
|
|
if (pData->nType == itControl)
|
|
{
|
|
// Destroy the site
|
|
CControlSiteInstance *pSite = pData->pControlSite;
|
|
if (pSite)
|
|
{
|
|
pSite->Detach();
|
|
pSite->Release();
|
|
}
|
|
#if defined(MOZ_ACTIVEX_PLUGIN_XPCONNECT) && defined(XPC_IDISPATCH_SUPPORT)
|
|
if (pData->pControlEventSink)
|
|
{
|
|
pData->pControlEventSink->UnsubscribeFromEvents();
|
|
pData->pControlEventSink->Release();
|
|
}
|
|
#endif
|
|
#ifdef MOZ_ACTIVEX_PLUGIN_XPCONNECT
|
|
if (pData->pScriptingPeer)
|
|
{
|
|
pData->pScriptingPeer->Release();
|
|
}
|
|
#endif
|
|
}
|
|
else if (pData->nType == itScript)
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
if (pData->szUrl)
|
|
free(pData->szUrl);
|
|
if (pData->szContentType)
|
|
free(pData->szContentType);
|
|
delete pData;
|
|
#ifdef MOZ_ACTIVEX_PLUGIN_XPCONNECT
|
|
MozAxPlugin::Release();
|
|
#endif
|
|
|
|
instance->pdata = 0;
|
|
|
|
CoUninitialize();
|
|
|
|
return NPERR_NO_ERROR;
|
|
|
|
}
|
|
|
|
|
|
// NPP_SetWindow
|
|
//
|
|
// Associates a platform specific window handle with a plug-in instance.
|
|
// Called multiple times while, e.g., scrolling. Can be called for three
|
|
// reasons:
|
|
//
|
|
// 1. A new window has been created
|
|
// 2. A window has been moved or resized
|
|
// 3. A window has been destroyed
|
|
//
|
|
// There is also the degenerate case; that it was called spuriously, and
|
|
// the window handle and or coords may have or have not changed, or
|
|
// the window handle and or coords may be ZERO. State information
|
|
// must be maintained by the plug-in to correctly handle the degenerate
|
|
// case.
|
|
//
|
|
NPError
|
|
NPP_SetWindow(NPP instance, NPWindow* window)
|
|
{
|
|
ATLTRACE(_T("NPP_SetWindow()\n"));
|
|
|
|
// Reject silly parameters
|
|
if (!window)
|
|
{
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
|
|
PluginInstanceData *pData = (PluginInstanceData *) instance->pdata;
|
|
if (pData == NULL)
|
|
{
|
|
return NPERR_INVALID_INSTANCE_ERROR;
|
|
}
|
|
|
|
if (pData->nType == itControl)
|
|
{
|
|
CControlSiteInstance *pSite = pData->pControlSite;
|
|
if (pSite == NULL)
|
|
{
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
|
|
HWND hwndParent = (HWND) window->window;
|
|
if (hwndParent)
|
|
{
|
|
RECT rcPos;
|
|
GetClientRect(hwndParent, &rcPos);
|
|
|
|
if (pSite->GetParentWindow() == NULL)
|
|
{
|
|
pSite->Attach(hwndParent, rcPos, NULL);
|
|
}
|
|
else
|
|
{
|
|
pSite->SetPosition(rcPos);
|
|
}
|
|
|
|
// Ensure clipping on parent to keep child controls happy
|
|
::SetWindowLong(hwndParent, GWL_STYLE,
|
|
::GetWindowLong(hwndParent, GWL_STYLE) | WS_CLIPCHILDREN);
|
|
}
|
|
}
|
|
|
|
return NPERR_NO_ERROR;
|
|
}
|
|
|
|
|
|
// NPP_NewStream
|
|
//
|
|
// Notifies the plugin of a new data stream.
|
|
// The data type of the stream (a MIME name) is provided.
|
|
// The stream object indicates whether it is seekable.
|
|
// The plugin specifies how it wants to handle the stream.
|
|
//
|
|
// In this case, I set the streamtype to be NPAsFile. This tells the Navigator
|
|
// that the plugin doesn't handle streaming and can only deal with the object as
|
|
// a complete disk file. It will still call the write functions but it will also
|
|
// pass the filename of the cached file in a later NPE_StreamAsFile call when it
|
|
// is done transferring the file.
|
|
//
|
|
// If a plugin handles the data in a streaming manner, it should set streamtype to
|
|
// NPNormal (e.g. *streamtype = NPNormal)...the NPE_StreamAsFile function will
|
|
// never be called in this case
|
|
//
|
|
NPError
|
|
NPP_NewStream(NPP instance,
|
|
NPMIMEType type,
|
|
NPStream *stream,
|
|
NPBool seekable,
|
|
uint16_t *stype)
|
|
{
|
|
ATLTRACE(_T("NPP_NewStream()\n"));
|
|
|
|
if(!instance)
|
|
{
|
|
return NPERR_INVALID_INSTANCE_ERROR;
|
|
}
|
|
|
|
// save the plugin instance object in the stream instance
|
|
stream->pdata = instance->pdata;
|
|
*stype = NP_ASFILE;
|
|
return NPERR_NO_ERROR;
|
|
}
|
|
|
|
|
|
// NPP_StreamAsFile
|
|
//
|
|
// The stream is done transferring and here is a pointer to the file in the cache
|
|
// This function is only called if the streamtype was set to NPAsFile.
|
|
//
|
|
void
|
|
NPP_StreamAsFile(NPP instance, NPStream *stream, const char* fname)
|
|
{
|
|
ATLTRACE(_T("NPP_StreamAsFile()\n"));
|
|
|
|
if(fname == NULL || fname[0] == NULL)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// These next 2 functions are really only directly relevant
|
|
// in a plug-in which handles the data in a streaming manner.
|
|
// For a NPAsFile stream, they are still called but can safely
|
|
// be ignored.
|
|
//
|
|
// In a streaming plugin, all data handling would take place here...
|
|
//
|
|
////\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//.
|
|
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\.
|
|
|
|
int32_t STREAMBUFSIZE = 0X0FFFFFFF; // we are reading from a file in NPAsFile mode
|
|
// so we can take any size stream in our write
|
|
// call (since we ignore it)
|
|
|
|
|
|
// NPP_WriteReady
|
|
//
|
|
// The number of bytes that a plug-in is willing to accept in a subsequent
|
|
// NPO_Write call.
|
|
//
|
|
int32_t
|
|
NPP_WriteReady(NPP instance, NPStream *stream)
|
|
{
|
|
return STREAMBUFSIZE;
|
|
}
|
|
|
|
|
|
// NPP_Write
|
|
//
|
|
// Provides len bytes of data.
|
|
//
|
|
int32_t
|
|
NPP_Write(NPP instance, NPStream *stream, int32_t offset, int32_t len, void *buffer)
|
|
{
|
|
return len;
|
|
}
|
|
|
|
|
|
// NPP_DestroyStream
|
|
//
|
|
// Closes a stream object.
|
|
// reason indicates why the stream was closed. Possible reasons are
|
|
// that it was complete, because there was some error, or because
|
|
// the user aborted it.
|
|
//
|
|
NPError
|
|
NPP_DestroyStream(NPP instance, NPStream *stream, NPError reason)
|
|
{
|
|
// because I am handling the stream as a file, I don't do anything here...
|
|
// If I was streaming, I would know that I was done and do anything appropriate
|
|
// to the end of the stream...
|
|
return NPERR_NO_ERROR;
|
|
}
|
|
|
|
|
|
// NPP_Print
|
|
//
|
|
// Printing the plugin (to be continued...)
|
|
//
|
|
void
|
|
NPP_Print(NPP instance, NPPrint* printInfo)
|
|
{
|
|
if(printInfo == NULL) // trap invalid parm
|
|
{
|
|
return;
|
|
}
|
|
|
|
// if (instance != NULL) {
|
|
// CPluginWindow* pluginData = (CPluginWindow*) instance->pdata;
|
|
// pluginData->Print(printInfo);
|
|
// }
|
|
}
|
|
|
|
/*******************************************************************************
|
|
// NPP_URLNotify:
|
|
// Notifies the instance of the completion of a URL request.
|
|
//
|
|
// NPP_URLNotify is called when Netscape completes a NPN_GetURLNotify or
|
|
// NPN_PostURLNotify request, to inform the plug-in that the request,
|
|
// identified by url, has completed for the reason specified by reason. The most
|
|
// common reason code is NPRES_DONE, indicating simply that the request
|
|
// completed normally. Other possible reason codes are NPRES_USER_BREAK,
|
|
// indicating that the request was halted due to a user action (for example,
|
|
// clicking the "Stop" button), and NPRES_NETWORK_ERR, indicating that the
|
|
// request could not be completed (for example, because the URL could not be
|
|
// found). The complete list of reason codes is found in npapi.h.
|
|
//
|
|
// The parameter notifyData is the same plug-in-private value passed as an
|
|
// argument to the corresponding NPN_GetURLNotify or NPN_PostURLNotify
|
|
// call, and can be used by your plug-in to uniquely identify the request.
|
|
******************************************************************************/
|
|
|
|
void
|
|
NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData)
|
|
{
|
|
PluginInstanceData *pData = (PluginInstanceData *) instance->pdata;
|
|
if (pData)
|
|
{
|
|
if (pData->szUrl)
|
|
free(pData->szUrl);
|
|
pData->szUrl = strdup(url);
|
|
}
|
|
}
|
|
|
|
NPError
|
|
NPP_GetValue(NPP instance, NPPVariable variable, void *value)
|
|
{
|
|
NPError rv = NPERR_GENERIC_ERROR;
|
|
#ifdef MOZ_ACTIVEX_PLUGIN_XPCONNECT
|
|
rv = MozAxPlugin::GetValue(instance, variable, value);
|
|
#endif
|
|
return rv;
|
|
}
|
|
|
|
NPError
|
|
NPP_SetValue(NPP instance, NPNVariable variable, void *value)
|
|
{
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|