PageRenderTime 772ms CodeModel.GetById 120ms app.highlight 443ms RepoModel.GetById 141ms app.codeStats 0ms

/indra/newview/llviewermenufile.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1272 lines | 1035 code | 136 blank | 101 comment | 126 complexity | 6c060c8a061115e8d2a0da66f51e7bc1 MD5 | raw file
   1/** 
   2 * @file llviewermenufile.cpp
   3 * @brief "File" menu in the main menu bar.
   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
  29#include "llviewermenufile.h"
  30
  31// project includes
  32#include "llagent.h"
  33#include "llagentcamera.h"
  34#include "llfilepicker.h"
  35#include "llfloaterreg.h"
  36#include "llbuycurrencyhtml.h"
  37#include "llfloatermodelpreview.h"
  38#include "llfloatersnapshot.h"
  39#include "llimage.h"
  40#include "llimagebmp.h"
  41#include "llimagepng.h"
  42#include "llimagej2c.h"
  43#include "llimagejpeg.h"
  44#include "llimagetga.h"
  45#include "llinventorymodel.h"	// gInventory
  46#include "llresourcedata.h"
  47#include "llfloaterperms.h"
  48#include "llstatusbar.h"
  49#include "llviewercontrol.h"	// gSavedSettings
  50#include "llviewertexturelist.h"
  51#include "lluictrlfactory.h"
  52#include "llvfile.h"
  53#include "llvfs.h"
  54#include "llviewerinventory.h"
  55#include "llviewermenu.h"	// gMenuHolder
  56#include "llviewerparcelmgr.h"
  57#include "llviewerregion.h"
  58#include "llviewerstats.h"
  59#include "llviewerwindow.h"
  60#include "llappviewer.h"
  61#include "lluploaddialog.h"
  62#include "lltrans.h"
  63#include "llfloaterbuycurrency.h"
  64
  65// linden libraries
  66#include "llassetuploadresponders.h"
  67#include "lleconomy.h"
  68#include "llhttpclient.h"
  69#include "llnotificationsutil.h"
  70#include "llsdserialize.h"
  71#include "llsdutil.h"
  72#include "llstring.h"
  73#include "lltransactiontypes.h"
  74#include "lluuid.h"
  75#include "llvorbisencode.h"
  76#include "message.h"
  77
  78// system libraries
  79#include <boost/tokenizer.hpp>
  80
  81class LLFileEnableUpload : public view_listener_t
  82{
  83	bool handleEvent(const LLSD& userdata)
  84	{
  85		bool new_value = gStatusBar && LLGlobalEconomy::Singleton::getInstance() && (gStatusBar->getBalance() >= LLGlobalEconomy::Singleton::getInstance()->getPriceUpload());
  86		return new_value;
  87	}
  88};
  89
  90class LLFileEnableUploadModel : public view_listener_t
  91{
  92	bool handleEvent(const LLSD& userdata)
  93	{
  94		return true;
  95	}
  96};
  97
  98class LLMeshEnabled : public view_listener_t
  99{
 100	bool handleEvent(const LLSD& userdata)
 101	{
 102		return gSavedSettings.getBOOL("MeshEnabled");
 103	}
 104};
 105
 106class LLMeshUploadVisible : public view_listener_t
 107{
 108	bool handleEvent(const LLSD& userdata)
 109	{
 110		return gMeshRepo.meshUploadEnabled();
 111	}
 112};
 113
 114LLMutex* LLFilePickerThread::sMutex = NULL;
 115std::queue<LLFilePickerThread*> LLFilePickerThread::sDeadQ;
 116
 117void LLFilePickerThread::getFile()
 118{
 119#if LL_WINDOWS
 120	start();
 121#else
 122	run();
 123#endif
 124}
 125
 126//virtual 
 127void LLFilePickerThread::run()
 128{
 129	LLFilePicker picker;
 130#if LL_WINDOWS
 131	if (picker.getOpenFile(mFilter, false))
 132	{
 133		mFile = picker.getFirstFile();
 134	}
 135#else
 136	if (picker.getOpenFile(mFilter, true))
 137	{
 138		mFile = picker.getFirstFile();
 139	}
 140#endif
 141
 142	{
 143		LLMutexLock lock(sMutex);
 144		sDeadQ.push(this);
 145	}
 146
 147}
 148
 149//static
 150void LLFilePickerThread::initClass()
 151{
 152	sMutex = new LLMutex(NULL);
 153}
 154
 155//static
 156void LLFilePickerThread::cleanupClass()
 157{
 158	clearDead();
 159	
 160	delete sMutex;
 161	sMutex = NULL;
 162}
 163
 164//static
 165void LLFilePickerThread::clearDead()
 166{
 167	if (!sDeadQ.empty())
 168	{
 169		LLMutexLock lock(sMutex);
 170		while (!sDeadQ.empty())
 171		{
 172			LLFilePickerThread* thread = sDeadQ.front();
 173			thread->notify(thread->mFile);
 174			delete thread;
 175			sDeadQ.pop();
 176		}
 177	}
 178}
 179
 180
 181//============================================================================
 182
 183#if LL_WINDOWS
 184static std::string SOUND_EXTENSIONS = "wav";
 185static std::string IMAGE_EXTENSIONS = "tga bmp jpg jpeg png";
 186static std::string ANIM_EXTENSIONS =  "bvh";
 187#ifdef _CORY_TESTING
 188static std::string GEOMETRY_EXTENSIONS = "slg";
 189#endif
 190static std::string XML_EXTENSIONS = "xml";
 191static std::string SLOBJECT_EXTENSIONS = "slobject";
 192#endif
 193static std::string ALL_FILE_EXTENSIONS = "*.*";
 194static std::string MODEL_EXTENSIONS = "dae";
 195
 196std::string build_extensions_string(LLFilePicker::ELoadFilter filter)
 197{
 198	switch(filter)
 199	{
 200#if LL_WINDOWS
 201	case LLFilePicker::FFLOAD_IMAGE:
 202		return IMAGE_EXTENSIONS;
 203	case LLFilePicker::FFLOAD_WAV:
 204		return SOUND_EXTENSIONS;
 205	case LLFilePicker::FFLOAD_ANIM:
 206		return ANIM_EXTENSIONS;
 207	case LLFilePicker::FFLOAD_SLOBJECT:
 208		return SLOBJECT_EXTENSIONS;
 209	case LLFilePicker::FFLOAD_MODEL:
 210		return MODEL_EXTENSIONS;
 211#ifdef _CORY_TESTING
 212	case LLFilePicker::FFLOAD_GEOMETRY:
 213		return GEOMETRY_EXTENSIONS;
 214#endif
 215	case LLFilePicker::FFLOAD_XML:
 216	    return XML_EXTENSIONS;
 217	case LLFilePicker::FFLOAD_ALL:
 218		return ALL_FILE_EXTENSIONS;
 219#endif
 220    default:
 221	return ALL_FILE_EXTENSIONS;
 222	}
 223}
 224
 225/**
 226   char* upload_pick(void* data)
 227
 228   If applicable, brings up a file chooser in which the user selects a file
 229   to upload for a particular task.  If the file is valid for the given action,
 230   returns the string to the full path filename, else returns NULL.
 231   Data is the load filter for the type of file as defined in LLFilePicker.
 232**/
 233const std::string upload_pick(void* data)
 234{
 235 	if( gAgentCamera.cameraMouselook() )
 236	{
 237		gAgentCamera.changeCameraToDefault();
 238		// This doesn't seem necessary. JC
 239		// display();
 240	}
 241
 242	LLFilePicker::ELoadFilter type;
 243	if(data)
 244	{
 245		type = (LLFilePicker::ELoadFilter)((intptr_t)data);
 246	}
 247	else
 248	{
 249		type = LLFilePicker::FFLOAD_ALL;
 250	}
 251
 252	LLFilePicker& picker = LLFilePicker::instance();
 253	if (!picker.getOpenFile(type))
 254	{
 255		llinfos << "Couldn't import objects from file" << llendl;
 256		return std::string();
 257	}
 258
 259	
 260	const std::string& filename = picker.getFirstFile();
 261	std::string ext = gDirUtilp->getExtension(filename);
 262
 263	//strincmp doesn't like NULL pointers
 264	if (ext.empty())
 265	{
 266		std::string short_name = gDirUtilp->getBaseFileName(filename);
 267		
 268		// No extension
 269		LLSD args;
 270		args["FILE"] = short_name;
 271		LLNotificationsUtil::add("NoFileExtension", args);
 272		return std::string();
 273	}
 274	else
 275	{
 276		//so there is an extension
 277		//loop over the valid extensions and compare to see
 278		//if the extension is valid
 279
 280		//now grab the set of valid file extensions
 281		std::string valid_extensions = build_extensions_string(type);
 282
 283		BOOL ext_valid = FALSE;
 284		
 285		typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
 286		boost::char_separator<char> sep(" ");
 287		tokenizer tokens(valid_extensions, sep);
 288		tokenizer::iterator token_iter;
 289
 290		//now loop over all valid file extensions
 291		//and compare them to the extension of the file
 292		//to be uploaded
 293		for( token_iter = tokens.begin();
 294			 token_iter != tokens.end() && ext_valid != TRUE;
 295			 ++token_iter)
 296		{
 297			const std::string& cur_token = *token_iter;
 298
 299			if (cur_token == ext || cur_token == "*.*")
 300			{
 301				//valid extension
 302				//or the acceptable extension is any
 303				ext_valid = TRUE;
 304			}
 305		}//end for (loop over all tokens)
 306
 307		if (ext_valid == FALSE)
 308		{
 309			//should only get here if the extension exists
 310			//but is invalid
 311			LLSD args;
 312			args["EXTENSION"] = ext;
 313			args["VALIDS"] = valid_extensions;
 314			LLNotificationsUtil::add("InvalidFileExtension", args);
 315			return std::string();
 316		}
 317	}//end else (non-null extension)
 318
 319	//valid file extension
 320	
 321	//now we check to see
 322	//if the file is actually a valid image/sound/etc.
 323	if (type == LLFilePicker::FFLOAD_WAV)
 324	{
 325		// pre-qualify wavs to make sure the format is acceptable
 326		std::string error_msg;
 327		if (check_for_invalid_wav_formats(filename,error_msg))
 328		{
 329			llinfos << error_msg << ": " << filename << llendl;
 330			LLSD args;
 331			args["FILE"] = filename;
 332			LLNotificationsUtil::add( error_msg, args );
 333			return std::string();
 334		}
 335	}//end if a wave/sound file
 336
 337	
 338	return filename;
 339}
 340
 341class LLFileUploadImage : public view_listener_t
 342{
 343	bool handleEvent(const LLSD& userdata)
 344	{
 345		std::string filename = upload_pick((void *)LLFilePicker::FFLOAD_IMAGE);
 346		if (!filename.empty())
 347		{
 348			LLFloaterReg::showInstance("upload_image", LLSD(filename));
 349		}
 350		return TRUE;
 351	}
 352};
 353
 354class LLFileUploadModel : public view_listener_t
 355{
 356	bool handleEvent(const LLSD& userdata)
 357	{
 358		LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) LLFloaterReg::getInstance("upload_model");
 359		if (fmp)
 360		{
 361			fmp->loadModel(3);
 362		}
 363		
 364		return TRUE;
 365	}
 366};
 367	
 368class LLFileUploadSound : public view_listener_t
 369{
 370	bool handleEvent(const LLSD& userdata)
 371	{
 372		std::string filename = upload_pick((void*)LLFilePicker::FFLOAD_WAV);
 373		if (!filename.empty())
 374		{
 375			LLFloaterReg::showInstance("upload_sound", LLSD(filename));
 376		}
 377		return true;
 378	}
 379};
 380
 381class LLFileUploadAnim : public view_listener_t
 382{
 383	bool handleEvent(const LLSD& userdata)
 384	{
 385		const std::string filename = upload_pick((void*)LLFilePicker::FFLOAD_ANIM);
 386		if (!filename.empty())
 387		{
 388			LLFloaterReg::showInstance("upload_anim", LLSD(filename));
 389		}
 390		return true;
 391	}
 392};
 393
 394class LLFileUploadBulk : public view_listener_t
 395{
 396	bool handleEvent(const LLSD& userdata)
 397	{
 398		if( gAgentCamera.cameraMouselook() )
 399		{
 400			gAgentCamera.changeCameraToDefault();
 401		}
 402
 403		// TODO:
 404		// Iterate over all files
 405		// Check extensions for uploadability, cost
 406		// Check user balance for entire cost
 407		// Charge user entire cost
 408		// Loop, uploading
 409		// If an upload fails, refund the user for that one
 410		//
 411		// Also fix single upload to charge first, then refund
 412
 413		LLFilePicker& picker = LLFilePicker::instance();
 414		if (picker.getMultipleOpenFiles())
 415		{
 416			const std::string& filename = picker.getFirstFile();
 417			std::string name = gDirUtilp->getBaseFileName(filename, true);
 418			
 419			std::string asset_name = name;
 420			LLStringUtil::replaceNonstandardASCII( asset_name, '?' );
 421			LLStringUtil::replaceChar(asset_name, '|', '?');
 422			LLStringUtil::stripNonprintable(asset_name);
 423			LLStringUtil::trim(asset_name);
 424			
 425			std::string display_name = LLStringUtil::null;
 426			LLAssetStorage::LLStoreAssetCallback callback = NULL;
 427			S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
 428			void *userdata = NULL;
 429
 430			upload_new_resource(
 431				filename,
 432				asset_name,
 433				asset_name,
 434				0,
 435				LLFolderType::FT_NONE,
 436				LLInventoryType::IT_NONE,
 437				LLFloaterPerms::getNextOwnerPerms(),
 438				LLFloaterPerms::getGroupPerms(),
 439				LLFloaterPerms::getEveryonePerms(),
 440				display_name,
 441				callback,
 442				expected_upload_cost,
 443				userdata);
 444
 445			// *NOTE: Ew, we don't iterate over the file list here,
 446			// we handle the next files in upload_done_callback()
 447		}
 448		else
 449		{
 450			llinfos << "Couldn't import objects from file" << llendl;
 451		}
 452		return true;
 453	}
 454};
 455
 456void upload_error(const std::string& error_message, const std::string& label, const std::string& filename, const LLSD& args) 
 457{
 458	llwarns << error_message << llendl;
 459	LLNotificationsUtil::add(label, args);
 460	if(LLFile::remove(filename) == -1)
 461	{
 462		lldebugs << "unable to remove temp file" << llendl;
 463	}
 464	LLFilePicker::instance().reset();						
 465}
 466
 467class LLFileEnableCloseWindow : public view_listener_t
 468{
 469	bool handleEvent(const LLSD& userdata)
 470	{
 471		bool new_value = NULL != LLFloater::getClosableFloaterFromFocus();
 472		return new_value;
 473	}
 474};
 475
 476class LLFileCloseWindow : public view_listener_t
 477{
 478	bool handleEvent(const LLSD& userdata)
 479	{
 480		LLFloater::closeFocusedFloater();
 481
 482		return true;
 483	}
 484};
 485
 486class LLFileEnableCloseAllWindows : public view_listener_t
 487{
 488	bool handleEvent(const LLSD& userdata)
 489	{
 490		bool open_children = gFloaterView->allChildrenClosed();
 491		return !open_children;
 492	}
 493};
 494
 495class LLFileCloseAllWindows : public view_listener_t
 496{
 497	bool handleEvent(const LLSD& userdata)
 498	{
 499		bool app_quitting = false;
 500		gFloaterView->closeAllChildren(app_quitting);
 501
 502		return true;
 503	}
 504};
 505
 506class LLFileTakeSnapshotToDisk : public view_listener_t
 507{
 508	bool handleEvent(const LLSD& userdata)
 509	{
 510		LLPointer<LLImageRaw> raw = new LLImageRaw;
 511
 512		S32 width = gViewerWindow->getWindowWidthRaw();
 513		S32 height = gViewerWindow->getWindowHeightRaw();
 514
 515		if (gSavedSettings.getBOOL("HighResSnapshot"))
 516		{
 517			width *= 2;
 518			height *= 2;
 519		}
 520
 521		if (gViewerWindow->rawSnapshot(raw,
 522									   width,
 523									   height,
 524									   TRUE,
 525									   FALSE,
 526									   gSavedSettings.getBOOL("RenderUIInSnapshot"),
 527									   FALSE))
 528		{
 529			gViewerWindow->playSnapshotAnimAndSound();
 530			
 531			LLPointer<LLImageFormatted> formatted = new LLImagePNG;
 532			formatted->enableOverSize() ;
 533			formatted->encode(raw, 0);
 534			formatted->disableOverSize() ;
 535			gViewerWindow->saveImageNumbered(formatted);
 536		}
 537		return true;
 538	}
 539};
 540
 541class LLFileQuit : public view_listener_t
 542{
 543	bool handleEvent(const LLSD& userdata)
 544	{
 545		LLAppViewer::instance()->userQuit();
 546		return true;
 547	}
 548};
 549
 550
 551void handle_compress_image(void*)
 552{
 553	LLFilePicker& picker = LLFilePicker::instance();
 554	if (picker.getMultipleOpenFiles(LLFilePicker::FFLOAD_IMAGE))
 555	{
 556		std::string infile = picker.getFirstFile();
 557		while (!infile.empty())
 558		{
 559			std::string outfile = infile + ".j2c";
 560
 561			llinfos << "Input:  " << infile << llendl;
 562			llinfos << "Output: " << outfile << llendl;
 563
 564			BOOL success;
 565
 566			success = LLViewerTextureList::createUploadFile(infile, outfile, IMG_CODEC_TGA);
 567
 568			if (success)
 569			{
 570				llinfos << "Compression complete" << llendl;
 571			}
 572			else
 573			{
 574				llinfos << "Compression failed: " << LLImage::getLastError() << llendl;
 575			}
 576
 577			infile = picker.getNextFile();
 578		}
 579	}
 580}
 581
 582LLUUID upload_new_resource(
 583	const std::string& src_filename,
 584	std::string name,
 585	std::string desc,
 586	S32 compression_info,
 587	LLFolderType::EType destination_folder_type,
 588	LLInventoryType::EType inv_type,
 589	U32 next_owner_perms,
 590	U32 group_perms,
 591	U32 everyone_perms,
 592	const std::string& display_name,
 593	LLAssetStorage::LLStoreAssetCallback callback,
 594	S32 expected_upload_cost,
 595	void *userdata)
 596{	
 597	// Generate the temporary UUID.
 598	std::string filename = gDirUtilp->getTempFilename();
 599	LLTransactionID tid;
 600	LLAssetID uuid;
 601	
 602	LLSD args;
 603
 604	std::string exten = gDirUtilp->getExtension(src_filename);
 605	U32 codec = LLImageBase::getCodecFromExtension(exten);
 606	LLAssetType::EType asset_type = LLAssetType::AT_NONE;
 607	std::string error_message;
 608
 609	BOOL error = FALSE;
 610	
 611	if (exten.empty())
 612	{
 613		std::string short_name = gDirUtilp->getBaseFileName(filename);
 614		
 615		// No extension
 616		error_message = llformat(
 617				"No file extension for the file: '%s'\nPlease make sure the file has a correct file extension",
 618				short_name.c_str());
 619		args["FILE"] = short_name;
 620 		upload_error(error_message, "NoFileExtension", filename, args);
 621		return LLUUID();
 622	}
 623	else if (codec != IMG_CODEC_INVALID)
 624	{
 625		// It's an image file, the upload procedure is the same for all
 626		asset_type = LLAssetType::AT_TEXTURE;
 627		if (!LLViewerTextureList::createUploadFile(src_filename, filename, codec ))
 628		{
 629			error_message = llformat( "Problem with file %s:\n\n%s\n",
 630									 src_filename.c_str(), LLImage::getLastError().c_str());
 631			args["FILE"] = src_filename;
 632			args["ERROR"] = LLImage::getLastError();
 633			upload_error(error_message, "ProblemWithFile", filename, args);
 634			return LLUUID();
 635		}
 636	}
 637	else if(exten == "wav")
 638	{
 639		asset_type = LLAssetType::AT_SOUND;  // tag it as audio
 640		S32 encode_result = 0;
 641
 642		llinfos << "Attempting to encode wav as an ogg file" << llendl;
 643
 644		encode_result = encode_vorbis_file(src_filename, filename);
 645		
 646		if (LLVORBISENC_NOERR != encode_result)
 647		{
 648			switch(encode_result)
 649			{
 650				case LLVORBISENC_DEST_OPEN_ERR:
 651				    error_message = llformat( "Couldn't open temporary compressed sound file for writing: %s\n", filename.c_str());
 652					args["FILE"] = filename;
 653					upload_error(error_message, "CannotOpenTemporarySoundFile", filename, args);
 654					break;
 655
 656				default:	
 657				  error_message = llformat("Unknown vorbis encode failure on: %s\n", src_filename.c_str());
 658					args["FILE"] = src_filename;
 659					upload_error(error_message, "UnknownVorbisEncodeFailure", filename, args);
 660					break;	
 661			}	
 662			return LLUUID();
 663		}
 664	}
 665	else if(exten == "tmp")	 	
 666	{	 	
 667		// This is a generic .lin resource file	 	
 668         asset_type = LLAssetType::AT_OBJECT;	 	
 669         LLFILE* in = LLFile::fopen(src_filename, "rb");		/* Flawfinder: ignore */	 	
 670         if (in)	 	
 671         {	 	
 672                 // read in the file header	 	
 673                 char buf[16384];		/* Flawfinder: ignore */ 	
 674                 size_t readbytes;
 675                 S32  version;	 	
 676                 if (fscanf(in, "LindenResource\nversion %d\n", &version))	 	
 677                 {	 	
 678                         if (2 == version)	 	
 679                         {
 680								// *NOTE: This buffer size is hard coded into scanf() below.
 681                                 char label[MAX_STRING];		/* Flawfinder: ignore */	 	
 682                                 char value[MAX_STRING];		/* Flawfinder: ignore */	 	
 683                                 S32  tokens_read;	 	
 684                                 while (fgets(buf, 1024, in))	 	
 685                                 {	 	
 686                                         label[0] = '\0';	 	
 687                                         value[0] = '\0';	 	
 688                                         tokens_read = sscanf(	/* Flawfinder: ignore */
 689											 buf,
 690											 "%254s %254s\n",
 691											 label, value);	 	
 692
 693                                         llinfos << "got: " << label << " = " << value	 	
 694                                                         << llendl;	 	
 695
 696                                         if (EOF == tokens_read)	 	
 697                                         {	 	
 698                                                 fclose(in);	 	
 699                                                 error_message = llformat("corrupt resource file: %s", src_filename.c_str());
 700												 args["FILE"] = src_filename;
 701												 upload_error(error_message, "CorruptResourceFile", filename, args);
 702                                                 return LLUUID();
 703                                         }	 	
 704
 705                                         if (2 == tokens_read)	 	
 706                                         {	 	
 707                                                 if (! strcmp("type", label))	 	
 708                                                 {	 	
 709                                                         asset_type = (LLAssetType::EType)(atoi(value));	 	
 710                                                 }	 	
 711                                         }	 	
 712                                         else	 	
 713                                         {	 	
 714                                                 if (! strcmp("_DATA_", label))	 	
 715                                                 {	 	
 716                                                         // below is the data section	 	
 717                                                         break;	 	
 718                                                 }	 	
 719                                         }	 	
 720                                         // other values are currently discarded	 	
 721                                 }	 	
 722
 723                         }	 	
 724                         else	 	
 725                         {	 	
 726                                 fclose(in);	 	
 727                                 error_message = llformat("unknown linden resource file version in file: %s", src_filename.c_str());
 728								 args["FILE"] = src_filename;
 729								 upload_error(error_message, "UnknownResourceFileVersion", filename, args);
 730                                 return LLUUID();
 731                         }	 	
 732                 }	 	
 733                 else	 	
 734                 {	 	
 735                         // this is an original binary formatted .lin file	 	
 736                         // start over at the beginning of the file	 	
 737                         fseek(in, 0, SEEK_SET);	 	
 738
 739                         const S32 MAX_ASSET_DESCRIPTION_LENGTH = 256;	 	
 740                         const S32 MAX_ASSET_NAME_LENGTH = 64;	 	
 741                         S32 header_size = 34 + MAX_ASSET_DESCRIPTION_LENGTH + MAX_ASSET_NAME_LENGTH;	 	
 742                         S16     type_num;	 	
 743
 744                         // read in and throw out most of the header except for the type	 	
 745                         if (fread(buf, header_size, 1, in) != 1)
 746						 {
 747							 llwarns << "Short read" << llendl;
 748						 }
 749                         memcpy(&type_num, buf + 16, sizeof(S16));		/* Flawfinder: ignore */	 	
 750                         asset_type = (LLAssetType::EType)type_num;	 	
 751                 }	 	
 752
 753                 // copy the file's data segment into another file for uploading	 	
 754                 LLFILE* out = LLFile::fopen(filename, "wb");		/* Flawfinder: ignore */	
 755                 if (out)	 	
 756                 {	 	
 757                         while((readbytes = fread(buf, 1, 16384, in)))		/* Flawfinder: ignore */	 	
 758                         {	 	
 759							 if (fwrite(buf, 1, readbytes, out) != readbytes)
 760							 {
 761								 llwarns << "Short write" << llendl;
 762							 }
 763                         }	 	
 764                         fclose(out);	 	
 765                 }	 	
 766                 else	 	
 767                 {	 	
 768                         fclose(in);	 	
 769                         error_message = llformat( "Unable to create output file: %s", filename.c_str());
 770						 args["FILE"] = filename;
 771						 upload_error(error_message, "UnableToCreateOutputFile", filename, args);
 772                         return LLUUID();
 773                 }	 	
 774
 775                 fclose(in);	 	
 776         }	 	
 777         else	 	
 778         {	 	
 779                 llinfos << "Couldn't open .lin file " << src_filename << llendl;	 	
 780         }	 	
 781	}
 782	else if (exten == "bvh")
 783	{
 784		error_message = llformat("We do not currently support bulk upload of animation files\n");
 785		upload_error(error_message, "DoNotSupportBulkAnimationUpload", filename, args);
 786		return LLUUID();
 787	}
 788	else
 789	{
 790		// Unknown extension
 791		error_message = llformat(LLTrans::getString("UnknownFileExtension").c_str(), exten.c_str());
 792		error = TRUE;;
 793	}
 794
 795	// gen a new transaction ID for this asset
 796	tid.generate();
 797
 798	if (!error)
 799	{
 800		uuid = tid.makeAssetID(gAgent.getSecureSessionID());
 801		// copy this file into the vfs for upload
 802		S32 file_size;
 803		LLAPRFile infile ;
 804		infile.open(filename, LL_APR_RB, NULL, &file_size);
 805		if (infile.getFileHandle())
 806		{
 807			LLVFile file(gVFS, uuid, asset_type, LLVFile::WRITE);
 808
 809			file.setMaxSize(file_size);
 810
 811			const S32 buf_size = 65536;
 812			U8 copy_buf[buf_size];
 813			while ((file_size = infile.read(copy_buf, buf_size)))
 814			{
 815				file.write(copy_buf, file_size);
 816			}
 817		}
 818		else
 819		{
 820			error_message = llformat( "Unable to access output file: %s", filename.c_str());
 821			error = TRUE;
 822		}
 823	}
 824
 825	if (!error)
 826	{
 827		std::string t_disp_name = display_name;
 828		if (t_disp_name.empty())
 829		{
 830			t_disp_name = src_filename;
 831		}
 832		upload_new_resource(
 833			tid,
 834			asset_type,
 835			name,
 836			desc,
 837			compression_info, // tid
 838			destination_folder_type,
 839			inv_type,
 840			next_owner_perms,
 841			group_perms,
 842			everyone_perms,
 843			display_name,
 844			callback,
 845			expected_upload_cost,
 846			userdata);
 847	}
 848	else
 849	{
 850		llwarns << error_message << llendl;
 851		LLSD args;
 852		args["ERROR_MESSAGE"] = error_message;
 853		LLNotificationsUtil::add("ErrorMessage", args);
 854		if(LLFile::remove(filename) == -1)
 855		{
 856			lldebugs << "unable to remove temp file" << llendl;
 857		}
 858		LLFilePicker::instance().reset();
 859	}
 860
 861	return uuid;
 862}
 863
 864void upload_done_callback(
 865	const LLUUID& uuid,
 866	void* user_data,
 867	S32 result,
 868	LLExtStat ext_status) // StoreAssetData callback (fixed)
 869{
 870	LLResourceData* data = (LLResourceData*)user_data;
 871	S32 expected_upload_cost = data ? data->mExpectedUploadCost : 0;
 872	//LLAssetType::EType pref_loc = data->mPreferredLocation;
 873	BOOL is_balance_sufficient = TRUE;
 874
 875	if(data)
 876	{
 877		if (result >= 0)
 878		{
 879			LLFolderType::EType dest_loc = (data->mPreferredLocation == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(data->mAssetInfo.mType) : data->mPreferredLocation;
 880			
 881			if (LLAssetType::AT_SOUND == data->mAssetInfo.mType ||
 882			    LLAssetType::AT_TEXTURE == data->mAssetInfo.mType ||
 883			    LLAssetType::AT_ANIMATION == data->mAssetInfo.mType)
 884			{
 885				// Charge the user for the upload.
 886				LLViewerRegion* region = gAgent.getRegion();
 887				
 888				if(!(can_afford_transaction(expected_upload_cost)))
 889				{
 890					LLStringUtil::format_map_t args;
 891					args["NAME"] = data->mAssetInfo.getName();
 892					args["AMOUNT"] = llformat("%d", expected_upload_cost);
 893					LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("UploadingCosts", args), expected_upload_cost );
 894					is_balance_sufficient = FALSE;
 895				}
 896				else if(region)
 897				{
 898					// Charge user for upload
 899					gStatusBar->debitBalance(expected_upload_cost);
 900					
 901					LLMessageSystem* msg = gMessageSystem;
 902					msg->newMessageFast(_PREHASH_MoneyTransferRequest);
 903					msg->nextBlockFast(_PREHASH_AgentData);
 904					msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
 905					msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
 906					msg->nextBlockFast(_PREHASH_MoneyData);
 907					msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID());
 908					msg->addUUIDFast(_PREHASH_DestID, LLUUID::null);
 909					msg->addU8("Flags", 0);
 910					// we tell the sim how much we were expecting to pay so it
 911					// can respond to any discrepancy
 912					msg->addS32Fast(_PREHASH_Amount, expected_upload_cost);
 913					msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY);
 914					msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY);
 915					msg->addS32Fast(_PREHASH_TransactionType, TRANS_UPLOAD_CHARGE);
 916					msg->addStringFast(_PREHASH_Description, NULL);
 917					msg->sendReliable(region->getHost());
 918				}
 919			}
 920
 921			if(is_balance_sufficient)
 922			{
 923				// Actually add the upload to inventory
 924				llinfos << "Adding " << uuid << " to inventory." << llendl;
 925				const LLUUID folder_id = gInventory.findCategoryUUIDForType(dest_loc);
 926				if(folder_id.notNull())
 927				{
 928					U32 next_owner_perms = data->mNextOwnerPerm;
 929					if(PERM_NONE == next_owner_perms)
 930					{
 931						next_owner_perms = PERM_MOVE | PERM_TRANSFER;
 932					}
 933					create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
 934							      folder_id, data->mAssetInfo.mTransactionID, data->mAssetInfo.getName(),
 935							      data->mAssetInfo.getDescription(), data->mAssetInfo.mType,
 936							      data->mInventoryType, NOT_WEARABLE, next_owner_perms,
 937							      LLPointer<LLInventoryCallback>(NULL));
 938				}
 939				else
 940				{
 941					llwarns << "Can't find a folder to put it in" << llendl;
 942				}
 943			}
 944		}
 945		else // 	if(result >= 0)
 946		{
 947			LLSD args;
 948			args["FILE"] = LLInventoryType::lookupHumanReadable(data->mInventoryType);
 949			args["REASON"] = std::string(LLAssetStorage::getErrorString(result));
 950			LLNotificationsUtil::add("CannotUploadReason", args);
 951		}
 952	}
 953
 954	LLUploadDialog::modalUploadFinished();
 955	delete data;
 956	data = NULL;
 957
 958	// *NOTE: This is a pretty big hack. What this does is check the
 959	// file picker if there are any more pending uploads. If so,
 960	// upload that file.
 961	const std::string& next_file = LLFilePicker::instance().getNextFile();
 962	if(is_balance_sufficient && !next_file.empty())
 963	{
 964		std::string asset_name = gDirUtilp->getBaseFileName(next_file, true);
 965		LLStringUtil::replaceNonstandardASCII( asset_name, '?' );
 966		LLStringUtil::replaceChar(asset_name, '|', '?');
 967		LLStringUtil::stripNonprintable(asset_name);
 968		LLStringUtil::trim(asset_name);
 969
 970		std::string display_name = LLStringUtil::null;
 971		LLAssetStorage::LLStoreAssetCallback callback = NULL;
 972		void *userdata = NULL;
 973		upload_new_resource(
 974			next_file,
 975			asset_name,
 976			asset_name,	// file
 977			0,
 978			LLFolderType::FT_NONE,
 979			LLInventoryType::IT_NONE,
 980			PERM_NONE,
 981			PERM_NONE,
 982			PERM_NONE,
 983			display_name,
 984			callback,
 985			expected_upload_cost, // assuming next in a group of uploads is of roughly the same type, i.e. same upload cost
 986			userdata);
 987	}
 988}
 989
 990static LLAssetID upload_new_resource_prep(
 991	const LLTransactionID& tid,
 992	LLAssetType::EType asset_type,
 993	LLInventoryType::EType& inventory_type,
 994	std::string& name,
 995	const std::string& display_name,
 996	std::string& description)
 997{
 998	LLAssetID uuid = generate_asset_id_for_new_upload(tid);
 999
1000	increase_new_upload_stats(asset_type);
1001
1002	assign_defaults_and_show_upload_message(
1003		asset_type,
1004		inventory_type,
1005		name,
1006		display_name,
1007		description);
1008
1009	return uuid;
1010}
1011
1012LLSD generate_new_resource_upload_capability_body(
1013	LLAssetType::EType asset_type,
1014	const std::string& name,
1015	const std::string& desc,
1016	LLFolderType::EType destination_folder_type,
1017	LLInventoryType::EType inv_type,
1018	U32 next_owner_perms,
1019	U32 group_perms,
1020	U32 everyone_perms)
1021{
1022	LLSD body;
1023
1024	body["folder_id"] = gInventory.findCategoryUUIDForType(
1025		(destination_folder_type == LLFolderType::FT_NONE) ?
1026		(LLFolderType::EType) asset_type :
1027		destination_folder_type);
1028
1029	body["asset_type"] = LLAssetType::lookup(asset_type);
1030	body["inventory_type"] = LLInventoryType::lookup(inv_type);
1031	body["name"] = name;
1032	body["description"] = desc;
1033	body["next_owner_mask"] = LLSD::Integer(next_owner_perms);
1034	body["group_mask"] = LLSD::Integer(group_perms);
1035	body["everyone_mask"] = LLSD::Integer(everyone_perms);
1036
1037	return body;
1038}
1039
1040void upload_new_resource(
1041	const LLTransactionID &tid,
1042	LLAssetType::EType asset_type,
1043	std::string name,
1044	std::string desc,
1045	S32 compression_info,
1046	LLFolderType::EType destination_folder_type,
1047	LLInventoryType::EType inv_type,
1048	U32 next_owner_perms,
1049	U32 group_perms,
1050	U32 everyone_perms,
1051	const std::string& display_name,
1052	LLAssetStorage::LLStoreAssetCallback callback,
1053	S32 expected_upload_cost,
1054	void *userdata)
1055{
1056	if(gDisconnected)
1057	{
1058		return ;
1059	}
1060	
1061	LLAssetID uuid = 
1062		upload_new_resource_prep(
1063			tid,
1064			asset_type,
1065			inv_type,
1066			name,
1067			display_name,
1068			desc);
1069	
1070	if( LLAssetType::AT_SOUND == asset_type )
1071	{
1072		LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_SOUND_COUNT );
1073	}
1074	else
1075	if( LLAssetType::AT_TEXTURE == asset_type )
1076	{
1077		LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_TEXTURE_COUNT );
1078	}
1079	else
1080	if( LLAssetType::AT_ANIMATION == asset_type)
1081	{
1082		LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_ANIM_COUNT );
1083	}
1084
1085	if(LLInventoryType::IT_NONE == inv_type)
1086	{
1087		inv_type = LLInventoryType::defaultForAssetType(asset_type);
1088	}
1089	LLStringUtil::stripNonprintable(name);
1090	LLStringUtil::stripNonprintable(desc);
1091	if(name.empty())
1092	{
1093		name = "(No Name)";
1094	}
1095	if(desc.empty())
1096	{
1097		desc = "(No Description)";
1098	}
1099	
1100	// At this point, we're ready for the upload.
1101	std::string upload_message = "Uploading...\n\n";
1102	upload_message.append(display_name);
1103	LLUploadDialog::modalUploadDialog(upload_message);
1104
1105	llinfos << "*** Uploading: " << llendl;
1106	llinfos << "Type: " << LLAssetType::lookup(asset_type) << llendl;
1107	llinfos << "UUID: " << uuid << llendl;
1108	llinfos << "Name: " << name << llendl;
1109	llinfos << "Desc: " << desc << llendl;
1110	llinfos << "Expected Upload Cost: " << expected_upload_cost << llendl;
1111	lldebugs << "Folder: " << gInventory.findCategoryUUIDForType((destination_folder_type == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(asset_type) : destination_folder_type) << llendl;
1112	lldebugs << "Asset Type: " << LLAssetType::lookup(asset_type) << llendl;
1113
1114	std::string url = gAgent.getRegion()->getCapability(
1115		"NewFileAgentInventory");
1116
1117	if ( !url.empty() )
1118	{
1119		llinfos << "New Agent Inventory via capability" << llendl;
1120
1121		LLSD body;
1122		body = generate_new_resource_upload_capability_body(
1123			asset_type,
1124			name,
1125			desc,
1126			destination_folder_type,
1127			inv_type,
1128			next_owner_perms,
1129			group_perms,
1130			everyone_perms);
1131
1132		LLHTTPClient::post(
1133			url,
1134			body,
1135			new LLNewAgentInventoryResponder(
1136				body,
1137				uuid,
1138				asset_type));
1139	}
1140	else
1141	{
1142		llinfos << "NewAgentInventory capability not found, new agent inventory via asset system." << llendl;
1143		// check for adequate funds
1144		// TODO: do this check on the sim
1145		if (LLAssetType::AT_SOUND == asset_type ||
1146			LLAssetType::AT_TEXTURE == asset_type ||
1147			LLAssetType::AT_ANIMATION == asset_type)
1148		{
1149			S32 balance = gStatusBar->getBalance();
1150			if (balance < expected_upload_cost)
1151			{
1152				// insufficient funds, bail on this upload
1153				LLStringUtil::format_map_t args;
1154				args["NAME"] = name;
1155				args["AMOUNT"] = llformat("%d", expected_upload_cost);
1156				LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("UploadingCosts", args), expected_upload_cost );
1157				return;
1158			}
1159		}
1160
1161		LLResourceData* data = new LLResourceData;
1162		data->mAssetInfo.mTransactionID = tid;
1163		data->mAssetInfo.mUuid = uuid;
1164		data->mAssetInfo.mType = asset_type;
1165		data->mAssetInfo.mCreatorID = gAgentID;
1166		data->mInventoryType = inv_type;
1167		data->mNextOwnerPerm = next_owner_perms;
1168		data->mExpectedUploadCost = expected_upload_cost;
1169		data->mUserData = userdata;
1170		data->mAssetInfo.setName(name);
1171		data->mAssetInfo.setDescription(desc);
1172		data->mPreferredLocation = destination_folder_type;
1173
1174		LLAssetStorage::LLStoreAssetCallback asset_callback = &upload_done_callback;
1175		if (callback)
1176		{
1177			asset_callback = callback;
1178		}
1179		gAssetStorage->storeAssetData(
1180			data->mAssetInfo.mTransactionID,
1181			data->mAssetInfo.mType,
1182			asset_callback,
1183			(void*)data,
1184			FALSE);
1185	}
1186}
1187
1188LLAssetID generate_asset_id_for_new_upload(const LLTransactionID& tid)
1189{
1190	if ( gDisconnected )
1191	{	
1192		LLAssetID rv;
1193
1194		rv.setNull();
1195		return rv;
1196	}
1197
1198	LLAssetID uuid = tid.makeAssetID(gAgent.getSecureSessionID());
1199
1200	return uuid;
1201}
1202
1203void increase_new_upload_stats(LLAssetType::EType asset_type)
1204{
1205	if ( LLAssetType::AT_SOUND == asset_type )
1206	{
1207		LLViewerStats::getInstance()->incStat(
1208			LLViewerStats::ST_UPLOAD_SOUND_COUNT );
1209	}
1210	else if ( LLAssetType::AT_TEXTURE == asset_type )
1211	{
1212		LLViewerStats::getInstance()->incStat(
1213			LLViewerStats::ST_UPLOAD_TEXTURE_COUNT );
1214	}
1215	else if ( LLAssetType::AT_ANIMATION == asset_type )
1216	{
1217		LLViewerStats::getInstance()->incStat(
1218			LLViewerStats::ST_UPLOAD_ANIM_COUNT );
1219	}
1220}
1221
1222void assign_defaults_and_show_upload_message(
1223	LLAssetType::EType asset_type,
1224	LLInventoryType::EType& inventory_type,
1225	std::string& name,
1226	const std::string& display_name,
1227	std::string& description)
1228{
1229	if ( LLInventoryType::IT_NONE == inventory_type )
1230	{
1231		inventory_type = LLInventoryType::defaultForAssetType(asset_type);
1232	}
1233	LLStringUtil::stripNonprintable(name);
1234	LLStringUtil::stripNonprintable(description);
1235
1236	if ( name.empty() )
1237	{
1238		name = "(No Name)";
1239	}
1240	if ( description.empty() )
1241	{
1242		description = "(No Description)";
1243	}
1244
1245	// At this point, we're ready for the upload.
1246	std::string upload_message = "Uploading...\n\n";
1247	upload_message.append(display_name);
1248	LLUploadDialog::modalUploadDialog(upload_message);
1249}
1250
1251
1252void init_menu_file()
1253{
1254	view_listener_t::addCommit(new LLFileUploadImage(), "File.UploadImage");
1255	view_listener_t::addCommit(new LLFileUploadSound(), "File.UploadSound");
1256	view_listener_t::addCommit(new LLFileUploadAnim(), "File.UploadAnim");
1257	view_listener_t::addCommit(new LLFileUploadModel(), "File.UploadModel");
1258	view_listener_t::addCommit(new LLFileUploadBulk(), "File.UploadBulk");
1259	view_listener_t::addCommit(new LLFileCloseWindow(), "File.CloseWindow");
1260	view_listener_t::addCommit(new LLFileCloseAllWindows(), "File.CloseAllWindows");
1261	view_listener_t::addEnable(new LLFileEnableCloseWindow(), "File.EnableCloseWindow");
1262	view_listener_t::addEnable(new LLFileEnableCloseAllWindows(), "File.EnableCloseAllWindows");
1263	view_listener_t::addCommit(new LLFileTakeSnapshotToDisk(), "File.TakeSnapshotToDisk");
1264	view_listener_t::addCommit(new LLFileQuit(), "File.Quit");
1265
1266	view_listener_t::addEnable(new LLFileEnableUpload(), "File.EnableUpload");
1267	view_listener_t::addEnable(new LLFileEnableUploadModel(), "File.EnableUploadModel");
1268	view_listener_t::addMenu(new LLMeshEnabled(), "File.MeshEnabled");
1269	view_listener_t::addMenu(new LLMeshUploadVisible(), "File.VisibleUploadModel");
1270
1271	// "File.SaveTexture" moved to llpanelmaininventory so that it can be properly handled.
1272}