PageRenderTime 182ms CodeModel.GetById 30ms app.highlight 101ms RepoModel.GetById 40ms app.codeStats 0ms

/indra/newview/llassetuploadresponders.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1164 lines | 881 code | 140 blank | 143 comment | 80 complexity | 4bd5c6a8cc32c0e9518d475f8f572f09 MD5 | raw file
   1/**
   2 * @file llassetuploadresponders.cpp
   3 * @brief Processes responses received for asset upload requests.
   4 *
   5 * $LicenseInfo:firstyear=2007&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */ 
  26
  27#include "llviewerprecompiledheaders.h"
  28
  29#include "llassetuploadresponders.h"
  30
  31// viewer includes
  32#include "llagent.h"
  33#include "llcompilequeue.h"
  34#include "llbuycurrencyhtml.h"
  35#include "llfilepicker.h"
  36#include "llinventorydefines.h"
  37#include "llinventoryobserver.h"
  38#include "llinventorypanel.h"
  39#include "llpermissionsflags.h"
  40#include "llpreviewnotecard.h"
  41#include "llpreviewscript.h"
  42#include "llpreviewgesture.h"
  43#include "llgesturemgr.h"
  44#include "llstatusbar.h"		// sendMoneyBalanceRequest()
  45#include "llsdserialize.h"
  46#include "lluploaddialog.h"
  47#include "llviewerobject.h"
  48#include "llviewercontrol.h"
  49#include "llviewerobjectlist.h"
  50#include "llviewermenufile.h"
  51#include "llviewerwindow.h"
  52#include "lltexlayer.h"
  53#include "lltrans.h"
  54
  55// library includes
  56#include "lldir.h"
  57#include "lleconomy.h"
  58#include "llfloaterreg.h"
  59#include "llfocusmgr.h"
  60#include "llnotificationsutil.h"
  61#include "llscrolllistctrl.h"
  62#include "llsdserialize.h"
  63#include "llsdutil.h"
  64#include "llvfs.h"
  65
  66// When uploading multiple files, don't display any of them when uploading more than this number.
  67static const S32 FILE_COUNT_DISPLAY_THRESHOLD = 5;
  68
  69void dialog_refresh_all();
  70
  71void on_new_single_inventory_upload_complete(
  72	LLAssetType::EType asset_type,
  73	LLInventoryType::EType inventory_type,
  74	const std::string inventory_type_string,
  75	const LLUUID& item_folder_id,
  76	const std::string& item_name,
  77	const std::string& item_description,
  78	const LLSD& server_response,
  79	S32 upload_price)
  80{
  81	bool success = false;
  82
  83	if ( upload_price > 0 )
  84	{
  85		// this upload costed us L$, update our balance
  86		// and display something saying that it cost L$
  87		LLStatusBar::sendMoneyBalanceRequest();
  88
  89		LLSD args;
  90		args["AMOUNT"] = llformat("%d", upload_price);
  91		LLNotificationsUtil::add("UploadPayment", args);
  92	}
  93
  94	if( item_folder_id.notNull() )
  95	{
  96		U32 everyone_perms = PERM_NONE;
  97		U32 group_perms = PERM_NONE;
  98		U32 next_owner_perms = PERM_ALL;
  99		if( server_response.has("new_next_owner_mask") )
 100		{
 101			// The server provided creation perms so use them.
 102			// Do not assume we got the perms we asked for in
 103			// since the server may not have granted them all.
 104			everyone_perms = server_response["new_everyone_mask"].asInteger();
 105			group_perms = server_response["new_group_mask"].asInteger();
 106			next_owner_perms = server_response["new_next_owner_mask"].asInteger();
 107		}
 108		else 
 109		{
 110			// The server doesn't provide creation perms
 111			// so use old assumption-based perms.
 112			if( inventory_type_string != "snapshot")
 113			{
 114				next_owner_perms = PERM_MOVE | PERM_TRANSFER;
 115			}
 116		}
 117
 118		LLPermissions new_perms;
 119		new_perms.init(
 120			gAgent.getID(),
 121			gAgent.getID(),
 122			LLUUID::null,
 123			LLUUID::null);
 124
 125		new_perms.initMasks(
 126			PERM_ALL,
 127			PERM_ALL,
 128			everyone_perms,
 129			group_perms,
 130			next_owner_perms);
 131
 132		U32 inventory_item_flags = 0;
 133		if (server_response.has("inventory_flags"))
 134		{
 135			inventory_item_flags = (U32) server_response["inventory_flags"].asInteger();
 136			if (inventory_item_flags != 0)
 137			{
 138				llinfos << "inventory_item_flags " << inventory_item_flags << llendl;
 139			}
 140		}
 141		S32 creation_date_now = time_corrected();
 142		LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem(
 143			server_response["new_inventory_item"].asUUID(),
 144			item_folder_id,
 145			new_perms,
 146			server_response["new_asset"].asUUID(),
 147			asset_type,
 148			inventory_type,
 149			item_name,
 150			item_description,
 151			LLSaleInfo::DEFAULT,
 152			inventory_item_flags,
 153			creation_date_now);
 154
 155		gInventory.updateItem(item);
 156		gInventory.notifyObservers();
 157		success = true;
 158
 159		// Show the preview panel for textures and sounds to let
 160		// user know that the image (or snapshot) arrived intact.
 161		LLInventoryPanel* panel = LLInventoryPanel::getActiveInventoryPanel();
 162		if ( panel )
 163		{
 164			LLFocusableElement* focus = gFocusMgr.getKeyboardFocus();
 165
 166			panel->setSelection(
 167				server_response["new_inventory_item"].asUUID(),
 168				TAKE_FOCUS_NO);
 169
 170			// restore keyboard focus
 171			gFocusMgr.setKeyboardFocus(focus);
 172		}
 173	}
 174	else
 175	{
 176		llwarns << "Can't find a folder to put it in" << llendl;
 177	}
 178
 179	// remove the "Uploading..." message
 180	LLUploadDialog::modalUploadFinished();	
 181
 182	// Let the Snapshot floater know we have finished uploading a snapshot to inventory.
 183	LLFloater* floater_snapshot = LLFloaterReg::findInstance("snapshot");
 184	if (asset_type == LLAssetType::AT_TEXTURE && floater_snapshot)
 185	{
 186		floater_snapshot->notify(LLSD().with("set-finished", LLSD().with("ok", success).with("msg", "inventory")));
 187	}
 188}
 189
 190LLAssetUploadResponder::LLAssetUploadResponder(const LLSD &post_data,
 191											   const LLUUID& vfile_id,
 192											   LLAssetType::EType asset_type)
 193	: LLHTTPClient::Responder(),
 194	  mPostData(post_data),
 195	  mVFileID(vfile_id),
 196	  mAssetType(asset_type)
 197{
 198	if (!gVFS->getExists(vfile_id, asset_type))
 199	{
 200		llwarns << "LLAssetUploadResponder called with nonexistant vfile_id" << llendl;
 201		mVFileID.setNull();
 202		mAssetType = LLAssetType::AT_NONE;
 203		return;
 204	}
 205}
 206
 207LLAssetUploadResponder::LLAssetUploadResponder(
 208	const LLSD &post_data,
 209	const std::string& file_name, 
 210	LLAssetType::EType asset_type)
 211	: LLHTTPClient::Responder(),
 212	  mPostData(post_data),
 213	  mFileName(file_name),
 214	  mAssetType(asset_type)
 215{
 216}
 217
 218LLAssetUploadResponder::~LLAssetUploadResponder()
 219{
 220	if (!mFileName.empty())
 221	{
 222		// Delete temp file
 223		LLFile::remove(mFileName);
 224	}
 225}
 226
 227// virtual
 228void LLAssetUploadResponder::error(U32 statusNum, const std::string& reason)
 229{
 230	llinfos << "LLAssetUploadResponder::error " << statusNum 
 231			<< " reason: " << reason << llendl;
 232	LLSD args;
 233	switch(statusNum)
 234	{
 235		case 400:
 236			args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName);
 237			args["REASON"] = "Error in upload request.  Please visit "
 238				"http://secondlife.com/support for help fixing this problem.";
 239			LLNotificationsUtil::add("CannotUploadReason", args);
 240			break;
 241		case 500:
 242		default:
 243			args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName);
 244			args["REASON"] = "The server is experiencing unexpected "
 245				"difficulties.";
 246			LLNotificationsUtil::add("CannotUploadReason", args);
 247			break;
 248	}
 249	LLUploadDialog::modalUploadFinished();
 250	LLFilePicker::instance().reset();  // unlock file picker when bulk upload fails
 251}
 252
 253//virtual 
 254void LLAssetUploadResponder::result(const LLSD& content)
 255{
 256	lldebugs << "LLAssetUploadResponder::result from capabilities" << llendl;
 257
 258	std::string state = content["state"];
 259
 260	if (state == "upload")
 261	{
 262		uploadUpload(content);
 263	}
 264	else if (state == "complete")
 265	{
 266		// rename file in VFS with new asset id
 267		if (mFileName.empty())
 268		{
 269			// rename the file in the VFS to the actual asset id
 270			// llinfos << "Changing uploaded asset UUID to " << content["new_asset"].asUUID() << llendl;
 271			gVFS->renameFile(mVFileID, mAssetType, content["new_asset"].asUUID(), mAssetType);
 272		}
 273		uploadComplete(content);
 274	}
 275	else
 276	{
 277		uploadFailure(content);
 278	}
 279}
 280
 281void LLAssetUploadResponder::uploadUpload(const LLSD& content)
 282{
 283	std::string uploader = content["uploader"];
 284	if (mFileName.empty())
 285	{
 286		LLHTTPClient::postFile(uploader, mVFileID, mAssetType, this);
 287	}
 288	else
 289	{
 290		LLHTTPClient::postFile(uploader, mFileName, this);
 291	}
 292}
 293
 294void LLAssetUploadResponder::uploadFailure(const LLSD& content)
 295{
 296	// remove the "Uploading..." message
 297	LLUploadDialog::modalUploadFinished();
 298	LLFloater* floater_snapshot = LLFloaterReg::findInstance("snapshot");
 299	if (floater_snapshot)
 300	{
 301		floater_snapshot->notify(LLSD().with("set-finished", LLSD().with("ok", false).with("msg", "inventory")));
 302	}
 303	
 304	std::string reason = content["state"];
 305	// deal with L$ errors
 306	if (reason == "insufficient funds")
 307	{
 308		S32 price = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
 309		LLStringUtil::format_map_t args;
 310		args["AMOUNT"] = llformat("%d", price);
 311		LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("uploading_costs", args), price );
 312	}
 313	else
 314	{
 315		LLSD args;
 316		args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName);
 317		args["REASON"] = content["message"].asString();
 318		LLNotificationsUtil::add("CannotUploadReason", args);
 319	}
 320}
 321
 322void LLAssetUploadResponder::uploadComplete(const LLSD& content)
 323{
 324}
 325
 326LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(
 327	const LLSD& post_data,
 328	const LLUUID& vfile_id,
 329	LLAssetType::EType asset_type)
 330	: LLAssetUploadResponder(post_data, vfile_id, asset_type)
 331{
 332}
 333
 334LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(
 335	const LLSD& post_data,
 336	const std::string& file_name,
 337	LLAssetType::EType asset_type)
 338	: LLAssetUploadResponder(post_data, file_name, asset_type)
 339{
 340}
 341
 342// virtual
 343void LLNewAgentInventoryResponder::error(U32 statusNum, const std::string& reason)
 344{
 345	LLAssetUploadResponder::error(statusNum, reason);
 346	//LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, LLUUID(), FALSE);
 347}
 348
 349
 350//virtual 
 351void LLNewAgentInventoryResponder::uploadFailure(const LLSD& content)
 352{
 353	LLAssetUploadResponder::uploadFailure(content);
 354
 355	//LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, content["new_asset"], FALSE);
 356}
 357
 358//virtual 
 359void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content)
 360{
 361	lldebugs << "LLNewAgentInventoryResponder::result from capabilities" << llendl;
 362	
 363	//std::ostringstream llsdxml;
 364	//LLSDSerialize::toXML(content, llsdxml);
 365	//llinfos << "upload complete content:\n " << llsdxml.str() << llendl;
 366
 367	LLAssetType::EType asset_type = LLAssetType::lookup(mPostData["asset_type"].asString());
 368	LLInventoryType::EType inventory_type = LLInventoryType::lookup(mPostData["inventory_type"].asString());
 369	S32 expected_upload_cost = 0;
 370
 371	// Update L$ and ownership credit information
 372	// since it probably changed on the server
 373	if (asset_type == LLAssetType::AT_TEXTURE ||
 374		asset_type == LLAssetType::AT_SOUND ||
 375		asset_type == LLAssetType::AT_ANIMATION ||
 376		asset_type == LLAssetType::AT_MESH)
 377	{
 378		expected_upload_cost = 
 379			LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
 380	}
 381
 382	on_new_single_inventory_upload_complete(
 383		asset_type,
 384		inventory_type,
 385		mPostData["asset_type"].asString(),
 386		mPostData["folder_id"].asUUID(),
 387		mPostData["name"],
 388		mPostData["description"],
 389		content,
 390		expected_upload_cost);
 391
 392	// continue uploading for bulk uploads
 393
 394	// *FIX: This is a pretty big hack. What this does is check the
 395	// file picker if there are any more pending uploads. If so,
 396	// upload that file.
 397	std::string next_file = LLFilePicker::instance().getNextFile();
 398	if(!next_file.empty())
 399	{
 400		std::string name = gDirUtilp->getBaseFileName(next_file, true);
 401
 402		std::string asset_name = name;
 403		LLStringUtil::replaceNonstandardASCII( asset_name, '?' );
 404		LLStringUtil::replaceChar(asset_name, '|', '?');
 405		LLStringUtil::stripNonprintable(asset_name);
 406		LLStringUtil::trim(asset_name);
 407
 408		// Continuing the horrible hack above, we need to extract the originally requested permissions data, if any,
 409		// and use them for each next file to be uploaded. Note the requested perms are not the same as the
 410		U32 everyone_perms =
 411			content.has("new_everyone_mask") ?
 412			content["new_everyone_mask"].asInteger() :
 413			PERM_NONE;
 414
 415		U32 group_perms =
 416			content.has("new_group_mask") ?
 417			content["new_group_mask"].asInteger() :
 418			PERM_NONE;
 419
 420		U32 next_owner_perms =
 421			content.has("new_next_owner_mask") ?
 422			content["new_next_owner_mask"].asInteger() :
 423			PERM_NONE;
 424
 425		std::string display_name = LLStringUtil::null;
 426		LLAssetStorage::LLStoreAssetCallback callback = NULL;
 427		void *userdata = NULL;
 428
 429		upload_new_resource(
 430			next_file,
 431			asset_name,
 432			asset_name,
 433			0,
 434			LLFolderType::FT_NONE,
 435			LLInventoryType::IT_NONE,
 436			next_owner_perms,
 437			group_perms,
 438			everyone_perms,
 439			display_name,
 440			callback,
 441			LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(),
 442			userdata);
 443	}
 444
 445	//LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, content["new_asset"], TRUE);
 446}
 447
 448LLSendTexLayerResponder::LLSendTexLayerResponder(const LLSD& post_data,
 449												 const LLUUID& vfile_id,
 450												 LLAssetType::EType asset_type,
 451												 LLBakedUploadData * baked_upload_data) : 
 452	LLAssetUploadResponder(post_data, vfile_id, asset_type),
 453	mBakedUploadData(baked_upload_data)
 454{
 455}
 456
 457LLSendTexLayerResponder::~LLSendTexLayerResponder()
 458{
 459	// mBakedUploadData is normally deleted by calls to LLTexLayerSetBuffer::onTextureUploadComplete() below
 460	if (mBakedUploadData)
 461	{	// ...but delete it in the case where uploadComplete() is never called
 462		delete mBakedUploadData;
 463		mBakedUploadData = NULL;
 464	}
 465}
 466
 467
 468// Baked texture upload completed
 469void LLSendTexLayerResponder::uploadComplete(const LLSD& content)
 470{
 471	LLUUID item_id = mPostData["item_id"];
 472
 473	std::string result = content["state"];
 474	LLUUID new_id = content["new_asset"];
 475
 476	llinfos << "result: " << result << " new_id: " << new_id << llendl;
 477	if (result == "complete"
 478		&& mBakedUploadData != NULL)
 479	{	// Invoke 
 480		LLTexLayerSetBuffer::onTextureUploadComplete(new_id, (void*) mBakedUploadData, 0, LL_EXSTAT_NONE);
 481		mBakedUploadData = NULL;	// deleted in onTextureUploadComplete()
 482	}
 483	else
 484	{	// Invoke the original callback with an error result
 485		LLTexLayerSetBuffer::onTextureUploadComplete(new_id, (void*) mBakedUploadData, -1, LL_EXSTAT_NONE);
 486		mBakedUploadData = NULL;	// deleted in onTextureUploadComplete()
 487	}
 488}
 489
 490void LLSendTexLayerResponder::error(U32 statusNum, const std::string& reason)
 491{
 492	llinfos << "status: " << statusNum << " reason: " << reason << llendl;
 493	
 494	// Invoke the original callback with an error result
 495	LLTexLayerSetBuffer::onTextureUploadComplete(LLUUID(), (void*) mBakedUploadData, -1, LL_EXSTAT_NONE);
 496	mBakedUploadData = NULL;	// deleted in onTextureUploadComplete()
 497}
 498
 499LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(
 500	const LLSD& post_data,
 501	const LLUUID& vfile_id,
 502	LLAssetType::EType asset_type)
 503	: LLAssetUploadResponder(post_data, vfile_id, asset_type)
 504{
 505}
 506
 507LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(
 508	const LLSD& post_data,
 509	const std::string& file_name,
 510	LLAssetType::EType asset_type)
 511	: LLAssetUploadResponder(post_data, file_name, asset_type)
 512{
 513}
 514
 515//virtual 
 516void LLUpdateAgentInventoryResponder::uploadComplete(const LLSD& content)
 517{
 518	llinfos << "LLUpdateAgentInventoryResponder::result from capabilities" << llendl;
 519	LLUUID item_id = mPostData["item_id"];
 520
 521	LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(item_id);
 522	if(!item)
 523	{
 524		llwarns << "Inventory item for " << mVFileID
 525			<< " is no longer in agent inventory." << llendl;
 526		return;
 527	}
 528
 529	// Update viewer inventory item
 530	LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
 531	new_item->setAssetUUID(content["new_asset"].asUUID());
 532	gInventory.updateItem(new_item);
 533	gInventory.notifyObservers();
 534
 535	llinfos << "Inventory item " << item->getName() << " saved into "
 536		<< content["new_asset"].asString() << llendl;
 537
 538	LLInventoryType::EType inventory_type = new_item->getInventoryType();
 539	switch(inventory_type)
 540	{
 541	  case LLInventoryType::IT_NOTECARD:
 542	  {
 543		  // Update the UI with the new asset.
 544		  LLPreviewNotecard* nc = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", LLSD(item_id));
 545		  if(nc)
 546		  {
 547			  // *HACK: we have to delete the asset in the VFS so
 548			  // that the viewer will redownload it. This is only
 549			  // really necessary if the asset had to be modified by
 550			  // the uploader, so this can be optimized away in some
 551			  // cases. A better design is to have a new uuid if the
 552			  // script actually changed the asset.
 553			  if(nc->hasEmbeddedInventory())
 554			  {
 555				  gVFS->removeFile(content["new_asset"].asUUID(), LLAssetType::AT_NOTECARD);
 556			  }
 557			  nc->refreshFromInventory(new_item->getUUID());
 558		  }
 559		  break;
 560	  }
 561	  case LLInventoryType::IT_LSL:
 562	  {
 563		  // Find our window and close it if requested.
 564		  LLPreviewLSL* preview = LLFloaterReg::findTypedInstance<LLPreviewLSL>("preview_script", LLSD(item_id));
 565		  if (preview)
 566		  {
 567			  // Bytecode save completed
 568			  if (content["compiled"])
 569			  {
 570				  preview->callbackLSLCompileSucceeded();
 571			  }
 572			  else
 573			  {
 574				  preview->callbackLSLCompileFailed(content["errors"]);
 575			  }
 576		  }
 577		  break;
 578	  }
 579
 580	  case LLInventoryType::IT_GESTURE:
 581	  {
 582		  // If this gesture is active, then we need to update the in-memory
 583		  // active map with the new pointer.				
 584		  if (LLGestureMgr::instance().isGestureActive(item_id))
 585		  {
 586			  LLUUID asset_id = new_item->getAssetUUID();
 587			  LLGestureMgr::instance().replaceGesture(item_id, asset_id);
 588			  gInventory.notifyObservers();
 589		  }				
 590
 591		  //gesture will have a new asset_id
 592		  LLPreviewGesture* previewp = LLFloaterReg::findTypedInstance<LLPreviewGesture>("preview_gesture", LLSD(item_id));
 593		  if(previewp)
 594		  {
 595			  previewp->onUpdateSucceeded();	
 596		  }			
 597				
 598		  break;
 599	  }
 600	  case LLInventoryType::IT_WEARABLE:
 601	  default:
 602		break;
 603	}
 604}
 605
 606
 607LLUpdateTaskInventoryResponder::LLUpdateTaskInventoryResponder(const LLSD& post_data,
 608																 const LLUUID& vfile_id,
 609																 LLAssetType::EType asset_type)
 610: LLAssetUploadResponder(post_data, vfile_id, asset_type)
 611{
 612}
 613
 614LLUpdateTaskInventoryResponder::LLUpdateTaskInventoryResponder(const LLSD& post_data,
 615															   const std::string& file_name, 
 616															   LLAssetType::EType asset_type)
 617: LLAssetUploadResponder(post_data, file_name, asset_type)
 618{
 619}
 620
 621LLUpdateTaskInventoryResponder::LLUpdateTaskInventoryResponder(const LLSD& post_data,
 622															   const std::string& file_name,
 623															   const LLUUID& queue_id, 
 624															   LLAssetType::EType asset_type)
 625: LLAssetUploadResponder(post_data, file_name, asset_type), mQueueId(queue_id)
 626{
 627}
 628
 629//virtual 
 630void LLUpdateTaskInventoryResponder::uploadComplete(const LLSD& content)
 631{
 632	llinfos << "LLUpdateTaskInventoryResponder::result from capabilities" << llendl;
 633	LLUUID item_id = mPostData["item_id"];
 634	LLUUID task_id = mPostData["task_id"];
 635
 636	dialog_refresh_all();
 637	
 638	switch(mAssetType)
 639	{
 640	  case LLAssetType::AT_NOTECARD:
 641	  {
 642		  // Update the UI with the new asset.
 643		  LLPreviewNotecard* nc = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", LLSD(item_id));
 644		  if(nc)
 645		  {
 646			  // *HACK: we have to delete the asset in the VFS so
 647			  // that the viewer will redownload it. This is only
 648			  // really necessary if the asset had to be modified by
 649			  // the uploader, so this can be optimized away in some
 650			  // cases. A better design is to have a new uuid if the
 651			  // script actually changed the asset.
 652			  if(nc->hasEmbeddedInventory())
 653			  {
 654				  gVFS->removeFile(content["new_asset"].asUUID(),
 655								   LLAssetType::AT_NOTECARD);
 656			  }
 657			  nc->setAssetId(content["new_asset"].asUUID());
 658			  nc->refreshFromInventory();
 659		  }
 660		  break;
 661	  }
 662	  case LLAssetType::AT_LSL_TEXT:
 663	  {
 664		  if(mQueueId.notNull())
 665		  {
 666			  LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance<LLFloaterCompileQueue>("compile_queue", mQueueId);
 667			  if(NULL != queue)
 668			  {
 669				  queue->removeItemByItemID(item_id);
 670			  }
 671		  }
 672		  else
 673		  {
 674			  LLLiveLSLEditor* preview = LLFloaterReg::findTypedInstance<LLLiveLSLEditor>("preview_scriptedit", LLSD(item_id));
 675			  if (preview)
 676			  {
 677				  // Bytecode save completed
 678				  if (content["compiled"])
 679				  {
 680					  preview->callbackLSLCompileSucceeded(task_id, item_id, mPostData["is_script_running"]);
 681				  }
 682				  else
 683				  {
 684					  preview->callbackLSLCompileFailed(content["errors"]);
 685				  }
 686			  }
 687		  }
 688		  break;
 689	  }
 690	  default:
 691		break;
 692	}
 693}
 694
 695
 696/////////////////////////////////////////////////////
 697// LLNewAgentInventoryVariablePriceResponder::Impl //
 698/////////////////////////////////////////////////////
 699class LLNewAgentInventoryVariablePriceResponder::Impl
 700{
 701public:
 702	Impl(
 703		const LLUUID& vfile_id,
 704		LLAssetType::EType asset_type,
 705		const LLSD& inventory_data) :
 706		mVFileID(vfile_id),
 707		mAssetType(asset_type),
 708		mInventoryData(inventory_data),
 709		mFileName("")
 710	{
 711		if (!gVFS->getExists(vfile_id, asset_type))
 712		{
 713			llwarns
 714				<< "LLAssetUploadResponder called with nonexistant "
 715				<< "vfile_id " << vfile_id << llendl;
 716			mVFileID.setNull();
 717			mAssetType = LLAssetType::AT_NONE;
 718		}
 719	}
 720
 721	Impl(
 722		const std::string& file_name,
 723		LLAssetType::EType asset_type,
 724		const LLSD& inventory_data) :
 725		mFileName(file_name),
 726		mAssetType(asset_type),
 727		mInventoryData(inventory_data)
 728	{
 729		mVFileID.setNull();
 730	}
 731
 732	std::string getFilenameOrIDString() const
 733	{
 734		return (mFileName.empty() ? mVFileID.asString() : mFileName);
 735	}
 736
 737	LLUUID getVFileID() const
 738	{
 739		return mVFileID;
 740	}
 741
 742	std::string getFilename() const
 743	{
 744		return mFileName;
 745	}
 746
 747	LLAssetType::EType getAssetType() const
 748	{
 749		return mAssetType;
 750	}
 751
 752	LLInventoryType::EType getInventoryType() const
 753	{
 754		return LLInventoryType::lookup(
 755			mInventoryData["inventory_type"].asString());
 756	}
 757
 758	std::string getInventoryTypeString() const
 759	{
 760		return mInventoryData["inventory_type"].asString();
 761	}
 762
 763	LLUUID getFolderID() const
 764	{
 765		return mInventoryData["folder_id"].asUUID();
 766	}
 767
 768	std::string getItemName() const
 769	{
 770		return mInventoryData["name"].asString();
 771	}
 772
 773	std::string getItemDescription() const
 774	{
 775		return mInventoryData["description"].asString();
 776	}
 777
 778	void displayCannotUploadReason(const std::string& reason)
 779	{
 780		LLSD args;
 781		args["FILE"] = getFilenameOrIDString();
 782		args["REASON"] = reason;
 783
 784
 785		LLNotificationsUtil::add("CannotUploadReason", args);
 786		LLUploadDialog::modalUploadFinished();
 787	}
 788
 789	void onApplicationLevelError(const LLSD& error)
 790	{
 791		static const std::string _IDENTIFIER = "identifier";
 792
 793		static const std::string _INSUFFICIENT_FUNDS =
 794			"NewAgentInventory_InsufficientLindenDollarBalance";
 795		static const std::string _MISSING_REQUIRED_PARAMETER =
 796			"NewAgentInventory_MissingRequiredParamater";
 797		static const std::string _INVALID_REQUEST_BODY =
 798			"NewAgentInventory_InvalidRequestBody";
 799		static const std::string _RESOURCE_COST_DIFFERS =
 800			"NewAgentInventory_ResourceCostDiffers";
 801
 802		static const std::string _MISSING_PARAMETER = "missing_parameter";
 803		static const std::string _INVALID_PARAMETER = "invalid_parameter";
 804		static const std::string _MISSING_RESOURCE = "missing_resource";
 805		static const std::string _INVALID_RESOURCE = "invalid_resource";
 806
 807		// TODO* Add the other error_identifiers
 808
 809		std::string error_identifier = error[_IDENTIFIER].asString();
 810
 811		// TODO*: Pull these user visible strings from an xml file
 812		// to be localized
 813		if ( _INSUFFICIENT_FUNDS == error_identifier )
 814		{
 815			displayCannotUploadReason("You do not have a sufficient L$ balance to complete this upload.");
 816		}
 817		else if ( _MISSING_REQUIRED_PARAMETER == error_identifier )
 818		{
 819			// Missing parameters
 820			if (error.has(_MISSING_PARAMETER) )
 821			{
 822				std::string message = 
 823					"Upload request was missing required parameter '[P]'";
 824				LLStringUtil::replaceString(
 825					message,
 826					"[P]",
 827					error[_MISSING_PARAMETER].asString());
 828
 829				displayCannotUploadReason(message);
 830			}
 831			else
 832			{
 833				std::string message = 
 834					"Upload request was missing a required parameter";
 835				displayCannotUploadReason(message);					
 836			}
 837		}
 838		else if ( _INVALID_REQUEST_BODY == error_identifier )
 839		{
 840			// Invalid request body, check to see if 
 841			// a particular parameter was invalid
 842			if ( error.has(_INVALID_PARAMETER) )
 843			{
 844				std::string message = "Upload parameter '[P]' is invalid.";
 845				LLStringUtil::replaceString(
 846					message,
 847					"[P]",
 848					error[_INVALID_PARAMETER].asString());
 849
 850				// See if the server also responds with what resource
 851				// is missing.
 852				if ( error.has(_MISSING_RESOURCE) )
 853				{
 854					message += "\nMissing resource '[R]'.";
 855
 856					LLStringUtil::replaceString(
 857						message,
 858						"[R]",
 859						error[_MISSING_RESOURCE].asString());
 860				}
 861				else if ( error.has(_INVALID_RESOURCE) )
 862				{
 863					message += "\nInvalid resource '[R]'.";
 864
 865					LLStringUtil::replaceString(
 866						message,
 867						"[R]",
 868						error[_INVALID_RESOURCE].asString());
 869				}
 870
 871				displayCannotUploadReason(message);
 872			}
 873			else
 874			{
 875				std::string message = "Upload request was malformed";
 876				displayCannotUploadReason(message);					
 877			}
 878		}
 879		else if ( _RESOURCE_COST_DIFFERS == error_identifier )
 880		{
 881			displayCannotUploadReason("The resource cost associated with this upload is not consistent with the server.");
 882		}
 883		else
 884		{
 885			displayCannotUploadReason("Unknown Error");
 886		}
 887	}
 888
 889	void onTransportError()
 890	{
 891		displayCannotUploadReason(
 892				"The server is experiencing unexpected difficulties.");
 893	}
 894
 895	void onTransportError(const LLSD& error)
 896	{
 897		static const std::string _IDENTIFIER = "identifier";
 898
 899		static const std::string _SERVER_ERROR_AFTER_CHARGE =
 900			"NewAgentInventory_ServerErrorAfterCharge";
 901
 902		std::string error_identifier = error[_IDENTIFIER].asString();
 903
 904		// TODO*: Pull the user visible strings from an xml file
 905		// to be localized
 906
 907		if ( _SERVER_ERROR_AFTER_CHARGE == error_identifier )
 908		{
 909			displayCannotUploadReason(
 910				"The server is experiencing unexpected difficulties.  You may have been charged for the upload.");
 911		}
 912		else
 913		{
 914			displayCannotUploadReason(
 915				"The server is experiencing unexpected difficulties.");
 916		}
 917	}
 918
 919	bool uploadConfirmationCallback(
 920		const LLSD& notification,
 921		const LLSD& response,
 922		boost::intrusive_ptr<LLNewAgentInventoryVariablePriceResponder> responder)
 923	{
 924		S32 option;
 925		std::string confirmation_url;
 926
 927		option = LLNotificationsUtil::getSelectedOption(
 928			notification,
 929			response);
 930
 931		confirmation_url =
 932			notification["payload"]["confirmation_url"].asString();
 933
 934		// Yay!  We are confirming or cancelling our upload
 935		switch(option)
 936		{
 937		case 0:
 938		    {
 939				confirmUpload(confirmation_url, responder);
 940			}
 941			break;
 942		case 1:
 943		default:
 944			break;
 945		}
 946
 947		return false;
 948	}
 949
 950	void confirmUpload(
 951		const std::string& confirmation_url,
 952		boost::intrusive_ptr<LLNewAgentInventoryVariablePriceResponder> responder)
 953	{
 954		if ( getFilename().empty() )
 955		{
 956			// we have no filename, use virtual file ID instead
 957			LLHTTPClient::postFile(
 958				confirmation_url,
 959				getVFileID(),
 960				getAssetType(),
 961				responder);
 962		}
 963		else
 964		{
 965			LLHTTPClient::postFile(
 966				confirmation_url,
 967				getFilename(),
 968				responder);
 969		}
 970	}
 971
 972
 973private:
 974	std::string mFileName;
 975
 976	LLSD mInventoryData;
 977	LLAssetType::EType mAssetType;
 978	LLUUID mVFileID;
 979};
 980
 981///////////////////////////////////////////////
 982// LLNewAgentInventoryVariablePriceResponder //
 983///////////////////////////////////////////////
 984LLNewAgentInventoryVariablePriceResponder::LLNewAgentInventoryVariablePriceResponder(
 985	const LLUUID& vfile_id,
 986	LLAssetType::EType asset_type,
 987	const LLSD& inventory_info)
 988{
 989	mImpl = new Impl(
 990		vfile_id,
 991		asset_type,
 992		inventory_info);
 993}
 994
 995LLNewAgentInventoryVariablePriceResponder::LLNewAgentInventoryVariablePriceResponder(
 996	const std::string& file_name,
 997	LLAssetType::EType asset_type,
 998	const LLSD& inventory_info)
 999{
1000	mImpl = new Impl(
1001		file_name,
1002		asset_type,
1003		inventory_info);
1004}
1005
1006LLNewAgentInventoryVariablePriceResponder::~LLNewAgentInventoryVariablePriceResponder()
1007{
1008	delete mImpl;
1009}
1010
1011void LLNewAgentInventoryVariablePriceResponder::errorWithContent(
1012	U32 statusNum,
1013	const std::string& reason,
1014	const LLSD& content)
1015{
1016	lldebugs 
1017		<< "LLNewAgentInventoryVariablePrice::error " << statusNum 
1018		<< " reason: " << reason << llendl;
1019
1020	if ( content.has("error") )
1021	{
1022		static const std::string _ERROR = "error";
1023
1024		mImpl->onTransportError(content[_ERROR]);
1025	}
1026	else
1027	{
1028		mImpl->onTransportError();
1029	}
1030}
1031
1032void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content)
1033{
1034	// Parse out application level errors and the appropriate
1035	// responses for them
1036	static const std::string _ERROR = "error";
1037	static const std::string _STATE = "state";
1038
1039	static const std::string _COMPLETE = "complete";
1040	static const std::string _CONFIRM_UPLOAD = "confirm_upload";
1041
1042	static const std::string _UPLOAD_PRICE = "upload_price";
1043	static const std::string _RESOURCE_COST = "resource_cost";
1044	static const std::string _RSVP = "rsvp";
1045
1046	// Check for application level errors
1047	if ( content.has(_ERROR) )
1048	{
1049		onApplicationLevelError(content[_ERROR]);
1050		return;
1051	}
1052
1053	std::string state = content[_STATE];
1054	LLAssetType::EType asset_type = mImpl->getAssetType();
1055
1056	if ( _COMPLETE == state )
1057	{
1058		// rename file in VFS with new asset id
1059		if (mImpl->getFilename().empty())
1060		{
1061			// rename the file in the VFS to the actual asset id
1062			// llinfos << "Changing uploaded asset UUID to " << content["new_asset"].asUUID() << llendl;
1063			gVFS->renameFile(
1064				mImpl->getVFileID(),
1065				asset_type,
1066				content["new_asset"].asUUID(),
1067				asset_type);
1068		}
1069
1070 		on_new_single_inventory_upload_complete(
1071 			asset_type,
1072 			mImpl->getInventoryType(),
1073			mImpl->getInventoryTypeString(),
1074			mImpl->getFolderID(),
1075			mImpl->getItemName(),
1076			mImpl->getItemDescription(),
1077			content,
1078			content[_UPLOAD_PRICE].asInteger());
1079
1080		// TODO* Add bulk (serial) uploading or add
1081		// a super class of this that does so
1082	}
1083	else if ( _CONFIRM_UPLOAD == state )
1084	{
1085		showConfirmationDialog(
1086			content[_UPLOAD_PRICE].asInteger(),
1087			content[_RESOURCE_COST].asInteger(),
1088			content[_RSVP].asString());
1089	}
1090	else
1091	{
1092		onApplicationLevelError("");
1093	}
1094}
1095
1096void LLNewAgentInventoryVariablePriceResponder::onApplicationLevelError(
1097	const LLSD& error)
1098{
1099	mImpl->onApplicationLevelError(error);
1100}
1101
1102void LLNewAgentInventoryVariablePriceResponder::showConfirmationDialog(
1103	S32 upload_price,
1104	S32 resource_cost,
1105	const std::string& confirmation_url)
1106{
1107	if ( 0 == upload_price )
1108	{
1109		// don't show confirmation dialog for free uploads, I mean,
1110		// they're free!
1111
1112		// The creating of a new instrusive_ptr(this)
1113		// creates a new boost::intrusive_ptr
1114		// which is a copy of this.  This code is required because
1115		// 'this' is always of type Class* and not the intrusive_ptr,
1116		// and thus, a reference to 'this' is not registered
1117		// by using just plain 'this'.
1118
1119		// Since LLNewAgentInventoryVariablePriceResponder is a
1120		// reference counted class, it is possible (since the
1121		// reference to a plain 'this' would be missed here) that,
1122		// when using plain ol' 'this', that this object
1123		// would be deleted before the callback is triggered
1124		// and cause sadness.
1125		mImpl->confirmUpload(
1126			confirmation_url,
1127			boost::intrusive_ptr<LLNewAgentInventoryVariablePriceResponder>(this));
1128	}
1129	else
1130	{
1131		LLSD substitutions;
1132		LLSD payload;
1133
1134		substitutions["PRICE"] = upload_price;
1135
1136		payload["confirmation_url"] = confirmation_url;
1137
1138		// The creating of a new instrusive_ptr(this)
1139		// creates a new boost::intrusive_ptr
1140		// which is a copy of this.  This code is required because
1141		// 'this' is always of type Class* and not the intrusive_ptr,
1142		// and thus, a reference to 'this' is not registered
1143		// by using just plain 'this'.
1144
1145		// Since LLNewAgentInventoryVariablePriceResponder is a
1146		// reference counted class, it is possible (since the
1147		// reference to a plain 'this' would be missed here) that,
1148		// when using plain ol' 'this', that this object
1149		// would be deleted before the callback is triggered
1150		// and cause sadness.
1151		LLNotificationsUtil::add(
1152			"UploadCostConfirmation",
1153			substitutions,
1154			payload,
1155			boost::bind(
1156				&LLNewAgentInventoryVariablePriceResponder::Impl::uploadConfirmationCallback,
1157				mImpl,
1158				_1,
1159				_2,
1160				boost::intrusive_ptr<LLNewAgentInventoryVariablePriceResponder>(this)));
1161	}
1162}
1163
1164