/** * @file llviewerparcelmedia.cpp * @brief Handlers for multimedia on a per-parcel basis * * $LicenseInfo:firstyear=2007&license=viewergpl$ * * Copyright (c) 2007-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or * online at * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ #include "llviewerprecompiledheaders.h" #include "llviewerparcelmedia.h" #include "kokuastreamingaudio.h" #include "llagent.h" #include "llviewercontrol.h" #include "llviewermedia.h" #include "llviewerregion.h" #include "llparcel.h" #include "llviewerparcelmgr.h" #include "lluuid.h" #include "message.h" #include "llviewermediafocus.h" #include "llviewerparcelmediaautoplay.h" #include "llviewerwindow.h" #include "llfirstuse.h" #include "llpluginclassmedia.h" #include "llnotify.h" #include "llsdserialize.h" #include "llmemory.h" #include "lloverlaybar.h" #include "slfloatermediafilter.h" #include "llinventorymodel.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; LLPointer LLViewerParcelMedia::sSavedMediaInfo; // 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() { LLMessageSystem* msg = gMessageSystem; msg->setHandlerFunc("ParcelMediaCommandMessage", processParcelMediaCommandMessage ); msg->setHandlerFunc("ParcelMediaUpdate", processParcelMediaUpdate ); LLViewerParcelMediaAutoPlay::initClass(); } //static void LLViewerParcelMedia::cleanupClass() { // This needs to be destroyed before global destructor time. sMediaImpl = NULL; } ////////////////////////////////////////////////////////////////////////////////////////// // static void LLViewerParcelMedia::update(LLParcel* parcel) { if (/*LLViewerMedia::hasMedia()*/ true) { // we have a player if (parcel) { if(!gAgent.getRegion()) { sMediaRegionID = LLUUID() ; stop() ; LL_DEBUGS("Media") << "no agent region, bailing out." << LL_ENDL; return ; } // we're in a parcel bool new_parcel = false; S32 parcelid = parcel->getLocalID(); LLUUID regionid = gAgent.getRegion()->getRegionID(); if (parcelid != sMediaParcelLocalID || regionid != sMediaRegionID) { LL_DEBUGS("Media") << "New parcel, parcel id = " << parcelid << ", region id = " << regionid << LL_ENDL; sMediaParcelLocalID = parcelid; sMediaRegionID = regionid; new_parcel = true; } std::string mediaUrl = std::string ( parcel->getMediaURL () ); std::string mediaCurrentUrl = std::string( parcel->getMediaCurrentURL()); // First use warning if( ! mediaUrl.empty() && gSavedSettings.getWarning("FirstStreamingVideo") ) { LLNotifications::instance().add("ParcelCanPlayMedia", LLSD(), LLSD(), boost::bind(callback_play_media, _1, _2, parcel)); return; } // if we have a current (link sharing) url, use it instead if (mediaCurrentUrl != "" && parcel->getMediaType() == "text/html") { mediaUrl = mediaCurrentUrl; } LLStringUtil::trim(mediaUrl); // If no parcel media is playing, nothing left to do if(sMediaImpl.isNull()) { return; } // Media is playing...has something changed? else if (( sMediaImpl->getMediaURL() != mediaUrl ) || ( sMediaImpl->getMediaTextureID() != parcel->getMediaID() ) || ( sMediaImpl->getMimeType() != parcel->getMediaType() )) { // Only play if the media types are the same. if(sMediaImpl->getMimeType() == parcel->getMediaType()) { play(parcel); } else { stop(); } } } else { stop(); } } /* else { // no audio player, do a first use dialog if there is media here if (parcel) { std::string mediaUrl = std::string ( parcel->getMediaURL () ); if (!mediaUrl.empty ()) { if (gSavedSettings.getWarning("QuickTimeInstalled")) { gSavedSettings.setWarning("QuickTimeInstalled", FALSE); LLNotifications::instance().add("NoQuickTime" ); }; } } } */ } // static void LLViewerParcelMedia::play(LLParcel* parcel, bool filter, const ECommandOrigin origin) { lldebugs << "LLViewerParcelMedia::play" << llendl; if (!parcel) return; if (!gSavedSettings.getBOOL("AudioStreamingVideo")) return; std::string media_url = parcel->getMediaURL(); LLStringUtil::trim(media_url); if (!media_url.empty() && gSavedSettings.getBOOL("MediaEnableFilter") && filter && (!allowedMedia(media_url) || origin == COMMAND_ORIGIN_REMOTE)) { // If filtering is needed or in case media_url just changed // to something we did not yet approve. LLViewerParcelMediaAutoPlay::playStarted(); filterMedia(parcel, 0, origin); return; } std::string mime_type = parcel->getMediaType(); LLUUID placeholder_texture_id = parcel->getMediaID(); U8 media_auto_scale = parcel->getMediaAutoScale(); U8 media_loop = parcel->getMediaLoop(); S32 media_width = parcel->getMediaWidth(); S32 media_height = parcel->getMediaHeight(); // Debug print // LL_DEBUGS("Media") << "Play media type : " << mime_type << ", url : " << media_url << LL_ENDL; if(sMediaImpl) { // If the url and mime type are the same, call play again if(sMediaImpl->getMediaURL() == media_url && sMediaImpl->getMimeType() == mime_type && sMediaImpl->getMediaTextureID() == placeholder_texture_id) { LL_DEBUGS("Media") << "playing with existing url " << media_url << LL_ENDL; sMediaImpl->play(); } // Else if the texture id's are the same, navigate and rediscover type // MBW -- This causes other state from the previous parcel (texture size, autoscale, and looping) to get re-used incorrectly. // It's also not really necessary -- just creating a new instance is fine. // else if(sMediaImpl->getMediaTextureID() == placeholder_texture_id) // { // sMediaImpl->navigateTo(media_url, mime_type, true); // } else { // Since the texture id is different, we need to generate a new impl LL_DEBUGS("Media") << "new media impl with mime type " << mime_type << ", url " << media_url << LL_ENDL; // Delete the old one first so they don't fight over the texture. sMediaImpl->stop(); sMediaImpl = LLViewerMedia::newMediaImpl(media_url, placeholder_texture_id, media_width, media_height, media_auto_scale, media_loop, mime_type); } } else { // There is no media impl, make a new one sMediaImpl = LLViewerMedia::newMediaImpl(media_url, placeholder_texture_id, media_width, media_height, media_auto_scale, media_loop, mime_type); } LLFirstUse::useMedia(); LLViewerParcelMediaAutoPlay::playStarted(); } // static void LLViewerParcelMedia::stop() { if(sMediaImpl.isNull()) { return; } // We need to remove the media HUD if it is up. LLViewerMediaFocus::getInstance()->clearFocus(); // This will kill the media instance. sMediaImpl->stop(); sMediaImpl = NULL; } // static void LLViewerParcelMedia::pause() { if(sMediaImpl.isNull()) { return; } sMediaImpl->pause(); } // static void LLViewerParcelMedia::start() { if(sMediaImpl.isNull()) { return; } sMediaImpl->start(); LLFirstUse::useMedia(); LLViewerParcelMediaAutoPlay::playStarted(); } // static void LLViewerParcelMedia::seek(F32 time) { if(sMediaImpl.isNull()) { return; } sMediaImpl->seek(time); } // static void LLViewerParcelMedia::focus(bool focus) { sMediaImpl->focus(focus); } // static LLViewerMediaImpl::EMediaStatus LLViewerParcelMedia::getStatus() { LLViewerMediaImpl::EMediaStatus result = LLViewerMediaImpl::MEDIA_NONE; if(sMediaImpl.notNull() && sMediaImpl->hasMedia()) { result = sMediaImpl->getMediaPlugin()->getStatus(); } return result; } // static std::string LLViewerParcelMedia::getMimeType() { return sMediaImpl.notNull() ? sMediaImpl->getMimeType() : "none/none"; } viewer_media_t LLViewerParcelMedia::getParcelMedia() { return sMediaImpl; } ////////////////////////////////////////////////////////////////////////////////////////// // static void LLViewerParcelMedia::processParcelMediaCommandMessage( LLMessageSystem *msg, void ** ) { // extract the agent id // LLUUID agent_id; // msg->getUUID( agent_id ); U32 flags; U32 command; F32 time; msg->getU32( "CommandBlock", "Flags", flags ); msg->getU32( "CommandBlock", "Command", command); msg->getF32( "CommandBlock", "Time", time ); if (flags &( (1<getAgentParcel(); play(parcel, true, COMMAND_ORIGIN_REMOTE); } } else // unload if( command == PARCEL_MEDIA_COMMAND_UNLOAD ) { stop(); } } if (flags & (1<getAgentParcel(); play(parcel, true, COMMAND_ORIGIN_REMOTE); } seek(time); } } ////////////////////////////////////////////////////////////////////////////////////////// // static void LLViewerParcelMedia::processParcelMediaUpdate( LLMessageSystem *msg, void ** ) { LLUUID media_id; std::string media_url; std::string media_type; S32 media_width = 0; S32 media_height = 0; U8 media_auto_scale = FALSE; U8 media_loop = FALSE; msg->getUUID( "DataBlock", "MediaID", media_id ); char media_url_buffer[257]; msg->getString( "DataBlock", "MediaURL", 255, media_url_buffer ); media_url = media_url_buffer; msg->getU8("DataBlock", "MediaAutoScale", media_auto_scale); LL_DEBUGS("MediaFilter") << "New media texture id: " << media_id << LL_ENDL; if (msg->has("DataBlockExtended")) // do we have the extended data? { char media_type_buffer[257]; msg->getString("DataBlockExtended", "MediaType", 255, media_type_buffer); media_type = media_type_buffer; msg->getU8("DataBlockExtended", "MediaLoop", media_loop); msg->getS32("DataBlockExtended", "MediaWidth", media_width); msg->getS32("DataBlockExtended", "MediaHeight", media_height); } LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); if (parcel) { LLViewerParcelMediaInfo* new_info = new LLViewerParcelMediaInfo(media_url, media_type, media_id, media_width, media_height, media_auto_scale, media_loop); LLViewerParcelMediaInfo* current_info = new LLViewerParcelMediaInfo(parcel); if (new_info != current_info) { if (!sSavedMediaInfo || (sSavedMediaInfo && !sSavedMediaInfo->sameParcel(parcel))) { // only save if no previously saved media info, because // we want to remeber the original parcel media info. sSavedMediaInfo = current_info; } // temporarily store these new values in the parcel new_info->applyToParcel(parcel); play(parcel, true, COMMAND_ORIGIN_REMOTE); } } } //static void LLViewerParcelMedia::undoParcelMediaUpdate() { LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); if (sSavedMediaInfo.notNull() && parcel) { sSavedMediaInfo->applyToParcel(parcel); } sSavedMediaInfo = NULL; } // Static ///////////////////////////////////////////////////////////////////////////////////////// void LLViewerParcelMedia::sendMediaNavigateMessage(const std::string& url) { std::string region_url = gAgent.getRegion()->getCapability("ParcelNavigateMedia"); if (!region_url.empty()) { // send navigate event to sim for link sharing LLSD body; body["agent-id"] = gAgent.getID(); body["local-id"] = LLViewerParcelMgr::getInstance()->getAgentParcel()->getLocalID(); body["url"] = url; LLHTTPClient::post(region_url, body, new LLHTTPClient::Responder); } else { llwarns << "can't get ParcelNavigateMedia capability" << llendl; } } ///////////////////////////////////////////////////////////////////////////////////////// // inherited from LLViewerMediaObserver // virtual void LLViewerParcelMedia::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) { switch(event) { case MEDIA_EVENT_CONTENT_UPDATED: { // LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CONTENT_UPDATED " << LL_ENDL; }; break; case MEDIA_EVENT_TIME_DURATION_UPDATED: { // LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_TIME_DURATION_UPDATED, time is " << self->getCurrentTime() << " of " << self->getDuration() << LL_ENDL; }; break; case MEDIA_EVENT_SIZE_CHANGED: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_SIZE_CHANGED " << LL_ENDL; }; break; case MEDIA_EVENT_CURSOR_CHANGED: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CURSOR_CHANGED, new cursor is " << self->getCursorName() << LL_ENDL; }; break; case MEDIA_EVENT_NAVIGATE_BEGIN: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_BEGIN " << LL_ENDL; }; break; case MEDIA_EVENT_NAVIGATE_COMPLETE: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_COMPLETE, result string is: " << self->getNavigateResultString() << LL_ENDL; }; break; case MEDIA_EVENT_PROGRESS_UPDATED: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PROGRESS_UPDATED, loading at " << self->getProgressPercent() << "%" << LL_ENDL; }; break; case MEDIA_EVENT_STATUS_TEXT_CHANGED: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_STATUS_TEXT_CHANGED, new status text is: " << self->getStatusText() << LL_ENDL; }; break; case MEDIA_EVENT_LOCATION_CHANGED: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_LOCATION_CHANGED, new uri is: " << self->getLocation() << LL_ENDL; }; break; case MEDIA_EVENT_CLICK_LINK_HREF: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << self->getClickTarget() << "\", uri is " << self->getClickURL() << LL_ENDL; }; break; case MEDIA_EVENT_CLICK_LINK_NOFOLLOW: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is " << self->getClickURL() << LL_ENDL; }; break; case MEDIA_EVENT_PLUGIN_FAILED: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PLUGIN_FAILED" << LL_ENDL; }; break; case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PLUGIN_FAILED_LAUNCH" << LL_ENDL; }; break; case MEDIA_EVENT_NAME_CHANGED: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAME_CHANGED" << LL_ENDL; }; break; }; } bool callback_play_media(const LLSD& notification, const LLSD& response, LLParcel* parcel) { S32 option = LLNotification::getSelectedOption(notification, response); if (option == 0) { gSavedSettings.setBOOL("AudioStreamingVideo", TRUE); LLViewerParcelMedia::play(parcel); } else { gSavedSettings.setBOOL("AudioStreamingVideo", FALSE); } gSavedSettings.setWarning("FirstStreamingVideo", FALSE); return false; } // TODO: observer /* void LLViewerParcelMediaNavigationObserver::onNavigateComplete( const EventType& event_in ) { std::string url = event_in.getStringValue(); if (mCurrentURL != url && ! mFromMessage) { LLViewerParcelMedia::sendMediaNavigateMessage(url); } mCurrentURL = url; mFromMessage = false; } */ 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, COMMAND_ORIGIN_LOCAL); } else if (gAudioStream) { LLStringUtil::trim(music_url); gAudioStream->startInternetStream(music_url); if (music_url.empty()) { LLOverlayBar::audioFilterStop(); } else { LLOverlayBar::audioFilterPlay(); } } } void LLViewerParcelMedia::stopStreamingMusic() { if (gAudioStream) { gAudioStream->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)) { 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, const ECommandOrigin origin) { 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); LL_DEBUGS("MediaFilter") << "Requested " << (type == 0 ? "media" : "music") << "-URL: " << media_url << LL_ENDL; 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 == 0) { undoParcelMediaUpdate(); } else if (type == 1) { LLViewerParcelMedia::stopStreamingMusic(); } return; } // skip local-originating play commands, unless the url is blacklisted. if (gSavedSettings.getBOOL("MediaFilterOnlyRemoteCommands") && (origin != COMMAND_ORIGIN_REMOTE) && (media_action != "ignore")) { sAllowedMedia.insert(domain); SLFloaterMediaFilter::setDirty(); if (type == 0) { play(parcel, false); } else { playStreamingMusic(parcel, false); } 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 == 0) { undoParcelMediaUpdate(); } 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 == 0) { LLViewerParcelMedia::undoParcelMediaUpdate(); } else 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); } std::string current_region = gAgent.getRegion()->getHost().getHostName(); if (!current_region.size()) { current_region = gAgent.getRegion()->getHost().getIPString(); } if (url.find(current_region) == 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 = current_region + 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(); if (!last_region.size()) { last_region = gAgent.getRegion()->getHost().getIPString(); } return url; } LLViewerParcelMediaInfo::LLViewerParcelMediaInfo(const std::string url, const std::string type, const LLUUID media_id, const S32 width, const S32 height, const U8 scale, const U8 loop) : mMediaURL(url), mMediaType(type), mMediaID(media_id), mMediaWidth(width), mMediaHeight(height), mMediaAutoScale(scale), mMediaLoop(loop) { LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); mParcelLocalID = parcel ? parcel->getLocalID() : 0; } LLViewerParcelMediaInfo::LLViewerParcelMediaInfo(const LLParcel* parcel) { mMediaURL = parcel->getMediaURL(); mMediaType = parcel->getMediaType(); mMediaID = parcel->getMediaID(); mMediaWidth = parcel->getMediaWidth(); mMediaHeight = parcel->getMediaHeight(); mMediaAutoScale = parcel->getMediaAutoScale(); mMediaLoop = parcel->getMediaLoop(); mParcelLocalID = parcel->getLocalID(); } void LLViewerParcelMediaInfo::applyToParcel(LLParcel* parcel) { if (parcel && sameParcel(parcel)) { parcel->setMediaURL(mMediaURL); parcel->setMediaType(mMediaType); parcel->setMediaID(mMediaID); parcel->setMediaWidth(mMediaWidth); parcel->setMediaHeight(mMediaHeight); parcel->setMediaAutoScale(mMediaAutoScale); parcel->setMediaLoop(mMediaLoop); } } bool LLViewerParcelMediaInfo::sameParcel(const LLParcel* parcel) const { return parcel && (parcel->getLocalID() == mParcelLocalID); } bool LLViewerParcelMediaInfo::operator==(const LLViewerParcelMediaInfo &rhs) const { return (mMediaURL == rhs.mMediaURL) && (mMediaType == rhs.mMediaType) && (mMediaID == rhs.mMediaID) && (mMediaWidth == rhs.mMediaWidth) && (mMediaHeight == rhs.mMediaHeight) && (mMediaAutoScale == rhs.mMediaAutoScale) && (mMediaLoop == rhs.mMediaLoop) && (mParcelLocalID == rhs.mParcelLocalID); }