From 45f5eb96717e420d0c39aa6037f9d2211265bf73 Mon Sep 17 00:00:00 2001 From: Cinder Date: Wed, 16 Jul 2014 21:22:12 -0600 Subject: [PATCH] Replace the media filter with something a little different --- indra/newview/CMakeLists.txt | 6 +- indra/newview/app_settings/settings.xml | 22 +- indra/newview/llfloatermediafilter.cpp | 153 +++++ indra/newview/llfloatermediafilter.h | 55 ++ indra/newview/llmediafilter.cpp | 491 ++++++++++++++++ indra/newview/llmediafilter.h | 92 +++ indra/newview/llmenucommands.cpp | 4 +- indra/newview/lloverlaybar.cpp | 4 +- indra/newview/llstartup.cpp | 3 +- indra/newview/llviewerparcelmedia.cpp | 531 ++++-------------- indra/newview/llviewerparcelmedia.h | 20 +- .../default/xui/en-us/floater_media_lists.xml | 216 +++++++ .../skins/default/xui/en-us/notifications.xml | 20 + .../xui/en-us/panel_preferences_audio.xml | 5 + .../skins/default/xui/en-us/strings.xml | 5 + indra/newview/slfloatermediafilter.cpp | 398 ------------- indra/newview/slfloatermediafilter.h | 66 --- 17 files changed, 1156 insertions(+), 935 deletions(-) create mode 100644 indra/newview/llfloatermediafilter.cpp create mode 100644 indra/newview/llfloatermediafilter.h create mode 100644 indra/newview/llmediafilter.cpp create mode 100644 indra/newview/llmediafilter.h create mode 100644 indra/newview/skins/default/xui/en-us/floater_media_lists.xml delete mode 100644 indra/newview/slfloatermediafilter.cpp delete mode 100644 indra/newview/slfloatermediafilter.h diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index c3427111f..95e635a3d 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -232,6 +232,7 @@ set(viewer_SOURCE_FILES llfloaterlandholdings.cpp llfloaterlandmark.cpp llfloatermap.cpp + llfloatermediafilter.cpp llfloatermediasettings.cpp llfloatermemleak.cpp llfloatermessagelog.cpp @@ -334,6 +335,7 @@ set(viewer_SOURCE_FILES llmaterialmgr.cpp llmediactrl.cpp llmediadataclient.cpp + llmediafilter.cpp llmediaremotectrl.cpp llmenucommands.cpp llmenuoptionpathfindingrebakenavmesh.cpp @@ -594,7 +596,6 @@ set(viewer_SOURCE_FILES sgversion.cpp shcommandhandler.cpp shfloatermediaticker.cpp - slfloatermediafilter.cpp wlfPanel_AdvSettings.cpp ) @@ -758,6 +759,7 @@ set(viewer_HEADER_FILES llfloaterlandholdings.h llfloaterlandmark.h llfloatermap.h + llfloatermediafilter.h llfloatermediasettings.h llfloatermemleak.h llfloatermessagelog.h @@ -860,6 +862,7 @@ set(viewer_HEADER_FILES llmaterialmgr.h llmediactrl.h llmediadataclient.h + llmediafilter.h llmediaremotectrl.h llmenucommands.h llmenuoptionpathfindingrebakenavmesh.h @@ -1130,7 +1133,6 @@ set(viewer_HEADER_FILES sgversion.h shcommandhandler.h shfloatermediaticker.h - slfloatermediafilter.h wlfPanel_AdvSettings.h VertexCache.h VorbisFramework.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 58b1502e0..c7d9d1615 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -345,17 +345,6 @@ - MediaEnableFilter - - Comment - Enable media domain filtering - Persist - 1 - Type - Boolean - Value - 1 - MediaFilterRect Comment @@ -18572,6 +18561,17 @@ This should be as low as possible, but too low may break functionality Value 0 + MediaFilterEnable + + Comment + Enable media domain filtering (0 = Off, 1 = Blacklist only, 2 = Prompt) + Persist + 1 + Type + U32 + Value + 2 + diff --git a/indra/newview/llfloatermediafilter.cpp b/indra/newview/llfloatermediafilter.cpp new file mode 100644 index 000000000..00d989d44 --- /dev/null +++ b/indra/newview/llfloatermediafilter.cpp @@ -0,0 +1,153 @@ +/* + * @file llfloatermediafilter.cpp + * @brief Stupid floater for listing junk + * @author Cinder Biscuits + * + * Permission is hereby granted, free of charge, to any person or organization + * obtaining a copy of the software and accompanying documentation covered by + * this license (the "Software") to use, reproduce, display, distribute, + * execute, and transmit the Software, and to prepare derivative works of the + * Software, and to permit third-parties to whom the Software is furnished to + * do so, all subject to the following: + * + * The copyright notices in the Software and this entire statement, including + * the above license grant, this restriction and the following disclaimer, + * must be included in all copies of the Software, in whole or in part, and + * all derivative works of the Software, unless such copies or derivative + * works are solely in the form of machine-executable object code generated by + * a source language processor. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include "llviewerprecompiledheaders.h" +#include "llfloatermediafilter.h" + +#include "llnotificationsutil.h" +#include "llscrolllistctrl.h" +#include "llscrolllistitem.h" +#include "lltrans.h" +#include "lluictrlfactory.h" + +bool handle_add_callback(const LLSD& notification, const LLSD& response); +// TODO: Maybe add removal confirmation? +//bool handle_remove_callback(const LLSD& notification, const LLSD& response); + +LLFloaterMediaFilter::LLFloaterMediaFilter(const LLSD& key) +: LLFloater(key) +{ + mCommitCallbackRegistrar.add("MediaFilter.CommitAction", boost::bind(&LLFloaterMediaFilter::onCommitAction, this, _2)); + mMediaListConnection = LLMediaFilter::getInstance()->setMediaListUpdateCallback(boost::bind(&LLFloaterMediaFilter::updateLists, this, _1)); + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_media_lists.xml", NULL, false); +} + +LLFloaterMediaFilter::~LLFloaterMediaFilter() +{ + if (mMediaListConnection.connected()) + mMediaListConnection.disconnect(); +} + +BOOL LLFloaterMediaFilter::postBuild() +{ + mWhitelist = getChild("whitelist"); + mBlacklist = getChild("blacklist"); + updateLists(LLMediaFilter::WHITELIST); + updateLists(LLMediaFilter::BLACKLIST); + + return TRUE; +} + +void LLFloaterMediaFilter::updateLists(LLMediaFilter::EMediaList list) +{ + if (list == LLMediaFilter::WHITELIST && mWhitelist) + { + LLMediaFilter::string_list_t list = LLMediaFilter::getInstance()->getWhiteList(); + mWhitelist->clearRows(); + for (LLMediaFilter::string_list_t::const_iterator itr = list.begin(); itr != list.end(); ++itr) + { + LLSD element; + element["columns"][0]["column"] = "list"; + element["columns"][0]["value"] = (*itr); + mWhitelist->addElement(element); + } + } + if (list == LLMediaFilter::BLACKLIST && mBlacklist) + { + LLMediaFilter::string_list_t list = LLMediaFilter::getInstance()->getBlackList(); + mBlacklist->clearRows(); + for (LLMediaFilter::string_list_t::const_iterator itr = list.begin(); itr != list.end(); ++itr) + { + LLSD element; + element["columns"][0]["column"] = "list"; + element["columns"][0]["value"] = (*itr); + mBlacklist->addElement(element); + } + } +} + +void LLFloaterMediaFilter::onCommitAction(const LLSD& userdata) +{ + std::string chosen_item = userdata.asString(); + if (chosen_item == "AddToWhitelist") + { + LLSD payload, args; + args["LIST"] = LLTrans::getString("MediaFilterWhitelist"); + payload = true; + LLNotificationsUtil::add("AddToMediaList", args, payload, &handle_add_callback); + } + else if (chosen_item == "AddToBlacklist") + { + LLSD payload, args; + args["LIST"] = LLTrans::getString("MediaFilterBlacklist"); + payload = false; + LLNotificationsUtil::add("AddToMediaList", args, payload, &handle_add_callback); + } + else if (chosen_item == "RemoveFromWhitelist") + { + std::vector selected = mWhitelist->getAllSelected(); + if (!selected.empty()) + { + LLMediaFilter::string_vec_t domains; + for (std::vector::iterator itr = selected.begin(); itr != selected.end(); ++itr) + { + domains.push_back((*itr)->getColumn(0)->getValue().asString()); + } + LLMediaFilter::getInstance()->removeFromMediaList(domains, LLMediaFilter::WHITELIST); + } + } + else if (chosen_item == "RemoveFromBlacklist") + { + std::vector selected = mBlacklist->getAllSelected(); + if (!selected.empty()) + { + LLMediaFilter::string_vec_t domains; + for (std::vector::iterator itr = selected.begin(); itr != selected.end(); ++itr) + { + domains.push_back((*itr)->getColumn(0)->getValue().asString()); + } + LLMediaFilter::getInstance()->removeFromMediaList(domains, LLMediaFilter::BLACKLIST); + } + } +} + +bool handle_add_callback(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) + { + std::string url = response["url"].asString(); + if (notification["payload"].asBoolean()) + LLMediaFilter::getInstance()->addToMediaList(url, LLMediaFilter::WHITELIST); + else + LLMediaFilter::getInstance()->addToMediaList(url, LLMediaFilter::BLACKLIST); + + } + return false; +} diff --git a/indra/newview/llfloatermediafilter.h b/indra/newview/llfloatermediafilter.h new file mode 100644 index 000000000..a96750d7f --- /dev/null +++ b/indra/newview/llfloatermediafilter.h @@ -0,0 +1,55 @@ +/* + * @file LLFloaterMediaFilter.h + * @brief Stupid floater for listing junk + * @author Cinder Biscuits + * + * Permission is hereby granted, free of charge, to any person or organization + * obtaining a copy of the software and accompanying documentation covered by + * this license (the "Software") to use, reproduce, display, distribute, + * execute, and transmit the Software, and to prepare derivative works of the + * Software, and to permit third-parties to whom the Software is furnished to + * do so, all subject to the following: + * + * The copyright notices in the Software and this entire statement, including + * the above license grant, this restriction and the following disclaimer, + * must be included in all copies of the Software, in whole or in part, and + * all derivative works of the Software, unless such copies or derivative + * works are solely in the form of machine-executable object code generated by + * a source language processor. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef LL_FLOATERMEDIAFILTER_H +#define LL_FLOATERMEDIAFILTER_H + +#include "llfloater.h" +#include "llmediafilter.h" +#include + +class LLScrollListCtrl; + +class LLFloaterMediaFilter : public LLFloater, public LLFloaterSingleton +{ + friend class LLUISingleton >; +public: + LLFloaterMediaFilter(const LLSD& key); + BOOL postBuild(); +private: + ~LLFloaterMediaFilter(); + void updateLists(LLMediaFilter::EMediaList list); + void onCommitAction(const LLSD& userdata); + + LLScrollListCtrl* mWhitelist; + LLScrollListCtrl* mBlacklist; + boost::signals2::connection mMediaListConnection; +}; + +#endif // LL_FLOATERMEDIAFILTER_H diff --git a/indra/newview/llmediafilter.cpp b/indra/newview/llmediafilter.cpp new file mode 100644 index 000000000..4c1e30b6f --- /dev/null +++ b/indra/newview/llmediafilter.cpp @@ -0,0 +1,491 @@ +/* + * @file llmediafilter.h + * @brief Hyperbalistic SLU paranoia controls + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Sione Lomu. + * Copyright (C) 2014, Cinder Roxley. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llmediafilter.h" + +#include "llaudioengine.h" +#include "llchat.h" +#include "llfloaterchat.h" +#include "llnotifications.h" +#include "llnotificationsutil.h" +#include "llsdserialize.h" +#include "lltrans.h" +#include "llvieweraudio.h" +#include "llviewercontrol.h" +#include "llviewerparcelmgr.h" +#include "llviewerparcelmedia.h" + +const std::string MEDIALIST_XML = "medialist.xml"; +bool handle_audio_filter_callback(const LLSD& notification, const LLSD& response); +bool handle_media_filter_callback(const LLSD& notification, const LLSD& response, LLParcel* parcel); +std::string extractDomain(const std::string& in_url); + +void reportToChat(const std::string& message) +{ + LLChat chat; + chat.mText = message; + chat.mSourceType = CHAT_SOURCE_SYSTEM; + LLFloaterChat::addChat(chat, FALSE, FALSE); +} + +void LLMediaFilter::filterMediaUrl(LLParcel* parcel) +{ + if (!parcel) return; + const std::string url = parcel->getMediaURL(); + if (url.empty()) + { + return; + } + + const std::string domain = extractDomain(url); + mCurrentParcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + U32 enabled = gSavedSettings.getU32("MediaFilterEnable"); + + if (enabled > 1 && (filter(domain, WHITELIST) || filter(url, WHITELIST))) + { + LL_DEBUGS("MediaFilter") << "Media filter: URL allowed by whitelist: " << url << LL_ENDL; + LLViewerParcelMedia::play(parcel); + //mAudioState = PLAY; + } + else if (enabled && (filter(domain, BLACKLIST) || filter(url, BLACKLIST))) + { + LLNotifications::instance().add("MediaBlocked", LLSD().with("DOMAIN", domain)); + //mAudioState = STOP; + } + else if (enabled && isAlertActive()) + { + mMediaQueue = parcel; + } + else if (enabled > 1) + { + LL_DEBUGS("MediaFilter") << "Media Filter: Unhanded by lists. Toasting: " << url << LL_ENDL; + setAlertStatus(true); + LLSD args, payload; + args["MEDIA_TYPE"] = LLTrans::getString("media"); + args["URL"] = url; + args["DOMAIN"] = domain; + payload = url; + LLNotifications::instance().add("MediaAlert", args, payload, + boost::bind(&handle_media_filter_callback, _1, _2, parcel)); + } + else + { + LL_DEBUGS("MediaFilter") << "Media Filter: Skipping filters and playing " << url << LL_ENDL; + LLViewerParcelMedia::play(parcel); + //mAudioState = PLAY; + } +} + +void LLMediaFilter::filterAudioUrl(const std::string& url) +{ + if (url.empty()) + { + gAudiop->startInternetStream(url); + return; + } + if (url == mCurrentAudioURL) return; + + const std::string domain = extractDomain(url); + mCurrentParcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + U32 enabled = gSavedSettings.getU32("MediaFilterEnable"); + + if (enabled > 1 && (filter(domain, WHITELIST) || filter(url, WHITELIST))) + { + LL_DEBUGS("MediaFilter") << "Audio filter: URL allowed by whitelist: " << url << LL_ENDL; + gAudiop->startInternetStream(url); + } + else if (enabled && (filter(domain, BLACKLIST) || filter(url, BLACKLIST))) + { + LLNotifications::instance().add("MediaBlocked", LLSD().with("DOMAIN", domain)); + gAudiop->stopInternetStream(); + } + else if (enabled && isAlertActive()) + { + mAudioQueue = url; + } + else if (enabled > 1) + { + LL_DEBUGS("MediaFilter") << "Audio Filter: Unhanded by lists. Toasting: " << url << LL_ENDL; + setAlertStatus(true); + LLSD args, payload; + args["MEDIA_TYPE"] = LLTrans::getString("audio"); + args["URL"] = url; + args["DOMAIN"] = domain; + payload = url; + LLNotifications::instance().add("MediaAlert", args, payload, + boost::bind(&handle_audio_filter_callback, _1, _2)); + } + else + { + LL_DEBUGS("MediaFilter") << "Audio Filter: Skipping filters and playing: " << url << LL_ENDL; + gAudiop->startInternetStream(url); + } + +} + +bool LLMediaFilter::filter(const std::string& url, EMediaList list) +{ + string_list_t p_list; + if (list == WHITELIST) + p_list = mWhiteList; + else + p_list = mBlackList; + string_list_t::const_iterator find_itr = std::find(p_list.begin(), p_list.end(), url); + return (find_itr != p_list.end()); +} + +// List bizznizz +void LLMediaFilter::addToMediaList(const std::string& in_url, EMediaList list, bool extract) +{ + std::string url = extract ? extractDomain(in_url) : in_url; + if (url.empty()) + { + LL_INFOS("MediaFilter") << "No url found. Can't add to list." << LL_ENDL; + return; + } + + switch (list) + { + case WHITELIST: + // Check for duplicates + for (string_list_t::const_iterator itr = mWhiteList.begin(); itr != mWhiteList.end(); ++itr) + { + if (url == *itr) + { + LL_INFOS("MediaFilter") << "URL " << url << " already in list!" << LL_ENDL; + return; + } + } + mWhiteList.push_back(url); + mMediaListUpdate(WHITELIST); + break; + case BLACKLIST: + for (string_list_t::const_iterator itr = mBlackList.begin(); itr != mBlackList.end(); ++itr) + { + if (url == *itr) + { + LL_INFOS("MediaFilter") << "URL " << url << "already in list!" << LL_ENDL; + return; + } + } + mBlackList.push_back(url); + mMediaListUpdate(BLACKLIST); + break; + } + saveMediaFilterToDisk(); +} + +void LLMediaFilter::init() +{ + loadMediaFilterFromDisk(); +} + +void LLMediaFilter::removeFromMediaList(string_vec_t domains, EMediaList list) +{ + switch (list) + { + case WHITELIST: + for (string_vec_t::const_iterator itr = domains.begin(); itr != domains.end(); ++itr) + mWhiteList.remove(*itr); + mMediaListUpdate(WHITELIST); + break; + case BLACKLIST: + for (string_vec_t::const_iterator itr = domains.begin(); itr != domains.end(); ++itr) + mBlackList.remove(*itr); + mMediaListUpdate(BLACKLIST); + break; + + } + saveMediaFilterToDisk(); +} + +void LLMediaFilter::loadMediaFilterFromDisk() +{ + const std::string medialist_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, MEDIALIST_XML); + mWhiteList.clear(); + mBlackList.clear(); + + LLSD medialist; + if (LLFile::isfile(medialist_filename)) + { + llifstream medialist_xml(medialist_filename); + LLSDSerialize::fromXML(medialist, medialist_xml); + medialist_xml.close(); + } + else + LL_INFOS("MediaFilter") << medialist_filename << " not found." << LL_ENDL; + + for (LLSD::array_const_iterator p_itr = medialist.beginArray(); + p_itr != medialist.endArray(); + ++p_itr) + { + LLSD itr = (*p_itr); + /// I hate this string shit more than you could ever imagine, + /// but I'm retaining it for backwards and cross-compatibility. :| + if (itr["action"].asString() == "allow") + { + LL_DEBUGS("MediaFilter") << "Adding " << itr["domain"].asString() << " to whitelist." << LL_ENDL; + mWhiteList.push_back(itr["domain"].asString()); + } + else if (itr["action"].asString() == "deny") + { + LL_DEBUGS("MediaFilter") << "Adding " << itr["domain"].asString() << " to blacklist." << LL_ENDL; + mBlackList.push_back(itr["domain"].asString()); + } + } +} + +void LLMediaFilter::saveMediaFilterToDisk() +{ + const std::string medialist_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, MEDIALIST_XML); + + LLSD medialist_llsd; + for (string_list_t::const_iterator itr = mWhiteList.begin(); itr != mWhiteList.end(); ++itr) + { + LLSD item; + item["domain"] = *itr; + item["action"] = "allow"; // <- $*#@()&%@ + medialist_llsd.append(item); + } + for (string_list_t::const_iterator itr = mBlackList.begin(); itr != mBlackList.end(); ++itr) + { + LLSD item; + item["domain"] = *itr; + item["action"] = "deny"; // sigh. + medialist_llsd.append(item); + } + + llofstream medialist; + medialist.open(medialist_filename); + LLSDSerialize::toPrettyXML(medialist_llsd, medialist); + medialist.close(); +} + +bool handle_audio_filter_callback(const LLSD& notification, const LLSD& response) +{ + LLMediaFilter::getInstance()->setAlertStatus(false); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + const std::string url = notification["payload"].asString(); + const std::string queue = LLMediaFilter::getInstance()->getQueuedAudio(); + switch(option) + { + case 3: // Whitelist domain + LLMediaFilter::getInstance()->addToMediaList(url, LLMediaFilter::WHITELIST); + case 0: // Allow + if (gAudiop != NULL) + { + if (LLMediaFilter::getInstance()->getCurrentParcel() == LLViewerParcelMgr::getInstance()->getAgentParcel()) + { + gAudiop->startInternetStream(url); + } + } + break; + case 2: // Blacklist domain + LLMediaFilter::getInstance()->addToMediaList(url, LLMediaFilter::BLACKLIST); + case 1: // Deny + if (gAudiop != NULL) + { + if (LLMediaFilter::getInstance()->getCurrentParcel() == LLViewerParcelMgr::getInstance()->getAgentParcel()) + { + gAudiop->stopInternetStream(); + } + } + break; + /*case 4: //Whitelist url + LLMediaFilter::getInstance()->addToMediaList(url, LLMediaFilter::WHITELIST, false); + if (gAudiop != NULL) + { + if (LLMediaFilter::getInstance()->getCurrentParcel() == LLViewerParcelMgr::getInstance()->getAgentParcel()) + { + gAudiop->startInternetStream(url); + } + } + break; + case 5: //Blacklist url + LLMediaFilter::getInstance()->addToMediaList(url, LLMediaFilter::BLACKLIST, false); + if (gAudiop != NULL) + { + if (LLMediaFilter::getInstance()->getCurrentParcel() == LLViewerParcelMgr::getInstance()->getAgentParcel()) + { + gAudiop->stopInternetStream(); + } + } + break;*/ + default: + // We should never be able to get here. + llassert(option); + break; + } + if (!queue.empty()) + { + LLMediaFilter::getInstance()->clearQueuedAudio(); + LLMediaFilter::getInstance()->filterAudioUrl(queue); + } + else if (LLMediaFilter::getInstance()->getQueuedMedia()) + { + LLMediaFilter::getInstance()->clearQueuedMedia(); + LLParcel* queued_media = LLMediaFilter::getInstance()->getQueuedMedia(); + if (queued_media) + LLMediaFilter::getInstance()->filterMediaUrl(queued_media); + } + else if (LLMediaFilter::getInstance()->getQueuedMediaCommand()) + { + U32 command = LLMediaFilter::getInstance()->getQueuedMediaCommand(); + if (command == PARCEL_MEDIA_COMMAND_STOP) + { + LLViewerParcelMedia::stop(); + } + else if (command == PARCEL_MEDIA_COMMAND_PAUSE) + { + LLViewerParcelMedia::pause(); + } + else if (command == PARCEL_MEDIA_COMMAND_UNLOAD) + { + LLViewerParcelMedia::stop(); + } + else if (command == PARCEL_MEDIA_COMMAND_TIME) + { + //LLViewerParcelMedia::seek(LLViewerParcelMedia::sMediaCommandTime); + } + LLMediaFilter::getInstance()->setQueuedMediaCommand(0); + } + + return false; +} + +bool handle_media_filter_callback(const LLSD& notification, const LLSD& response, LLParcel* parcel) +{ + LLMediaFilter::getInstance()->setAlertStatus(false); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + const std::string url = notification["payload"].asString(); + LLParcel* queue = LLMediaFilter::getInstance()->getQueuedMedia(); + switch(option) + { + case 2: // Whitelist domain + LLMediaFilter::getInstance()->addToMediaList(url, LLMediaFilter::WHITELIST); + case 0: // Allow + if (LLMediaFilter::getInstance()->getCurrentParcel() == LLViewerParcelMgr::getInstance()->getAgentParcel()) + LLViewerParcelMedia::play(parcel); + break; + case 3: // Blacklist domain + LLMediaFilter::getInstance()->addToMediaList(url, LLMediaFilter::BLACKLIST); + case 1: // Deny + break; + case 4: //Whitelist url + LLMediaFilter::getInstance()->addToMediaList(url, LLMediaFilter::WHITELIST, false); + if (LLMediaFilter::getInstance()->getCurrentParcel() == LLViewerParcelMgr::getInstance()->getAgentParcel()) + LLViewerParcelMedia::play(parcel); + break; + case 5: + LLMediaFilter::getInstance()->addToMediaList(url, LLMediaFilter::BLACKLIST, false); + break; + default: + // We should never be able to get here. + llassert(option); + break; + } + const std::string audio_queue = LLMediaFilter::getInstance()->getQueuedAudio(); + if (queue) + { + LLMediaFilter::getInstance()->clearQueuedMedia(); + LLMediaFilter::getInstance()->filterMediaUrl(queue); + } + else if (!audio_queue.empty()) + { + LLMediaFilter::getInstance()->clearQueuedAudio(); + LLMediaFilter::getInstance()->filterAudioUrl(audio_queue); + } + else if (LLMediaFilter::getInstance()->getQueuedMediaCommand()) + { + U32 command = LLMediaFilter::getInstance()->getQueuedMediaCommand(); + if (command == PARCEL_MEDIA_COMMAND_STOP) + { + LLViewerParcelMedia::stop(); + } + else if (command == PARCEL_MEDIA_COMMAND_PAUSE) + { + LLViewerParcelMedia::pause(); + } + else if (command == PARCEL_MEDIA_COMMAND_UNLOAD) + { + LLViewerParcelMedia::stop(); + } + else if (command == PARCEL_MEDIA_COMMAND_TIME) + { + //LLViewerParcelMedia::seek(LLViewerParcelMedia::sMediaCommandTime); + } + LLMediaFilter::getInstance()->setQueuedMediaCommand(0); + } + + return false; +} + +// Local Functions +std::string extractDomain(const std::string& in_url) +{ + std::string url = in_url; + // First, find and strip any protocol prefix. + size_t pos = url.find("//"); + + if (pos != std::string::npos) + { + S32 count = url.size()-pos+2; + url = url.substr(pos+2, count); + } + + // Now, look for a / marking a local part; if there is one, + // strip it and anything after. + pos = url.find("/"); + + if (pos != std::string::npos) + { + url = url.substr(0, pos); + } + + // If there's a user{,:password}@ part, remove it, + pos = url.find("@"); + + if (pos != std::string::npos) + { + S32 count = url.size()-pos+1; + url = url.substr(pos+1, count); + } + + // Finally, find and strip away any port number. This has to be done + // after the previous step, or else the extra : for the password, + // if supplied, will confuse things. + pos = url.find(":"); + + if (pos != std::string::npos) + { + url = url.substr(0, pos); + } + + // Now map the whole thing to lowercase, since domain names aren't + // case sensitive. + std::transform(url.begin(), url.end(),url.begin(), ::tolower); + return url; +} diff --git a/indra/newview/llmediafilter.h b/indra/newview/llmediafilter.h new file mode 100644 index 000000000..eb6f509b3 --- /dev/null +++ b/indra/newview/llmediafilter.h @@ -0,0 +1,92 @@ +/* + * @file llmediafilter.h + * @brief Definitions for paranoia controls + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Sione Lomu. + * Copyright (C) 2014, Cinder Roxley. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * $/LicenseInfo$ + */ + +#ifndef LL_MEDIAFILTER_H +#define LL_MEDIAFILTER_H + +#include "llparcel.h" + +class LLMediaFilter : public LLSingleton +{ + friend class LLSingleton; +public: + typedef enum e_media_list { + WHITELIST, + BLACKLIST + } EMediaList; + + typedef std::list string_list_t; + typedef std::vector string_vec_t; + typedef boost::signals2::signal media_list_signal_t; + media_list_signal_t mMediaListUpdate; + boost::signals2::connection setMediaListUpdateCallback(const media_list_signal_t::slot_type& cb) + { + return mMediaListUpdate.connect(cb); + }; + + void filterMediaUrl(LLParcel* parcel); + void filterAudioUrl(const std::string& url); + //void filterSharedMediaUrl + + void addToMediaList(const std::string& in_url, EMediaList list, bool extract = true); + void removeFromMediaList(string_vec_t, EMediaList list); + string_list_t getWhiteList() { return mWhiteList; }; + string_list_t getBlackList() { return mBlackList; }; + U32 getQueuedMediaCommand() { return mMediaCommandQueue; }; + void setQueuedMediaCommand(U32 command) { mMediaCommandQueue = command; }; + bool isAlertActive() { return mAlertActive; }; + void setAlertStatus(bool active) { mAlertActive = active; }; + LLParcel* getCurrentParcel() { return mCurrentParcel; }; + LLParcel* getQueuedMedia() { return mMediaQueue; }; + void clearQueuedMedia() { mMediaQueue = NULL; }; + std::string getQueuedAudio() { return mAudioQueue; }; + void clearQueuedAudio() { mAudioQueue.clear(); }; + void setCurrentAudioURL(const std::string url ) { mCurrentAudioURL = url; }; + void clearCurrentAudioURL() { mCurrentAudioURL.clear(); }; + bool filter(const std::string& url, EMediaList list); + void init(); + +private: + void loadMediaFilterFromDisk(); + void saveMediaFilterToDisk(); + + string_list_t mBlackList; + string_list_t mWhiteList; + U32 mMediaCommandQueue; + LLParcel* mCurrentParcel; + LLParcel* mMediaQueue; + std::string mAudioQueue; + std::string mCurrentAudioURL; + std::string mCurrentMediaURL; + bool mAlertActive; + //typedef enum e_audio_state { + // PLAY, + // STOP + //} EAudioState; + //EAudioState mAudioState; + +}; + +#endif // LL_MEDIAFILTER_H diff --git a/indra/newview/llmenucommands.cpp b/indra/newview/llmenucommands.cpp index ed0278f67..109801206 100644 --- a/indra/newview/llmenucommands.cpp +++ b/indra/newview/llmenucommands.cpp @@ -74,6 +74,7 @@ #include "llfloaterland.h" #include "llfloaterlandholdings.h" #include "llfloatermap.h" +#include "llfloatermediafilter.h" #include "llfloatermemleak.h" #include "llfloatermessagelog.h" #include "llfloatermute.h" @@ -112,7 +113,6 @@ #include "rlvfloaters.h" // [/RLVa:LF] #include "shfloatermediaticker.h" -#include "slfloatermediafilter.h" void handle_chat() { @@ -231,7 +231,7 @@ struct MenuFloaterDict : public LLSingleton registerFloater ("inspect"); registerFloater ("joystick"); registerFloater ("lag meter"); - registerFloater ("media filter"); + registerFloater ("media filter"); registerFloater ("mini map"); registerFloater ("movement controls"); registerFloater ("mute list"); diff --git a/indra/newview/lloverlaybar.cpp b/indra/newview/lloverlaybar.cpp index 9bbf00567..b616f6c7e 100644 --- a/indra/newview/lloverlaybar.cpp +++ b/indra/newview/lloverlaybar.cpp @@ -479,7 +479,7 @@ void LLOverlayBar::toggleMediaPlay(void*) LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); if (parcel) { - LLViewerParcelMedia::sIsUserAction = true; + //LLViewerParcelMedia::sIsUserAction = true; LLViewerParcelMedia::play(parcel); } } @@ -505,7 +505,7 @@ void LLOverlayBar::toggleMusicPlay(void*) // stream is stopped, it doesn't return the right thing - commenting out for now. // if ( gAudiop->isInternetStreamPlaying() == 0 ) { - LLViewerParcelMedia::sIsUserAction = true; + //LLViewerParcelMedia::sIsUserAction = true; LLViewerParcelMedia::playStreamingMusic(parcel); } } diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 9d17dc7d0..679bdb5c5 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -140,6 +140,7 @@ #include "llkeyboard.h" #include "llloginhandler.h" // gLoginHandler, SLURL support #include "llpanellogin.h" +#include "llmediafilter.h" #include "llmutelist.h" #include "llnotify.h" #include "llpanelavatar.h" @@ -1723,6 +1724,7 @@ bool idle_startup() if (STATE_MULTIMEDIA_INIT == LLStartUp::getStartupState()) { LLStartUp::multimediaInit(); + LLMediaFilter::getInstance()->init(); LLStartUp::setStartupState( STATE_FONT_INIT ); display_startup(); return FALSE; @@ -2633,7 +2635,6 @@ bool idle_startup() { set_startup_status(1.0, "", ""); display_startup(); - LLViewerParcelMedia::loadDomainFilterList(); // Let the map know about the inventory. LLFloaterWorldMap* floater_world_map = gFloaterWorldMap; diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index dc62522cf..0df255f8d 100644 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -49,11 +49,11 @@ #include "llviewerwindow.h" #include "llfirstuse.h" #include "llpluginclassmedia.h" +#include "llmediafilter.h" #include "llnotify.h" #include "llsdserialize.h" #include "llaudioengine.h" #include "lloverlaybar.h" -#include "slfloatermediafilter.h" #include "llstreamingaudio.h" // Static Variables @@ -61,12 +61,7 @@ S32 LLViewerParcelMedia::sMediaParcelLocalID = 0; LLUUID LLViewerParcelMedia::sMediaRegionID; viewer_media_t LLViewerParcelMedia::sMediaImpl; -bool LLViewerParcelMedia::sIsUserAction = false; -bool LLViewerParcelMedia::sMediaFilterListLoaded = false; -LLSD LLViewerParcelMedia::sMediaFilterList; -std::set LLViewerParcelMedia::sMediaQueries; -std::set LLViewerParcelMedia::sAllowedMedia; -std::set LLViewerParcelMedia::sDeniedMedia; +F32 LLViewerParcelMedia::sMediaCommandTime = 0; // Local functions bool callback_play_media(const LLSD& notification, const LLSD& response, LLParcel* parcel); @@ -151,7 +146,15 @@ void LLViewerParcelMedia::update(LLParcel* parcel) // Only play if the media types are the same. if(sMediaImpl->getMimeType() == parcel->getMediaType()) { - play(parcel); + if (gSavedSettings.getU32("MediaFilterEnable")) + { + LL_DEBUGS("MediaFilter") << "Filtering media URL: " << parcel->getMediaURL() << LL_ENDL; + LLMediaFilter::getInstance()->filterMediaUrl(parcel); + } + else + { + play(parcel); + } } else @@ -187,7 +190,7 @@ void LLViewerParcelMedia::update(LLParcel* parcel) } // static -void LLViewerParcelMedia::play(LLParcel* parcel, bool filter) +void LLViewerParcelMedia::play(LLParcel* parcel) { lldebugs << "LLViewerParcelMedia::play" << llendl; @@ -197,17 +200,7 @@ void LLViewerParcelMedia::play(LLParcel* parcel, bool filter) return; std::string media_url = parcel->getMediaURL(); - LLStringUtil::trim(media_url); - - if (!media_url.empty() && gSavedSettings.getBOOL("MediaEnableFilter") && (filter || !allowedMedia(media_url))) - { - // If filtering is needed or in case media_url just changed - // to something we did not yet approve. - LLViewerParcelMediaAutoPlay::playStarted(); - filterMedia(parcel, 0); - return; - } - + std::string media_current_url = parcel->getMediaCurrentURL(); std::string mime_type = parcel->getMediaType(); LLUUID placeholder_texture_id = parcel->getMediaID(); U8 media_auto_scale = parcel->getMediaAutoScale(); @@ -399,13 +392,27 @@ void LLViewerParcelMedia::processParcelMediaCommandMessage( LLMessageSystem *msg // stop if( command == PARCEL_MEDIA_COMMAND_STOP ) { - stop(); + if (!LLMediaFilter::getInstance()->isAlertActive()) + { + stop(); + } + else + { + LLMediaFilter::getInstance()->setQueuedMediaCommand(PARCEL_MEDIA_COMMAND_STOP); + } } else // pause if( command == PARCEL_MEDIA_COMMAND_PAUSE ) { - pause(); + if (!LLMediaFilter::getInstance()->isAlertActive()) + { + pause(); + } + else + { + LLMediaFilter::getInstance()->setQueuedMediaCommand(PARCEL_MEDIA_COMMAND_PAUSE); + } } else // play @@ -419,14 +426,29 @@ void LLViewerParcelMedia::processParcelMediaCommandMessage( LLMessageSystem *msg else { LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - play(parcel); + if (gSavedSettings.getU32("MediaFilterEnable")) + { + LL_DEBUGS("MediaFilter") << "PARCEL_MEDIA_COMMAND_PLAY: Filtering media URL: " << parcel->getMediaURL() << LL_ENDL; + LLMediaFilter::getInstance()->filterMediaUrl(parcel); + } + else + { + play(parcel); + } } } else // unload if( command == PARCEL_MEDIA_COMMAND_UNLOAD ) { - stop(); + if (!LLMediaFilter::getInstance()->isAlertActive()) + { + stop(); + } + else + { + LLMediaFilter::getInstance()->setQueuedMediaCommand(PARCEL_MEDIA_COMMAND_UNLOAD); + } } } @@ -435,10 +457,26 @@ void LLViewerParcelMedia::processParcelMediaCommandMessage( LLMessageSystem *msg if(sMediaImpl.isNull()) { LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - play(parcel); + if (gSavedSettings.getU32("MediaFilterEnable")) + { + LL_DEBUGS("MediaFilter") << "PARCEL_MEDIA_COMMAND_TIME: Filtering media URL: " << parcel->getMediaURL() << LL_ENDL; + LLMediaFilter::getInstance()->filterMediaUrl(parcel); + } + else + { + play(parcel); + } } + } + if (!LLMediaFilter::getInstance()->isAlertActive()) + { seek(time); } + else + { + LLMediaFilter::getInstance()->setQueuedMediaCommand(PARCEL_MEDIA_COMMAND_TIME); + sMediaCommandTime = time; + } } ////////////////////////////////////////////////////////////////////////////////////////// @@ -492,7 +530,18 @@ void LLViewerParcelMedia::processParcelMediaUpdate( LLMessageSystem *msg, void * parcel->setMediaAutoScale(media_auto_scale); parcel->setMediaLoop(media_loop); - play(parcel); + if (sMediaImpl.notNull()) + { + if (gSavedSettings.getU32("MediaFilterEnable")) + { + LL_DEBUGS("MediaFilter") << "Parcel media changed. Filtering media URL: " << parcel->getMediaURL() << LL_ENDL; + LLMediaFilter::getInstance()->filterMediaUrl(parcel); + } + else + { + play(parcel); + } + } } } } @@ -623,37 +672,37 @@ void LLViewerParcelMedia::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent case MEDIA_EVENT_CLOSE_REQUEST: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLOSE_REQUEST" << LL_ENDL; - }; + } break; case MEDIA_EVENT_PICK_FILE_REQUEST: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PICK_FILE_REQUEST" << LL_ENDL; - }; + } break; case MEDIA_EVENT_GEOMETRY_CHANGE: { - LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_GEOMETRY_CHANGE" << LL_ENDL; - }; + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_GEOMETRY_CHANGE, uuid is " << self->getClickUUID() << LL_ENDL; + } break; case MEDIA_EVENT_AUTH_REQUEST: { - LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_AUTH_REQUEST" << LL_ENDL; - }; + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_AUTH_REQUEST, url " << self->getAuthURL() << ", realm " << self->getAuthRealm() << LL_ENDL; + } break; case MEDIA_EVENT_LINK_HOVERED: { - LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_LINK_HOVERED" << LL_ENDL; + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_LINK_HOVERED, hover text is: " << self->getHoverText() << LL_ENDL; }; break; default: { LL_WARNS("Media") << "Media event: unknown event type" << LL_ENDL; - }; + } }; } @@ -663,7 +712,14 @@ bool callback_play_media(const LLSD& notification, const LLSD& response, LLParce if (option == 0) { gSavedSettings.setBOOL("AudioStreamingMedia", TRUE); - LLViewerParcelMedia::play(parcel); + if (gSavedSettings.getU32("MediaFilterEnable")) + { + LLMediaFilter::getInstance()->filterMediaUrl(parcel); + } + else + { + LLViewerParcelMedia::play(parcel); + } } else { @@ -694,11 +750,10 @@ void LLViewerParcelMedia::playStreamingMusic(LLParcel* parcel, bool filter) { std::string music_url = parcel->getMusicURL(); LLStringUtil::trim(music_url); - if (!music_url.empty() && gSavedSettings.getBOOL("MediaEnableFilter") && (filter || !allowedMedia(music_url))) + if (gSavedSettings.getU32("MediaFilterEnable")) { - // If filtering is needed or in case music_url just changed - // to something we did not yet approve. - filterMedia(parcel, 1); + LL_DEBUGS("MediaFilter") << "Filtering media URL: " << parcel->getMediaURL() << LL_ENDL; + LLMediaFilter::getInstance()->filterAudioUrl(music_url); } else if (gAudiop) { @@ -726,401 +781,3 @@ void LLViewerParcelMedia::stopStreamingMusic() LLOverlayBar::audioFilterStop(); } } - -bool LLViewerParcelMedia::allowedMedia(std::string media_url) -{ - LLStringUtil::trim(media_url); - std::string domain = extractDomain(media_url); - LLHost host; - host.setHostByName(domain); - std::string ip = host.getIPString(); - if (sAllowedMedia.count(domain) || sAllowedMedia.count(ip)) - { - return true; - } - std::string server; - for (S32 i = 0; i < (S32)sMediaFilterList.size(); i++) - { - server = sMediaFilterList[i]["domain"].asString(); - if (server == domain || server == ip) - { - if (sMediaFilterList[i]["action"].asString() == "allow") - { - return true; - } - else - { - return false; - } - } - } - return false; -} - -void LLViewerParcelMedia::filterMedia(LLParcel* parcel, U32 type) -{ - std::string media_action; - std::string media_url; - std::string domain; - std::string ip; - - if (parcel != LLViewerParcelMgr::getInstance()->getAgentParcel()) - { - // The parcel just changed (may occur right out after a TP) - sIsUserAction = false; - return; - } - - if (type == 0) - { - media_url = parcel->getMediaURL(); - } - else - { - media_url = parcel->getMusicURL(); - } - LLStringUtil::trim(media_url); - - domain = extractDomain(media_url); - - if (sMediaQueries.count(domain) > 0) - { - sIsUserAction = false; - return; - } - - LLHost host; - host.setHostByName(domain); - ip = host.getIPString(); - - if (sIsUserAction) - { - // This was a user manual request to play this media, so give - // it another chance... - sIsUserAction = false; - bool dirty = false; - if (sDeniedMedia.count(domain)) - { - sDeniedMedia.erase(domain); - dirty = true; - } - if (sDeniedMedia.count(ip)) - { - sDeniedMedia.erase(ip); - dirty = true; - } - if (dirty && SLFloaterMediaFilter::findInstance()) - { - SLFloaterMediaFilter::getInstance()->setDirty(); - } - } - - if (media_url.empty()) - { - media_action = "allow"; - } - else if (!sMediaFilterListLoaded || sDeniedMedia.count(domain) || sDeniedMedia.count(ip)) - { - media_action = "ignore"; - } - else if (sAllowedMedia.count(domain) || sAllowedMedia.count(ip)) - { - media_action = "allow"; - } - else - { - std::string server; - for (S32 i = 0; i < (S32)sMediaFilterList.size(); i++) - { - server = sMediaFilterList[i]["domain"].asString(); - if (server == domain || server == ip) - { - media_action = sMediaFilterList[i]["action"].asString(); - break; - } - } - } - - if (media_action == "allow") - { - if (type == 0) - { - play(parcel, false); - } - else - { - playStreamingMusic(parcel, false); - } - return; - } - if (media_action == "ignore") - { - if (type == 1) - { - LLViewerParcelMedia::stopStreamingMusic(); - } - return; - } - - LLSD args; - if (ip != domain && domain.find('/') == std::string::npos) - { - args["DOMAIN"] = domain + " (" + ip + ")"; - } - else - { - args["DOMAIN"] = domain; - } - - if (media_action == "deny") - { - LLNotificationsUtil::add("MediaBlocked", args); - if (type == 1) - { - LLViewerParcelMedia::stopStreamingMusic(); - } - // So to avoid other "blocked" messages later in the session - // for this url should it be requested again by a script. - // We don't add the IP, on purpose (want to show different - // blocks for different domains pointing to the same IP). - sDeniedMedia.insert(domain); - } - else - { - sMediaQueries.insert(domain); - args["URL"] = media_url; - if (type == 0) - { - args["TYPE"] = "media"; - } - else - { - args["TYPE"] = "audio"; - } - LLNotificationsUtil::add("MediaAlert", args, LLSD(), boost::bind(callback_media_alert, _1, _2, parcel, type, domain)); - } -} - -void callback_media_alert(const LLSD ¬ification, const LLSD &response, LLParcel* parcel, U32 type, std::string domain) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - - LLHost host; - host.setHostByName(domain); - std::string ip = host.getIPString(); - - LLSD args; - if (ip != domain && domain.find('/') == std::string::npos) - { - args["DOMAIN"] = domain + " (" + ip + ")"; - } - else - { - args["DOMAIN"] = domain; - } - - if (option == 0 || option == 3) // Allow or Whitelist - { - LLViewerParcelMedia::sAllowedMedia.insert(domain); - if (option == 3) // Whitelist - { - LLSD newmedia; - newmedia["domain"] = domain; - newmedia["action"] = "allow"; - LLViewerParcelMedia::sMediaFilterList.append(newmedia); - if (ip != domain && domain.find('/') == std::string::npos) - { - newmedia["domain"] = ip; - LLViewerParcelMedia::sMediaFilterList.append(newmedia); - } - LLViewerParcelMedia::saveDomainFilterList(); - args["LISTED"] = "whitelisted"; - LLNotificationsUtil::add("MediaListed", args); - } - if (type == 0) - { - LLViewerParcelMedia::play(parcel, false); - } - else - { - LLViewerParcelMedia::playStreamingMusic(parcel, false); - } - } - else - { - if (type == 1) - { - LLViewerParcelMedia::stopStreamingMusic(); - } - else - { - LLViewerParcelMedia::stopStreamingMusic(); - } - if (option == 1 || option == 2) // Deny or Blacklist - { - LLViewerParcelMedia::sDeniedMedia.insert(domain); - if (ip != domain && domain.find('/') == std::string::npos) - { - LLViewerParcelMedia::sDeniedMedia.insert(ip); - } - - if (option == 1) // Deny - { - LLNotificationsUtil::add("MediaBlocked", args); - } - else // Blacklist - { - LLSD newmedia; - newmedia["domain"] = domain; - newmedia["action"] = "deny"; - LLViewerParcelMedia::sMediaFilterList.append(newmedia); - if (ip != domain && domain.find('/') == std::string::npos) - { - newmedia["domain"] = ip; - LLViewerParcelMedia::sMediaFilterList.append(newmedia); - } - LLViewerParcelMedia::saveDomainFilterList(); - args["LISTED"] = "blacklisted"; - LLNotificationsUtil::add("MediaListed", args); - } - } - } - - LLViewerParcelMedia::sMediaQueries.erase(domain); - if (SLFloaterMediaFilter::findInstance()) SLFloaterMediaFilter::getInstance()->setDirty(); -} - -void LLViewerParcelMedia::saveDomainFilterList() -{ - std::string medialist_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "media_filter.xml"); - - llofstream medialistFile(medialist_filename); - LLSDSerialize::toPrettyXML(sMediaFilterList, medialistFile); - medialistFile.close(); -} - -bool LLViewerParcelMedia::loadDomainFilterList() -{ - sMediaFilterListLoaded = true; - - std::string medialist_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "media_filter.xml"); - - if (!LLFile::isfile(medialist_filename)) - { - LLSD emptyllsd; - llofstream medialistFile(medialist_filename); - LLSDSerialize::toPrettyXML(emptyllsd, medialistFile); - medialistFile.close(); - } - - if (LLFile::isfile(medialist_filename)) - { - llifstream medialistFile(medialist_filename); - LLSDSerialize::fromXML(sMediaFilterList, medialistFile); - medialistFile.close(); - if (SLFloaterMediaFilter::findInstance()) SLFloaterMediaFilter::getInstance()->setDirty(); - return true; - } - else - { - return false; - } -} - -void LLViewerParcelMedia::clearDomainFilterList() -{ - sMediaFilterList.clear(); - sAllowedMedia.clear(); - sDeniedMedia.clear(); - saveDomainFilterList(); - LLNotificationsUtil::add("MediaFiltersCleared"); - if (SLFloaterMediaFilter::findInstance()) SLFloaterMediaFilter::getInstance()->setDirty(); -} - -std::string LLViewerParcelMedia::extractDomain(std::string url) -{ - static std::string last_region = "@"; - - if (url.empty()) - { - return url; - } - - LLStringUtil::toLower(url); - - size_t pos = url.find("//"); - - if (pos != std::string::npos) - { - size_t count = url.size() - pos + 2; - url = url.substr(pos + 2, count); - } - - // Check that there is at least one slash in the URL and add a trailing - // one if not (for media/audio URLs such as http://mydomain.net) - if (url.find('/') == std::string::npos) - { - url += '/'; - } - - // If there's a user:password@ part, remove it - pos = url.find('@'); - if (pos != std::string::npos && pos < url.find('/')) // if '@' is not before the first '/', then it's not a user:password - { - size_t count = url.size() - pos + 1; - url = url.substr(pos + 1, count); - } - - //Singu note: The call to getHostName() freezes the viewer for a few seconds if the region has no reverse DNS... - // Avoid calling it three times therefore -- not to mention that if it fails, it returns an empty string which - // does NOT mean that it should match the current url as if the current url contains the current regions hostname! - std::string const hostname = gAgent.getRegion()->getHost().getHostName(); - if ((!hostname.empty() && url.find(hostname) == 0) || url.find(last_region) == 0) - { - // This must be a scripted object rezzed in the region: - // extend the concept of "domain" to encompass the - // scripted object server id and avoid blocking all other - // objects at once in this region... - - // Get rid of any port number - pos = url.find('/'); // We earlier made sure that there's one - url = hostname + url.substr(pos); - - pos = url.find('?'); - if (pos != std::string::npos) - { - // Get rid of any parameter - url = url.substr(0, pos); - } - - pos = url.rfind('/'); - if (pos != std::string::npos) - { - // Get rid of the filename, if any, keeping only the server + path - url = url.substr(0, pos); - } - } - else - { - pos = url.find(':'); - if (pos != std::string::npos && pos < url.find('/')) - { - // Keep anything before the port number and strip the rest off - url = url.substr(0, pos); - } - else - { - pos = url.find('/'); // We earlier made sure that there's one - url = url.substr(0, pos); - } - } - - // Remember this region, so to cope with requests occuring just after a - // TP out of it. - if (!hostname.empty()) // Singu note: also make sure that last_region doesn't become empty. - { - last_region = hostname; - } - - return url; -} diff --git a/indra/newview/llviewerparcelmedia.h b/indra/newview/llviewerparcelmedia.h index f6c85bf3b..ff954c37a 100644 --- a/indra/newview/llviewerparcelmedia.h +++ b/indra/newview/llviewerparcelmedia.h @@ -57,21 +57,13 @@ class LLViewerParcelMedia : public LLViewerMediaObserver // called when the agent's parcel has a new URL, or the agent has // walked on to a new parcel with media - static void play(LLParcel* parcel, bool filter = true); + static void play(LLParcel* parcel); // user clicked play button in media transport controls static void playStreamingMusic(LLParcel* parcel, bool filter = true); // play the parcel music stream static void stopStreamingMusic(); // stop the parcel music stream - static void filterMedia(LLParcel* parcel, U32 type); // type: 0 = media, 1 = streaming music - static bool allowedMedia(std::string media_url); - - static bool loadDomainFilterList(); - static void saveDomainFilterList(); - static void clearDomainFilterList(); - static std::string extractDomain(std::string url); - static void stop(); // user clicked stop button in media transport controls @@ -102,13 +94,9 @@ class LLViewerParcelMedia : public LLViewerMediaObserver static LLUUID sMediaRegionID; // HACK: this will change with Media on a Prim static viewer_media_t sMediaImpl; - - static bool sIsUserAction; - static bool sMediaFilterListLoaded; - static LLSD sMediaFilterList; - static std::set sMediaQueries; - static std::set sAllowedMedia; - static std::set sDeniedMedia; + + // Media Filter + static F32 sMediaCommandTime; }; diff --git a/indra/newview/skins/default/xui/en-us/floater_media_lists.xml b/indra/newview/skins/default/xui/en-us/floater_media_lists.xml new file mode 100644 index 000000000..a29793d1a --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/floater_media_lists.xml @@ -0,0 +1,216 @@ + + + + Enter domain or URL to always allow: + + + Enter domain or URL to never allow: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/notifications.xml b/indra/newview/skins/default/xui/en-us/notifications.xml index b71f3505f..d352a063f 100644 --- a/indra/newview/skins/default/xui/en-us/notifications.xml +++ b/indra/newview/skins/default/xui/en-us/notifications.xml @@ -179,6 +179,26 @@ You may choose to allow or deny the corresponding domain or in-world scripted ob text="Whitelist"/> + + +Enter a domain name to be added to the [LIST]: + confirm +
+ +