diff --git a/indra/llinventory/llparcel.cpp b/indra/llinventory/llparcel.cpp index 1962b91cd..0144ffa00 100644 --- a/indra/llinventory/llparcel.cpp +++ b/indra/llinventory/llparcel.cpp @@ -195,8 +195,6 @@ void LLParcel::init(const LLUUID &owner_id, mMediaID.setNull(); mMediaAutoScale = 0; mMediaLoop = TRUE; - mObscureMedia = 1; - mObscureMusic = 1; mMediaWidth = 0; mMediaHeight = 0; setMediaCurrentURL(LLStringUtil::null); @@ -692,8 +690,8 @@ void LLParcel::packMessage(LLSD& msg) msg["auto_scale"] = getMediaAutoScale(); msg["media_loop"] = getMediaLoop(); msg["media_current_url"] = getMediaCurrentURL(); - msg["obscure_media"] = getObscureMedia(); - msg["obscure_music"] = getObscureMusic(); + msg["obscure_media"] = FALSE; // OBSOLETE - no longer used + msg["obscure_music"] = FALSE; // OBSOLETE - no longer used msg["media_id"] = getMediaID(); msg["media_allow_navigate"] = getMediaAllowNavigate(); msg["media_prevent_camera_zoom"] = getMediaPreventCameraZoom(); @@ -757,16 +755,12 @@ void LLParcel::unpackMessage(LLMessageSystem* msg) msg->getS32("MediaData", "MediaWidth", mMediaWidth); msg->getS32("MediaData", "MediaHeight", mMediaHeight); msg->getU8 ( "MediaData", "MediaLoop", mMediaLoop ); - msg->getU8 ( "MediaData", "ObscureMedia", mObscureMedia ); - msg->getU8 ( "MediaData", "ObscureMusic", mObscureMusic ); } else { setMediaType(std::string("video/vnd.secondlife.qt.legacy")); setMediaDesc(std::string("No Description available without Server Upgrade")); mMediaLoop = true; - mObscureMedia = true; - mObscureMusic = true; } if(msg->getNumberOfBlocks("MediaLinkSharing") > 0) @@ -1232,8 +1226,6 @@ void LLParcel::clearParcel() setMediaDesc(LLStringUtil::null); setMediaAutoScale(0); setMediaLoop(TRUE); - mObscureMedia = 1; - mObscureMusic = 1; mMediaWidth = 0; mMediaHeight = 0; setMediaCurrentURL(LLStringUtil::null); diff --git a/indra/llinventory/llparcel.h b/indra/llinventory/llparcel.h index 8faa673c3..fcbd01b9a 100644 --- a/indra/llinventory/llparcel.h +++ b/indra/llinventory/llparcel.h @@ -243,8 +243,6 @@ public: void setMediaID(const LLUUID& id) { mMediaID = id; } void setMediaAutoScale ( U8 flagIn ) { mMediaAutoScale = flagIn; } void setMediaLoop (U8 loop) { mMediaLoop = loop; } - void setObscureMedia( U8 flagIn ) { mObscureMedia = flagIn; } - void setObscureMusic( U8 flagIn ) { mObscureMusic = flagIn; } void setMediaWidth(S32 width); void setMediaHeight(S32 height); void setMediaCurrentURL(const std::string& url); @@ -351,8 +349,6 @@ public: U8 getMediaAutoScale() const { return mMediaAutoScale; } U8 getMediaLoop() const { return mMediaLoop; } const std::string& getMediaCurrentURL() const { return mMediaCurrentURL; } - U8 getObscureMedia() const { return mObscureMedia; } - U8 getObscureMusic() const { return mObscureMusic; } U8 getMediaURLFilterEnable() const { return mMediaURLFilterEnable; } LLSD getMediaURLFilterList() const { return mMediaURLFilterList; } U8 getMediaAllowNavigate() const { return mMediaAllowNavigate; } @@ -644,8 +640,6 @@ protected: U8 mMediaAutoScale; U8 mMediaLoop; std::string mMediaCurrentURL; - U8 mObscureMedia; - U8 mObscureMusic; LLUUID mMediaID; U8 mMediaURLFilterEnable; LLSD mMediaURLFilterList; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index bb4bb62d7..d06efa9e2 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -64,6 +64,7 @@ include_directories( ) set(viewer_SOURCE_FILES + slfloatermediafilter.cpp floaterlocalassetbrowse.cpp aoremotectrl.cpp floaterao.cpp @@ -536,6 +537,7 @@ set(viewer_HEADER_FILES CMakeLists.txt ViewerInstall.cmake + slfloatermediafilter.h floaterlocalassetbrowse.h aoremotectrl.h floaterao.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index c69f84889..3fb8a4433 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -10,6 +10,34 @@ + MediaEnableFilter + + Comment + Enable media domain filtering + Persist + 1 + Type + Boolean + Value + 0 + + MediaFilterRect + + Comment + Rectangle for Media Filter floater + Persist + 1 + Type + Rect + Value + + 0 + 100 + 100 + 100 + + + UseServersideWindlightSettings Comment diff --git a/indra/newview/llmediaremotectrl.cpp b/indra/newview/llmediaremotectrl.cpp index a62973a83..877ba0de5 100644 --- a/indra/newview/llmediaremotectrl.cpp +++ b/indra/newview/llmediaremotectrl.cpp @@ -169,7 +169,7 @@ void LLMediaRemoteCtrl::enableMediaButtons() { // Set the tooltip // Put this text into xui file - media_url = parcel->getObscureMedia() ? mControls->getString("media_hidden_label") : parcel->getMediaURL(); + media_url = parcel->getMediaURL(); media_type = parcel->getMediaType(); play_media_enabled = true; diff --git a/indra/newview/lloverlaybar.cpp b/indra/newview/lloverlaybar.cpp index badeed15f..7decd1eaa 100644 --- a/indra/newview/lloverlaybar.cpp +++ b/indra/newview/lloverlaybar.cpp @@ -477,6 +477,23 @@ void LLOverlayBar::setCancelTPButtonVisible(BOOL b, const std::string& label) } +//////////////////////////////////////////////////////////////////////////////// +void LLOverlayBar::audioFilterPlay() +{ + if (gOverlayBar && gOverlayBar->mMusicState != PLAYING) + { + gOverlayBar->mMusicState = PLAYING; + } +} + +void LLOverlayBar::audioFilterStop() +{ + if (gOverlayBar && gOverlayBar->mMusicState != STOPPED) + { + gOverlayBar->mMusicState = STOPPED; + } +} + //////////////////////////////////////////////////////////////////////////////// // static media helpers // *TODO: Move this into an audio manager abstraction diff --git a/indra/newview/lloverlaybar.h b/indra/newview/lloverlaybar.h index 53c0a8f9f..8f9c8ed2f 100644 --- a/indra/newview/lloverlaybar.h +++ b/indra/newview/lloverlaybar.h @@ -78,6 +78,9 @@ public: static void onClickResetView(void* data); static void onClickFlycam(void* data); + static void audioFilterPlay(); + static void audioFilterStop(); + //static media helper functions static void toggleMediaPlay(void*); static void toggleMusicPlay(void*); diff --git a/indra/newview/llpanellandaudio.cpp b/indra/newview/llpanellandaudio.cpp index 1252c2cd9..dd38bdbd4 100644 --- a/indra/newview/llpanellandaudio.cpp +++ b/indra/newview/llpanellandaudio.cpp @@ -74,8 +74,7 @@ LLPanelLandAudio::LLPanelLandAudio(LLParcelSelectionHandle& parcel) mCheckSoundLocal(NULL), mSoundHelpButton(NULL), mRadioVoiceChat(NULL), - mMusicURLEdit(NULL), - mMusicUrlCheck(NULL) + mMusicURLEdit(NULL) { } @@ -100,9 +99,6 @@ BOOL LLPanelLandAudio::postBuild() mMusicURLEdit = getChild("music_url"); childSetCommitCallback("music_url", onCommitAny, this); - mMusicUrlCheck = getChild("hide_music_url"); - childSetCommitCallback("hide_music_url", onCommitAny, this); - return TRUE; } @@ -126,12 +122,6 @@ void LLPanelLandAudio::refresh() mMusicURLEdit->setText(parcel->getMusicURL()); mMusicURLEdit->setEnabled( can_change_media ); - mMusicUrlCheck->set( parcel->getObscureMusic() ); - mMusicUrlCheck->setEnabled( can_change_media ); - - bool obscure_music = ! can_change_media && parcel->getObscureMusic(); - mMusicURLEdit->setDrawAsterixes( obscure_music ); - mCheckSoundLocal->set( parcel->getSoundLocal() ); mCheckSoundLocal->setEnabled( can_change_media ); @@ -166,8 +156,6 @@ void LLPanelLandAudio::onCommitAny(LLUICtrl*, void *userdata) BOOL sound_local = self->mCheckSoundLocal->get(); int voice_setting = self->mRadioVoiceChat->getSelectedIndex(); std::string music_url = self->mMusicURLEdit->getText(); - U8 obscure_music = self->mMusicUrlCheck->get(); - BOOL voice_enabled; BOOL voice_estate_chan; @@ -197,7 +185,6 @@ void LLPanelLandAudio::onCommitAny(LLUICtrl*, void *userdata) parcel->setParcelFlag(PF_USE_ESTATE_VOICE_CHAN, voice_estate_chan); parcel->setParcelFlag(PF_SOUND_LOCAL, sound_local); parcel->setMusicURL(music_url); - parcel->setObscureMusic(obscure_music); // Send current parcel data upstream to server LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel ); diff --git a/indra/newview/llpanellandmedia.cpp b/indra/newview/llpanellandmedia.cpp index ab2e6fc10..417d14897 100644 --- a/indra/newview/llpanellandmedia.cpp +++ b/indra/newview/llpanellandmedia.cpp @@ -74,8 +74,7 @@ LLPanelLandMedia::LLPanelLandMedia(LLParcelSelectionHandle& parcel) mMediaSizeCtrlLabel(NULL), mMediaTextureCtrl(NULL), mMediaAutoScaleCheck(NULL), - mMediaLoopCheck(NULL), - mMediaUrlCheck(NULL) + mMediaLoopCheck(NULL) { } @@ -101,9 +100,6 @@ BOOL LLPanelLandMedia::postBuild() mMediaLoopCheck = getChild("media_loop"); childSetCommitCallback("media_loop", onCommitAny, this ); - mMediaUrlCheck = getChild("hide_media_url"); - childSetCommitCallback("hide_media_url", onCommitAny, this ); - mMediaURLEdit = getChild("media_url"); childSetCommitCallback("media_url", onCommitAny, this ); @@ -186,25 +182,6 @@ void LLPanelLandMedia::refresh() mMediaTypeCombo->setEnabled( can_change_media ); childSetText("mime_type", mime_type); - mMediaUrlCheck->set( parcel->getObscureMedia() ); - mMediaUrlCheck->setEnabled( can_change_media ); - - // don't display urls if you're not able to change it - // much requested change in forums so people can't 'steal' urls - // NOTE: bug#2009 means this is still vunerable - however, bug - // should be closed since this bug opens up major security issues elsewhere. - bool obscure_media = ! can_change_media && parcel->getObscureMedia(); - - // Special code to disable asterixes for html type - if(mime_type == "text/html") - { - obscure_media = false; - mMediaUrlCheck->set( 0 ); - mMediaUrlCheck->setEnabled( false ); - } - - mMediaURLEdit->setDrawAsterixes( obscure_media ); - mMediaAutoScaleCheck->set( parcel->getMediaAutoScale () ); mMediaAutoScaleCheck->setEnabled ( can_change_media ); @@ -369,7 +346,6 @@ void LLPanelLandMedia::onCommitAny(LLUICtrl*, void *userdata) std::string mime_type = self->childGetText("mime_type"); U8 media_auto_scale = self->mMediaAutoScaleCheck->get(); U8 media_loop = self->mMediaLoopCheck->get(); - U8 obscure_media = self->mMediaUrlCheck->get(); F32 media_reset_time = (F32)self->mMediaResetCtrl->get(); S32 media_width = (S32)self->mMediaWidthCtrl->get(); S32 media_height = (S32)self->mMediaHeightCtrl->get(); @@ -392,7 +368,6 @@ void LLPanelLandMedia::onCommitAny(LLUICtrl*, void *userdata) parcel->setMediaID(media_id); parcel->setMediaAutoScale ( media_auto_scale ); parcel->setMediaLoop ( media_loop ); - parcel->setObscureMedia( obscure_media ); parcel->setMediaURLFilterEnable(navigate_filter); parcel->setMediaAllowNavigate(navigate_allow); parcel->setMediaURLTimeout(media_reset_time); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index ab14d91d3..3a843e5c6 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -2846,6 +2846,8 @@ bool idle_startup() { set_startup_status(1.0, "", ""); + LLViewerParcelMedia::loadDomainFilterList(); + // Let the map know about the inventory. if(gFloaterWorldMap) { diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 089f52af8..8adbde0d5 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -61,6 +61,7 @@ #include "llworld.h" #include "pipeline.h" #include "llviewerjoystick.h" +#include "llviewerparcelmedia.h" #include "llviewerparcelmgr.h" #include "llparcel.h" #include "llnotify.h" @@ -313,7 +314,7 @@ static bool handleAudioStreamMusicChanged(const LLSD& newvalue) // otherwise music will briefly stop if ( !gAudiop->isInternetStreamPlaying() ) { - gAudiop->startInternetStream(LLViewerParcelMgr::getInstance()->getAgentParcel()->getMusicURL()); + LLViewerParcelMedia::playStreamingMusic(LLViewerParcelMgr::getInstance()->getAgentParcel()); } } } diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index f5f3513d8..6fb3fa9be 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -252,6 +252,7 @@ #include "llfloaterdisplayname.h" #include "llavatarnamecache.h" #include "floaterao.h" +#include "slfloatermediafilter.h" #include "hippogridmanager.h" @@ -6470,6 +6471,10 @@ class LLShowFloater : public view_listener_t { LLFloaterMute::toggleInstance(); } + else if (floater_name == "media filter") + { + SLFloaterMediaFilter::toggleInstance(); + } else if (floater_name == "camera controls") { LLFloaterCamera::toggleInstance(); @@ -6629,6 +6634,10 @@ class LLFloaterVisible : public view_listener_t { new_value = LLFloaterMute::instanceVisible(); } + else if (floater_name == "media filter") + { + new_value = SLFloaterMediaFilter::instanceVisible(); + } else if (floater_name == "camera controls") { new_value = LLFloaterCamera::instanceVisible(); diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index 2b6ba910f..be304fc9f 100644 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -46,17 +46,27 @@ #include "llviewerwindow.h" #include "llfirstuse.h" #include "llpluginclassmedia.h" +#include "llnotify.h" +#include "llsdserialize.h" +#include "llaudioengine.h" +#include "lloverlaybar.h" +#include "slfloatermediafilter.h" // Static Variables 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; // Local functions bool callback_play_media(const LLSD& notification, const LLSD& response, LLParcel* parcel); - +void callback_media_alert(const LLSD& notification, const LLSD& response, LLParcel* parcel, U32 type, std::string domain); // static void LLViewerParcelMedia::initClass() @@ -175,7 +185,7 @@ void LLViewerParcelMedia::update(LLParcel* parcel) } // static -void LLViewerParcelMedia::play(LLParcel* parcel) +void LLViewerParcelMedia::play(LLParcel* parcel, bool filter) { lldebugs << "LLViewerParcelMedia::play" << llendl; @@ -185,7 +195,17 @@ void LLViewerParcelMedia::play(LLParcel* parcel) return; std::string media_url = parcel->getMediaURL(); - std::string media_current_url = parcel->getMediaCurrentURL(); + 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 mime_type = parcel->getMediaType(); LLUUID placeholder_texture_id = parcel->getMediaID(); U8 media_auto_scale = parcel->getMediaAutoScale(); @@ -575,3 +595,421 @@ void LLViewerParcelMediaNavigationObserver::onNavigateComplete( const EventType& } */ + +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 filtering is needed or in case music_url just changed + // to something we did not yet approve. + filterMedia(parcel, 1); + } + else if (gAudiop) + { + LLStringUtil::trim(music_url); + gAudiop->startInternetStream(music_url); + if (music_url.empty()) + { + LLOverlayBar::audioFilterStop(); + } + else + { + LLOverlayBar::audioFilterPlay(); + } + } +} + +void LLViewerParcelMedia::stopStreamingMusic() +{ + if (gAudiop) + { + gAudiop->stopInternetStream(); + 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::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") + { + LLNotifications::instance().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"; + } + LLNotifications::instance().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"; + LLNotifications::instance().add("MediaListed", args); + } + if (type == 0) + { + LLViewerParcelMedia::play(parcel, false); + } + else + { + LLViewerParcelMedia::playStreamingMusic(parcel, false); + } + } + else 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 (type == 1) + { + LLViewerParcelMedia::stopStreamingMusic(); + } + if (option == 1) // Deny + { + LLNotifications::instance().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"; + LLNotifications::instance().add("MediaListed", args); + } + } + + LLViewerParcelMedia::sMediaQueries.erase(domain); + SLFloaterMediaFilter::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(); + SLFloaterMediaFilter::setDirty(); + return true; + } + else + { + return false; + } +} + +void LLViewerParcelMedia::clearDomainFilterList() +{ + sMediaFilterList.clear(); + sAllowedMedia.clear(); + sDeniedMedia.clear(); + saveDomainFilterList(); + LLNotifications::instance().add("MediaFiltersCleared"); + SLFloaterMediaFilter::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); + } + + if (url.find(gAgent.getRegion()->getHost().getHostName()) == 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 = gAgent.getRegion()->getHost().getHostName() + 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. + last_region = gAgent.getRegion()->getHost().getHostName(); + + return url; +} diff --git a/indra/newview/llviewerparcelmedia.h b/indra/newview/llviewerparcelmedia.h index 0f1e85c78..7531a0f59 100644 --- a/indra/newview/llviewerparcelmedia.h +++ b/indra/newview/llviewerparcelmedia.h @@ -35,6 +35,9 @@ #include "llviewermedia.h" +// For use by other patches so they know that media filtering is implemented. +#define MEDIA_FILTERING 1 + class LLMessageSystem; class LLParcel; class LLViewerParcelMediaNavigationObserver; @@ -54,8 +57,20 @@ 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); + static void play(LLParcel* parcel, bool filter = true); // 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 @@ -85,6 +100,13 @@ 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; }; diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 40928c7be..72a3f159d 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -86,7 +86,7 @@ LLPointer sBlockedImage; LLPointer sPassImage; // Local functions -void optionally_start_music(const std::string& music_url); +void optionally_start_music(LLParcel* parcel); void callback_start_music(S32 option, void* data); void optionally_prepare_video(const LLParcel *parcelp); void callback_prepare_video(S32 option, void* data); @@ -1689,7 +1689,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use { if (music_url.substr(0,7) == "http://") { - optionally_start_music(music_url); + optionally_start_music(parcel); } else { @@ -1717,18 +1717,18 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use }; } -void optionally_start_music(const std::string& music_url) +void optionally_start_music(LLParcel* parcel) { if (gSavedSettings.getBOOL("AudioStreamingMusic")) { // Make the user click the start button on the overlay bar. JC - // llinfos << "Starting parcel music " << music_url << llendl; + // llinfos << "Starting parcel music " << parcel->getMusicURL() << llendl; // now only play music when you enter a new parcel if the control is in PLAY state // changed as part of SL-4878 - if ( gOverlayBar && gOverlayBar->musicPlaying()) + if (gOverlayBar && gOverlayBar->musicPlaying()) { - gAudiop->startInternetStream(music_url); + LLViewerParcelMedia::playStreamingMusic(parcel); } } } diff --git a/indra/newview/skins/default/xui/en-us/floater_about_land.xml b/indra/newview/skins/default/xui/en-us/floater_about_land.xml index 9da335451..f1fd3617d 100644 --- a/indra/newview/skins/default/xui/en-us/floater_about_land.xml +++ b/indra/newview/skins/default/xui/en-us/floater_about_land.xml @@ -918,32 +918,18 @@ Only large parcels can be listed in search. right="-12" scale_image="true" width="70" /> - + width="120"> Return to Home URL in: - Minutes + minutes - + + + Domains in bold are in the persistent list (i.e. they are whitelisted or blacklisted). + + + Domains in italics are in the session list (i.e. they are temporarily allowed or denied). + + + + + + + + + + +