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