PageRenderTime 126ms CodeModel.GetById 20ms app.highlight 93ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/newview/llviewermedia.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 2092 lines | 1447 code | 290 blank | 355 comment | 267 complexity | 6c863bb92bbd6d18258348eca7b38dc3 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/**
   2 * @file llviewermedia.cpp
   3 * @brief Client interface to the media engine
   4 *
   5 * $LicenseInfo:firstyear=2007&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27#include "llviewerprecompiledheaders.h"
  28
  29#include "llviewermedia.h"
  30
  31#include "llagent.h"
  32#include "llagentcamera.h"
  33#include "llappviewer.h"
  34#include "llaudioengine.h"  // for gAudiop
  35#include "llcallbacklist.h"
  36#include "lldir.h"
  37#include "lldiriterator.h"
  38#include "llevent.h"		// LLSimpleListener
  39#include "llfilepicker.h"
  40#include "llfloaterwebcontent.h"	// for handling window close requests and geometry change requests in media browser windows.
  41#include "llfocusmgr.h"
  42#include "llkeyboard.h"
  43#include "lllogininstance.h"
  44#include "llmarketplacefunctions.h"
  45#include "llmediaentry.h"
  46#include "llmimetypes.h"
  47#include "llmutelist.h"
  48#include "llnotifications.h"
  49#include "llnotificationsutil.h"
  50#include "llpanelprofile.h"
  51#include "llparcel.h"
  52#include "llpluginclassmedia.h"
  53#include "llplugincookiestore.h"
  54#include "llurldispatcher.h"
  55#include "lluuid.h"
  56#include "llversioninfo.h"
  57#include "llviewermediafocus.h"
  58#include "llviewercontrol.h"
  59#include "llviewernetwork.h"
  60#include "llviewerparcelmedia.h"
  61#include "llviewerparcelmgr.h"
  62#include "llviewerregion.h"
  63#include "llviewertexture.h"
  64#include "llviewertexturelist.h"
  65#include "llviewerwindow.h"
  66#include "llvoavatar.h"
  67#include "llvoavatarself.h"
  68#include "llvovolume.h"
  69#include "llwebprofile.h"
  70#include "llwebsharing.h"	// For LLWebSharing::setOpenIDCookie(), *TODO: find a better way to do this!
  71#include "llwindow.h"
  72#include "llvieweraudio.h"
  73
  74#include "llfloaterwebcontent.h"	// for handling window close requests and geometry change requests in media browser windows.
  75
  76#include <boost/bind.hpp>	// for SkinFolder listener
  77#include <boost/signals2.hpp>
  78
  79/*static*/ const char* LLViewerMedia::AUTO_PLAY_MEDIA_SETTING = "ParcelMediaAutoPlayEnable";
  80/*static*/ const char* LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING = "MediaShowOnOthers";
  81/*static*/ const char* LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING = "MediaShowWithinParcel";
  82/*static*/ const char* LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING = "MediaShowOutsideParcel";
  83
  84
  85// Move this to its own file.
  86
  87LLViewerMediaEventEmitter::~LLViewerMediaEventEmitter()
  88{
  89	observerListType::iterator iter = mObservers.begin();
  90
  91	while( iter != mObservers.end() )
  92	{
  93		LLViewerMediaObserver *self = *iter;
  94		iter++;
  95		remObserver(self);
  96	}
  97}
  98
  99///////////////////////////////////////////////////////////////////////////////
 100//
 101bool LLViewerMediaEventEmitter::addObserver( LLViewerMediaObserver* observer )
 102{
 103	if ( ! observer )
 104		return false;
 105
 106	if ( std::find( mObservers.begin(), mObservers.end(), observer ) != mObservers.end() )
 107		return false;
 108
 109	mObservers.push_back( observer );
 110	observer->mEmitters.push_back( this );
 111
 112	return true;
 113}
 114
 115///////////////////////////////////////////////////////////////////////////////
 116//
 117bool LLViewerMediaEventEmitter::remObserver( LLViewerMediaObserver* observer )
 118{
 119	if ( ! observer )
 120		return false;
 121
 122	mObservers.remove( observer );
 123	observer->mEmitters.remove(this);
 124
 125	return true;
 126}
 127
 128///////////////////////////////////////////////////////////////////////////////
 129//
 130void LLViewerMediaEventEmitter::emitEvent( LLPluginClassMedia* media, LLViewerMediaObserver::EMediaEvent event )
 131{
 132	// Broadcast the event to any observers.
 133	observerListType::iterator iter = mObservers.begin();
 134	while( iter != mObservers.end() )
 135	{
 136		LLViewerMediaObserver *self = *iter;
 137		++iter;
 138		self->handleMediaEvent( media, event );
 139	}
 140}
 141
 142// Move this to its own file.
 143LLViewerMediaObserver::~LLViewerMediaObserver()
 144{
 145	std::list<LLViewerMediaEventEmitter *>::iterator iter = mEmitters.begin();
 146
 147	while( iter != mEmitters.end() )
 148	{
 149		LLViewerMediaEventEmitter *self = *iter;
 150		iter++;
 151		self->remObserver( this );
 152	}
 153}
 154
 155
 156// Move this to its own file.
 157// helper class that tries to download a URL from a web site and calls a method
 158// on the Panel Land Media and to discover the MIME type
 159class LLMimeDiscoveryResponder : public LLHTTPClient::Responder
 160{
 161LOG_CLASS(LLMimeDiscoveryResponder);
 162public:
 163	LLMimeDiscoveryResponder( viewer_media_t media_impl)
 164		: mMediaImpl(media_impl),
 165		  mInitialized(false)
 166	{
 167		if(mMediaImpl->mMimeTypeProbe != NULL)
 168		{
 169			llerrs << "impl already has an outstanding responder" << llendl;
 170		}
 171		
 172		mMediaImpl->mMimeTypeProbe = this;
 173	}
 174
 175	~LLMimeDiscoveryResponder()
 176	{
 177		disconnectOwner();
 178	}
 179
 180	virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content)
 181	{
 182		std::string media_type = content["content-type"].asString();
 183		std::string::size_type idx1 = media_type.find_first_of(";");
 184		std::string mime_type = media_type.substr(0, idx1);
 185
 186		lldebugs << "status is " << status << ", media type \"" << media_type << "\"" << llendl;
 187		
 188		// 2xx status codes indicate success.
 189		// Most 4xx status codes are successful enough for our purposes.
 190		// 499 is the error code for host not found, timeout, etc.
 191		// 500 means "Internal Server error" but we decided it's okay to 
 192		//     accept this and go past it in the MIME type probe
 193		// 302 means the resource can be found temporarily in a different place - added this for join.secondlife.com
 194		// 499 is a code specifc to join.secondlife.com (????) apparently safe to ignore
 195//		if(	((status >= 200) && (status < 300))	||
 196//			((status >= 400) && (status < 499))	|| 
 197//			(status == 500) ||
 198//			(status == 302) ||
 199//			(status == 499) 
 200//			)
 201		// We now no longer check the error code returned from the probe.
 202		// If we have a mime type, use it.  If not, default to the web plugin and let it handle error reporting.
 203		if(1)
 204		{
 205			// The probe was successful.
 206			if(mime_type.empty())
 207			{
 208				// Some sites don't return any content-type header at all.
 209				// Treat an empty mime type as text/html.
 210				mime_type = "text/html";
 211			}
 212			
 213			completeAny(status, mime_type);
 214		}
 215		else
 216		{
 217			llwarns << "responder failed with status " << status << ", reason " << reason << llendl;
 218		
 219			if(mMediaImpl)
 220			{
 221				mMediaImpl->mMediaSourceFailed = true;
 222			}
 223		}
 224
 225	}
 226
 227	void completeAny(U32 status, const std::string& mime_type)
 228	{
 229		// the call to initializeMedia may disconnect the responder, which will clear mMediaImpl.
 230		// Make a local copy so we can call loadURI() afterwards.
 231		LLViewerMediaImpl *impl = mMediaImpl;
 232		
 233		if(impl && !mInitialized && ! mime_type.empty())
 234		{
 235			if(impl->initializeMedia(mime_type))
 236			{
 237				mInitialized = true;
 238				impl->loadURI();
 239				disconnectOwner();
 240			}
 241		}
 242	}
 243	
 244	void cancelRequest()
 245	{
 246		disconnectOwner();
 247	}
 248	
 249private:
 250	void disconnectOwner()
 251	{
 252		if(mMediaImpl)
 253		{
 254			if(mMediaImpl->mMimeTypeProbe != this)
 255			{
 256				llerrs << "internal error: mMediaImpl->mMimeTypeProbe != this" << llendl;
 257			}
 258
 259			mMediaImpl->mMimeTypeProbe = NULL;
 260		}
 261		mMediaImpl = NULL;
 262	}
 263	
 264	
 265public:
 266		LLViewerMediaImpl *mMediaImpl;
 267		bool mInitialized;
 268};
 269
 270class LLViewerMediaOpenIDResponder : public LLHTTPClient::Responder
 271{
 272LOG_CLASS(LLViewerMediaOpenIDResponder);
 273public:
 274	LLViewerMediaOpenIDResponder( )
 275	{
 276	}
 277
 278	~LLViewerMediaOpenIDResponder()
 279	{
 280	}
 281
 282	/* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content)
 283	{
 284		LL_DEBUGS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL;
 285		LL_DEBUGS("MediaAuth") << content << LL_ENDL;
 286		std::string cookie = content["set-cookie"].asString();
 287		
 288		LLViewerMedia::openIDCookieResponse(cookie);
 289	}
 290
 291	/* virtual */ void completedRaw(
 292		U32 status,
 293		const std::string& reason,
 294		const LLChannelDescriptors& channels,
 295		const LLIOPipe::buffer_ptr_t& buffer)
 296	{
 297		// This is just here to disable the default behavior (attempting to parse the response as llsd).
 298		// We don't care about the content of the response, only the set-cookie header.
 299	}
 300
 301};
 302
 303class LLViewerMediaWebProfileResponder : public LLHTTPClient::Responder
 304{
 305LOG_CLASS(LLViewerMediaWebProfileResponder);
 306public:
 307	LLViewerMediaWebProfileResponder(std::string host)
 308	{
 309		mHost = host;
 310	}
 311
 312	~LLViewerMediaWebProfileResponder()
 313	{
 314	}
 315
 316	/* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content)
 317	{
 318		LL_WARNS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL;
 319		LL_WARNS("MediaAuth") << content << LL_ENDL;
 320
 321		std::string cookie = content["set-cookie"].asString();
 322
 323		LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, mHost);
 324
 325		// Set cookie for snapshot publishing.
 326		std::string auth_cookie = cookie.substr(0, cookie.find(";")); // strip path
 327		LLWebProfile::setAuthCookie(auth_cookie);
 328	}
 329
 330	 void completedRaw(
 331		U32 status,
 332		const std::string& reason,
 333		const LLChannelDescriptors& channels,
 334		const LLIOPipe::buffer_ptr_t& buffer)
 335	{
 336		// This is just here to disable the default behavior (attempting to parse the response as llsd).
 337		// We don't care about the content of the response, only the set-cookie header.
 338	}
 339
 340	std::string mHost;
 341};
 342
 343
 344LLPluginCookieStore *LLViewerMedia::sCookieStore = NULL;
 345LLURL LLViewerMedia::sOpenIDURL;
 346std::string LLViewerMedia::sOpenIDCookie;
 347LLPluginClassMedia* LLViewerMedia::sSpareBrowserMediaSource = NULL;
 348static LLViewerMedia::impl_list sViewerMediaImplList;
 349static LLViewerMedia::impl_id_map sViewerMediaTextureIDMap;
 350static LLTimer sMediaCreateTimer;
 351static const F32 LLVIEWERMEDIA_CREATE_DELAY = 1.0f;
 352static F32 sGlobalVolume = 1.0f;
 353static bool sForceUpdate = false;
 354static LLUUID sOnlyAudibleTextureID = LLUUID::null;
 355static F64 sLowestLoadableImplInterest = 0.0f;
 356static bool sAnyMediaShowing = false;
 357static boost::signals2::connection sTeleportFinishConnection;
 358static std::string sUpdatedCookies;
 359static const char *PLUGIN_COOKIE_FILE_NAME = "plugin_cookies.txt";
 360
 361//////////////////////////////////////////////////////////////////////////////////////////
 362static void add_media_impl(LLViewerMediaImpl* media)
 363{
 364	sViewerMediaImplList.push_back(media);
 365}
 366
 367//////////////////////////////////////////////////////////////////////////////////////////
 368static void remove_media_impl(LLViewerMediaImpl* media)
 369{
 370	LLViewerMedia::impl_list::iterator iter = sViewerMediaImplList.begin();
 371	LLViewerMedia::impl_list::iterator end = sViewerMediaImplList.end();
 372	
 373	for(; iter != end; iter++)
 374	{
 375		if(media == *iter)
 376		{
 377			sViewerMediaImplList.erase(iter);
 378			return;
 379		}
 380	}
 381}
 382
 383class LLViewerMediaMuteListObserver : public LLMuteListObserver
 384{
 385	/* virtual */ void onChange()  { LLViewerMedia::muteListChanged();}
 386};
 387
 388static LLViewerMediaMuteListObserver sViewerMediaMuteListObserver;
 389static bool sViewerMediaMuteListObserverInitialized = false;
 390static bool sInWorldMediaDisabled = false;
 391
 392
 393//////////////////////////////////////////////////////////////////////////////////////////
 394// LLViewerMedia
 395
 396//////////////////////////////////////////////////////////////////////////////////////////
 397// static
 398viewer_media_t LLViewerMedia::newMediaImpl(
 399											 const LLUUID& texture_id,
 400											 S32 media_width, 
 401											 S32 media_height, 
 402											 U8 media_auto_scale,
 403											 U8 media_loop)
 404{
 405	LLViewerMediaImpl* media_impl = getMediaImplFromTextureID(texture_id);
 406	if(media_impl == NULL || texture_id.isNull())
 407	{
 408		// Create the media impl
 409		media_impl = new LLViewerMediaImpl(texture_id, media_width, media_height, media_auto_scale, media_loop);
 410	}
 411	else
 412	{
 413		media_impl->unload();
 414		media_impl->setTextureID(texture_id);
 415		media_impl->mMediaWidth = media_width;
 416		media_impl->mMediaHeight = media_height;
 417		media_impl->mMediaAutoScale = media_auto_scale;
 418		media_impl->mMediaLoop = media_loop;
 419	}
 420
 421	return media_impl;
 422}
 423
 424viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const std::string& previous_url, bool update_from_self)
 425{	
 426	// Try to find media with the same media ID
 427	viewer_media_t media_impl = getMediaImplFromTextureID(media_entry->getMediaID());
 428	
 429	lldebugs << "called, current URL is \"" << media_entry->getCurrentURL() 
 430			<< "\", previous URL is \"" << previous_url 
 431			<< "\", update_from_self is " << (update_from_self?"true":"false")
 432			<< llendl;
 433			
 434	bool was_loaded = false;
 435	bool needs_navigate = false;
 436	
 437	if(media_impl)
 438	{	
 439		was_loaded = media_impl->hasMedia();
 440		
 441		media_impl->setHomeURL(media_entry->getHomeURL());
 442		
 443		media_impl->mMediaAutoScale = media_entry->getAutoScale();
 444		media_impl->mMediaLoop = media_entry->getAutoLoop();
 445		media_impl->mMediaWidth = media_entry->getWidthPixels();
 446		media_impl->mMediaHeight = media_entry->getHeightPixels();
 447		media_impl->mMediaAutoPlay = media_entry->getAutoPlay();
 448		media_impl->mMediaEntryURL = media_entry->getCurrentURL();
 449		if (media_impl->mMediaSource)
 450		{
 451			media_impl->mMediaSource->setAutoScale(media_impl->mMediaAutoScale);
 452			media_impl->mMediaSource->setLoop(media_impl->mMediaLoop);
 453			media_impl->mMediaSource->setSize(media_entry->getWidthPixels(), media_entry->getHeightPixels());
 454		}
 455		
 456		bool url_changed = (media_impl->mMediaEntryURL != previous_url);
 457		if(media_impl->mMediaEntryURL.empty())
 458		{
 459			if(url_changed)
 460			{
 461				// The current media URL is now empty.  Unload the media source.
 462				media_impl->unload();
 463			
 464				lldebugs << "Unloading media instance (new current URL is empty)." << llendl;
 465			}
 466		}
 467		else
 468		{
 469			// The current media URL is not empty.
 470			// If (the media was already loaded OR the media was set to autoplay) AND this update didn't come from this agent,
 471			// do a navigate.
 472			bool auto_play = media_impl->isAutoPlayable();			
 473			if((was_loaded || auto_play) && !update_from_self)
 474			{
 475				needs_navigate = url_changed;
 476			}
 477			
 478			lldebugs << "was_loaded is " << (was_loaded?"true":"false") 
 479					<< ", auto_play is " << (auto_play?"true":"false") 
 480					<< ", needs_navigate is " << (needs_navigate?"true":"false") << llendl;
 481		}
 482	}
 483	else
 484	{
 485		media_impl = newMediaImpl(
 486			media_entry->getMediaID(), 
 487			media_entry->getWidthPixels(),
 488			media_entry->getHeightPixels(), 
 489			media_entry->getAutoScale(), 
 490			media_entry->getAutoLoop());
 491		
 492		media_impl->setHomeURL(media_entry->getHomeURL());
 493		media_impl->mMediaAutoPlay = media_entry->getAutoPlay();
 494		media_impl->mMediaEntryURL = media_entry->getCurrentURL();
 495		if(media_impl->isAutoPlayable())
 496		{
 497			needs_navigate = true;
 498		}
 499	}
 500	
 501	if(media_impl)
 502	{
 503		if(needs_navigate)
 504		{
 505			media_impl->navigateTo(media_impl->mMediaEntryURL, "", true, true);
 506			lldebugs << "navigating to URL " << media_impl->mMediaEntryURL << llendl;
 507		}
 508		else if(!media_impl->mMediaURL.empty() && (media_impl->mMediaURL != media_impl->mMediaEntryURL))
 509		{
 510			// If we already have a non-empty media URL set and we aren't doing a navigate, update the media URL to match the media entry.
 511			media_impl->mMediaURL = media_impl->mMediaEntryURL;
 512
 513			// If this causes a navigate at some point (such as after a reload), it should be considered server-driven so it isn't broadcast.
 514			media_impl->mNavigateServerRequest = true;
 515
 516			lldebugs << "updating URL in the media impl to " << media_impl->mMediaEntryURL << llendl;
 517		}
 518	}
 519	
 520	return media_impl;
 521}
 522
 523//////////////////////////////////////////////////////////////////////////////////////////
 524// static
 525LLViewerMediaImpl* LLViewerMedia::getMediaImplFromTextureID(const LLUUID& texture_id)
 526{
 527	LLViewerMediaImpl* result = NULL;
 528	
 529	// Look up the texture ID in the texture id->impl map.
 530	impl_id_map::iterator iter = sViewerMediaTextureIDMap.find(texture_id);
 531	if(iter != sViewerMediaTextureIDMap.end())
 532	{
 533		result = iter->second;
 534	}
 535
 536	return result;
 537}
 538
 539//////////////////////////////////////////////////////////////////////////////////////////
 540// static
 541std::string LLViewerMedia::getCurrentUserAgent()
 542{
 543	// Don't use user-visible string to avoid 
 544	// punctuation and strange characters.
 545	std::string skin_name = gSavedSettings.getString("SkinCurrent");
 546
 547	// Just in case we need to check browser differences in A/B test
 548	// builds.
 549	std::string channel = LLVersionInfo::getChannel();
 550
 551	// append our magic version number string to the browser user agent id
 552	// See the HTTP 1.0 and 1.1 specifications for allowed formats:
 553	// http://www.ietf.org/rfc/rfc1945.txt section 10.15
 554	// http://www.ietf.org/rfc/rfc2068.txt section 3.8
 555	// This was also helpful:
 556	// http://www.mozilla.org/build/revised-user-agent-strings.html
 557	std::ostringstream codec;
 558	codec << "SecondLife/";
 559	codec << LLVersionInfo::getVersion();
 560	codec << " (" << channel << "; " << skin_name << " skin)";
 561	llinfos << codec.str() << llendl;
 562	
 563	return codec.str();
 564}
 565
 566//////////////////////////////////////////////////////////////////////////////////////////
 567// static
 568void LLViewerMedia::updateBrowserUserAgent()
 569{
 570	std::string user_agent = getCurrentUserAgent();
 571	
 572	impl_list::iterator iter = sViewerMediaImplList.begin();
 573	impl_list::iterator end = sViewerMediaImplList.end();
 574
 575	for(; iter != end; iter++)
 576	{
 577		LLViewerMediaImpl* pimpl = *iter;
 578		if(pimpl->mMediaSource && pimpl->mMediaSource->pluginSupportsMediaBrowser())
 579		{
 580			pimpl->mMediaSource->setBrowserUserAgent(user_agent);
 581		}
 582	}
 583
 584}
 585
 586//////////////////////////////////////////////////////////////////////////////////////////
 587// static
 588bool LLViewerMedia::handleSkinCurrentChanged(const LLSD& /*newvalue*/)
 589{
 590	// gSavedSettings is already updated when this function is called.
 591	updateBrowserUserAgent();
 592	return true;
 593}
 594
 595//////////////////////////////////////////////////////////////////////////////////////////
 596// static
 597bool LLViewerMedia::textureHasMedia(const LLUUID& texture_id)
 598{
 599	impl_list::iterator iter = sViewerMediaImplList.begin();
 600	impl_list::iterator end = sViewerMediaImplList.end();
 601
 602	for(; iter != end; iter++)
 603	{
 604		LLViewerMediaImpl* pimpl = *iter;
 605		if(pimpl->getMediaTextureID() == texture_id)
 606		{
 607			return true;
 608		}
 609	}
 610	return false;
 611}
 612
 613//////////////////////////////////////////////////////////////////////////////////////////
 614// static
 615void LLViewerMedia::setVolume(F32 volume)
 616{
 617	if(volume != sGlobalVolume || sForceUpdate)
 618	{
 619		sGlobalVolume = volume;
 620		impl_list::iterator iter = sViewerMediaImplList.begin();
 621		impl_list::iterator end = sViewerMediaImplList.end();
 622
 623		for(; iter != end; iter++)
 624		{
 625			LLViewerMediaImpl* pimpl = *iter;
 626			pimpl->updateVolume();
 627		}
 628
 629		sForceUpdate = false;
 630	}
 631}
 632
 633//////////////////////////////////////////////////////////////////////////////////////////
 634// static
 635F32 LLViewerMedia::getVolume()
 636{
 637	return sGlobalVolume;
 638}
 639
 640//////////////////////////////////////////////////////////////////////////////////////////
 641// static
 642void LLViewerMedia::muteListChanged()
 643{
 644	// When the mute list changes, we need to check mute status on all impls.
 645	impl_list::iterator iter = sViewerMediaImplList.begin();
 646	impl_list::iterator end = sViewerMediaImplList.end();
 647
 648	for(; iter != end; iter++)
 649	{
 650		LLViewerMediaImpl* pimpl = *iter;
 651		pimpl->mNeedsMuteCheck = true;
 652	}
 653}
 654
 655//////////////////////////////////////////////////////////////////////////////////////////
 656// static
 657void LLViewerMedia::setInWorldMediaDisabled(bool disabled)
 658{
 659	sInWorldMediaDisabled = disabled;
 660}
 661
 662//////////////////////////////////////////////////////////////////////////////////////////
 663// static
 664bool LLViewerMedia::getInWorldMediaDisabled()
 665{
 666	return sInWorldMediaDisabled;
 667}
 668
 669//////////////////////////////////////////////////////////////////////////////////////////
 670// static
 671bool LLViewerMedia::isInterestingEnough(const LLVOVolume *object, const F64 &object_interest)
 672{
 673	bool result = false;
 674	
 675	if (NULL == object)
 676	{
 677		result = false;
 678	}
 679	// Focused?  Then it is interesting!
 680	else if (LLViewerMediaFocus::getInstance()->getFocusedObjectID() == object->getID())
 681	{
 682		result = true;
 683	}
 684	// Selected?  Then it is interesting!
 685	// XXX Sadly, 'contains()' doesn't take a const :(
 686	else if (LLSelectMgr::getInstance()->getSelection()->contains(const_cast<LLVOVolume*>(object)))
 687	{
 688		result = true;
 689	}
 690	else 
 691	{
 692		lldebugs << "object interest = " << object_interest << ", lowest loadable = " << sLowestLoadableImplInterest << llendl;
 693		if(object_interest >= sLowestLoadableImplInterest)
 694			result = true;
 695	}
 696	
 697	return result;
 698}
 699
 700LLViewerMedia::impl_list &LLViewerMedia::getPriorityList()
 701{
 702	return sViewerMediaImplList;
 703}
 704
 705// This is the predicate function used to sort sViewerMediaImplList by priority.
 706bool LLViewerMedia::priorityComparitor(const LLViewerMediaImpl* i1, const LLViewerMediaImpl* i2)
 707{
 708	if(i1->isForcedUnloaded() && !i2->isForcedUnloaded())
 709	{
 710		// Muted or failed items always go to the end of the list, period.
 711		return false;
 712	}
 713	else if(i2->isForcedUnloaded() && !i1->isForcedUnloaded())
 714	{
 715		// Muted or failed items always go to the end of the list, period.
 716		return true;
 717	}
 718	else if(i1->hasFocus())
 719	{
 720		// The item with user focus always comes to the front of the list, period.
 721		return true;
 722	}
 723	else if(i2->hasFocus())
 724	{
 725		// The item with user focus always comes to the front of the list, period.
 726		return false;
 727	}
 728	else if(i1->isParcelMedia())
 729	{
 730		// The parcel media impl sorts above all other inworld media, unless one has focus.
 731		return true;
 732	}
 733	else if(i2->isParcelMedia())
 734	{
 735		// The parcel media impl sorts above all other inworld media, unless one has focus.
 736		return false;
 737	}
 738	else if(i1->getUsedInUI() && !i2->getUsedInUI())
 739	{
 740		// i1 is a UI element, i2 is not.  This makes i1 "less than" i2, so it sorts earlier in our list.
 741		return true;
 742	}
 743	else if(i2->getUsedInUI() && !i1->getUsedInUI())
 744	{
 745		// i2 is a UI element, i1 is not.  This makes i2 "less than" i1, so it sorts earlier in our list.
 746		return false;
 747	}
 748	else if(i1->isPlayable() && !i2->isPlayable())
 749	{
 750		// Playable items sort above ones that wouldn't play even if they got high enough priority
 751		return true;
 752	}
 753	else if(!i1->isPlayable() && i2->isPlayable())
 754	{
 755		// Playable items sort above ones that wouldn't play even if they got high enough priority
 756		return false;
 757	}
 758	else if(i1->getInterest() == i2->getInterest())
 759	{
 760		// Generally this will mean both objects have zero interest.  In this case, sort on distance.
 761		return (i1->getProximityDistance() < i2->getProximityDistance());
 762	}
 763	else
 764	{
 765		// The object with the larger interest value should be earlier in the list, so we reverse the sense of the comparison here.
 766		return (i1->getInterest() > i2->getInterest());
 767	}
 768}
 769
 770static bool proximity_comparitor(const LLViewerMediaImpl* i1, const LLViewerMediaImpl* i2)
 771{
 772	if(i1->getProximityDistance() < i2->getProximityDistance())
 773	{
 774		return true;
 775	}
 776	else if(i1->getProximityDistance() > i2->getProximityDistance())
 777	{
 778		return false;
 779	}
 780	else
 781	{
 782		// Both objects have the same distance.  This most likely means they're two faces of the same object.
 783		// They may also be faces on different objects with exactly the same distance (like HUD objects).
 784		// We don't actually care what the sort order is for this case, as long as it's stable and doesn't change when you enable/disable media.
 785		// Comparing the impl pointers gives a completely arbitrary ordering, but it will be stable.
 786		return (i1 < i2);
 787	}
 788}
 789
 790static LLFastTimer::DeclareTimer FTM_MEDIA_UPDATE("Update Media");
 791static LLFastTimer::DeclareTimer FTM_MEDIA_SPARE_IDLE("Spare Idle");
 792static LLFastTimer::DeclareTimer FTM_MEDIA_UPDATE_INTEREST("Update/Interest");
 793static LLFastTimer::DeclareTimer FTM_MEDIA_SORT("Sort");
 794static LLFastTimer::DeclareTimer FTM_MEDIA_SORT2("Sort 2");
 795static LLFastTimer::DeclareTimer FTM_MEDIA_MISC("Misc");
 796
 797
 798//////////////////////////////////////////////////////////////////////////////////////////
 799// static
 800void LLViewerMedia::updateMedia(void *dummy_arg)
 801{
 802	LLFastTimer t1(FTM_MEDIA_UPDATE);
 803	
 804	// Enable/disable the plugin read thread
 805	LLPluginProcessParent::setUseReadThread(gSavedSettings.getBOOL("PluginUseReadThread"));
 806	
 807	// HACK: we always try to keep a spare running webkit plugin around to improve launch times.
 808	createSpareBrowserMediaSource();
 809	
 810	sAnyMediaShowing = false;
 811	sUpdatedCookies = getCookieStore()->getChangedCookies();
 812	if(!sUpdatedCookies.empty())
 813	{
 814		lldebugs << "updated cookies will be sent to all loaded plugins: " << llendl;
 815		lldebugs << sUpdatedCookies << llendl;
 816	}
 817	
 818	impl_list::iterator iter = sViewerMediaImplList.begin();
 819	impl_list::iterator end = sViewerMediaImplList.end();
 820
 821	{
 822		LLFastTimer t(FTM_MEDIA_UPDATE_INTEREST);
 823		for(; iter != end;)
 824		{
 825			LLViewerMediaImpl* pimpl = *iter++;
 826			pimpl->update();
 827			pimpl->calculateInterest();
 828		}
 829	}
 830	
 831	// Let the spare media source actually launch
 832	if(sSpareBrowserMediaSource)
 833	{
 834		LLFastTimer t(FTM_MEDIA_SPARE_IDLE);
 835		sSpareBrowserMediaSource->idle();
 836	}
 837		
 838	{
 839		LLFastTimer t(FTM_MEDIA_SORT);
 840		// Sort the static instance list using our interest criteria
 841		sViewerMediaImplList.sort(priorityComparitor);
 842	}
 843
 844	// Go through the list again and adjust according to priority.
 845	iter = sViewerMediaImplList.begin();
 846	end = sViewerMediaImplList.end();
 847	
 848	F64 total_cpu = 0.0f;
 849	int impl_count_total = 0;
 850	int impl_count_interest_low = 0;
 851	int impl_count_interest_normal = 0;
 852	
 853	std::vector<LLViewerMediaImpl*> proximity_order;
 854	
 855	bool inworld_media_enabled = gSavedSettings.getBOOL("AudioStreamingMedia");
 856	bool inworld_audio_enabled = gSavedSettings.getBOOL("AudioStreamingMusic");
 857	U32 max_instances = gSavedSettings.getU32("PluginInstancesTotal");
 858	U32 max_normal = gSavedSettings.getU32("PluginInstancesNormal");
 859	U32 max_low = gSavedSettings.getU32("PluginInstancesLow");
 860	F32 max_cpu = gSavedSettings.getF32("PluginInstancesCPULimit");
 861	// Setting max_cpu to 0.0 disables CPU usage checking.
 862	bool check_cpu_usage = (max_cpu != 0.0f);
 863	
 864	LLViewerMediaImpl* lowest_interest_loadable = NULL;
 865	
 866	// Notes on tweakable params:
 867	// max_instances must be set high enough to allow the various instances used in the UI (for the help browser, search, etc.) to be loaded.
 868	// If max_normal + max_low is less than max_instances, things will tend to get unloaded instead of being set to slideshow.
 869	
 870	{
 871		LLFastTimer t(FTM_MEDIA_MISC);
 872		for(; iter != end; iter++)
 873		{
 874			LLViewerMediaImpl* pimpl = *iter;
 875		
 876			LLPluginClassMedia::EPriority new_priority = LLPluginClassMedia::PRIORITY_NORMAL;
 877
 878			if(pimpl->isForcedUnloaded() || (impl_count_total >= (int)max_instances))
 879			{
 880				// Never load muted or failed impls.
 881				// Hard limit on the number of instances that will be loaded at one time
 882				new_priority = LLPluginClassMedia::PRIORITY_UNLOADED;
 883			}
 884			else if(!pimpl->getVisible())
 885			{
 886				new_priority = LLPluginClassMedia::PRIORITY_HIDDEN;
 887			}
 888			else if(pimpl->hasFocus())
 889			{
 890				new_priority = LLPluginClassMedia::PRIORITY_HIGH;
 891				impl_count_interest_normal++;	// count this against the count of "normal" instances for priority purposes
 892			}
 893			else if(pimpl->getUsedInUI())
 894			{
 895				new_priority = LLPluginClassMedia::PRIORITY_NORMAL;
 896				impl_count_interest_normal++;
 897			}
 898			else if(pimpl->isParcelMedia())
 899			{
 900				new_priority = LLPluginClassMedia::PRIORITY_NORMAL;
 901				impl_count_interest_normal++;
 902			}
 903			else
 904			{
 905				// Look at interest and CPU usage for instances that aren't in any of the above states.
 906			
 907				// Heuristic -- if the media texture's approximate screen area is less than 1/4 of the native area of the texture,
 908				// turn it down to low instead of normal.  This may downsample for plugins that support it.
 909				bool media_is_small = false;
 910				F64 approximate_interest = pimpl->getApproximateTextureInterest();
 911				if(approximate_interest == 0.0f)
 912				{
 913					// this media has no current size, which probably means it's not loaded.
 914					media_is_small = true;
 915				}
 916				else if(pimpl->getInterest() < (approximate_interest / 4))
 917				{
 918					media_is_small = true;
 919				}
 920			
 921				if(pimpl->getInterest() == 0.0f)
 922				{
 923					// This media is completely invisible, due to being outside the view frustrum or out of range.
 924					new_priority = LLPluginClassMedia::PRIORITY_HIDDEN;
 925				}
 926				else if(check_cpu_usage && (total_cpu > max_cpu))
 927				{
 928					// Higher priority plugins have already used up the CPU budget.  Set remaining ones to slideshow priority.
 929					new_priority = LLPluginClassMedia::PRIORITY_SLIDESHOW;
 930				}
 931				else if((impl_count_interest_normal < (int)max_normal) && !media_is_small)
 932				{
 933					// Up to max_normal inworld get normal priority
 934					new_priority = LLPluginClassMedia::PRIORITY_NORMAL;
 935					impl_count_interest_normal++;
 936				}
 937				else if (impl_count_interest_low + impl_count_interest_normal < (int)max_low + (int)max_normal)
 938				{
 939					// The next max_low inworld get turned down
 940					new_priority = LLPluginClassMedia::PRIORITY_LOW;
 941					impl_count_interest_low++;
 942				
 943					// Set the low priority size for downsampling to approximately the size the texture is displayed at.
 944					{
 945						F32 approximate_interest_dimension = (F32) sqrt(pimpl->getInterest());
 946					
 947						pimpl->setLowPrioritySizeLimit(llround(approximate_interest_dimension));
 948					}
 949				}
 950				else
 951				{
 952					// Any additional impls (up to max_instances) get very infrequent time
 953					new_priority = LLPluginClassMedia::PRIORITY_SLIDESHOW;
 954				}
 955			}
 956		
 957			if(!pimpl->getUsedInUI() && (new_priority != LLPluginClassMedia::PRIORITY_UNLOADED))
 958			{
 959				// This is a loadable inworld impl -- the last one in the list in this class defines the lowest loadable interest.
 960				lowest_interest_loadable = pimpl;
 961			
 962				impl_count_total++;
 963			}
 964
 965			// Overrides if the window is minimized or we lost focus (taking care
 966			// not to accidentally "raise" the priority either)
 967			if (!gViewerWindow->getActive() /* viewer window minimized? */ 
 968				&& new_priority > LLPluginClassMedia::PRIORITY_HIDDEN)
 969			{
 970				new_priority = LLPluginClassMedia::PRIORITY_HIDDEN;
 971			}
 972			else if (!gFocusMgr.getAppHasFocus() /* viewer window lost focus? */
 973					 && new_priority > LLPluginClassMedia::PRIORITY_LOW)
 974			{
 975				new_priority = LLPluginClassMedia::PRIORITY_LOW;
 976			}
 977		
 978			if(!inworld_media_enabled)
 979			{
 980				// If inworld media is locked out, force all inworld media to stay unloaded.
 981				if(!pimpl->getUsedInUI())
 982				{
 983					new_priority = LLPluginClassMedia::PRIORITY_UNLOADED;
 984				}
 985			}
 986			// update the audio stream here as well
 987			if( !inworld_audio_enabled)
 988			{
 989				if(LLViewerMedia::isParcelAudioPlaying() && gAudiop && LLViewerMedia::hasParcelAudio())
 990				{
 991					LLViewerAudio::getInstance()->stopInternetStreamWithAutoFade();
 992				}
 993			}
 994			pimpl->setPriority(new_priority);
 995		
 996			if(pimpl->getUsedInUI())
 997			{
 998				// Any impls used in the UI should not be in the proximity list.
 999				pimpl->mProximity = -1;
1000			}
1001			else
1002			{
1003				proximity_order.push_back(pimpl);
1004			}
1005
1006			total_cpu += pimpl->getCPUUsage();
1007		
1008			if (!pimpl->getUsedInUI() && pimpl->hasMedia())
1009			{
1010				sAnyMediaShowing = true;
1011			}
1012
1013		}
1014	}
1015
1016	// Re-calculate this every time.
1017	sLowestLoadableImplInterest	= 0.0f;
1018
1019	// Only do this calculation if we've hit the impl count limit -- up until that point we always need to load media data.
1020	if(lowest_interest_loadable && (impl_count_total >= (int)max_instances))
1021	{
1022		// Get the interest value of this impl's object for use by isInterestingEnough
1023		LLVOVolume *object = lowest_interest_loadable->getSomeObject();
1024		if(object)
1025		{
1026			// NOTE: Don't use getMediaInterest() here.  We want the pixel area, not the total media interest,
1027			// 		so that we match up with the calculation done in LLMediaDataClient.
1028			sLowestLoadableImplInterest = object->getPixelArea();
1029		}
1030	}
1031	
1032	if(gSavedSettings.getBOOL("MediaPerformanceManagerDebug"))
1033	{
1034		// Give impls the same ordering as the priority list
1035		// they're already in the right order for this.
1036	}
1037	else
1038	{
1039		LLFastTimer t(FTM_MEDIA_SORT2);
1040		// Use a distance-based sort for proximity values.  
1041		std::stable_sort(proximity_order.begin(), proximity_order.end(), proximity_comparitor);
1042	}
1043
1044	// Transfer the proximity order to the proximity fields in the objects.
1045	for(int i = 0; i < (int)proximity_order.size(); i++)
1046	{
1047		proximity_order[i]->mProximity = i;
1048	}
1049	
1050	LL_DEBUGS("PluginPriority") << "Total reported CPU usage is " << total_cpu << llendl;
1051
1052}
1053
1054//////////////////////////////////////////////////////////////////////////////////////////
1055// static
1056bool LLViewerMedia::isAnyMediaShowing()
1057{
1058	return sAnyMediaShowing;
1059}
1060
1061//////////////////////////////////////////////////////////////////////////////////////////
1062// static
1063void LLViewerMedia::setAllMediaEnabled(bool val)
1064{
1065	// Set "tentative" autoplay first.  We need to do this here or else
1066	// re-enabling won't start up the media below.
1067	gSavedSettings.setBOOL("MediaTentativeAutoPlay", val);
1068	
1069	// Then 
1070	impl_list::iterator iter = sViewerMediaImplList.begin();
1071	impl_list::iterator end = sViewerMediaImplList.end();
1072	
1073	for(; iter != end; iter++)
1074	{
1075		LLViewerMediaImpl* pimpl = *iter;
1076		if (!pimpl->getUsedInUI())
1077		{
1078			pimpl->setDisabled(!val);
1079		}
1080	}
1081	
1082	// Also do Parcel Media and Parcel Audio
1083	if (val)
1084	{
1085		if (!LLViewerMedia::isParcelMediaPlaying() && LLViewerMedia::hasParcelMedia())
1086		{	
1087			LLViewerParcelMedia::play(LLViewerParcelMgr::getInstance()->getAgentParcel());
1088		}
1089		
1090		if (gSavedSettings.getBOOL("AudioStreamingMusic") &&
1091			!LLViewerMedia::isParcelAudioPlaying() &&
1092			gAudiop && 
1093			LLViewerMedia::hasParcelAudio())
1094		{
1095			if (LLAudioEngine::AUDIO_PAUSED == gAudiop->isInternetStreamPlaying())
1096			{
1097				// 'false' means unpause
1098				gAudiop->pauseInternetStream(false);
1099			}
1100			else
1101			{
1102				LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLViewerMedia::getParcelAudioURL());
1103			}
1104		}
1105	}
1106	else {
1107		// This actually unloads the impl, as opposed to "stop"ping the media
1108		LLViewerParcelMedia::stop();
1109		if (gAudiop)
1110		{
1111			LLViewerAudio::getInstance()->stopInternetStreamWithAutoFade();
1112		}
1113	}
1114}
1115
1116//////////////////////////////////////////////////////////////////////////////////////////
1117// static
1118bool LLViewerMedia::isParcelMediaPlaying()
1119{
1120	return (LLViewerMedia::hasParcelMedia() && LLViewerParcelMedia::getParcelMedia() && LLViewerParcelMedia::getParcelMedia()->hasMedia());
1121}
1122
1123/////////////////////////////////////////////////////////////////////////////////////////
1124// static
1125bool LLViewerMedia::isParcelAudioPlaying()
1126{
1127	return (LLViewerMedia::hasParcelAudio() && gAudiop && LLAudioEngine::AUDIO_PLAYING == gAudiop->isInternetStreamPlaying());
1128}
1129
1130void LLViewerMedia::onAuthSubmit(const LLSD& notification, const LLSD& response)
1131{
1132	LLViewerMediaImpl *impl = LLViewerMedia::getMediaImplFromTextureID(notification["payload"]["media_id"]);
1133	if(impl)
1134	{
1135		LLPluginClassMedia* media = impl->getMediaPlugin();
1136		if(media)
1137		{
1138			if (response["ok"])
1139			{
1140				media->sendAuthResponse(true, response["username"], response["password"]);
1141			}
1142			else
1143			{
1144				media->sendAuthResponse(false, "", "");
1145			}
1146		}
1147	}
1148}
1149
1150/////////////////////////////////////////////////////////////////////////////////////////
1151// static
1152void LLViewerMedia::clearAllCookies()
1153{
1154	// Clear all cookies for all plugins
1155	impl_list::iterator iter = sViewerMediaImplList.begin();
1156	impl_list::iterator end = sViewerMediaImplList.end();
1157	for (; iter != end; iter++)
1158	{
1159		LLViewerMediaImpl* pimpl = *iter;
1160		if(pimpl->mMediaSource)
1161		{
1162			pimpl->mMediaSource->clear_cookies();
1163		}
1164	}
1165	
1166	// Clear all cookies from the cookie store
1167	getCookieStore()->setAllCookies("");
1168
1169	// FIXME: this may not be sufficient, since the on-disk cookie file won't get written until some browser instance exits cleanly.
1170	// It also won't clear cookies for other accounts, or for any account if we're not logged in, and won't do anything at all if there are no webkit plugins loaded.
1171	// Until such time as we can centralize cookie storage, the following hack should cover these cases:
1172	
1173	// HACK: Look for cookie files in all possible places and delete them.
1174	// NOTE: this assumes knowledge of what happens inside the webkit plugin (it's what adds 'browser_profile' to the path and names the cookie file)
1175	
1176	// Places that cookie files can be:
1177	// <getOSUserAppDir>/browser_profile/cookies
1178	// <getOSUserAppDir>/first_last/browser_profile/cookies  (note that there may be any number of these!)
1179	// <getOSUserAppDir>/first_last/plugin_cookies.txt  (note that there may be any number of these!)
1180	
1181	std::string base_dir = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter();
1182	std::string target;
1183	std::string filename;
1184	
1185	lldebugs << "base dir = " << base_dir << llendl;
1186
1187	// The non-logged-in version is easy
1188	target = base_dir;
1189	target += "browser_profile";
1190	target += gDirUtilp->getDirDelimiter();
1191	target += "cookies";
1192	lldebugs << "target = " << target << llendl;
1193	if(LLFile::isfile(target))
1194	{
1195		LLFile::remove(target);
1196	}
1197	
1198	// the hard part: iterate over all user directories and delete the cookie file from each one
1199	LLDirIterator dir_iter(base_dir, "*_*");
1200	while (dir_iter.next(filename))
1201	{
1202		target = base_dir;
1203		target += filename;
1204		target += gDirUtilp->getDirDelimiter();
1205		target += "browser_profile";
1206		target += gDirUtilp->getDirDelimiter();
1207		target += "cookies";
1208		lldebugs << "target = " << target << llendl;
1209		if(LLFile::isfile(target))
1210		{	
1211			LLFile::remove(target);
1212		}
1213		
1214		// Other accounts may have new-style cookie files too -- delete them as well
1215		target = base_dir;
1216		target += filename;
1217		target += gDirUtilp->getDirDelimiter();
1218		target += PLUGIN_COOKIE_FILE_NAME;
1219		lldebugs << "target = " << target << llendl;
1220		if(LLFile::isfile(target))
1221		{	
1222			LLFile::remove(target);
1223		}
1224	}
1225	
1226	// If we have an OpenID cookie, re-add it to the cookie store.
1227	setOpenIDCookie();
1228}
1229	
1230/////////////////////////////////////////////////////////////////////////////////////////
1231// static 
1232void LLViewerMedia::clearAllCaches()
1233{
1234	// Clear all plugins' caches
1235	impl_list::iterator iter = sViewerMediaImplList.begin();
1236	impl_list::iterator end = sViewerMediaImplList.end();
1237	for (; iter != end; iter++)
1238	{
1239		LLViewerMediaImpl* pimpl = *iter;
1240		pimpl->clearCache();
1241	}
1242}
1243	
1244/////////////////////////////////////////////////////////////////////////////////////////
1245// static 
1246void LLViewerMedia::setCookiesEnabled(bool enabled)
1247{
1248	// Set the "cookies enabled" flag for all loaded plugins
1249	impl_list::iterator iter = sViewerMediaImplList.begin();
1250	impl_list::iterator end = sViewerMediaImplList.end();
1251	for (; iter != end; iter++)
1252	{
1253		LLViewerMediaImpl* pimpl = *iter;
1254		if(pimpl->mMediaSource)
1255		{
1256			pimpl->mMediaSource->enable_cookies(enabled);
1257		}
1258	}
1259}
1260	
1261/////////////////////////////////////////////////////////////////////////////////////////
1262// static 
1263void LLViewerMedia::setProxyConfig(bool enable, const std::string &host, int port)
1264{
1265	// Set the proxy config for all loaded plugins
1266	impl_list::iterator iter = sViewerMediaImplList.begin();
1267	impl_list::iterator end = sViewerMediaImplList.end();
1268	for (; iter != end; iter++)
1269	{
1270		LLViewerMediaImpl* pimpl = *iter;
1271		if(pimpl->mMediaSource)
1272		{
1273			pimpl->mMediaSource->proxy_setup(enable, host, port);
1274		}
1275	}
1276}
1277
1278/////////////////////////////////////////////////////////////////////////////////////////
1279// static 
1280/////////////////////////////////////////////////////////////////////////////////////////
1281// static
1282LLPluginCookieStore *LLViewerMedia::getCookieStore()
1283{
1284	if(sCookieStore == NULL)
1285	{
1286		sCookieStore = new LLPluginCookieStore;
1287	}
1288	
1289	return sCookieStore;
1290}
1291
1292/////////////////////////////////////////////////////////////////////////////////////////
1293// static
1294void LLViewerMedia::loadCookieFile()
1295{
1296	// build filename for each user
1297	std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PLUGIN_COOKIE_FILE_NAME);
1298
1299	if (resolved_filename.empty())
1300	{
1301		llinfos << "can't get path to plugin cookie file - probably not logged in yet." << llendl;
1302		return;
1303	}
1304	
1305	// open the file for reading
1306	llifstream file(resolved_filename);
1307	if (!file.is_open())
1308	{
1309		llwarns << "can't load plugin cookies from file \"" << PLUGIN_COOKIE_FILE_NAME << "\"" << llendl;
1310		return;
1311	}
1312	
1313	getCookieStore()->readAllCookies(file, true);
1314
1315	file.close();
1316	
1317	// send the clear_cookies message to all loaded plugins
1318	impl_list::iterator iter = sViewerMediaImplList.begin();
1319	impl_list::iterator end = sViewerMediaImplList.end();
1320	for (; iter != end; iter++)
1321	{
1322		LLViewerMediaImpl* pimpl = *iter;
1323		if(pimpl->mMediaSource)
1324		{
1325			pimpl->mMediaSource->clear_cookies();
1326		}
1327	}
1328	
1329	// If we have an OpenID cookie, re-add it to the cookie store.
1330	setOpenIDCookie();
1331}
1332
1333
1334/////////////////////////////////////////////////////////////////////////////////////////
1335// static
1336void LLViewerMedia::saveCookieFile()
1337{
1338	// build filename for each user
1339	std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PLUGIN_COOKIE_FILE_NAME);
1340
1341	if (resolved_filename.empty())
1342	{
1343		llinfos << "can't get path to plugin cookie file - probably not logged in yet." << llendl;
1344		return;
1345	}
1346
1347	// open a file for writing
1348	llofstream file (resolved_filename);
1349	if (!file.is_open())
1350	{
1351		llwarns << "can't open plugin cookie file \"" << PLUGIN_COOKIE_FILE_NAME << "\" for writing" << llendl;
1352		return;
1353	}
1354
1355	getCookieStore()->writePersistentCookies(file);
1356
1357	file.close();
1358}
1359
1360/////////////////////////////////////////////////////////////////////////////////////////
1361// static
1362void LLViewerMedia::addCookie(const std::string &name, const std::string &value, const std::string &domain, const LLDate &expires, const std::string &path, bool secure)
1363{
1364	std::stringstream cookie;
1365	
1366	cookie << name << "=" << LLPluginCookieStore::quoteString(value);
1367	
1368	if(expires.notNull())
1369	{
1370		cookie << "; expires=" << expires.asRFC1123();
1371	}
1372	
1373	cookie << "; domain=" << domain;
1374
1375	cookie << "; path=" << path;
1376	
1377	if(secure)
1378	{
1379		cookie << "; secure";
1380	}
1381	
1382	getCookieStore()->setCookies(cookie.str());
1383}
1384
1385/////////////////////////////////////////////////////////////////////////////////////////
1386// static
1387void LLViewerMedia::addSessionCookie(const std::string &name, const std::string &value, const std::string &domain, const std::string &path, bool secure)
1388{
1389	// A session cookie just has a NULL date.
1390	addCookie(name, value, domain, LLDate(), path, secure);
1391}
1392
1393/////////////////////////////////////////////////////////////////////////////////////////
1394// static
1395void LLViewerMedia::removeCookie(const std::string &name, const std::string &domain, const std::string &path )
1396{
1397	// To remove a cookie, add one with the same name, domain, and path that expires in the past.
1398	
1399	addCookie(name, "", domain, LLDate(LLDate::now().secondsSinceEpoch() - 1.0), path);
1400}
1401
1402
1403LLSD LLViewerMedia::getHeaders()
1404{
1405	LLSD headers = LLSD::emptyMap();
1406	headers["Accept"] = "*/*";
1407	headers["Content-Type"] = "application/xml";
1408	headers["Cookie"] = sOpenIDCookie;
1409	headers["User-Agent"] = getCurrentUserAgent();
1410
1411	return headers;
1412}
1413
1414/////////////////////////////////////////////////////////////////////////////////////////
1415// static
1416void LLViewerMedia::setOpenIDCookie()
1417{
1418	if(!sOpenIDCookie.empty())
1419	{
1420		// The LLURL can give me the 'authority', which is of the form: [username[:password]@]hostname[:port]
1421		// We want just the hostname for the cookie code, but LLURL doesn't seem to have a way to extract that.
1422		// We therefore do it here.
1423		std::string authority = sOpenIDURL.mAuthority;
1424		std::string::size_type host_start = authority.find('@'); 
1425		if(host_start == std::string::npos)
1426		{
1427			// no username/password
1428			host_start = 0;
1429		}
1430		else
1431		{
1432			// Hostname starts after the @. 
1433			// (If the hostname part is empty, this may put host_start at the end of the string.  In that case, it will end up passing through an empty hostname, which is correct.)
1434			++host_start;
1435		}
1436		std::string::size_type host_end = authority.rfind(':'); 
1437		if((host_end == std::string::npos) || (host_end < host_start))
1438		{
1439			// no port
1440			host_end = authority.size();
1441		}
1442		
1443		getCookieStore()->setCookiesFromHost(sOpenIDCookie, authority.substr(host_start, host_end - host_start));
1444
1445		// *HACK: Doing this here is nasty, find a better way.
1446		LLWebSharing::instance().setOpenIDCookie(sOpenIDCookie);
1447
1448		// Do a web profile get so we can store the cookie 
1449		LLSD headers = LLSD::emptyMap();
1450		headers["Accept"] = "*/*";
1451		headers["Cookie"] = sOpenIDCookie;
1452		headers["User-Agent"] = getCurrentUserAgent();
1453
1454		std::string profile_url = getProfileURL("");
1455		LLURL raw_profile_url( profile_url.c_str() );
1456
1457		LL_DEBUGS("MediaAuth") << "Requesting " << profile_url << llendl;
1458		LL_DEBUGS("MediaAuth") << "sOpenIDCookie = [" << sOpenIDCookie << "]" << llendl;
1459		LLHTTPClient::get(profile_url,  
1460			new LLViewerMediaWebProfileResponder(raw_profile_url.getAuthority()),
1461			headers);
1462	}
1463}
1464
1465/////////////////////////////////////////////////////////////////////////////////////////
1466// static
1467void LLViewerMedia::openIDSetup(const std::string &openid_url, const std::string &openid_token)
1468{
1469	LL_DEBUGS("MediaAuth") << "url = \"" << openid_url << "\", token = \"" << openid_token << "\"" << LL_ENDL;
1470
1471	// post the token to the url 
1472	// the responder will need to extract the cookie(s).
1473
1474	// Save the OpenID URL for later -- we may need the host when adding the cookie.
1475	sOpenIDURL.init(openid_url.c_str());
1476	
1477	// We shouldn't ever do this twice, but just in case this code gets repurposed later, clear existing cookies.
1478	sOpenIDCookie.clear();
1479
1480	LLSD headers = LLSD::emptyMap();
1481	// Keep LLHTTPClient from adding an "Accept: application/llsd+xml" header
1482	headers["Accept"] = "*/*";
1483	// and use the expected content-type for a post, instead of the LLHTTPClient::postRaw() default of "application/octet-stream"
1484	headers["Content-Type"] = "application/x-www-form-urlencoded";
1485
1486	// postRaw() takes ownership of the buffer and releases it later, so we need to allocate a new buffer here.
1487	size_t size = openid_token.size();
1488	U8 *data = new U8[size];
1489	memcpy(data, openid_token.data(), size);
1490
1491	LLHTTPClient::postRaw( 
1492		openid_url, 
1493		data, 
1494		size, 
1495		new LLViewerMediaOpenIDResponder(),
1496		headers);
1497			
1498}
1499
1500/////////////////////////////////////////////////////////////////////////////////////////
1501// static
1502void LLViewerMedia::openIDCookieResponse(const std::string &cookie)
1503{
1504	LL_DEBUGS("MediaAuth") << "Cookie received: \"" << cookie << "\"" << LL_ENDL;
1505	
1506	sOpenIDCookie += cookie;
1507
1508	setOpenIDCookie();
1509}
1510
1511/////////////////////////////////////////////////////////////////////////////////////////
1512// static
1513void LLViewerMedia::proxyWindowOpened(const std::string &target, const std::string &uuid)
1514{
1515	if(uuid.empty())
1516		return;
1517		
1518	for (impl_list::iterator iter = sViewerMediaImplList.begin(); iter != sViewerMediaImplList.end(); iter++)
1519	{
1520		if((*iter)->mMediaSource && (*iter)->mMediaSource->pluginSupportsMediaBrowser())
1521		{
1522			(*iter)->mMediaSource->proxyWindowOpened(target, uuid);
1523		}
1524	}
1525}
1526
1527/////////////////////////////////////////////////////////////////////////////////////////
1528// static
1529void LLViewerMedia::proxyWindowClosed(const std::string &uuid)
1530{
1531	if(uuid.empty())
1532		return;
1533
1534	for (impl_list::iterator iter = sViewerMediaImplList.begin(); iter != sViewerMediaImplList.end(); iter++)
1535	{
1536		if((*iter)->mMediaSource && (*iter)->mMediaSource->pluginSupportsMediaBrowser())
1537		{
1538			(*iter)->mMediaSource->proxyWindowClosed(uuid);
1539		}
1540	}
1541}
1542
1543/////////////////////////////////////////////////////////////////////////////////////////
1544// static
1545void LLViewerMedia::createSpareBrowserMediaSource()
1546{
1547	// If we don't have a spare browser media source, create one.
1548	// However, if PluginAttachDebuggerToPlugins is set then don't spawn a spare
1549	// SLPlugin process in order to not be confused by an unrelated gdb terminal
1550	// popping up at the moment we start a media plugin.
1551	if (!sSpareBrowserMediaSource && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins"))
1552	{
1553		// The null owner will keep the browser plugin from fully initializing 
1554		// (specifically, it keeps LLPluginClassMedia from negotiating a size change, 
1555		// which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color)
1556		sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType("text/html", NULL, 0, 0);
1557	}
1558}
1559
1560/////////////////////////////////////////////////////////////////////////////////////////
1561// static
1562LLPluginClassMedia* LLViewerMedia::getSpareBrowserMediaSource() 
1563{
1564	LLPluginClassMedia* result = sSpareBrowserMediaSource;
1565	sSpareBrowserMediaSource = NULL;
1566	return result; 
1567};
1568
1569bool LLViewerMedia::hasInWorldMedia()
1570{
1571	if (sInWorldMediaDisabled) return false;
1572	impl_list::iterator iter = sViewerMediaImplList.begin();
1573	impl_list::iterator end = sViewerMediaImplList.end();
1574	// This should be quick, because there should be very few non-in-world-media impls
1575	for (; iter != end; iter++)
1576	{
1577		LLViewerMediaImpl* pimpl = *iter;
1578		if (!pimpl->getUsedInUI() && !pimpl->isParcelMedia())
1579		{
1580			// Found an in-world media impl
1581			return true;
1582		}
1583	}
1584	return false;
1585}
1586
1587//////////////////////////////////////////////////////////////////////////////////////////
1588// static
1589bool LLViewerMedia::hasParcelMedia()
1590{
1591	return !LLViewerParcelMedia::getURL().empty();
1592}
1593
1594//////////////////////////////////////////////////////////////////////////////////////////
1595// static
1596bool LLViewerMedia::hasParcelAudio()
1597{
1598	return !LLViewerMedia::getParcelAudioURL().empty();
1599}
1600
1601//////////////////////////////////////////////////////////////////////////////////////////
1602// static
1603std::string LLViewerMedia::getParcelAudioURL()
1604{
1605	return LLViewerParcelMgr::getInstance()->getAgentParcel()->getMusicURL();
1606}
1607
1608//////////////////////////////////////////////////////////////////////////////////////////
1609// static
1610void LLViewerMedia::initClass()
1611{
1612	gId

Large files files are truncated, but you can click here to view the full file