/* -*- 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) 2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * 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 "nsPopupWindowManager.h" #include "nsCOMPtr.h" #include "nsCRT.h" #include "nsPermissions.h" #include "nsIObserverService.h" #include "nsIPrefBranch.h" #include "nsIPrefBranchInternal.h" #include "nsIPrefService.h" #include "nsIPermissionManager.h" #include "nsIServiceManagerUtils.h" #include "nsIURI.h" /* The Popup Window Manager maintains popup window permissions by website. */ static const char *sPopupPrefRoot = "dom."; static const char *sPopupPrefLeaf = "disable_open_during_load"; static const char *sPermissionChangeNotification = PPM_CHANGE_NOTIFICATION; static const char *sXPCOMShutdownTopic = NS_XPCOM_SHUTDOWN_OBSERVER_ID; static const char *sPrefChangedTopic = NS_PREFBRANCH_PREFCHANGE_TOPIC_ID; //***************************************************************************** //*** nsPopupWindowManager object management and nsISupports //***************************************************************************** nsPopupWindowManager::nsPopupWindowManager() : mAllowPopupsPref(PR_TRUE) { NS_INIT_ISUPPORTS(); } nsPopupWindowManager::~nsPopupWindowManager(void) { StopObservingThings(); } NS_IMPL_ISUPPORTS2(nsPopupWindowManager, nsIPopupWindowManager, nsIObserver); nsresult nsPopupWindowManager::Init() { mOS = do_GetService("@mozilla.org/observer-service;1"); mPermManager = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); nsCOMPtr prefs(do_GetService(NS_PREFSERVICE_CONTRACTID)); if (prefs) prefs->GetBranch(sPopupPrefRoot, getter_AddRefs(mDomPrefBranch)); if (mOS && mPermManager && mDomPrefBranch) { Observe(NS_STATIC_CAST(nsIPopupWindowManager *, this), sPrefChangedTopic, 0); // initialize our local copy of the pref return ObserveThings(); } return NS_ERROR_FAILURE; } //***************************************************************************** //*** nsPopupWindowManager::nsIPopupWindowManager //***************************************************************************** NS_IMETHODIMP nsPopupWindowManager::GetDefaultPermission(PRUint32 *aDefaultPermission) { return eDisallow; } NS_IMETHODIMP nsPopupWindowManager::SetDefaultPermission(PRUint32 aDefaultPermission) { NS_ASSERTION(aDefaultPermission == eDisallow, "whitelist not supported"); return aDefaultPermission == eDisallow ? NS_OK : NS_ERROR_FAILURE; } /* Note: since we don't support whitelists, Add(uri, true) is the same thing as Remove(uri). However Add(uri, true) is not considered an error because the method is used that way. */ NS_IMETHODIMP nsPopupWindowManager::Add(nsIURI *aURI, PRBool aPermit) { NS_ENSURE_ARG_POINTER(aURI); if (!mPermManager) return NS_ERROR_UNEXPECTED; nsCAutoString uri; aURI->GetPrePath(uri); if (NS_SUCCEEDED(mPermManager->Add(uri, aPermit, WINDOWPERMISSION))) return NotifyObservers(); return NS_ERROR_FAILURE; } NS_IMETHODIMP nsPopupWindowManager::Remove(nsIURI *aURI) { NS_ENSURE_ARG_POINTER(aURI); if (!mPermManager) return NS_ERROR_UNEXPECTED; nsCAutoString uri; aURI->GetPrePath(uri); if (NS_SUCCEEDED(mPermManager->Add(uri, PR_TRUE, WINDOWPERMISSION))) return NotifyObservers(); return NS_ERROR_FAILURE; } NS_IMETHODIMP nsPopupWindowManager::RemoveAll() { return NS_ERROR_NOT_IMPLEMENTED; } /* The underlying manager, nsPermissionManager, won't store permissions for an url lacking a host. It's good to know these things up front. */ NS_IMETHODIMP nsPopupWindowManager::TestSuitability(nsIURI *aURI, PRBool *_retval) { NS_ENSURE_ARG_POINTER(aURI); NS_ENSURE_ARG_POINTER(_retval); nsCAutoString hostPort; aURI->GetHostPort(hostPort); *_retval = hostPort.IsEmpty() ? PR_FALSE : PR_TRUE; return NS_OK; } NS_IMETHODIMP nsPopupWindowManager::TestPermission(nsIURI *aURI, PRUint32 *_retval) { NS_ENSURE_ARG_POINTER(aURI); NS_ENSURE_ARG_POINTER(_retval); *_retval = eAllow; if (!mAllowPopupsPref) { *_retval = eDisallow; if (mPermManager) { /* Because of a bug/quirk/something in the PermissionManager the value of blockDomain will be left unchanged if the URI has no host port (like a local file URI, for instance). And the PermissionManager will refuse to save permissions for such URIs. A default of "false," then, allows local files to show popup windows, and this can't be stopped. ("true" would do just the opposite.) */ PRBool blockDomain = PR_FALSE; // default to not blocked nsCAutoString uri; aURI->GetPrePath(uri); mPermManager->TestForBlocking(uri, WINDOWPERMISSION, &blockDomain); if (!blockDomain) *_retval = eAllowConditionally; } } return NS_OK; } NS_IMETHODIMP nsPopupWindowManager::GetEnumerator(nsISimpleEnumerator **_retval) { NS_ENSURE_ARG_POINTER(_retval); *_retval = 0; return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsPopupWindowManager::AddObserver(nsIObserver *aObserver) { if (mOS) return mOS->AddObserver(aObserver, sPermissionChangeNotification, PR_FALSE); return NS_ERROR_FAILURE; } NS_IMETHODIMP nsPopupWindowManager::RemoveObserver(nsIObserver *aObserver) { if (mOS) return mOS->RemoveObserver(aObserver, sPermissionChangeNotification); return NS_ERROR_FAILURE; } //***************************************************************************** //*** nsPopupWindowManager::nsIObserver //***************************************************************************** NS_IMETHODIMP nsPopupWindowManager::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData) { if (nsCRT::strcmp(aTopic, sPrefChangedTopic) == 0) { // refresh our local copy of the "allow popups" pref mAllowPopupsPref = PR_TRUE; if (mDomPrefBranch) { PRBool disallowPopups = PR_FALSE; mDomPrefBranch->GetBoolPref(sPopupPrefLeaf, &disallowPopups); mAllowPopupsPref = !disallowPopups; } } else if (nsCRT::strcmp(aTopic, sXPCOMShutdownTopic) == 0) { // unhook cyclical references StopObservingThings(); DeInitialize(); } return NS_OK; } //***************************************************************************** //*** nsPopupWindowManager private methods //***************************************************************************** /* Register for notifications of interest. That's a change in the pref we're watching and XPCOM shutdown. */ nsresult nsPopupWindowManager::ObserveThings() { nsresult rv = NS_ERROR_FAILURE; if (mOS) rv = mOS->AddObserver(this, sXPCOMShutdownTopic, PR_FALSE); if (NS_SUCCEEDED(rv)) { nsCOMPtr ibranch(do_QueryInterface(mDomPrefBranch)); if (ibranch) rv = ibranch->AddObserver(sPopupPrefLeaf, this, PR_FALSE); } return rv; } // undo ObserveThings nsresult nsPopupWindowManager::StopObservingThings() { nsCOMPtr ibranch(do_QueryInterface(mDomPrefBranch)); if (ibranch) ibranch->RemoveObserver(sPopupPrefLeaf, this); if (mOS) mOS->RemoveObserver(this, sXPCOMShutdownTopic); return NS_OK; } // broadcast a notification that a popup pref has changed nsresult nsPopupWindowManager::NotifyObservers() { if (mOS) return mOS->NotifyObservers(NS_STATIC_CAST(nsIPopupWindowManager *, this), sPermissionChangeNotification, 0); return NS_ERROR_FAILURE; } // unhook cyclical references so we can be properly shut down void nsPopupWindowManager::DeInitialize() { mOS = 0; mPermManager = 0; mDomPrefBranch = 0; }