PageRenderTime 250ms CodeModel.GetById 30ms app.highlight 187ms RepoModel.GetById 15ms app.codeStats 1ms

/indra/newview/llviewerinventory.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 2048 lines | 1583 code | 254 blank | 211 comment | 200 complexity | 443d9ac190f49e6dae4d3cbdd8cf37f7 MD5 | raw file

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

   1/** 
   2 * @file llviewerinventory.cpp
   3 * @brief Implementation of the viewer side inventory objects.
   4 *
   5 * $LicenseInfo:firstyear=2002&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#include "llviewerinventory.h"
  29
  30#include "llnotificationsutil.h"
  31#include "llsdserialize.h"
  32#include "message.h"
  33
  34#include "llagent.h"
  35#include "llagentcamera.h"
  36#include "llagentwearables.h"
  37#include "llfloatersidepanelcontainer.h"
  38#include "llviewerfoldertype.h"
  39#include "llfloatersidepanelcontainer.h"
  40#include "llfolderview.h"
  41#include "llviewercontrol.h"
  42#include "llconsole.h"
  43#include "llinventorydefines.h"
  44#include "llinventoryfunctions.h"
  45#include "llinventorymodel.h"
  46#include "llinventorymodelbackgroundfetch.h"
  47#include "llgesturemgr.h"
  48
  49#include "llinventorybridge.h"
  50#include "llinventorypanel.h"
  51#include "llfloaterinventory.h"
  52#include "lllandmarkactions.h"
  53
  54#include "llviewerassettype.h"
  55#include "llviewerregion.h"
  56#include "llviewerobjectlist.h"
  57#include "llpreviewgesture.h"
  58#include "llviewerwindow.h"
  59#include "lltrans.h"
  60#include "llappearancemgr.h"
  61#include "llcommandhandler.h"
  62#include "llviewermessage.h"
  63#include "llsidepanelappearance.h"
  64#include "llavatarnamecache.h"
  65#include "llavataractions.h"
  66#include "lllogininstance.h"
  67
  68///----------------------------------------------------------------------------
  69/// Helper class to store special inventory item names and their localized values.
  70///----------------------------------------------------------------------------
  71class LLLocalizedInventoryItemsDictionary : public LLSingleton<LLLocalizedInventoryItemsDictionary>
  72{
  73public:
  74	std::map<std::string, std::string> mInventoryItemsDict;
  75
  76	LLLocalizedInventoryItemsDictionary()
  77	{
  78		mInventoryItemsDict["New Shape"]		= LLTrans::getString("New Shape");
  79		mInventoryItemsDict["New Skin"]			= LLTrans::getString("New Skin");
  80		mInventoryItemsDict["New Hair"]			= LLTrans::getString("New Hair");
  81		mInventoryItemsDict["New Eyes"]			= LLTrans::getString("New Eyes");
  82		mInventoryItemsDict["New Shirt"]		= LLTrans::getString("New Shirt");
  83		mInventoryItemsDict["New Pants"]		= LLTrans::getString("New Pants");
  84		mInventoryItemsDict["New Shoes"]		= LLTrans::getString("New Shoes");
  85		mInventoryItemsDict["New Socks"]		= LLTrans::getString("New Socks");
  86		mInventoryItemsDict["New Jacket"]		= LLTrans::getString("New Jacket");
  87		mInventoryItemsDict["New Gloves"]		= LLTrans::getString("New Gloves");
  88		mInventoryItemsDict["New Undershirt"]	= LLTrans::getString("New Undershirt");
  89		mInventoryItemsDict["New Underpants"]	= LLTrans::getString("New Underpants");
  90		mInventoryItemsDict["New Skirt"]		= LLTrans::getString("New Skirt");
  91		mInventoryItemsDict["New Alpha"]		= LLTrans::getString("New Alpha");
  92		mInventoryItemsDict["New Tattoo"]		= LLTrans::getString("New Tattoo");
  93		mInventoryItemsDict["New Physics"]		= LLTrans::getString("New Physics");
  94		mInventoryItemsDict["Invalid Wearable"] = LLTrans::getString("Invalid Wearable");
  95
  96		mInventoryItemsDict["New Gesture"]		= LLTrans::getString("New Gesture");
  97		mInventoryItemsDict["New Script"]		= LLTrans::getString("New Script");
  98		mInventoryItemsDict["New Folder"]		= LLTrans::getString("New Folder");
  99		mInventoryItemsDict["New Note"]			= LLTrans::getString("New Note");
 100		mInventoryItemsDict["Contents"]			= LLTrans::getString("Contents");
 101
 102		mInventoryItemsDict["Gesture"]			= LLTrans::getString("Gesture");
 103		mInventoryItemsDict["Male Gestures"]	= LLTrans::getString("Male Gestures");
 104		mInventoryItemsDict["Female Gestures"]	= LLTrans::getString("Female Gestures");
 105		mInventoryItemsDict["Other Gestures"]	= LLTrans::getString("Other Gestures");
 106		mInventoryItemsDict["Speech Gestures"]	= LLTrans::getString("Speech Gestures");
 107		mInventoryItemsDict["Common Gestures"]	= LLTrans::getString("Common Gestures");
 108
 109		//predefined gestures
 110
 111		//male
 112		mInventoryItemsDict["Male - Excuse me"]			= LLTrans::getString("Male - Excuse me");
 113		mInventoryItemsDict["Male  - Get lost"]			= LLTrans::getString("Male - Get lost"); // double space after Male. EXT-8319
 114		mInventoryItemsDict["Male - Blow kiss"]			= LLTrans::getString("Male - Blow kiss");
 115		mInventoryItemsDict["Male - Boo"]				= LLTrans::getString("Male - Boo");
 116		mInventoryItemsDict["Male - Bored"]				= LLTrans::getString("Male - Bored");
 117		mInventoryItemsDict["Male - Hey"]				= LLTrans::getString("Male - Hey");
 118		mInventoryItemsDict["Male - Laugh"]				= LLTrans::getString("Male - Laugh");
 119		mInventoryItemsDict["Male - Repulsed"]			= LLTrans::getString("Male - Repulsed");
 120		mInventoryItemsDict["Male - Shrug"]				= LLTrans::getString("Male - Shrug");
 121		mInventoryItemsDict["Male - Stick tougue out"]	= LLTrans::getString("Male - Stick tougue out");
 122		mInventoryItemsDict["Male - Wow"]				= LLTrans::getString("Male - Wow");
 123
 124		//female
 125		mInventoryItemsDict["Female - Chuckle"]			= LLTrans::getString("Female - Chuckle");
 126		mInventoryItemsDict["Female - Cry"]				= LLTrans::getString("Female - Cry");
 127		mInventoryItemsDict["Female - Embarrassed"]		= LLTrans::getString("Female - Embarrassed");
 128		mInventoryItemsDict["Female - Excuse me"]		= LLTrans::getString("Female - Excuse me");
 129		mInventoryItemsDict["Female  - Get lost"]		= LLTrans::getString("Female - Get lost"); // double space after Female. EXT-8319
 130		mInventoryItemsDict["Female - Blow kiss"]		= LLTrans::getString("Female - Blow kiss");
 131		mInventoryItemsDict["Female - Boo"]				= LLTrans::getString("Female - Boo");
 132		mInventoryItemsDict["Female - Bored"]			= LLTrans::getString("Female - Bored");
 133		mInventoryItemsDict["Female - Hey"]				= LLTrans::getString("Female - Hey");
 134		mInventoryItemsDict["Female - Hey baby"]		= LLTrans::getString("Female - Hey baby");
 135		mInventoryItemsDict["Female - Laugh"]			= LLTrans::getString("Female - Laugh");
 136		mInventoryItemsDict["Female - Looking good"]	= LLTrans::getString("Female - Looking good");
 137		mInventoryItemsDict["Female - Over here"]		= LLTrans::getString("Female - Over here");
 138		mInventoryItemsDict["Female - Please"]			= LLTrans::getString("Female - Please");
 139		mInventoryItemsDict["Female - Repulsed"]		= LLTrans::getString("Female - Repulsed");
 140		mInventoryItemsDict["Female - Shrug"]			= LLTrans::getString("Female - Shrug");
 141		mInventoryItemsDict["Female - Stick tougue out"]= LLTrans::getString("Female - Stick tougue out");
 142		mInventoryItemsDict["Female - Wow"]				= LLTrans::getString("Female - Wow");
 143
 144		//common
 145		mInventoryItemsDict["/bow"]						= LLTrans::getString("/bow");
 146		mInventoryItemsDict["/clap"]					= LLTrans::getString("/clap");
 147		mInventoryItemsDict["/count"]					= LLTrans::getString("/count");
 148		mInventoryItemsDict["/extinguish"]				= LLTrans::getString("/extinguish");
 149		mInventoryItemsDict["/kmb"]						= LLTrans::getString("/kmb");
 150		mInventoryItemsDict["/muscle"]					= LLTrans::getString("/muscle");
 151		mInventoryItemsDict["/no"]						= LLTrans::getString("/no");
 152		mInventoryItemsDict["/no!"]						= LLTrans::getString("/no!");
 153		mInventoryItemsDict["/paper"]					= LLTrans::getString("/paper");
 154		mInventoryItemsDict["/pointme"]					= LLTrans::getString("/pointme");
 155		mInventoryItemsDict["/pointyou"]				= LLTrans::getString("/pointyou");
 156		mInventoryItemsDict["/rock"]					= LLTrans::getString("/rock");
 157		mInventoryItemsDict["/scissor"]					= LLTrans::getString("/scissor");
 158		mInventoryItemsDict["/smoke"]					= LLTrans::getString("/smoke");
 159		mInventoryItemsDict["/stretch"]					= LLTrans::getString("/stretch");
 160		mInventoryItemsDict["/whistle"]					= LLTrans::getString("/whistle");
 161		mInventoryItemsDict["/yes"]						= LLTrans::getString("/yes");
 162		mInventoryItemsDict["/yes!"]					= LLTrans::getString("/yes!");
 163		mInventoryItemsDict["afk"]						= LLTrans::getString("afk");
 164		mInventoryItemsDict["dance1"]					= LLTrans::getString("dance1");
 165		mInventoryItemsDict["dance2"]					= LLTrans::getString("dance2");
 166		mInventoryItemsDict["dance3"]					= LLTrans::getString("dance3");
 167		mInventoryItemsDict["dance4"]					= LLTrans::getString("dance4");
 168		mInventoryItemsDict["dance5"]					= LLTrans::getString("dance5");
 169		mInventoryItemsDict["dance6"]					= LLTrans::getString("dance6");
 170		mInventoryItemsDict["dance7"]					= LLTrans::getString("dance7");
 171		mInventoryItemsDict["dance8"]					= LLTrans::getString("dance8");
 172	}
 173
 174	/**
 175	 * Finds passed name in dictionary and replaces it with found localized value.
 176	 *
 177	 * @param object_name - string to be localized.
 178	 * @return true if passed name was found and localized, false otherwise.
 179	 */
 180	bool localizeInventoryObjectName(std::string& object_name)
 181	{
 182		LL_DEBUGS("InventoryLocalize") << "Searching for localization: " << object_name << LL_ENDL;
 183
 184		std::map<std::string, std::string>::const_iterator dictionary_iter = mInventoryItemsDict.find(object_name);
 185
 186		bool found = dictionary_iter != mInventoryItemsDict.end();
 187		if(found)
 188		{
 189			object_name = dictionary_iter->second;
 190			LL_DEBUGS("InventoryLocalize") << "Found, new name is: " << object_name << LL_ENDL;
 191		}
 192		return found;
 193	}
 194};
 195
 196
 197///----------------------------------------------------------------------------
 198/// Local function declarations, constants, enums, and typedefs
 199///----------------------------------------------------------------------------
 200
 201class LLInventoryHandler : public LLCommandHandler
 202{
 203public:
 204	// requires trusted browser to trigger
 205	LLInventoryHandler() : LLCommandHandler("inventory", UNTRUSTED_THROTTLE) { }
 206	
 207	bool handle(const LLSD& params, const LLSD& query_map,
 208				LLMediaCtrl* web)
 209	{
 210		if (params.size() < 1)
 211		{
 212			return false;
 213		}
 214
 215		if (!LLUI::sSettingGroups["config"]->getBOOL("EnableInventory"))
 216		{
 217				LLNotificationsUtil::add("NoInventory", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
 218				return true;
 219		}
 220
 221		// support secondlife:///app/inventory/show
 222		if (params[0].asString() == "show")
 223		{
 224			LLFloaterSidePanelContainer::showPanel("inventory", LLSD());
 225			return true;
 226		}
 227
 228		// otherwise, we need a UUID and a verb...
 229		if (params.size() < 2) 
 230		{
 231			return false;
 232		}
 233		LLUUID inventory_id;
 234		if (!inventory_id.set(params[0], FALSE))
 235		{
 236			return false;
 237		}
 238		
 239		const std::string verb = params[1].asString();
 240		if (verb == "select")
 241		{
 242			uuid_vec_t items_to_open;
 243			items_to_open.push_back(inventory_id);
 244			//inventory_handler is just a stub, because we don't know from who this offer
 245			open_inventory_offer(items_to_open, "inventory_handler");
 246			return true;
 247		}
 248		
 249		return false;
 250	}
 251};
 252LLInventoryHandler gInventoryHandler;
 253
 254
 255///----------------------------------------------------------------------------
 256/// Class LLViewerInventoryItem
 257///----------------------------------------------------------------------------
 258
 259LLViewerInventoryItem::LLViewerInventoryItem(const LLUUID& uuid,
 260											 const LLUUID& parent_uuid,
 261											 const LLPermissions& perm,
 262											 const LLUUID& asset_uuid,
 263											 LLAssetType::EType type,
 264											 LLInventoryType::EType inv_type,
 265											 const std::string& name,
 266											 const std::string& desc,
 267											 const LLSaleInfo& sale_info,
 268											 U32 flags,
 269											 time_t creation_date_utc) :
 270	LLInventoryItem(uuid, parent_uuid, perm, asset_uuid, type, inv_type,
 271					name, desc, sale_info, flags, creation_date_utc),
 272	mIsComplete(TRUE)
 273{
 274}
 275
 276LLViewerInventoryItem::LLViewerInventoryItem(const LLUUID& item_id,
 277											 const LLUUID& parent_id,
 278											 const std::string& name,
 279											 LLInventoryType::EType inv_type) :
 280	LLInventoryItem(),
 281	mIsComplete(FALSE)
 282{
 283	mUUID = item_id;
 284	mParentUUID = parent_id;
 285	mInventoryType = inv_type;
 286	mName = name;
 287}
 288
 289LLViewerInventoryItem::LLViewerInventoryItem() :
 290	LLInventoryItem(),
 291	mIsComplete(FALSE)
 292{
 293}
 294
 295LLViewerInventoryItem::LLViewerInventoryItem(const LLViewerInventoryItem* other) :
 296	LLInventoryItem()
 297{
 298	copyViewerItem(other);
 299	if (!mIsComplete)
 300	{
 301		llwarns << "LLViewerInventoryItem copy constructor for incomplete item"
 302			<< mUUID << llendl;
 303	}
 304}
 305
 306LLViewerInventoryItem::LLViewerInventoryItem(const LLInventoryItem *other) :
 307	LLInventoryItem(other),
 308	mIsComplete(TRUE)
 309{
 310}
 311
 312
 313LLViewerInventoryItem::~LLViewerInventoryItem()
 314{
 315}
 316
 317void LLViewerInventoryItem::copyViewerItem(const LLViewerInventoryItem* other)
 318{
 319	LLInventoryItem::copyItem(other);
 320	mIsComplete = other->mIsComplete;
 321	mTransactionID = other->mTransactionID;
 322}
 323
 324// virtual
 325void LLViewerInventoryItem::copyItem(const LLInventoryItem *other)
 326{
 327	LLInventoryItem::copyItem(other);
 328	mIsComplete = true;
 329	mTransactionID.setNull();
 330}
 331
 332void LLViewerInventoryItem::cloneViewerItem(LLPointer<LLViewerInventoryItem>& newitem) const
 333{
 334	newitem = new LLViewerInventoryItem(this);
 335	if(newitem.notNull())
 336	{
 337		LLUUID item_id;
 338		item_id.generate();
 339		newitem->setUUID(item_id);
 340	}
 341}
 342
 343void LLViewerInventoryItem::removeFromServer()
 344{
 345	llinfos << "Removing inventory item " << mUUID << " from server."
 346			<< llendl;
 347
 348	LLInventoryModel::LLCategoryUpdate up(mParentUUID, -1);
 349	gInventory.accountForUpdate(up);
 350
 351	LLMessageSystem* msg = gMessageSystem;
 352	msg->newMessageFast(_PREHASH_RemoveInventoryItem);
 353	msg->nextBlockFast(_PREHASH_AgentData);
 354	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
 355	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); 
 356	msg->nextBlockFast(_PREHASH_InventoryData);
 357	msg->addUUIDFast(_PREHASH_ItemID, mUUID);
 358	gAgent.sendReliableMessage();
 359}
 360
 361void LLViewerInventoryItem::updateServer(BOOL is_new) const
 362{
 363	if(!mIsComplete)
 364	{
 365		// *FIX: deal with this better.
 366		// If we're crashing here then the UI is incorrectly enabled.
 367		llerrs << "LLViewerInventoryItem::updateServer() - for incomplete item"
 368			   << llendl;
 369		return;
 370	}
 371	if(gAgent.getID() != mPermissions.getOwner())
 372	{
 373		// *FIX: deal with this better.
 374		llwarns << "LLViewerInventoryItem::updateServer() - for unowned item"
 375				<< llendl;
 376		return;
 377	}
 378	LLInventoryModel::LLCategoryUpdate up(mParentUUID, is_new ? 1 : 0);
 379	gInventory.accountForUpdate(up);
 380
 381	LLMessageSystem* msg = gMessageSystem;
 382	msg->newMessageFast(_PREHASH_UpdateInventoryItem);
 383	msg->nextBlockFast(_PREHASH_AgentData);
 384	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
 385	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
 386	msg->addUUIDFast(_PREHASH_TransactionID, mTransactionID);
 387	msg->nextBlockFast(_PREHASH_InventoryData);
 388	msg->addU32Fast(_PREHASH_CallbackID, 0);
 389	packMessage(msg);
 390	gAgent.sendReliableMessage();
 391}
 392
 393void LLViewerInventoryItem::fetchFromServer(void) const
 394{
 395	if(!mIsComplete)
 396	{
 397		std::string url; 
 398
 399		LLViewerRegion* region = gAgent.getRegion();
 400		// we have to check region. It can be null after region was destroyed. See EXT-245
 401		if (region)
 402		{
 403		  if(gAgent.getID() != mPermissions.getOwner())
 404		    {
 405		      url = region->getCapability("FetchLib2");
 406		    }
 407		  else
 408		    {	
 409		      url = region->getCapability("FetchInventory2");
 410		    }
 411		}
 412		else
 413		{
 414			llwarns << "Agent Region is absent" << llendl;
 415		}
 416
 417		if (!url.empty())
 418		{
 419			LLSD body;
 420			body["agent_id"]	= gAgent.getID();
 421			body["items"][0]["owner_id"]	= mPermissions.getOwner();
 422			body["items"][0]["item_id"]		= mUUID;
 423
 424			LLHTTPClient::post(url, body, new LLInventoryModel::fetchInventoryResponder(body));
 425		}
 426		else
 427		{
 428			LLMessageSystem* msg = gMessageSystem;
 429			msg->newMessage("FetchInventory");
 430			msg->nextBlock("AgentData");
 431			msg->addUUID("AgentID", gAgent.getID());
 432			msg->addUUID("SessionID", gAgent.getSessionID());
 433			msg->nextBlock("InventoryData");
 434			msg->addUUID("OwnerID", mPermissions.getOwner());
 435			msg->addUUID("ItemID", mUUID);
 436			gAgent.sendReliableMessage();
 437		}
 438	}
 439	else
 440	{
 441		// *FIX: this can be removed after a bit.
 442		llwarns << "request to fetch complete item" << llendl;
 443	}
 444}
 445
 446// virtual
 447BOOL LLViewerInventoryItem::unpackMessage(LLSD item)
 448{
 449	BOOL rv = LLInventoryItem::fromLLSD(item);
 450
 451	LLLocalizedInventoryItemsDictionary::getInstance()->localizeInventoryObjectName(mName);
 452
 453	mIsComplete = TRUE;
 454	return rv;
 455}
 456
 457// virtual
 458BOOL LLViewerInventoryItem::unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num)
 459{
 460	BOOL rv = LLInventoryItem::unpackMessage(msg, block, block_num);
 461
 462	LLLocalizedInventoryItemsDictionary::getInstance()->localizeInventoryObjectName(mName);
 463
 464	mIsComplete = TRUE;
 465	return rv;
 466}
 467
 468void LLViewerInventoryItem::setTransactionID(const LLTransactionID& transaction_id)
 469{
 470	mTransactionID = transaction_id;
 471}
 472// virtual
 473void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const
 474{
 475	msg->addUUIDFast(_PREHASH_ItemID, mUUID);
 476	msg->addUUIDFast(_PREHASH_FolderID, mParentUUID);
 477	mPermissions.packMessage(msg);
 478	msg->addUUIDFast(_PREHASH_TransactionID, mTransactionID);
 479	S8 type = static_cast<S8>(mType);
 480	msg->addS8Fast(_PREHASH_Type, type);
 481	type = static_cast<S8>(mInventoryType);
 482	msg->addS8Fast(_PREHASH_InvType, type);
 483	msg->addU32Fast(_PREHASH_Flags, mFlags);
 484	mSaleInfo.packMessage(msg);
 485	msg->addStringFast(_PREHASH_Name, mName);
 486	msg->addStringFast(_PREHASH_Description, mDescription);
 487	msg->addS32Fast(_PREHASH_CreationDate, mCreationDate);
 488	U32 crc = getCRC32();
 489	msg->addU32Fast(_PREHASH_CRC, crc);
 490}
 491// virtual
 492BOOL LLViewerInventoryItem::importFile(LLFILE* fp)
 493{
 494	BOOL rv = LLInventoryItem::importFile(fp);
 495	mIsComplete = TRUE;
 496	return rv;
 497}
 498
 499// virtual
 500BOOL LLViewerInventoryItem::importLegacyStream(std::istream& input_stream)
 501{
 502	BOOL rv = LLInventoryItem::importLegacyStream(input_stream);
 503	mIsComplete = TRUE;
 504	return rv;
 505}
 506
 507bool LLViewerInventoryItem::importFileLocal(LLFILE* fp)
 508{
 509	// TODO: convert all functions that return BOOL to return bool
 510	bool rv = (LLInventoryItem::importFile(fp) ? true : false);
 511	mIsComplete = false;
 512	return rv;
 513}
 514
 515bool LLViewerInventoryItem::exportFileLocal(LLFILE* fp) const
 516{
 517	std::string uuid_str;
 518	fprintf(fp, "\tinv_item\t0\n\t{\n");
 519	mUUID.toString(uuid_str);
 520	fprintf(fp, "\t\titem_id\t%s\n", uuid_str.c_str());
 521	mParentUUID.toString(uuid_str);
 522	fprintf(fp, "\t\tparent_id\t%s\n", uuid_str.c_str());
 523	mPermissions.exportFile(fp);
 524	fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType));
 525	const std::string inv_type_str = LLInventoryType::lookup(mInventoryType);
 526	if(!inv_type_str.empty()) fprintf(fp, "\t\tinv_type\t%s\n", inv_type_str.c_str());
 527	fprintf(fp, "\t\tname\t%s|\n", mName.c_str());
 528	fprintf(fp, "\t\tcreation_date\t%d\n", (S32) mCreationDate);
 529	fprintf(fp,"\t}\n");
 530	return true;
 531}
 532
 533void LLViewerInventoryItem::updateParentOnServer(BOOL restamp) const
 534{
 535	LLMessageSystem* msg = gMessageSystem;
 536	msg->newMessageFast(_PREHASH_MoveInventoryItem);
 537	msg->nextBlockFast(_PREHASH_AgentData);
 538	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
 539	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
 540	msg->addBOOLFast(_PREHASH_Stamp, restamp);
 541	msg->nextBlockFast(_PREHASH_InventoryData);
 542	msg->addUUIDFast(_PREHASH_ItemID, mUUID);
 543	msg->addUUIDFast(_PREHASH_FolderID, mParentUUID);
 544	msg->addString("NewName", NULL);
 545	gAgent.sendReliableMessage();
 546}
 547
 548//void LLViewerInventoryItem::setCloneCount(S32 clones)
 549//{
 550//	mClones = clones;
 551//}
 552
 553//S32 LLViewerInventoryItem::getCloneCount() const
 554//{
 555//	return mClones;
 556//}
 557
 558///----------------------------------------------------------------------------
 559/// Class LLViewerInventoryCategory
 560///----------------------------------------------------------------------------
 561
 562LLViewerInventoryCategory::LLViewerInventoryCategory(const LLUUID& uuid,
 563													 const LLUUID& parent_uuid,
 564													 LLFolderType::EType pref,
 565													 const std::string& name,
 566													 const LLUUID& owner_id) :
 567	LLInventoryCategory(uuid, parent_uuid, pref, name),
 568	mOwnerID(owner_id),
 569	mVersion(LLViewerInventoryCategory::VERSION_UNKNOWN),
 570	mDescendentCount(LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN)
 571{
 572	mDescendentsRequested.reset();
 573}
 574
 575LLViewerInventoryCategory::LLViewerInventoryCategory(const LLUUID& owner_id) :
 576	mOwnerID(owner_id),
 577	mVersion(LLViewerInventoryCategory::VERSION_UNKNOWN),
 578	mDescendentCount(LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN)
 579{
 580	mDescendentsRequested.reset();
 581}
 582
 583LLViewerInventoryCategory::LLViewerInventoryCategory(const LLViewerInventoryCategory* other)
 584{
 585	copyViewerCategory(other);
 586}
 587
 588LLViewerInventoryCategory::~LLViewerInventoryCategory()
 589{
 590}
 591
 592void LLViewerInventoryCategory::copyViewerCategory(const LLViewerInventoryCategory* other)
 593{
 594	copyCategory(other);
 595	mOwnerID = other->mOwnerID;
 596	mVersion = other->mVersion;
 597	mDescendentCount = other->mDescendentCount;
 598	mDescendentsRequested = other->mDescendentsRequested;
 599}
 600
 601
 602void LLViewerInventoryCategory::updateParentOnServer(BOOL restamp) const
 603{
 604	LLMessageSystem* msg = gMessageSystem;
 605	msg->newMessageFast(_PREHASH_MoveInventoryFolder);
 606	msg->nextBlockFast(_PREHASH_AgentData);
 607	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
 608	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
 609
 610	msg->addBOOL("Stamp", restamp);
 611	msg->nextBlockFast(_PREHASH_InventoryData);
 612	msg->addUUIDFast(_PREHASH_FolderID, mUUID);
 613	msg->addUUIDFast(_PREHASH_ParentID, mParentUUID);
 614	gAgent.sendReliableMessage();
 615}
 616
 617void LLViewerInventoryCategory::updateServer(BOOL is_new) const
 618{
 619	// communicate that change with the server.
 620
 621	if (LLFolderType::lookupIsProtectedType(mPreferredType))
 622	{
 623		LLNotificationsUtil::add("CannotModifyProtectedCategories");
 624		return;
 625	}
 626
 627	LLInventoryModel::LLCategoryUpdate up(mParentUUID, is_new ? 1 : 0);
 628	gInventory.accountForUpdate(up);
 629
 630	LLMessageSystem* msg = gMessageSystem;
 631	msg->newMessageFast(_PREHASH_UpdateInventoryFolder);
 632	msg->nextBlockFast(_PREHASH_AgentData);
 633	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
 634	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
 635	msg->nextBlockFast(_PREHASH_FolderData);
 636	packMessage(msg);
 637	gAgent.sendReliableMessage();
 638}
 639
 640void LLViewerInventoryCategory::removeFromServer( void )
 641{
 642	llinfos << "Removing inventory category " << mUUID << " from server."
 643			<< llendl;
 644	// communicate that change with the server.
 645	if(LLFolderType::lookupIsProtectedType(mPreferredType))
 646	{
 647		LLNotificationsUtil::add("CannotRemoveProtectedCategories");
 648		return;
 649	}
 650
 651	LLInventoryModel::LLCategoryUpdate up(mParentUUID, -1);
 652	gInventory.accountForUpdate(up);
 653
 654	LLMessageSystem* msg = gMessageSystem;
 655	msg->newMessageFast(_PREHASH_RemoveInventoryFolder);
 656	msg->nextBlockFast(_PREHASH_AgentData);
 657	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
 658	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
 659	msg->nextBlockFast(_PREHASH_FolderData);
 660	msg->addUUIDFast(_PREHASH_FolderID, mUUID);
 661	gAgent.sendReliableMessage();
 662}
 663
 664bool LLViewerInventoryCategory::fetch()
 665{
 666	if((VERSION_UNKNOWN == mVersion)
 667	   && mDescendentsRequested.hasExpired())	//Expired check prevents multiple downloads.
 668	{
 669		LL_DEBUGS("InventoryFetch") << "Fetching category children: " << mName << ", UUID: " << mUUID << LL_ENDL;
 670		const F32 FETCH_TIMER_EXPIRY = 10.0f;
 671		mDescendentsRequested.reset();
 672		mDescendentsRequested.setTimerExpirySec(FETCH_TIMER_EXPIRY);
 673
 674		// bitfield
 675		// 1 = by date
 676		// 2 = folders by date
 677		// Need to mask off anything but the first bit.
 678		// This comes from LLInventoryFilter from llfolderview.h
 679		U32 sort_order = gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER) & 0x1;
 680
 681		// *NOTE: For bug EXT-2879, originally commented out
 682		// gAgent.getRegion()->getCapability in order to use the old
 683		// message-based system.  This has been uncommented now that
 684		// AIS folks are aware of the issue and have a fix in process.
 685		// see ticket for details.
 686
 687		std::string url;
 688		if (gAgent.getRegion())
 689		{
 690			url = gAgent.getRegion()->getCapability("FetchInventoryDescendents2");
 691		}
 692		else
 693		{
 694			llwarns << "agent region is null" << llendl;
 695		}
 696		if (!url.empty()) //Capability found.  Build up LLSD and use it.
 697		{
 698			LLInventoryModelBackgroundFetch::instance().start(mUUID, false);			
 699		}
 700		else
 701		{	//Deprecated, but if we don't have a capability, use the old system.
 702			llinfos << "FetchInventoryDescendents2 capability not found.  Using deprecated UDP message." << llendl;
 703			LLMessageSystem* msg = gMessageSystem;
 704			msg->newMessage("FetchInventoryDescendents");
 705			msg->nextBlock("AgentData");
 706			msg->addUUID("AgentID", gAgent.getID());
 707			msg->addUUID("SessionID", gAgent.getSessionID());
 708			msg->nextBlock("InventoryData");
 709			msg->addUUID("FolderID", mUUID);
 710			msg->addUUID("OwnerID", mOwnerID);
 711
 712			msg->addS32("SortOrder", sort_order);
 713			msg->addBOOL("FetchFolders", FALSE);
 714			msg->addBOOL("FetchItems", TRUE);
 715			gAgent.sendReliableMessage();
 716		}
 717		return true;
 718	}
 719	return false;
 720}
 721
 722bool LLViewerInventoryCategory::importFileLocal(LLFILE* fp)
 723{
 724	// *NOTE: This buffer size is hard coded into scanf() below.
 725	char buffer[MAX_STRING];		/* Flawfinder: ignore */
 726	char keyword[MAX_STRING];		/* Flawfinder: ignore */
 727	char valuestr[MAX_STRING];		/* Flawfinder: ignore */
 728
 729	keyword[0] = '\0';
 730	valuestr[0] = '\0';
 731	while(!feof(fp))
 732	{
 733		if (fgets(buffer, MAX_STRING, fp) == NULL)
 734		{
 735			buffer[0] = '\0';
 736		}
 737		
 738		sscanf(	/* Flawfinder: ignore */
 739			buffer, " %254s %254s", keyword, valuestr); 
 740		if(0 == strcmp("{",keyword))
 741		{
 742			continue;
 743		}
 744		if(0 == strcmp("}", keyword))
 745		{
 746			break;
 747		}
 748		else if(0 == strcmp("cat_id", keyword))
 749		{
 750			mUUID.set(valuestr);
 751		}
 752		else if(0 == strcmp("parent_id", keyword))
 753		{
 754			mParentUUID.set(valuestr);
 755		}
 756		else if(0 == strcmp("type", keyword))
 757		{
 758			mType = LLAssetType::lookup(valuestr);
 759		}
 760		else if(0 == strcmp("pref_type", keyword))
 761		{
 762			mPreferredType = LLFolderType::lookup(valuestr);
 763		}
 764		else if(0 == strcmp("name", keyword))
 765		{
 766			//strcpy(valuestr, buffer + strlen(keyword) + 3);
 767			// *NOTE: Not ANSI C, but widely supported.
 768			sscanf(	/* Flawfinder: ignore */
 769				buffer, " %254s %254[^|]", keyword, valuestr);
 770			mName.assign(valuestr);
 771			LLStringUtil::replaceNonstandardASCII(mName, ' ');
 772			LLStringUtil::replaceChar(mName, '|', ' ');
 773		}
 774		else if(0 == strcmp("owner_id", keyword))
 775		{
 776			mOwnerID.set(valuestr);
 777		}
 778		else if(0 == strcmp("version", keyword))
 779		{
 780			sscanf(valuestr, "%d", &mVersion);
 781		}
 782		else
 783		{
 784			llwarns << "unknown keyword '" << keyword
 785					<< "' in inventory import category "  << mUUID << llendl;
 786		}
 787	}
 788	return true;
 789}
 790
 791bool LLViewerInventoryCategory::exportFileLocal(LLFILE* fp) const
 792{
 793	std::string uuid_str;
 794	fprintf(fp, "\tinv_category\t0\n\t{\n");
 795	mUUID.toString(uuid_str);
 796	fprintf(fp, "\t\tcat_id\t%s\n", uuid_str.c_str());
 797	mParentUUID.toString(uuid_str);
 798	fprintf(fp, "\t\tparent_id\t%s\n", uuid_str.c_str());
 799	fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType));
 800	fprintf(fp, "\t\tpref_type\t%s\n", LLFolderType::lookup(mPreferredType).c_str());
 801	fprintf(fp, "\t\tname\t%s|\n", mName.c_str());
 802	mOwnerID.toString(uuid_str);
 803	fprintf(fp, "\t\towner_id\t%s\n", uuid_str.c_str());
 804	fprintf(fp, "\t\tversion\t%d\n", mVersion);
 805	fprintf(fp,"\t}\n");
 806	return true;
 807}
 808
 809void LLViewerInventoryCategory::determineFolderType()
 810{
 811	/* Do NOT uncomment this code.  This is for future 2.1 support of ensembles.
 812	llassert(FALSE);
 813	LLFolderType::EType original_type = getPreferredType();
 814	if (LLFolderType::lookupIsProtectedType(original_type))
 815		return;
 816
 817	U64 folder_valid = 0;
 818	U64 folder_invalid = 0;
 819	LLInventoryModel::cat_array_t category_array;
 820	LLInventoryModel::item_array_t item_array;
 821	gInventory.collectDescendents(getUUID(),category_array,item_array,FALSE);
 822
 823	// For ensembles
 824	if (category_array.empty())
 825	{
 826		for (LLInventoryModel::item_array_t::iterator item_iter = item_array.begin();
 827			 item_iter != item_array.end();
 828			 item_iter++)
 829		{
 830			const LLViewerInventoryItem *item = (*item_iter);
 831			if (item->getIsLinkType())
 832				return;
 833			if (item->isWearableType())
 834			{
 835				const LLWearableType::EType wearable_type = item->getWearableType();
 836				const std::string& wearable_name = LLWearableType::getTypeName(wearable_type);
 837				U64 valid_folder_types = LLViewerFolderType::lookupValidFolderTypes(wearable_name);
 838				folder_valid |= valid_folder_types;
 839				folder_invalid |= ~valid_folder_types;
 840			}
 841		}
 842		for (U8 i = LLFolderType::FT_ENSEMBLE_START; i <= LLFolderType::FT_ENSEMBLE_END; i++)
 843		{
 844			if ((folder_valid & (1LL << i)) &&
 845				!(folder_invalid & (1LL << i)))
 846			{
 847				changeType((LLFolderType::EType)i);
 848				return;
 849			}
 850		}
 851	}
 852	if (LLFolderType::lookupIsEnsembleType(original_type))
 853	{
 854		changeType(LLFolderType::FT_NONE);
 855	}
 856	llassert(FALSE);
 857	*/
 858}
 859
 860void LLViewerInventoryCategory::changeType(LLFolderType::EType new_folder_type)
 861{
 862	const LLUUID &folder_id = getUUID();
 863	const LLUUID &parent_id = getParentUUID();
 864	const std::string &name = getName();
 865		
 866	LLMessageSystem* msg = gMessageSystem;
 867	msg->newMessageFast(_PREHASH_UpdateInventoryFolder);
 868	msg->nextBlockFast(_PREHASH_AgentData);
 869	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
 870	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
 871	msg->nextBlockFast(_PREHASH_FolderData);
 872	msg->addUUIDFast(_PREHASH_FolderID, folder_id);
 873	msg->addUUIDFast(_PREHASH_ParentID, parent_id);
 874	msg->addS8Fast(_PREHASH_Type, new_folder_type);
 875	msg->addStringFast(_PREHASH_Name, name);
 876	gAgent.sendReliableMessage();
 877
 878	setPreferredType(new_folder_type);
 879	gInventory.addChangedMask(LLInventoryObserver::LABEL, folder_id);
 880}
 881
 882void LLViewerInventoryCategory::localizeName()
 883{
 884	LLLocalizedInventoryItemsDictionary::getInstance()->localizeInventoryObjectName(mName);
 885}
 886
 887///----------------------------------------------------------------------------
 888/// Local function definitions
 889///----------------------------------------------------------------------------
 890
 891LLInventoryCallbackManager *LLInventoryCallbackManager::sInstance = NULL;
 892
 893LLInventoryCallbackManager::LLInventoryCallbackManager() :
 894	mLastCallback(0)
 895{
 896	if( sInstance != NULL )
 897	{
 898		llwarns << "LLInventoryCallbackManager::LLInventoryCallbackManager: unexpected multiple instances" << llendl;
 899		return;
 900	}
 901	sInstance = this;
 902}
 903
 904LLInventoryCallbackManager::~LLInventoryCallbackManager()
 905{
 906	if( sInstance != this )
 907	{
 908		llwarns << "LLInventoryCallbackManager::~LLInventoryCallbackManager: unexpected multiple instances" << llendl;
 909		return;
 910	}
 911	sInstance = NULL;
 912}
 913
 914//static 
 915void LLInventoryCallbackManager::destroyClass()
 916{
 917	if (sInstance)
 918	{
 919		for (callback_map_t::iterator it = sInstance->mMap.begin(), end_it = sInstance->mMap.end(); it != end_it; ++it)
 920		{
 921			// drop LLPointer reference to callback
 922			it->second = NULL;
 923		}
 924		sInstance->mMap.clear();
 925	}
 926}
 927
 928
 929U32 LLInventoryCallbackManager::registerCB(LLPointer<LLInventoryCallback> cb)
 930{
 931	if (cb.isNull())
 932		return 0;
 933
 934	mLastCallback++;
 935	if (!mLastCallback)
 936		mLastCallback++;
 937
 938	mMap[mLastCallback] = cb;
 939	return mLastCallback;
 940}
 941
 942void LLInventoryCallbackManager::fire(U32 callback_id, const LLUUID& item_id)
 943{
 944	if (!callback_id || item_id.isNull())
 945		return;
 946
 947	std::map<U32, LLPointer<LLInventoryCallback> >::iterator i;
 948
 949	i = mMap.find(callback_id);
 950	if (i != mMap.end())
 951	{
 952		(*i).second->fire(item_id);
 953		mMap.erase(i);
 954	}
 955}
 956
 957void WearOnAvatarCallback::fire(const LLUUID& inv_item)
 958{
 959	if (inv_item.isNull())
 960		return;
 961
 962	LLViewerInventoryItem *item = gInventory.getItem(inv_item);
 963	if (item)
 964	{
 965		LLAppearanceMgr::instance().wearItemOnAvatar(inv_item, true, mReplace);
 966	}
 967}
 968
 969void ModifiedCOFCallback::fire(const LLUUID& inv_item)
 970{
 971	LLAppearanceMgr::instance().updateAppearanceFromCOF();
 972
 973	// Start editing the item if previously requested.
 974	gAgentWearables.editWearableIfRequested(inv_item);
 975
 976	// TODO: camera mode may not be changed if a debug setting is tweaked
 977	if( gAgentCamera.cameraCustomizeAvatar() )
 978	{
 979		// If we're in appearance editing mode, the current tab may need to be refreshed
 980		LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>(LLFloaterSidePanelContainer::getPanel("appearance"));
 981		if (panel)
 982		{
 983			panel->showDefaultSubpart();
 984		}
 985	}
 986}
 987
 988RezAttachmentCallback::RezAttachmentCallback(LLViewerJointAttachment *attachmentp)
 989{
 990	mAttach = attachmentp;
 991}
 992RezAttachmentCallback::~RezAttachmentCallback()
 993{
 994}
 995
 996void RezAttachmentCallback::fire(const LLUUID& inv_item)
 997{
 998	if (inv_item.isNull())
 999		return;
1000
1001	LLViewerInventoryItem *item = gInventory.getItem(inv_item);
1002	if (item)
1003	{
1004		rez_attachment(item, mAttach);
1005	}
1006}
1007
1008void ActivateGestureCallback::fire(const LLUUID& inv_item)
1009{
1010	if (inv_item.isNull())
1011		return;
1012	LLViewerInventoryItem* item = gInventory.getItem(inv_item);
1013	if (!item)
1014		return;
1015	if (item->getType() != LLAssetType::AT_GESTURE)
1016		return;
1017
1018	LLGestureMgr::instance().activateGesture(inv_item);
1019}
1020
1021void CreateGestureCallback::fire(const LLUUID& inv_item)
1022{
1023	if (inv_item.isNull())
1024		return;
1025
1026	LLGestureMgr::instance().activateGesture(inv_item);
1027	
1028	LLViewerInventoryItem* item = gInventory.getItem(inv_item);
1029	if (!item) return;
1030    gInventory.updateItem(item);
1031    gInventory.notifyObservers();
1032
1033	LLPreviewGesture* preview = LLPreviewGesture::show(inv_item,  LLUUID::null);
1034	// Force to be entirely onscreen.
1035	gFloaterView->adjustToFitScreen(preview, FALSE);
1036}
1037
1038void AddFavoriteLandmarkCallback::fire(const LLUUID& inv_item_id)
1039{
1040	if (mTargetLandmarkId.isNull()) return;
1041
1042	gInventory.rearrangeFavoriteLandmarks(inv_item_id, mTargetLandmarkId);
1043}
1044
1045LLInventoryCallbackManager gInventoryCallbacks;
1046
1047void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id,
1048						   const LLUUID& parent, const LLTransactionID& transaction_id,
1049						   const std::string& name,
1050						   const std::string& desc, LLAssetType::EType asset_type,
1051						   LLInventoryType::EType inv_type, LLWearableType::EType wtype,
1052						   U32 next_owner_perm,
1053						   LLPointer<LLInventoryCallback> cb)
1054{
1055	//check if name is equal to one of special inventory items names
1056	//EXT-5839
1057	std::string server_name = name;
1058
1059	{
1060		std::map<std::string, std::string>::const_iterator dictionary_iter;
1061
1062		for (dictionary_iter = LLLocalizedInventoryItemsDictionary::getInstance()->mInventoryItemsDict.begin();
1063			 dictionary_iter != LLLocalizedInventoryItemsDictionary::getInstance()->mInventoryItemsDict.end();
1064			 dictionary_iter++)
1065		{
1066			const std::string& localized_name = dictionary_iter->second;
1067			if(localized_name == name)
1068			{
1069				server_name = dictionary_iter->first;
1070			}
1071		}
1072	}
1073
1074	LLMessageSystem* msg = gMessageSystem;
1075	msg->newMessageFast(_PREHASH_CreateInventoryItem);
1076	msg->nextBlock(_PREHASH_AgentData);
1077	msg->addUUIDFast(_PREHASH_AgentID, agent_id);
1078	msg->addUUIDFast(_PREHASH_SessionID, session_id);
1079	msg->nextBlock(_PREHASH_InventoryBlock);
1080	msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb));
1081	msg->addUUIDFast(_PREHASH_FolderID, parent);
1082	msg->addUUIDFast(_PREHASH_TransactionID, transaction_id);
1083	msg->addU32Fast(_PREHASH_NextOwnerMask, next_owner_perm);
1084	msg->addS8Fast(_PREHASH_Type, (S8)asset_type);
1085	msg->addS8Fast(_PREHASH_InvType, (S8)inv_type);
1086	msg->addU8Fast(_PREHASH_WearableType, (U8)wtype);
1087	msg->addStringFast(_PREHASH_Name, server_name);
1088	msg->addStringFast(_PREHASH_Description, desc);
1089	
1090	gAgent.sendReliableMessage();
1091}
1092
1093void create_inventory_callingcard(const LLUUID& avatar_id, const LLUUID& parent /*= LLUUID::null*/, LLPointer<LLInventoryCallback> cb/*=NULL*/)
1094{
1095	std::string item_desc = avatar_id.asString();
1096	std::string item_name;
1097	gCacheName->getFullName(avatar_id, item_name);
1098	create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
1099						  parent, LLTransactionID::tnull, item_name, item_desc, LLAssetType::AT_CALLINGCARD,
1100						  LLInventoryType::IT_CALLINGCARD, NOT_WEARABLE, PERM_MOVE | PERM_TRANSFER, cb);
1101}
1102
1103void copy_inventory_item(
1104	const LLUUID& agent_id,
1105	const LLUUID& current_owner,
1106	const LLUUID& item_id,
1107	const LLUUID& parent_id,
1108	const std::string& new_name,
1109	LLPointer<LLInventoryCallback> cb)
1110{
1111	LLMessageSystem* msg = gMessageSystem;
1112	msg->newMessageFast(_PREHASH_CopyInventoryItem);
1113	msg->nextBlockFast(_PREHASH_AgentData);
1114	msg->addUUIDFast(_PREHASH_AgentID, agent_id);
1115	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
1116	msg->nextBlockFast(_PREHASH_InventoryData);
1117	msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb));
1118	msg->addUUIDFast(_PREHASH_OldAgentID, current_owner);
1119	msg->addUUIDFast(_PREHASH_OldItemID, item_id);
1120	msg->addUUIDFast(_PREHASH_NewFolderID, parent_id);
1121	msg->addStringFast(_PREHASH_NewName, new_name);
1122	gAgent.sendReliableMessage();
1123}
1124
1125void link_inventory_item(
1126	const LLUUID& agent_id,
1127	const LLUUID& item_id,
1128	const LLUUID& parent_id,
1129	const std::string& new_name,
1130	const std::string& new_description,
1131	const LLAssetType::EType asset_type,
1132	LLPointer<LLInventoryCallback> cb)
1133{
1134	const LLInventoryObject *baseobj = gInventory.getObject(item_id);
1135	if (!baseobj)
1136	{
1137		llwarns << "attempt to link to unknown item, linked-to-item's itemID " << item_id << llendl;
1138		return;
1139	}
1140	if (baseobj && baseobj->getIsLinkType())
1141	{
1142		llwarns << "attempt to create a link to a link, linked-to-item's itemID " << item_id << llendl;
1143		return;
1144	}
1145
1146	if (baseobj && !LLAssetType::lookupCanLink(baseobj->getType()))
1147	{
1148		// Fail if item can be found but is of a type that can't be linked.
1149		// Arguably should fail if the item can't be found too, but that could
1150		// be a larger behavioral change.
1151		llwarns << "attempt to link an unlinkable item, type = " << baseobj->getActualType() << llendl;
1152		return;
1153	}
1154	
1155	LLUUID transaction_id;
1156	LLInventoryType::EType inv_type = LLInventoryType::IT_NONE;
1157	if (dynamic_cast<const LLInventoryCategory *>(baseobj))
1158	{
1159		inv_type = LLInventoryType::IT_CATEGORY;
1160	}
1161	else
1162	{
1163		const LLViewerInventoryItem *baseitem = dynamic_cast<const LLViewerInventoryItem *>(baseobj);
1164		if (baseitem)
1165		{
1166			inv_type = baseitem->getInventoryType();
1167		}
1168	}
1169
1170	LLMessageSystem* msg = gMessageSystem;
1171	msg->newMessageFast(_PREHASH_LinkInventoryItem);
1172	msg->nextBlock(_PREHASH_AgentData);
1173	{
1174		msg->addUUIDFast(_PREHASH_AgentID, agent_id);
1175		msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
1176	}
1177	msg->nextBlock(_PREHASH_InventoryBlock);
1178	{
1179		msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb));
1180		msg->addUUIDFast(_PREHASH_FolderID, parent_id);
1181		msg->addUUIDFast(_PREHASH_TransactionID, transaction_id);
1182		msg->addUUIDFast(_PREHASH_OldItemID, item_id);
1183		msg->addS8Fast(_PREHASH_Type, (S8)asset_type);
1184		msg->addS8Fast(_PREHASH_InvType, (S8)inv_type);
1185		msg->addStringFast(_PREHASH_Name, new_name);
1186		msg->addStringFast(_PREHASH_Description, new_description);
1187	}
1188	gAgent.sendReliableMessage();
1189}
1190
1191void move_inventory_item(
1192	const LLUUID& agent_id,
1193	const LLUUID& session_id,
1194	const LLUUID& item_id,
1195	const LLUUID& parent_id,
1196	const std::string& new_name,
1197	LLPointer<LLInventoryCallback> cb)
1198{
1199	LLMessageSystem* msg = gMessageSystem;
1200	msg->newMessageFast(_PREHASH_MoveInventoryItem);
1201	msg->nextBlockFast(_PREHASH_AgentData);
1202	msg->addUUIDFast(_PREHASH_AgentID, agent_id);
1203	msg->addUUIDFast(_PREHASH_SessionID, session_id);
1204	msg->addBOOLFast(_PREHASH_Stamp, FALSE);
1205	msg->nextBlockFast(_PREHASH_InventoryData);
1206	msg->addUUIDFast(_PREHASH_ItemID, item_id);
1207	msg->addUUIDFast(_PREHASH_FolderID, parent_id);
1208	msg->addStringFast(_PREHASH_NewName, new_name);
1209	gAgent.sendReliableMessage();
1210}
1211
1212const LLUUID get_folder_by_itemtype(const LLInventoryItem *src)
1213{
1214	LLUUID retval = LLUUID::null;
1215	
1216	if (src)
1217	{
1218		retval = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(src->getType()));
1219	}
1220	
1221	return retval;
1222}
1223
1224void copy_inventory_from_notecard(const LLUUID& destination_id,
1225								  const LLUUID& object_id,
1226								  const LLUUID& notecard_inv_id,
1227								  const LLInventoryItem *src,
1228								  U32 callback_id)
1229{
1230	if (NULL == src)
1231	{
1232		LL_WARNS("copy_inventory_from_notecard") << "Null pointer to item was passed for object_id "
1233												 << object_id << " and notecard_inv_id "
1234												 << notecard_inv_id << LL_ENDL;
1235		return;
1236	}
1237
1238	LLViewerRegion* viewer_region = NULL;
1239    LLViewerObject* vo = NULL;
1240	if (object_id.notNull() && (vo = gObjectList.findObject(object_id)) != NULL)
1241    {
1242        viewer_region = vo->getRegion();
1243	}
1244
1245	// Fallback to the agents region if for some reason the 
1246	// object isn't found in the viewer.
1247	if (! viewer_region)
1248	{
1249		viewer_region = gAgent.getRegion();
1250	}
1251
1252	if (! viewer_region)
1253	{
1254        LL_WARNS("copy_inventory_from_notecard") << "Can't find region from object_id "
1255                                                 << object_id << " or gAgent"
1256                                                 << LL_ENDL;
1257        return;
1258    }
1259
1260	// check capability to prevent a crash while LL_ERRS in LLCapabilityListener::capListener. See EXT-8459.
1261	std::string url = viewer_region->getCapability("CopyInventoryFromNotecard");
1262	if (url.empty())
1263	{
1264        LL_WARNS("copy_inventory_from_notecard") << "There is no 'CopyInventoryFromNotecard' capability"
1265												 << " for region: " << viewer_region->getName()
1266                                                 << LL_ENDL;
1267		return;
1268	}
1269
1270    LLSD request, body;
1271    body["notecard-id"] = notecard_inv_id;
1272    body["object-id"] = object_id;
1273    body["item-id"] = src->getUUID();
1274	body["folder-id"] = destination_id;
1275    body["callback-id"] = (LLSD::Integer)callback_id;
1276
1277    request["message"] = "CopyInventoryFromNotecard";
1278    request["payload"] = body;
1279
1280    viewer_region->getCapAPI().post(request);
1281}
1282
1283void create_new_item(const std::string& name,
1284				   const LLUUID& parent_id,
1285				   LLAssetType::EType asset_type,
1286				   LLInventoryType::EType inv_type,
1287				   U32 next_owner_perm)
1288{
1289	std::string desc;
1290	LLViewerAssetType::generateDescriptionFor(asset_type, desc);
1291	next_owner_perm = (next_owner_perm) ? next_owner_perm : PERM_MOVE | PERM_TRANSFER;
1292
1293	
1294	if (inv_type == LLInventoryType::IT_GESTURE)
1295	{
1296		LLPointer<LLInventoryCallback> cb = new CreateGestureCallback();
1297		create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
1298							  parent_id, LLTransactionID::tnull, name, desc, asset_type, inv_type,
1299							  NOT_WEARABLE, next_owner_perm, cb);
1300	}
1301	else
1302	{
1303		LLPointer<LLInventoryCallback> cb = NULL;
1304		create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
1305							  parent_id, LLTransactionID::tnull, name, desc, asset_type, inv_type,
1306							  NOT_WEARABLE, next_owner_perm, cb);
1307	}
1308	
1309}	
1310
1311const std::string NEW_LSL_NAME = "New Script"; // *TODO:Translate? (probably not)
1312const std::string NEW_NOTECARD_NAME = "New Note"; // *TODO:Translate? (probably not)
1313const std::string NEW_GESTURE_NAME = "New Gesture"; // *TODO:Translate? (probably not)
1314
1315// ! REFACTOR ! Really need to refactor this so that it's not a bunch of if-then statements...
1316void menu_create_inventory_item(LLFolderView* root, LLFolderBridge *bridge, const LLSD& userdata, const LLUUID& default_parent_uuid)
1317{
1318	std::string type_name = userdata.asString();
1319	
1320	if (("inbox" == type_name) || ("outbox" == type_name) || ("category" == type_name) || ("current" == type_name) || ("outfit" == type_name) || ("my_otfts" == type_name))
1321	{
1322		LLFolderType::EType preferred_type = LLFolderType::lookup(type_name);
1323
1324		LLUUID parent_id;
1325		if (bridge)
1326		{
1327			parent_id = bridge->getUUID();
1328		}
1329		else if (default_parent_uuid.notNull())
1330		{
1331			parent_id = default_parent_uuid;
1332		}
1333		else
1334		{
1335			parent_id = gInventory.getRootFolderID();
1336		}
1337
1338		LLUUID category = gInventory.createNewCategory(parent_id, preferred_type, LLStringUtil::null);
1339		gInventory.notifyObservers();
1340		root->setSelectionByID(category, TRUE);
1341	}
1342	else if ("lsl" == type_name)
1343	{
1344		const LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLFolderType::FT_LSL_TEXT);
1345		create_new_item(NEW_LSL_NAME,
1346					  parent_id,
1347					  LLAssetType::AT_LSL_TEXT,
1348					  LLInventoryType::IT_LSL,
1349					  PERM_MOVE | PERM_TRANSFER);
1350	}
1351	else if ("notecard" == type_name)
1352	{
1353		const LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLFolderType::FT_NOTECARD);
1354		create_new_item(NEW_NOTECARD_NAME,
1355					  parent_id,
1356					  LLAssetType::AT_NOTECARD,
1357					  LLInventoryType::IT_NOTECARD,
1358					  PERM_ALL);
1359	}
1360	else if ("gesture" == type_name)
1361	{
1362		const LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE);
1363		create_new_item(NEW_GESTURE_NAME,
1364					  parent_id,
1365					  LLAssetType::AT_GESTURE,
1366					  LLInventoryType::IT_GESTURE,
1367					  PERM_ALL);
1368	}
1369	else
1370	{
1371		// Use for all clothing and body parts.  Adding new wearable types requires updating LLWearableDictionary.
1372		LLWearableType::EType wearable_type = LLWearableType::typeNameToType(type_name);
1373		if (wearable_type >= LLWearableType::WT_SHAPE && wearable_type < LLWearableType::WT_COUNT)
1374		{
1375			const LLUUID parent_id = bridge ? bridge->getUUID() : LLUUID::null;
1376			LLAgentWearables::createWearable(wearable_type, false, parent_id);
1377		}
1378		else
1379		{
1380			llwarns << "Can't create unrecognized type " << type_name << llendl;
1381		}
1382	}
1383	root->setNeedsAutoRename(TRUE);	
1384}
1385
1386LLAssetType::EType LLViewerInventoryItem::getType() const
1387{
1388	if (const LLViewerInventoryItem *linked_item = getLinkedItem())
1389	{
1390		return linked_item->getType();
1391	}
1392	if (const LLViewerInventoryCategory *linked_category = getLinkedCategory())
1393	{
1394		return linked_category->getType();
1395	}	
1396	return LLInventoryItem::getType();
1397}
1398
1399const LLUUID& LLViewerInventoryItem::getAssetUUID() const
1400{
1401	if (const LLViewerInventoryItem *linked_item = getLinkedItem())
1402	{
1403		return linked_item->getAssetUUID();
1404	}
1405
1406	return LLInventoryItem::getAssetUUID();
1407}
1408
1409const LLUUID& LLViewerInventoryItem::getProtectedAssetUUID() const
1410{
1411	if (const LLViewerInventoryItem *linked_item = getLinkedItem())
1412	{
1413		return linked_item->getProtectedAssetUUID();
1414	}
1415
1416	// check for conditions under which we may return a visible UUID to the user
1417	bool item_is_fullperm = getIsFullPerm();
1418	bool agent_is_godlike = gAgent.isGodlikeWithoutAdminMenuFakery();
1419	if (item_is_fullperm || agent_is_godlike)
1420	{
1421		return LLInventoryItem::getAssetUUID();
1422	}
1423
1424	return LLUUID::null;
1425}
1426
1427const bool LLViewerInventoryItem::getIsFullPerm() const
1428{
1429	LLPermissions item_permissions = getPermissions();
1430
1431	// modify-ok & copy-ok & transfer-ok
1432	return ( item_permissions.allowOperationBy(PERM_MODIFY,
1433						   gAgent.getID(),
1434						   gAgent.getGroupID()) &&
1435		 item_permissions.allowOperationBy(PERM_COPY,
1436						   gAgent.getID(),
1437						   gAgent.getGroupID()) &&
1438		 item_permissions.allowOperationBy(PERM_TRANSFER,
1439						   gAgent.getID(),
1440						   gAgent.getGroupID()) );
1441}
1442
1443const std::string& LLViewerInventoryItem::getName() const
1444{
1445	if (const LLViewerInventoryItem *linked_item = getLinkedItem())
1446	{
1447		return linked_item->getName();
1448	}
1449	if (const LLViewerInventoryCategory *linked_category = getLinkedCategory())
1450	{
1451		return linked_category->getName();
1452	}
1453
1454	return  LLInventoryItem::getName();
1455}
1456
1457/**
1458 * Class to store sorting order of favorites landmarks in a local file. EXT-3985.
1459 * It replaced previously implemented solution to store sort index in landmark's name as a "<N>@" prefix.
1460 * Data are stored in user home directory.
1461 */
1462class LLFavoritesOrderStorage : public LLSingleton<LLFavoritesOrderStorage>
1463	, public LLDestroyClass<LLFavoritesOrderStorage>
1464{
1465public:
1466	/**
1467	 * Sets sort index for specified with LLUUID favorite landmark
1468	 */
1469	void setSortIndex(const LLUUID& inv_item_id, S32 sort_index);
1470
1471	/**
1472	 * Gets sort index for specified with LLUUID favorite landmark
1473	 */
1474	S32 getSortIndex(const LLUUID& inv_item_id);
1475	void removeSortIndex(const LLUUID& inv_item_id);
1476
1477	void getSLURL(const LLUUID& asset_id);
1478
1479	/**
1480	 * Implementation of LLDestroyClass. Calls cleanup() instance method.
1481	 *
1482	 * It is important this callback is called before gInventory is cleaned.
1483	 * For now it is called from LLAppViewer::cleanup() -> LLAppViewer::disconnectViewer(),
1484	 * Inventory is cleaned later from LLAppViewer::cleanup() after LLAppViewer::disconnectViewer() is called.
1485	 * @see cleanup()
1486	 */
1487	static void destroyClass();
1488
1489	const static S32 NO_INDEX;
1490private:
1491	friend class LLSingleton<LLFavoritesOrderStorage>;
1492	LLFavoritesOrderStorage() : mIsDirty(false) { load(); }
1493	~LLFavoritesOrderStorage() { save(); }
1494
1495	/**
1496	 * Removes sort indexes for items which are not in Favorites bar for now.
1497	 */
1498	void cleanup();
1499
1500	const static std::string SORTING_DATA_FILE_NAME;
1501
1502	void load();
1503	void save();
1504
1505	void saveFavoritesSLURLs();
1506
1507	// Remove record of current user's favorites from file on disk.
1508	void removeFavoritesRecordOfUser();
1509
1510	void onLandmarkLoaded(const LLUUID& asset_id, LLLandmark* landmark);
1511	void storeFavoriteSLURL(const LLUUID& asset_id, std::string& slurl);
1512
1513	typedef std::map<LLUUID, S32> sort_index_map_t;
1514	sort_index_map_t mSortIndexes;
1515
1516	typedef std::map<LLUUID, std::string> slurls_map_t;
1517	slurls_map_t mSLURLs;
1518
1519	bool mIsDirty;
1520
1521	struct IsNotInFavorites
1522	{
1523		IsNotInFavorites(const LLInventoryModel::item_array_t& items)
1524			: mFavoriteItems(items)
1525		{
1526
1527		}
1528
1529		/**
1530		 * Returns true if specified item is not found among inventory items
1531		 */
1532		bool operator()(const sort_index_map_t::value_type& id_index_pair) const
1533		{
1534			LLPointer<LLViewerInventoryItem> item = gInventory.getItem(id_index_pair.first);
1535			if (item.isNull()) return true;
1536
1537			LLInventoryModel::item_array_t::const_iterator found_it =
1538				std::find(mFavoriteItems.begin(), mFavoriteItems.end(), item);
1539
1540			return found_it == mFavoriteItems.end();
1541		}
1542	private:
1543		LLInventoryModel::item_array_t mFavoriteItems;
1544	};
1545
1546};
1547
1548const std::string LLFavoritesOrderStorage::SORTING_DATA_FILE_NAME = "landmarks_sorting.xml";
1549const S32 LLFavoritesOrderStorage::NO_INDEX = -1;
1550
1551void LLFavoritesOrderStorage::setSortIndex(const LLUUID& inv_item_id, S32 sort_index)
1552{
1553	mSortIndexes[inv_item_id] = sort_index;
1554	mIsDirty = true;
1555}
1556
1557S32 LLFavorit

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