diff options
| -rw-r--r-- | indra/newview/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | indra/newview/app_settings/settings.xml | 26 | ||||
| -rw-r--r-- | indra/newview/llavataractions.cpp | 2 | ||||
| -rw-r--r-- | indra/newview/llimview.cpp | 102 | ||||
| -rw-r--r-- | indra/newview/llimview.h | 22 | ||||
| -rw-r--r-- | indra/newview/llinventorymodel.cpp | 507 | ||||
| -rw-r--r-- | indra/newview/llinventorymodel.h | 231 | ||||
| -rw-r--r-- | indra/newview/llinventoryobserver.cpp | 564 | ||||
| -rw-r--r-- | indra/newview/llinventoryobserver.h | 249 | ||||
| -rw-r--r-- | indra/newview/lllogininstance.cpp | 3 | ||||
| -rw-r--r-- | indra/newview/llpanelpeople.cpp | 2 | ||||
| -rw-r--r-- | indra/newview/llviewerfloaterreg.cpp | 2 | ||||
| -rw-r--r-- | indra/newview/llvoicechannel.cpp | 15 | ||||
| -rw-r--r-- | indra/newview/llvoicechannel.h | 1 | ||||
| -rw-r--r-- | indra/newview/llvoiceclient.cpp | 2 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/floater_incoming_call.xml | 40 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/floater_outgoing_call.xml | 67 | ||||
| -rw-r--r-- | indra/newview/tests/lllogininstance_test.cpp | 1 | ||||
| -rw-r--r-- | indra/viewer_components/login/lllogin.cpp | 29 | ||||
| -rw-r--r-- | indra/viewer_components/login/tests/lllogin_test.cpp | 37 | 
20 files changed, 1153 insertions, 751 deletions
| diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index b129bca1f3..9d44f34ea8 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -252,6 +252,7 @@ set(viewer_SOURCE_FILES      llinventoryfilter.cpp      llinventoryfunctions.cpp      llinventorymodel.cpp +    llinventoryobserver.cpp      llinventorypanel.cpp      llinventorysubtreepanel.cpp      lljoystickbutton.cpp @@ -748,6 +749,7 @@ set(viewer_HEADER_FILES      llinventoryfilter.h      llinventoryfunctions.h      llinventorymodel.h +    llinventoryobserver.h      llinventorypanel.h      llinventorysubtreepanel.h      lljoystickbutton.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 15c9499bbc..eb4148f92f 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -4259,7 +4259,29 @@        <key>Value</key>        <integer>0</integer>      </map> -    <key>LogMessages</key> +  <key>LoginSRVTimeout</key> +  <map> +    <key>Comment</key> +    <string>Duration in seconds of the login SRV request timeout</string> +    <key>Persist</key> +    <integer>0</integer> +    <key>Type</key> +    <string>F32</string> +    <key>Value</key> +    <real>10.0</real> +  </map> +  <key>LoginSRVPump</key> +  <map> +    <key>Comment</key> +    <string>Name of the message pump that handles SRV request</string> +    <key>Persist</key> +    <integer>0</integer> +    <key>Type</key> +    <string>String</string> +    <key>Value</key> +    <string>LLAres</string> +  </map> +  <key>LogMessages</key>      <map>        <key>Comment</key>        <string>Log network traffic</string> @@ -5501,7 +5523,7 @@        <key>Type</key>        <string>Boolean</string>        <key>Value</key> -      <integer>0</integer> +      <integer>1</integer>      </map>      <key>QAMode</key>      <map> diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index f631978565..ee4a9df15f 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -192,7 +192,7 @@ void LLAvatarActions::startIM(const LLUUID& id)  // static  void LLAvatarActions::startCall(const LLUUID& id)  { -	if (id.isNull() || isCalling(id)) +	if (id.isNull())  	{  		return;  	} diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index be5fbdbbf8..a94254e17e 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -46,6 +46,7 @@  #include "llagent.h"  #include "llavatariconctrl.h" +#include "llbottomtray.h"  #include "llcallingcard.h"  #include "llchat.h"  #include "llresmgr.h" @@ -73,6 +74,7 @@  #include "llvoicechannel.h"  #include "lltrans.h"  #include "llrecentpeople.h" +#include "llsyswellwindow.h"  #include "llfirstuse.h"  #include "llagentui.h" @@ -1091,16 +1093,90 @@ LLIMMgr::onConfirmForceCloseError(  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLOutgoingCallDialog +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LLOutgoingCallDialog::LLOutgoingCallDialog(const LLSD& payload) : +	LLDockableFloater(NULL, false, payload), +	mPayload(payload) +{ +} + +void LLOutgoingCallDialog::getAllowedRect(LLRect& rect) +{ +	rect = gViewerWindow->getWorldViewRectRaw(); +} + +void LLOutgoingCallDialog::onOpen(const LLSD& key) +{ +	// tell the user which voice channel they are leaving +	if (!mPayload["old_channel_name"].asString().empty()) +	{ +		childSetTextArg("leaving", "[CURRENT_CHAT]", mPayload["old_channel_name"].asString()); +	} +	else +	{ +		childSetTextArg("leaving", "[CURRENT_CHAT]", getString("localchat")); +	} + +	std::string callee_name = mPayload["session_name"].asString(); +	if (callee_name == "anonymous") +	{ +		callee_name = getString("anonymous"); +	} +	 +	setTitle(callee_name); + +	LLSD callee_id = mPayload["other_user_id"]; +	childSetTextArg("calling", "[CALLEE_NAME]", callee_name); +	LLAvatarIconCtrl* icon = getChild<LLAvatarIconCtrl>("avatar_icon"); +	icon->setValue(callee_id); + +	// dock the dialog to the sys well, where other sys messages appear +	setDockControl(new LLDockControl(LLBottomTray::getInstance()->getSysWell(), +					 this, getDockTongue(), LLDockControl::TOP, +					 boost::bind(&LLOutgoingCallDialog::getAllowedRect, this, _1))); +} + + +//static +void LLOutgoingCallDialog::onCancel(void* user_data) +{ +	LLOutgoingCallDialog* self = (LLOutgoingCallDialog*)user_data; + +	if (!gIMMgr) +		return; + +	LLUUID session_id = self->mPayload["session_id"].asUUID(); +	gIMMgr->endCall(session_id); +	 +	self->closeFloater(); +} + + +BOOL LLOutgoingCallDialog::postBuild() +{ +	BOOL success = LLDockableFloater::postBuild(); + +	childSetAction("Cancel", onCancel, this); + +	return success; +} + + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  // Class LLIncomingCallDialog  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  LLIncomingCallDialog::LLIncomingCallDialog(const LLSD& payload) : -	LLModalDialog(payload), +	LLDockableFloater(NULL, false, payload),  	mPayload(payload)  {  }  BOOL LLIncomingCallDialog::postBuild()  { +	LLDockableFloater::postBuild(); +  	LLSD caller_id = mPayload["caller_id"];  	EInstantMessage type = (EInstantMessage)mPayload["type"].asInteger(); @@ -1132,6 +1208,30 @@ BOOL LLIncomingCallDialog::postBuild()  	return TRUE;  } +void LLIncomingCallDialog::getAllowedRect(LLRect& rect) +{ +	rect = gViewerWindow->getWorldViewRectRaw(); +} + +void LLIncomingCallDialog::onOpen(const LLSD& key) +{ +	// tell the user which voice channel they would be leaving +	LLVoiceChannel *voice = LLVoiceChannel::getCurrentVoiceChannel(); +	if (voice && !voice->getSessionName().empty()) +	{ +		childSetTextArg("question", "[CURRENT_CHAT]", voice->getSessionName()); +	} +	else +	{ +		childSetTextArg("question", "[CURRENT_CHAT]", getString("localchat")); +	} + +	// dock the dialog to the sys well, where other sys messages appear +	setDockControl(new LLDockControl(LLBottomTray::getInstance()->getSysWell(), +									 this, getDockTongue(), LLDockControl::TOP, +									 boost::bind(&LLIncomingCallDialog::getAllowedRect, this, _1))); +} +  //static  void LLIncomingCallDialog::onAccept(void* user_data)  { diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index c566b111ca..62a54bc081 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -34,9 +34,11 @@  #define LL_LLIMVIEW_H  #include "lldarray.h" +#include "lldockablefloater.h"  #include "llspeakers.h" //for LLIMSpeakerMgr  #include "llimpanel.h" //for voice channels  #include "llmodaldialog.h" +#include "lldockablefloater.h"  #include "llinstantmessage.h"  #include "lluuid.h"  #include "llmultifloater.h" @@ -401,12 +403,13 @@ private:  	LLSD mPendingAgentListUpdates;  }; -class LLIncomingCallDialog : public LLModalDialog +class LLIncomingCallDialog : public LLDockableFloater  {  public:  	LLIncomingCallDialog(const LLSD& payload);  	/*virtual*/ BOOL postBuild(); +	/*virtual*/ void onOpen(const LLSD& key);  	static void onAccept(void* user_data);  	static void onReject(void* user_data); @@ -414,6 +417,23 @@ public:  private:  	void processCallResponse(S32 response); +	void getAllowedRect(LLRect& rect); + +	LLSD mPayload; +}; + +class LLOutgoingCallDialog : public LLDockableFloater +{ +public: +	LLOutgoingCallDialog(const LLSD& payload); + +	/*virtual*/ BOOL postBuild(); +	/*virtual*/ void onOpen(const LLSD& key); + +	static void onCancel(void* user_data); + +private: +	void getAllowedRect(LLRect& rect);  	LLSD mPayload;  }; diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index c57e41e9b3..4b0d524906 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -3721,513 +3721,6 @@ bool LLNameCategoryCollector::operator()(  	return false;  } - - -///---------------------------------------------------------------------------- -/// Observers -///---------------------------------------------------------------------------- - -void LLInventoryCompletionObserver::changed(U32 mask) -{ -	// scan through the incomplete items and move or erase them as -	// appropriate. -	if(!mIncomplete.empty()) -	{ -		for(item_ref_t::iterator it = mIncomplete.begin(); it < mIncomplete.end(); ) -		{ -			LLViewerInventoryItem* item = gInventory.getItem(*it); -			if(!item) -			{ -				it = mIncomplete.erase(it); -				continue; -			} -			if(item->isComplete()) -			{ -				mComplete.push_back(*it); -				it = mIncomplete.erase(it); -				continue; -			} -			++it; -		} -		if(mIncomplete.empty()) -		{ -			done(); -		} -	} -} - -void LLInventoryCompletionObserver::watchItem(const LLUUID& id) -{ -	if(id.notNull()) -	{ -		mIncomplete.push_back(id); -	} -} - - -void LLInventoryFetchObserver::changed(U32 mask) -{ -	// scan through the incomplete items and move or erase them as -	// appropriate. -	if(!mIncomplete.empty()) -	{ -		for(item_ref_t::iterator it = mIncomplete.begin(); it < mIncomplete.end(); ) -		{ -			LLViewerInventoryItem* item = gInventory.getItem(*it); -			if(!item) -			{ -				// BUG: This can cause done() to get called prematurely below. -				// This happens with the LLGestureInventoryFetchObserver that -				// loads gestures at startup. JC -				it = mIncomplete.erase(it); -				continue; -			} -			if(item->isComplete()) -			{ -				mComplete.push_back(*it); -				it = mIncomplete.erase(it); -				continue; -			} -			++it; -		} -		if(mIncomplete.empty()) -		{ -			done(); -		} -	} -	//llinfos << "LLInventoryFetchObserver::changed() mComplete size " << mComplete.size() << llendl; -	//llinfos << "LLInventoryFetchObserver::changed() mIncomplete size " << mIncomplete.size() << llendl; -} - -bool LLInventoryFetchObserver::isEverythingComplete() const -{ -	return mIncomplete.empty(); -} - -void fetch_items_from_llsd(const LLSD& items_llsd) -{ -	if (!items_llsd.size()) return; -	LLSD body; -	body[0]["cap_name"] = "FetchInventory"; -	body[1]["cap_name"] = "FetchLib"; -	for (S32 i=0; i<items_llsd.size();i++) -	{ -		if (items_llsd[i]["owner_id"].asString() == gAgent.getID().asString()) -		{ -			body[0]["items"].append(items_llsd[i]); -			continue; -		} -		if (items_llsd[i]["owner_id"].asString() == ALEXANDRIA_LINDEN_ID.asString()) -		{ -			body[1]["items"].append(items_llsd[i]); -			continue; -		} -	} -		 -	for (S32 i=0; i<body.size(); i++) -	{ -		if (0 >= body[i].size()) continue; -		std::string url = gAgent.getRegion()->getCapability(body[i]["cap_name"].asString()); - -		if (!url.empty()) -		{ -			body[i]["agent_id"]	= gAgent.getID(); -			LLHTTPClient::post(url, body[i], new LLInventoryModel::fetchInventoryResponder(body[i])); -			break; -		} - -		LLMessageSystem* msg = gMessageSystem; -		BOOL start_new_message = TRUE; -		for (S32 j=0; j<body[i]["items"].size(); j++) -		{ -			LLSD item_entry = body[i]["items"][j]; -			if(start_new_message) -			{ -				start_new_message = FALSE; -				msg->newMessageFast(_PREHASH_FetchInventory); -				msg->nextBlockFast(_PREHASH_AgentData); -				msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); -				msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); -			} -			msg->nextBlockFast(_PREHASH_InventoryData); -			msg->addUUIDFast(_PREHASH_OwnerID, item_entry["owner_id"].asUUID()); -			msg->addUUIDFast(_PREHASH_ItemID, item_entry["item_id"].asUUID()); -			if(msg->isSendFull(NULL)) -			{ -				start_new_message = TRUE; -				gAgent.sendReliableMessage(); -			} -		} -		if(!start_new_message) -		{ -			gAgent.sendReliableMessage(); -		} -	} -} - -void LLInventoryFetchObserver::fetchItems( -	const LLInventoryFetchObserver::item_ref_t& ids) -{ -	LLUUID owner_id; -	LLSD items_llsd; -	for(item_ref_t::const_iterator it = ids.begin(); it < ids.end(); ++it) -	{ -		LLViewerInventoryItem* item = gInventory.getItem(*it); -		if(item) -		{ -			if(item->isComplete()) -			{ -				// It's complete, so put it on the complete container. -				mComplete.push_back(*it); -				continue; -			} -			else -			{ -				owner_id = item->getPermissions().getOwner(); -			} -		} -		else -		{ -			// assume it's agent inventory. -			owner_id = gAgent.getID(); -		} -		 -		// It's incomplete, so put it on the incomplete container, and -		// pack this on the message. -		mIncomplete.push_back(*it); -		 -		// Prepare the data to fetch -		LLSD item_entry; -		item_entry["owner_id"] = owner_id; -		item_entry["item_id"] = (*it); -		items_llsd.append(item_entry); -	} -	fetch_items_from_llsd(items_llsd); -} - -// virtual -void LLInventoryFetchDescendentsObserver::changed(U32 mask) -{ -	for(folder_ref_t::iterator it = mIncompleteFolders.begin(); it < mIncompleteFolders.end();) -	{ -		LLViewerInventoryCategory* cat = gInventory.getCategory(*it); -		if(!cat) -		{ -			it = mIncompleteFolders.erase(it); -			continue; -		} -		if(isComplete(cat)) -		{ -			mCompleteFolders.push_back(*it); -			it = mIncompleteFolders.erase(it); -			continue; -		} -		++it; -	} -	if(mIncompleteFolders.empty()) -	{ -		done(); -	} -} - -void LLInventoryFetchDescendentsObserver::fetchDescendents( -	const folder_ref_t& ids) -{ -	for(folder_ref_t::const_iterator it = ids.begin(); it != ids.end(); ++it) -	{ -		LLViewerInventoryCategory* cat = gInventory.getCategory(*it); -		if(!cat) continue; -		if(!isComplete(cat)) -		{ -			cat->fetchDescendents();		//blindly fetch it without seeing if anything else is fetching it. -			mIncompleteFolders.push_back(*it);	//Add to list of things being downloaded for this observer. -		} -		else -		{ -			mCompleteFolders.push_back(*it); -		} -	} -} - -bool LLInventoryFetchDescendentsObserver::isEverythingComplete() const -{ -	return mIncompleteFolders.empty(); -} - -bool LLInventoryFetchDescendentsObserver::isComplete(LLViewerInventoryCategory* cat) -{ -	S32 version = cat->getVersion(); -	S32 descendents = cat->getDescendentCount(); -	if((LLViewerInventoryCategory::VERSION_UNKNOWN == version) -	   || (LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN == descendents)) -	{ -		return false; -	} -	// it might be complete - check known descendents against -	// currently available. -	LLInventoryModel::cat_array_t* cats; -	LLInventoryModel::item_array_t* items; -	gInventory.getDirectDescendentsOf(cat->getUUID(), cats, items); -	if(!cats || !items) -	{ -		// bit of a hack - pretend we're done if they are gone or -		// incomplete. should never know, but it would suck if this -		// kept tight looping because of a corrupt memory state. -		return true; -	} -	S32 known = cats->count() + items->count(); -	if(descendents == known) -	{ -		// hey - we're done. -		return true; -	} -	return false; -} - -void LLInventoryFetchComboObserver::changed(U32 mask) -{ -	if(!mIncompleteItems.empty()) -	{ -		for(item_ref_t::iterator it = mIncompleteItems.begin(); it < mIncompleteItems.end(); ) -		{ -			LLViewerInventoryItem* item = gInventory.getItem(*it); -			if(!item) -			{ -				it = mIncompleteItems.erase(it); -				continue; -			} -			if(item->isComplete()) -			{ -				mCompleteItems.push_back(*it); -				it = mIncompleteItems.erase(it); -				continue; -			} -			++it; -		} -	} -	if(!mIncompleteFolders.empty()) -	{ -		for(folder_ref_t::iterator it = mIncompleteFolders.begin(); it < mIncompleteFolders.end();) -		{ -			LLViewerInventoryCategory* cat = gInventory.getCategory(*it); -			if(!cat) -			{ -				it = mIncompleteFolders.erase(it); -				continue; -			} -			if(gInventory.isCategoryComplete(*it)) -			{ -				mCompleteFolders.push_back(*it); -				it = mIncompleteFolders.erase(it); -				continue; -			} -			++it; -		} -	} -	if(!mDone && mIncompleteItems.empty() && mIncompleteFolders.empty()) -	{ -		mDone = true; -		done(); -	} -} - -void LLInventoryFetchComboObserver::fetch( -	const folder_ref_t& folder_ids, -	const item_ref_t& item_ids) -{ -	lldebugs << "LLInventoryFetchComboObserver::fetch()" << llendl; -	for(folder_ref_t::const_iterator fit = folder_ids.begin(); fit != folder_ids.end(); ++fit) -	{ -		LLViewerInventoryCategory* cat = gInventory.getCategory(*fit); -		if(!cat) continue; -		if(!gInventory.isCategoryComplete(*fit)) -		{ -			cat->fetchDescendents(); -			lldebugs << "fetching folder " << *fit <<llendl; -			mIncompleteFolders.push_back(*fit); -		} -		else -		{ -			mCompleteFolders.push_back(*fit); -			lldebugs << "completing folder " << *fit <<llendl; -		} -	} - -	// Now for the items - we fetch everything which is not a direct -	// descendent of an incomplete folder because the item will show -	// up in an inventory descendents message soon enough so we do not -	// have to fetch it individually. -	LLSD items_llsd; -	LLUUID owner_id; -	for(item_ref_t::const_iterator iit = item_ids.begin(); iit != item_ids.end(); ++iit) -	{ -		LLViewerInventoryItem* item = gInventory.getItem(*iit); -		if(!item) -		{ -			lldebugs << "uanble to find item " << *iit << llendl; -			continue; -		} -		if(item->isComplete()) -		{ -			// It's complete, so put it on the complete container. -			mCompleteItems.push_back(*iit); -			lldebugs << "completing item " << *iit << llendl; -			continue; -		} -		else -		{ -			mIncompleteItems.push_back(*iit); -			owner_id = item->getPermissions().getOwner(); -		} -		if(std::find(mIncompleteFolders.begin(), mIncompleteFolders.end(), item->getParentUUID()) == mIncompleteFolders.end()) -		{ -			LLSD item_entry; -			item_entry["owner_id"] = owner_id; -			item_entry["item_id"] = (*iit); -			items_llsd.append(item_entry); -		} -		else -		{ -			lldebugs << "not worrying about " << *iit << llendl; -		} -	} -	fetch_items_from_llsd(items_llsd); -} - -void LLInventoryExistenceObserver::watchItem(const LLUUID& id) -{ -	if(id.notNull()) -	{ -		mMIA.push_back(id); -	} -} - -void LLInventoryExistenceObserver::changed(U32 mask) -{ -	// scan through the incomplete items and move or erase them as -	// appropriate. -	if(!mMIA.empty()) -	{ -		for(item_ref_t::iterator it = mMIA.begin(); it < mMIA.end(); ) -		{ -			LLViewerInventoryItem* item = gInventory.getItem(*it); -			if(!item) -			{ -				++it; -				continue; -			} -			mExist.push_back(*it); -			it = mMIA.erase(it); -		} -		if(mMIA.empty()) -		{ -			done(); -		} -	} -} - -void LLInventoryAddedObserver::changed(U32 mask) -{ -	if(!(mask & LLInventoryObserver::ADD)) -	{ -		return; -	} - -	// *HACK: If this was in response to a packet off -	// the network, figure out which item was updated. -	LLMessageSystem* msg = gMessageSystem; - -	std::string msg_name; -	if (mMessageName.empty()) -	{ -		msg_name = msg->getMessageName(); -	} -	else -	{ -		msg_name = mMessageName; -	} - -	if (msg_name.empty()) -	{ -		return; -	} -	 -	// We only want newly created inventory items. JC -	if ( msg_name != "UpdateCreateInventoryItem") -	{ -		return; -	} - -	LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; -	S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); -	for(S32 i = 0; i < num_blocks; ++i) -	{ -		titem->unpackMessage(msg, _PREHASH_InventoryData, i); -		if (!(titem->getUUID().isNull())) -		{ -			//we don't do anything with null keys -			mAdded.push_back(titem->getUUID()); -		} -	} -	if (!mAdded.empty()) -	{ -		done(); -	} -} - -LLInventoryTransactionObserver::LLInventoryTransactionObserver( -	const LLTransactionID& transaction_id) : -	mTransactionID(transaction_id) -{ -} - -void LLInventoryTransactionObserver::changed(U32 mask) -{ -	if(mask & LLInventoryObserver::ADD) -	{ -		// This could be it - see if we are processing a bulk update -		LLMessageSystem* msg = gMessageSystem; -		if(msg->getMessageName() -		   && (0 == strcmp(msg->getMessageName(), "BulkUpdateInventory"))) -		{ -			// we have a match for the message - now check the -			// transaction id. -			LLUUID id; -			msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, id); -			if(id == mTransactionID) -			{ -				// woo hoo, we found it -				folder_ref_t folders; -				item_ref_t items; -				S32 count; -				count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); -				S32 i; -				for(i = 0; i < count; ++i) -				{ -					msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, id, i); -					if(id.notNull()) -					{ -						folders.push_back(id); -					} -				} -				count = msg->getNumberOfBlocksFast(_PREHASH_ItemData); -				for(i = 0; i < count; ++i) -				{ -					msg->getUUIDFast(_PREHASH_ItemData, _PREHASH_ItemID, id, i); -					if(id.notNull()) -					{ -						items.push_back(id); -					} -				} - -				// call the derived class the implements this method. -				done(folders, items); -			} -		} -	} -} - -  ///----------------------------------------------------------------------------  /// LLAssetIDMatches   ///---------------------------------------------------------------------------- diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index ebfb0a7000..bd64591194 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -41,40 +41,27 @@  #include "lluuid.h"  #include "llpermissionsflags.h"  #include "llstring.h" -  #include <map>  #include <set>  #include <string>  #include <vector> -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryObserver -// -// This class is designed to be a simple abstract base class which can -// relay messages when the inventory changes. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// ! REFACTOR ! Remove llinventoryobservers.h and have other files that need it explicitly  +// include llinventoryobservers.h instead of llinventorymodel.h .  This will reduce dependency on +// llinventorymodel.h. +#include "llinventoryobserver.h"  + +class LLInventoryObserver; +class LLInventoryObject; +class LLInventoryItem; +class LLInventoryCategory; +class LLViewerInventoryItem; +class LLViewerInventoryCategory; +class LLViewerInventoryItem; +class LLViewerInventoryCategory; +class LLMessageSystem; +class LLInventoryCollectFunctor; -class LLInventoryObserver -{ -public: -	// This enumeration is a way to refer to what changed in a more -	// human readable format. You can mask the value provided by -	// chaged() to see if the observer is interested in the change. -	enum  -	{ -		NONE = 0, -		LABEL = 1,			// name changed -		INTERNAL = 2,		// internal change, eg, asset uuid different -		ADD = 4,			// something added -		REMOVE = 8,			// something deleted -		STRUCTURE = 16,		// structural change, eg, item or folder moved -		CALLING_CARD = 32,	// online, grant status, cancel, etc change -		ALL = 0xffffffff -	}; -	virtual ~LLInventoryObserver() {}; -	virtual void changed(U32 mask) = 0; -	std::string mMessageName; // used by Agent Inventory Service only. [DEV-20328] -};  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  // Class LLInventoryModel @@ -87,16 +74,6 @@ public:  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLInventoryObject; -class LLInventoryItem; -class LLInventoryCategory; -class LLViewerInventoryItem; -class LLViewerInventoryCategory; -class LLViewerInventoryItem; -class LLViewerInventoryCategory; -class LLMessageSystem; -class LLInventoryCollectFunctor; -  class LLInventoryModel  {  public: @@ -771,183 +748,5 @@ public:  							LLInventoryItem* item);  }; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryCompletionObserver -// -// Class which can be used as a base class for doing something when -// when all observed items are locally complete. This class implements -// the changed() method of LLInventoryObserver and declares a new -// method named done() which is called when all watched items have -// complete information in the inventory model. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLInventoryCompletionObserver : public LLInventoryObserver -{ -public: -	LLInventoryCompletionObserver() {} -	virtual void changed(U32 mask); - -	void watchItem(const LLUUID& id); - -protected: -	virtual void done() = 0; - -	typedef std::vector<LLUUID> item_ref_t; -	item_ref_t mComplete; -	item_ref_t mIncomplete; -}; - - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryFetchObserver -// -// This class is much like the LLInventoryCompletionObserver, except -// that it handles all the the fetching necessary. Override the done() -// method to do the thing you want. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLInventoryFetchObserver : public LLInventoryObserver -{ -public: -	LLInventoryFetchObserver() {} -	virtual void changed(U32 mask); - -	typedef std::vector<LLUUID> item_ref_t; - -	bool isEverythingComplete() const; -	void fetchItems(const item_ref_t& ids); -	virtual void done() = 0; - -protected: -	item_ref_t mComplete; -	item_ref_t mIncomplete; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryFetchDescendentsObserver -// -// This class is much like the LLInventoryCompletionObserver, except -// that it handles fetching based on category. Override the done() -// method to do the thing you want. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLInventoryFetchDescendentsObserver : public LLInventoryObserver -{ -public: -	LLInventoryFetchDescendentsObserver() {} -	virtual void changed(U32 mask); - -	typedef std::vector<LLUUID> folder_ref_t; -	void fetchDescendents(const folder_ref_t& ids); -	bool isEverythingComplete() const; -	virtual void done() = 0; - -protected: -	bool isComplete(LLViewerInventoryCategory* cat); -	folder_ref_t mIncompleteFolders; -	folder_ref_t mCompleteFolders; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryFetchComboObserver -// -// This class does an appropriate combination of fetch descendents and -// item fetches based on completion of categories and items. Much like -// the fetch and fetch descendents, this will call done() when everything -// has arrived. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLInventoryFetchComboObserver : public LLInventoryObserver -{ -public: -	LLInventoryFetchComboObserver() : mDone(false) {} -	virtual void changed(U32 mask); - -	typedef std::vector<LLUUID> folder_ref_t; -	typedef std::vector<LLUUID> item_ref_t; -	void fetch(const folder_ref_t& folder_ids, const item_ref_t& item_ids); - -	virtual void done() = 0; - -protected: -	bool mDone; -	folder_ref_t mCompleteFolders; -	folder_ref_t mIncompleteFolders; -	item_ref_t mCompleteItems; -	item_ref_t mIncompleteItems; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryExistenceObserver -// -// This class is used as a base class for doing somethign when all the -// observed item ids exist in the inventory somewhere. You can derive -// a class from this class and implement the done() method to do -// something useful. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLInventoryExistenceObserver : public LLInventoryObserver -{ -public: -	LLInventoryExistenceObserver() {} -	virtual void changed(U32 mask); - -	void watchItem(const LLUUID& id); - -protected: -	virtual void done() = 0; - -	typedef std::vector<LLUUID> item_ref_t; -	item_ref_t mExist; -	item_ref_t mMIA; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryAddedObserver -// -// This class is used as a base class for doing something when  -// a new item arrives in inventory. -// It does not watch for a certain UUID, rather it acts when anything is added -// Derive a class from this class and implement the done() method to do -// something useful. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLInventoryAddedObserver : public LLInventoryObserver -{ -public: -	LLInventoryAddedObserver() : mAdded() {} -	virtual void changed(U32 mask); - -protected: -	virtual void done() = 0; - -	typedef std::vector<LLUUID> item_ref_t; -	item_ref_t mAdded; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryTransactionObserver -// -// Class which can be used as a base class for doing something when an -// inventory transaction completes. -// -// *NOTE: This class is not quite complete. Avoid using unless you fix up it's -// functionality gaps. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLInventoryTransactionObserver : public LLInventoryObserver -{ -public: -	LLInventoryTransactionObserver(const LLTransactionID& transaction_id); -	virtual void changed(U32 mask); - -protected: -	typedef std::vector<LLUUID> folder_ref_t; -	typedef std::vector<LLUUID> item_ref_t; -	virtual void done(const folder_ref_t& folders, const item_ref_t& items) = 0; - -	LLTransactionID mTransactionID; -}; - -  #endif // LL_LLINVENTORYMODEL_H diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp new file mode 100644 index 0000000000..3ccf593d27 --- /dev/null +++ b/indra/newview/llinventoryobserver.cpp @@ -0,0 +1,564 @@ +/**  + * @file llinventoryobserver.cpp + * @brief Implementation of the inventory observers used to track agent inventory. + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + *  + * Copyright (c) 2002-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 "llinventoryobserver.h" + +#include "llassetstorage.h" +#include "llcrc.h" +#include "lldir.h" +#include "llsys.h" +#include "llxfermanager.h" +#include "message.h" + +#include "llagent.h" +#include "llagentwearables.h" +#include "llfloater.h" +#include "llfocusmgr.h" +#include "llinventorybridge.h" +#include "llinventoryfunctions.h" +#include "llinventorymodel.h" +#include "llviewermessage.h" +#include "llviewerwindow.h" +#include "llviewerregion.h" +#include "llappviewer.h" +#include "lldbstrings.h" +#include "llviewerstats.h" +#include "llmutelist.h" +#include "llnotifications.h" +#include "llcallbacklist.h" +#include "llpreview.h" +#include "llviewercontrol.h" +#include "llvoavatarself.h" +#include "llsdutil.h" +#include <deque> + +void LLInventoryCompletionObserver::changed(U32 mask) +{ +	// scan through the incomplete items and move or erase them as +	// appropriate. +	if(!mIncomplete.empty()) +	{ +		for(item_ref_t::iterator it = mIncomplete.begin(); it < mIncomplete.end(); ) +		{ +			LLViewerInventoryItem* item = gInventory.getItem(*it); +			if(!item) +			{ +				it = mIncomplete.erase(it); +				continue; +			} +			if(item->isComplete()) +			{ +				mComplete.push_back(*it); +				it = mIncomplete.erase(it); +				continue; +			} +			++it; +		} +		if(mIncomplete.empty()) +		{ +			done(); +		} +	} +} + +void LLInventoryCompletionObserver::watchItem(const LLUUID& id) +{ +	if(id.notNull()) +	{ +		mIncomplete.push_back(id); +	} +} + + +void LLInventoryFetchObserver::changed(U32 mask) +{ +	// scan through the incomplete items and move or erase them as +	// appropriate. +	if(!mIncomplete.empty()) +	{ +		for(item_ref_t::iterator it = mIncomplete.begin(); it < mIncomplete.end(); ) +		{ +			LLViewerInventoryItem* item = gInventory.getItem(*it); +			if(!item) +			{ +				// BUG: This can cause done() to get called prematurely below. +				// This happens with the LLGestureInventoryFetchObserver that +				// loads gestures at startup. JC +				it = mIncomplete.erase(it); +				continue; +			} +			if(item->isComplete()) +			{ +				mComplete.push_back(*it); +				it = mIncomplete.erase(it); +				continue; +			} +			++it; +		} +		if(mIncomplete.empty()) +		{ +			done(); +		} +	} +	//llinfos << "LLInventoryFetchObserver::changed() mComplete size " << mComplete.size() << llendl; +	//llinfos << "LLInventoryFetchObserver::changed() mIncomplete size " << mIncomplete.size() << llendl; +} + +bool LLInventoryFetchObserver::isEverythingComplete() const +{ +	return mIncomplete.empty(); +} + +void fetch_items_from_llsd(const LLSD& items_llsd) +{ +	if (!items_llsd.size()) return; +	LLSD body; +	body[0]["cap_name"] = "FetchInventory"; +	body[1]["cap_name"] = "FetchLib"; +	for (S32 i=0; i<items_llsd.size();i++) +	{ +		if (items_llsd[i]["owner_id"].asString() == gAgent.getID().asString()) +		{ +			body[0]["items"].append(items_llsd[i]); +			continue; +		} +		if (items_llsd[i]["owner_id"].asString() == ALEXANDRIA_LINDEN_ID.asString()) +		{ +			body[1]["items"].append(items_llsd[i]); +			continue; +		} +	} +		 +	for (S32 i=0; i<body.size(); i++) +	{ +		if (0 >= body[i].size()) continue; +		std::string url = gAgent.getRegion()->getCapability(body[i]["cap_name"].asString()); + +		if (!url.empty()) +		{ +			body[i]["agent_id"]	= gAgent.getID(); +			LLHTTPClient::post(url, body[i], new LLInventoryModel::fetchInventoryResponder(body[i])); +			break; +		} + +		LLMessageSystem* msg = gMessageSystem; +		BOOL start_new_message = TRUE; +		for (S32 j=0; j<body[i]["items"].size(); j++) +		{ +			LLSD item_entry = body[i]["items"][j]; +			if(start_new_message) +			{ +				start_new_message = FALSE; +				msg->newMessageFast(_PREHASH_FetchInventory); +				msg->nextBlockFast(_PREHASH_AgentData); +				msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); +				msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); +			} +			msg->nextBlockFast(_PREHASH_InventoryData); +			msg->addUUIDFast(_PREHASH_OwnerID, item_entry["owner_id"].asUUID()); +			msg->addUUIDFast(_PREHASH_ItemID, item_entry["item_id"].asUUID()); +			if(msg->isSendFull(NULL)) +			{ +				start_new_message = TRUE; +				gAgent.sendReliableMessage(); +			} +		} +		if(!start_new_message) +		{ +			gAgent.sendReliableMessage(); +		} +	} +} + +void LLInventoryFetchObserver::fetchItems( +	const LLInventoryFetchObserver::item_ref_t& ids) +{ +	LLUUID owner_id; +	LLSD items_llsd; +	for(item_ref_t::const_iterator it = ids.begin(); it < ids.end(); ++it) +	{ +		LLViewerInventoryItem* item = gInventory.getItem(*it); +		if(item) +		{ +			if(item->isComplete()) +			{ +				// It's complete, so put it on the complete container. +				mComplete.push_back(*it); +				continue; +			} +			else +			{ +				owner_id = item->getPermissions().getOwner(); +			} +		} +		else +		{ +			// assume it's agent inventory. +			owner_id = gAgent.getID(); +		} +		 +		// It's incomplete, so put it on the incomplete container, and +		// pack this on the message. +		mIncomplete.push_back(*it); +		 +		// Prepare the data to fetch +		LLSD item_entry; +		item_entry["owner_id"] = owner_id; +		item_entry["item_id"] = (*it); +		items_llsd.append(item_entry); +	} +	fetch_items_from_llsd(items_llsd); +} + +// virtual +void LLInventoryFetchDescendentsObserver::changed(U32 mask) +{ +	for(folder_ref_t::iterator it = mIncompleteFolders.begin(); it < mIncompleteFolders.end();) +	{ +		LLViewerInventoryCategory* cat = gInventory.getCategory(*it); +		if(!cat) +		{ +			it = mIncompleteFolders.erase(it); +			continue; +		} +		if(isComplete(cat)) +		{ +			mCompleteFolders.push_back(*it); +			it = mIncompleteFolders.erase(it); +			continue; +		} +		++it; +	} +	if(mIncompleteFolders.empty()) +	{ +		done(); +	} +} + +void LLInventoryFetchDescendentsObserver::fetchDescendents( +	const folder_ref_t& ids) +{ +	for(folder_ref_t::const_iterator it = ids.begin(); it != ids.end(); ++it) +	{ +		LLViewerInventoryCategory* cat = gInventory.getCategory(*it); +		if(!cat) continue; +		if(!isComplete(cat)) +		{ +			cat->fetchDescendents();		//blindly fetch it without seeing if anything else is fetching it. +			mIncompleteFolders.push_back(*it);	//Add to list of things being downloaded for this observer. +		} +		else +		{ +			mCompleteFolders.push_back(*it); +		} +	} +} + +bool LLInventoryFetchDescendentsObserver::isEverythingComplete() const +{ +	return mIncompleteFolders.empty(); +} + +bool LLInventoryFetchDescendentsObserver::isComplete(LLViewerInventoryCategory* cat) +{ +	S32 version = cat->getVersion(); +	S32 descendents = cat->getDescendentCount(); +	if((LLViewerInventoryCategory::VERSION_UNKNOWN == version) +	   || (LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN == descendents)) +	{ +		return false; +	} +	// it might be complete - check known descendents against +	// currently available. +	LLInventoryModel::cat_array_t* cats; +	LLInventoryModel::item_array_t* items; +	gInventory.getDirectDescendentsOf(cat->getUUID(), cats, items); +	if(!cats || !items) +	{ +		// bit of a hack - pretend we're done if they are gone or +		// incomplete. should never know, but it would suck if this +		// kept tight looping because of a corrupt memory state. +		return true; +	} +	S32 known = cats->count() + items->count(); +	if(descendents == known) +	{ +		// hey - we're done. +		return true; +	} +	return false; +} + +void LLInventoryFetchComboObserver::changed(U32 mask) +{ +	if(!mIncompleteItems.empty()) +	{ +		for(item_ref_t::iterator it = mIncompleteItems.begin(); it < mIncompleteItems.end(); ) +		{ +			LLViewerInventoryItem* item = gInventory.getItem(*it); +			if(!item) +			{ +				it = mIncompleteItems.erase(it); +				continue; +			} +			if(item->isComplete()) +			{ +				mCompleteItems.push_back(*it); +				it = mIncompleteItems.erase(it); +				continue; +			} +			++it; +		} +	} +	if(!mIncompleteFolders.empty()) +	{ +		for(folder_ref_t::iterator it = mIncompleteFolders.begin(); it < mIncompleteFolders.end();) +		{ +			LLViewerInventoryCategory* cat = gInventory.getCategory(*it); +			if(!cat) +			{ +				it = mIncompleteFolders.erase(it); +				continue; +			} +			if(gInventory.isCategoryComplete(*it)) +			{ +				mCompleteFolders.push_back(*it); +				it = mIncompleteFolders.erase(it); +				continue; +			} +			++it; +		} +	} +	if(!mDone && mIncompleteItems.empty() && mIncompleteFolders.empty()) +	{ +		mDone = true; +		done(); +	} +} + +void LLInventoryFetchComboObserver::fetch( +	const folder_ref_t& folder_ids, +	const item_ref_t& item_ids) +{ +	lldebugs << "LLInventoryFetchComboObserver::fetch()" << llendl; +	for(folder_ref_t::const_iterator fit = folder_ids.begin(); fit != folder_ids.end(); ++fit) +	{ +		LLViewerInventoryCategory* cat = gInventory.getCategory(*fit); +		if(!cat) continue; +		if(!gInventory.isCategoryComplete(*fit)) +		{ +			cat->fetchDescendents(); +			lldebugs << "fetching folder " << *fit <<llendl; +			mIncompleteFolders.push_back(*fit); +		} +		else +		{ +			mCompleteFolders.push_back(*fit); +			lldebugs << "completing folder " << *fit <<llendl; +		} +	} + +	// Now for the items - we fetch everything which is not a direct +	// descendent of an incomplete folder because the item will show +	// up in an inventory descendents message soon enough so we do not +	// have to fetch it individually. +	LLSD items_llsd; +	LLUUID owner_id; +	for(item_ref_t::const_iterator iit = item_ids.begin(); iit != item_ids.end(); ++iit) +	{ +		LLViewerInventoryItem* item = gInventory.getItem(*iit); +		if(!item) +		{ +			lldebugs << "uanble to find item " << *iit << llendl; +			continue; +		} +		if(item->isComplete()) +		{ +			// It's complete, so put it on the complete container. +			mCompleteItems.push_back(*iit); +			lldebugs << "completing item " << *iit << llendl; +			continue; +		} +		else +		{ +			mIncompleteItems.push_back(*iit); +			owner_id = item->getPermissions().getOwner(); +		} +		if(std::find(mIncompleteFolders.begin(), mIncompleteFolders.end(), item->getParentUUID()) == mIncompleteFolders.end()) +		{ +			LLSD item_entry; +			item_entry["owner_id"] = owner_id; +			item_entry["item_id"] = (*iit); +			items_llsd.append(item_entry); +		} +		else +		{ +			lldebugs << "not worrying about " << *iit << llendl; +		} +	} +	fetch_items_from_llsd(items_llsd); +} + +void LLInventoryExistenceObserver::watchItem(const LLUUID& id) +{ +	if(id.notNull()) +	{ +		mMIA.push_back(id); +	} +} + +void LLInventoryExistenceObserver::changed(U32 mask) +{ +	// scan through the incomplete items and move or erase them as +	// appropriate. +	if(!mMIA.empty()) +	{ +		for(item_ref_t::iterator it = mMIA.begin(); it < mMIA.end(); ) +		{ +			LLViewerInventoryItem* item = gInventory.getItem(*it); +			if(!item) +			{ +				++it; +				continue; +			} +			mExist.push_back(*it); +			it = mMIA.erase(it); +		} +		if(mMIA.empty()) +		{ +			done(); +		} +	} +} + +void LLInventoryAddedObserver::changed(U32 mask) +{ +	if(!(mask & LLInventoryObserver::ADD)) +	{ +		return; +	} + +	// *HACK: If this was in response to a packet off +	// the network, figure out which item was updated. +	LLMessageSystem* msg = gMessageSystem; + +	std::string msg_name; +	if (mMessageName.empty()) +	{ +		msg_name = msg->getMessageName(); +	} +	else +	{ +		msg_name = mMessageName; +	} + +	if (msg_name.empty()) +	{ +		return; +	} +	 +	// We only want newly created inventory items. JC +	if ( msg_name != "UpdateCreateInventoryItem") +	{ +		return; +	} + +	LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; +	S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); +	for(S32 i = 0; i < num_blocks; ++i) +	{ +		titem->unpackMessage(msg, _PREHASH_InventoryData, i); +		if (!(titem->getUUID().isNull())) +		{ +			//we don't do anything with null keys +			mAdded.push_back(titem->getUUID()); +		} +	} +	if (!mAdded.empty()) +	{ +		done(); +	} +} + +LLInventoryTransactionObserver::LLInventoryTransactionObserver( +	const LLTransactionID& transaction_id) : +	mTransactionID(transaction_id) +{ +} + +void LLInventoryTransactionObserver::changed(U32 mask) +{ +	if(mask & LLInventoryObserver::ADD) +	{ +		// This could be it - see if we are processing a bulk update +		LLMessageSystem* msg = gMessageSystem; +		if(msg->getMessageName() +		   && (0 == strcmp(msg->getMessageName(), "BulkUpdateInventory"))) +		{ +			// we have a match for the message - now check the +			// transaction id. +			LLUUID id; +			msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, id); +			if(id == mTransactionID) +			{ +				// woo hoo, we found it +				folder_ref_t folders; +				item_ref_t items; +				S32 count; +				count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); +				S32 i; +				for(i = 0; i < count; ++i) +				{ +					msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, id, i); +					if(id.notNull()) +					{ +						folders.push_back(id); +					} +				} +				count = msg->getNumberOfBlocksFast(_PREHASH_ItemData); +				for(i = 0; i < count; ++i) +				{ +					msg->getUUIDFast(_PREHASH_ItemData, _PREHASH_ItemID, id, i); +					if(id.notNull()) +					{ +						items.push_back(id); +					} +				} + +				// call the derived class the implements this method. +				done(folders, items); +			} +		} +	} +} diff --git a/indra/newview/llinventoryobserver.h b/indra/newview/llinventoryobserver.h new file mode 100644 index 0000000000..384e6292e8 --- /dev/null +++ b/indra/newview/llinventoryobserver.h @@ -0,0 +1,249 @@ +/**  + * @file llinventoryobserver.h + * @brief LLInventoryObserver class header file + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + *  + * Copyright (c) 2002-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$ + */ + +#ifndef LL_LLINVENTORYOBSERVERS_H +#define LL_LLINVENTORYOBSERVERS_H + +#include "lluuid.h" +#include <string> +#include <vector> + +class LLViewerInventoryCategory; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryObserver +// +// This class is designed to be a simple abstract base class which can +// relay messages when the inventory changes. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLInventoryObserver +{ +public: +	// This enumeration is a way to refer to what changed in a more +	// human readable format. You can mask the value provided by +	// chaged() to see if the observer is interested in the change. +	enum  +	{ +		NONE = 0, +		LABEL = 1,			// name changed +		INTERNAL = 2,		// internal change, eg, asset uuid different +		ADD = 4,			// something added +		REMOVE = 8,			// something deleted +		STRUCTURE = 16,		// structural change, eg, item or folder moved +		CALLING_CARD = 32,	// online, grant status, cancel, etc change +		ALL = 0xffffffff +	}; +	virtual ~LLInventoryObserver() {}; +	virtual void changed(U32 mask) = 0; +	std::string mMessageName; // used by Agent Inventory Service only. [DEV-20328] +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryCompletionObserver +// +// Class which can be used as a base class for doing something when +// when all observed items are locally complete. This class implements +// the changed() method of LLInventoryObserver and declares a new +// method named done() which is called when all watched items have +// complete information in the inventory model. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLInventoryCompletionObserver : public LLInventoryObserver +{ +public: +	LLInventoryCompletionObserver() {} +	virtual void changed(U32 mask); + +	void watchItem(const LLUUID& id); + +protected: +	virtual void done() = 0; + +	typedef std::vector<LLUUID> item_ref_t; +	item_ref_t mComplete; +	item_ref_t mIncomplete; +}; + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryFetchObserver +// +// This class is much like the LLInventoryCompletionObserver, except +// that it handles all the the fetching necessary. Override the done() +// method to do the thing you want. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLInventoryFetchObserver : public LLInventoryObserver +{ +public: +	LLInventoryFetchObserver() {} +	virtual void changed(U32 mask); + +	typedef std::vector<LLUUID> item_ref_t; + +	bool isEverythingComplete() const; +	void fetchItems(const item_ref_t& ids); +	virtual void done() = 0; + +protected: +	item_ref_t mComplete; +	item_ref_t mIncomplete; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryFetchDescendentsObserver +// +// This class is much like the LLInventoryCompletionObserver, except +// that it handles fetching based on category. Override the done() +// method to do the thing you want. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLInventoryFetchDescendentsObserver : public LLInventoryObserver +{ +public: +	LLInventoryFetchDescendentsObserver() {} +	virtual void changed(U32 mask); + +	typedef std::vector<LLUUID> folder_ref_t; +	void fetchDescendents(const folder_ref_t& ids); +	bool isEverythingComplete() const; +	virtual void done() = 0; + +protected: +	bool isComplete(LLViewerInventoryCategory* cat); +	folder_ref_t mIncompleteFolders; +	folder_ref_t mCompleteFolders; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryFetchComboObserver +// +// This class does an appropriate combination of fetch descendents and +// item fetches based on completion of categories and items. Much like +// the fetch and fetch descendents, this will call done() when everything +// has arrived. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLInventoryFetchComboObserver : public LLInventoryObserver +{ +public: +	LLInventoryFetchComboObserver() : mDone(false) {} +	virtual void changed(U32 mask); + +	typedef std::vector<LLUUID> folder_ref_t; +	typedef std::vector<LLUUID> item_ref_t; +	void fetch(const folder_ref_t& folder_ids, const item_ref_t& item_ids); + +	virtual void done() = 0; + +protected: +	bool mDone; +	folder_ref_t mCompleteFolders; +	folder_ref_t mIncompleteFolders; +	item_ref_t mCompleteItems; +	item_ref_t mIncompleteItems; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryExistenceObserver +// +// This class is used as a base class for doing somethign when all the +// observed item ids exist in the inventory somewhere. You can derive +// a class from this class and implement the done() method to do +// something useful. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLInventoryExistenceObserver : public LLInventoryObserver +{ +public: +	LLInventoryExistenceObserver() {} +	virtual void changed(U32 mask); + +	void watchItem(const LLUUID& id); + +protected: +	virtual void done() = 0; + +	typedef std::vector<LLUUID> item_ref_t; +	item_ref_t mExist; +	item_ref_t mMIA; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryAddedObserver +// +// This class is used as a base class for doing something when  +// a new item arrives in inventory. +// It does not watch for a certain UUID, rather it acts when anything is added +// Derive a class from this class and implement the done() method to do +// something useful. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLInventoryAddedObserver : public LLInventoryObserver +{ +public: +	LLInventoryAddedObserver() : mAdded() {} +	virtual void changed(U32 mask); + +protected: +	virtual void done() = 0; + +	typedef std::vector<LLUUID> item_ref_t; +	item_ref_t mAdded; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryTransactionObserver +// +// Class which can be used as a base class for doing something when an +// inventory transaction completes. +// +// *NOTE: This class is not quite complete. Avoid using unless you fix up it's +// functionality gaps. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLInventoryTransactionObserver : public LLInventoryObserver +{ +public: +	LLInventoryTransactionObserver(const LLTransactionID& transaction_id); +	virtual void changed(U32 mask); + +protected: +	typedef std::vector<LLUUID> folder_ref_t; +	typedef std::vector<LLUUID> item_ref_t; +	virtual void done(const folder_ref_t& folders, const item_ref_t& items) = 0; + +	LLTransactionID mTransactionID; +}; + + +#endif // LL_LLINVENTORYOBSERVERS_H + diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index 945294f3f2..a01426ea87 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -182,6 +182,9 @@ void LLLoginInstance::constructAuthParams(const LLSD& credentials)  	mRequestData["method"] = "login_to_simulator";  	mRequestData["params"] = request_params;  	mRequestData["options"] = requested_options; + +	mRequestData["cfg_srv_timeout"] = gSavedSettings.getF32("LoginSRVTimeout"); +	mRequestData["cfg_srv_pump"] = gSavedSettings.getString("LoginSRVPump");  }  bool LLLoginInstance::handleLoginEvent(const LLSD& event) diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 9ba94c8ca9..2bbb2b7153 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -1193,7 +1193,7 @@ void LLPanelPeople::onCallButtonClicked()  	if (selected_uuids.size() == 1)  	{  		// initiate a P2P voice chat with the selected user -		LLAvatarActions::startCall(selected_uuids[0]); +		LLAvatarActions::startCall(getCurrentItemID());  	}  	else if (selected_uuids.size() > 1)  	{ diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 964d3bc2fa..7772f613f0 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -197,7 +197,7 @@ void LLViewerFloaterReg::registerFloaters()  	LLFloaterReg::add("notifications_console", "floater_notifications_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotificationConsole>);  	LLFloaterReg::add("openobject", "floater_openobject.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterOpenObject>); -	 +	LLFloaterReg::add("outgoing_call", "floater_outgoing_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLOutgoingCallDialog>);  	LLFloaterReg::add("parcel_info", "floater_preview_url.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterParcelInfo>);  	LLFloaterPayUtil::registerFloater(); diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp index 89649407ff..d93913b944 100644 --- a/indra/newview/llvoicechannel.cpp +++ b/indra/newview/llvoicechannel.cpp @@ -306,8 +306,10 @@ void LLVoiceChannel::activate()  		// activating the proximal channel between IM calls  		LLVoiceChannel* old_channel = sCurrentVoiceChannel;  		sCurrentVoiceChannel = this; +		mCallDialogPayload["old_channel_name"] = "";  		if (old_channel)  		{ +			mCallDialogPayload["old_channel_name"] = old_channel->getSessionName();  			old_channel->deactivate();  		}  	} @@ -870,6 +872,19 @@ void LLVoiceChannelP2P::setState(EState state)  {  	// HACK: Open/close the call window if needed.  	toggleCallWindowIfNeeded(state); +	 +	// *HACK: open outgoing call floater if needed, might be better done elsewhere. +	mCallDialogPayload["session_id"] = mSessionID; +	mCallDialogPayload["session_name"] = mSessionName; +	mCallDialogPayload["other_user_id"] = mOtherUserID; +	if (!mReceivedCall && state == STATE_RINGING) +	{ +		llinfos << "RINGINGGGGGGGG " << mSessionName << llendl; +		if (!mSessionName.empty()) +		{ +			LLFloaterReg::showInstance("outgoing_call", mCallDialogPayload, TRUE); +		} +	}  	// you only "answer" voice invites in p2p mode  	// so provide a special purpose message here diff --git a/indra/newview/llvoicechannel.h b/indra/newview/llvoicechannel.h index 20b6157b48..639585de55 100644 --- a/indra/newview/llvoicechannel.h +++ b/indra/newview/llvoicechannel.h @@ -109,6 +109,7 @@ protected:  	EState		mState;  	std::string	mSessionName;  	LLSD mNotifyArgs; +	LLSD mCallDialogPayload;  	BOOL		mIgnoreNextSessionLeave;  	LLHandle<LLPanel> mLoginNotificationHandle; diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 39d4bb0c02..fe24c30022 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -4273,7 +4273,7 @@ void LLVoiceClient::mediaStreamUpdatedEvent(  				if(incoming)  				{  					// Send the voice chat invite to the GUI layer -					// TODO: Question: Should we correlate with the mute list here? +					// *TODO: Question: Should we correlate with the mute list here?  					session->mIMSessionID = LLIMMgr::computeSessionID(IM_SESSION_P2P_INVITE, session->mCallerID);  					session->mVoiceInvitePending = true;  					if(session->mName.empty()) diff --git a/indra/newview/skins/default/xui/en/floater_incoming_call.xml b/indra/newview/skins/default/xui/en/floater_incoming_call.xml index 16873df310..9c2898945b 100644 --- a/indra/newview/skins/default/xui/en/floater_incoming_call.xml +++ b/indra/newview/skins/default/xui/en/floater_incoming_call.xml @@ -4,13 +4,17 @@   can_close="false"   can_minimize="false"   can_tear_off="false" - height="200" + height="125"   layout="topleft"   name="incoming call"   help_topic="incoming_call"   title="UNKNOWN PERSON IS CALLING" - width="240"> -     <floater.string + width="410"> +    <floater.string +     name="localchat"> +        Local Voice Chat +    </floater.string> +    <floater.string       name="anonymous">          anonymous      </floater.string> @@ -31,18 +35,26 @@       left_delta="19"       top="35"       width="36" /> -    <text_editor -     font="SansSerif" -     height="64" -     border_visible="false" +    <text +     font="SansSerifLarge" +     height="20"       layout="topleft"       left="77" -     max_length="2147483647"       name="caller name" -     read_only="true" -     top="21" -     width="163" +     top="27" +     width="315"       word_wrap="true" /> +    <text +     font="SansSerif" +     height="50" +     layout="topleft" +     left="77" +     name="question" +     top="52" +     width="315" +     word_wrap="true"> +     Do you want to leave [CURRENT_CHAT] and join this voice chat? +    </text>      <button       height="24"       label="Accept" @@ -57,16 +69,14 @@       label="Reject"       label_selected="Reject"       layout="topleft" -     left_delta="0"       name="Reject" -     top_pad="12" +     left_pad="10"       width="100" />      <button       height="24"       label="Start IM"       layout="topleft" -     left_delta="0"       name="Start IM" -     top_pad="12" +     left_pad="10"       width="100" />  </floater> diff --git a/indra/newview/skins/default/xui/en/floater_outgoing_call.xml b/indra/newview/skins/default/xui/en/floater_outgoing_call.xml new file mode 100644 index 0000000000..6713700372 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_outgoing_call.xml @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + legacy_header_height="18" + can_close="false" + can_minimize="false" + can_tear_off="false" + height="125" + layout="topleft" + name="outgoing call" + help_topic="outgoing_call" + title="CALLING" + width="410"> +    <floater.string +     name="localchat"> +        Local Voice Chat +    </floater.string> +    <floater.string +     name="anonymous"> +        anonymous +    </floater.string> +    <floater.string +     name="VoiceInviteP2P"> +        is calling. +    </floater.string> +    <floater.string +     name="VoiceInviteAdHoc"> +        has joined a Voice Chat call with a conference chat. +    </floater.string> +    <avatar_icon +     enabled="false" +     follows="left|top" +     height="36" +     image_name="icon_avatar_online.tga" +     layout="topleft" +     left_delta="19" +     top="35" +     width="36" /> +    <text +     font="SansSerifLarge" +     height="20" +     layout="topleft" +     left="77" +     name="calling" +     top="27" +     width="315" +     word_wrap="true"> +Calling [CALLEE_NAME] +    </text> +    <text +     font="SansSerif" +     height="50" +     layout="topleft" +     left="77" +     name="leaving" +     top="52" +     width="315" +     word_wrap="true"> +Leaving [CURRENT_CHAT]. +    </text> +    <button +     height="24" +     label="Cancel" +     layout="topleft" +     name="Cancel" +     left_pad="10" +     width="100" /> +</floater> diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp index d31a81e128..7b28a3b72c 100644 --- a/indra/newview/tests/lllogininstance_test.cpp +++ b/indra/newview/tests/lllogininstance_test.cpp @@ -76,6 +76,7 @@ LLControlGroup::LLControlGroup(const std::string& name) :  LLControlGroup::~LLControlGroup() {}  void LLControlGroup::setBOOL(const std::string& name, BOOL val) {}  BOOL LLControlGroup::getBOOL(const std::string& name) { return FALSE; } +F32 LLControlGroup::getF32(const std::string& name) { return 0.0f; }  U32 LLControlGroup::saveToFile(const std::string& filename, BOOL nondefault_only) { return 1; }  void LLControlGroup::setString(const std::string& name, const std::string& val) {}  std::string LLControlGroup::getString(const std::string& name) { return "test_string"; } diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp index 7a30315b9a..b14c59ab9a 100644 --- a/indra/viewer_components/login/lllogin.cpp +++ b/indra/viewer_components/login/lllogin.cpp @@ -70,7 +70,7 @@ public:  	LLEventPump& getEventPump() { return mPump; }  private: -	void sendProgressEvent(const std::string& state, const std::string& change, +	LLSD getProgressEventLLSD(const std::string& state, const std::string& change,  						   const LLSD& data = LLSD())  	{  		LLSD status_data; @@ -87,7 +87,13 @@ private:  		{  			status_data["data"] = data;  		} +		return status_data; +	} +	void sendProgressEvent(const std::string& state, const std::string& change, +						   const LLSD& data = LLSD()) +	{ +		LLSD status_data = getProgressEventLLSD(state, change, data);  		mPump.post(status_data);  	} @@ -140,15 +146,28 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD credential          // Request SRV record.          LL_INFOS("LLLogin") << "Requesting SRV record from " << uri << LL_ENDL; -        // *NOTE:Mani - Completely arbitrary timeout value for SRV request. -        filter.errorAfter(5, "SRV Request timed out!"); +        // *NOTE:Mani - Completely arbitrary default timeout value for SRV request. +		F32 seconds_to_timeout = 5.0f; +		if(credentials.has("cfg_srv_timeout")) +		{ +			seconds_to_timeout = credentials["cfg_srv_timeout"].asReal(); +		} + +		filter.eventAfter(seconds_to_timeout,  +			getProgressEventLLSD("offline", "fail.login")); + +		std::string srv_pump_name = "LLAres"; +		if(credentials.has("cfg_srv_pump")) +		{ +			srv_pump_name = credentials["cfg_srv_pump"].asString(); +		} -        // Make request +		// Make request          LLSD request;          request["op"] = "rewriteURI";          request["uri"] = uri;          request["reply"] = replyPump.getName(); -        rewrittenURIs = postAndWait(self, request, "LLAres", filter); +        rewrittenURIs = postAndWait(self, request, srv_pump_name, filter);      } // we no longer need the filter      LLEventPump& xmlrpcPump(LLEventPumps::instance().obtain("LLXMLRPCTransaction")); diff --git a/indra/viewer_components/login/tests/lllogin_test.cpp b/indra/viewer_components/login/tests/lllogin_test.cpp index a8ae2883d5..56c21016bd 100644 --- a/indra/viewer_components/login/tests/lllogin_test.cpp +++ b/indra/viewer_components/login/tests/lllogin_test.cpp @@ -47,6 +47,7 @@ public:  	bool call(const LLSD& event)  	{  		mDebug(STRINGIZE("LoginListener called!: " << event)); +		  		mLastEvent = event;  		return false;  	} @@ -414,4 +415,40 @@ namespace tut  		ensure_equals("Failed to offline", listener.lastEvent()["state"].asString(), "offline");  	} + +    template<> template<> +    void llviewerlogin_object::test<5>() +    { +        DEBUG; +		// Test SRV request timeout. +		set_test_name("LLLogin SRV timeout testing"); + +		// Testing normal login procedure. +		LLEventStream llaresPump("LLAres"); // Dummy LLAres pump. + +		// LLAresListener dummyLLAres("dummy_llares"); +		// dummyLLAres.listenTo(llaresPump); + +		LLLogin login; +		LoginListener listener("test_ear"); +		listener.listenTo(login.getEventPump()); + +		LLSD credentials; +		credentials["first"] = "these"; +		credentials["last"] = "don't"; +		credentials["passwd"] = "matter"; +		credentials["cfg_srv_timeout"] = 0.0f; + +		login.connect("login.bar.com", credentials); + +		ensure_equals("SRV State", listener.lastEvent()["change"].asString(), "srvrequest");  + +		// Get the mainloop eventpump, which needs a pinging in order to drive the  +		// SRV timeout. +		LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop")); +		LLSD frame_event; +		mainloop.post(frame_event); + +		ensure_equals("SRV Failure", listener.lastEvent()["change"].asString(), "fail.login");  +	}  } | 
