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