PageRenderTime 64ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/llviewermessage.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 2181 lines | 1546 code | 231 blank | 404 comment | 190 complexity | 8f1f020fd1913110055cba2576d7da61 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llviewermessage.cpp
  3. * @brief Dumping ground for viewer-side message system callbacks.
  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 "llviewermessage.h"
  28. #include "boost/lexical_cast.hpp"
  29. // Linden libraries
  30. #include "llanimationstates.h"
  31. #include "llaudioengine.h"
  32. #include "llavataractions.h"
  33. #include "llavatarnamecache.h" // IDEVO HACK
  34. #include "lscript_byteformat.h"
  35. #include "lleconomy.h"
  36. #include "lleventtimer.h"
  37. #include "llfloaterreg.h"
  38. #include "llfolderview.h"
  39. #include "llfollowcamparams.h"
  40. #include "llinventorydefines.h"
  41. #include "lllslconstants.h"
  42. #include "llregionhandle.h"
  43. #include "llsdserialize.h"
  44. #include "llteleportflags.h"
  45. #include "lltransactionflags.h"
  46. #include "llvfile.h"
  47. #include "llvfs.h"
  48. #include "llxfermanager.h"
  49. #include "mean_collision_data.h"
  50. #include "llagent.h"
  51. #include "llagentcamera.h"
  52. #include "llcallingcard.h"
  53. #include "llbuycurrencyhtml.h"
  54. #include "llfirstuse.h"
  55. #include "llfloaterbuyland.h"
  56. #include "llfloaterland.h"
  57. #include "llfloaterregioninfo.h"
  58. #include "llfloaterlandholdings.h"
  59. #include "llfloaterpreference.h"
  60. #include "llfloatersidepanelcontainer.h"
  61. #include "llfloatersnapshot.h"
  62. #include "llhudeffecttrail.h"
  63. #include "llhudmanager.h"
  64. #include "llinventoryfunctions.h"
  65. #include "llinventoryobserver.h"
  66. #include "llinventorypanel.h"
  67. #include "llnearbychat.h"
  68. #include "llnotifications.h"
  69. #include "llnotificationsutil.h"
  70. #include "llpanelgrouplandmoney.h"
  71. #include "llrecentpeople.h"
  72. #include "llscriptfloater.h"
  73. #include "llselectmgr.h"
  74. #include "llstartup.h"
  75. #include "llsky.h"
  76. #include "llslurl.h"
  77. #include "llstatenums.h"
  78. #include "llstatusbar.h"
  79. #include "llimview.h"
  80. #include "llspeakers.h"
  81. #include "lltrans.h"
  82. #include "lltranslate.h"
  83. #include "llviewerfoldertype.h"
  84. #include "llvoavatar.h" // IDEVO HACK
  85. #include "lluri.h"
  86. #include "llviewergenericmessage.h"
  87. #include "llviewermenu.h"
  88. #include "llviewerinventory.h"
  89. #include "llviewerjoystick.h"
  90. #include "llviewerobjectlist.h"
  91. #include "llviewerparcelmgr.h"
  92. #include "llviewerstats.h"
  93. #include "llviewertexteditor.h"
  94. #include "llviewerthrottle.h"
  95. #include "llviewerwindow.h"
  96. #include "llvlmanager.h"
  97. #include "llvoavatarself.h"
  98. #include "llworld.h"
  99. #include "pipeline.h"
  100. #include "llfloaterworldmap.h"
  101. #include "llviewerdisplay.h"
  102. #include "llkeythrottle.h"
  103. #include "llgroupactions.h"
  104. #include "llagentui.h"
  105. #include "llpanelblockedlist.h"
  106. #include "llpanelplaceprofile.h"
  107. #include <boost/algorithm/string/split.hpp> //
  108. #include <boost/regex.hpp>
  109. #include "llnotificationmanager.h" //
  110. #if LL_MSVC
  111. // disable boost::lexical_cast warning
  112. #pragma warning (disable:4702)
  113. #endif
  114. //
  115. // Constants
  116. //
  117. const F32 BIRD_AUDIBLE_RADIUS = 32.0f;
  118. const F32 SIT_DISTANCE_FROM_TARGET = 0.25f;
  119. const F32 CAMERA_POSITION_THRESHOLD_SQUARED = 0.001f * 0.001f;
  120. static const F32 LOGOUT_REPLY_TIME = 3.f; // Wait this long after LogoutReply before quitting.
  121. // Determine how quickly residents' scripts can issue question dialogs
  122. // Allow bursts of up to 5 dialogs in 10 seconds. 10*2=20 seconds recovery if throttle kicks in
  123. static const U32 LLREQUEST_PERMISSION_THROTTLE_LIMIT = 5; // requests
  124. static const F32 LLREQUEST_PERMISSION_THROTTLE_INTERVAL = 10.0f; // seconds
  125. extern BOOL gDebugClicks;
  126. // function prototypes
  127. bool check_offer_throttle(const std::string& from_name, bool check_only);
  128. static void process_money_balance_reply_extended(LLMessageSystem* msg);
  129. //inventory offer throttle globals
  130. LLFrameTimer gThrottleTimer;
  131. const U32 OFFER_THROTTLE_MAX_COUNT=5; //number of items per time period
  132. const F32 OFFER_THROTTLE_TIME=10.f; //time period in seconds
  133. //script permissions
  134. const std::string SCRIPT_QUESTIONS[SCRIPT_PERMISSION_EOF] =
  135. {
  136. "ScriptTakeMoney",
  137. "ActOnControlInputs",
  138. "RemapControlInputs",
  139. "AnimateYourAvatar",
  140. "AttachToYourAvatar",
  141. "ReleaseOwnership",
  142. "LinkAndDelink",
  143. "AddAndRemoveJoints",
  144. "ChangePermissions",
  145. "TrackYourCamera",
  146. "ControlYourCamera"
  147. };
  148. const BOOL SCRIPT_QUESTION_IS_CAUTION[SCRIPT_PERMISSION_EOF] =
  149. {
  150. TRUE, // ScriptTakeMoney,
  151. FALSE, // ActOnControlInputs
  152. FALSE, // RemapControlInputs
  153. FALSE, // AnimateYourAvatar
  154. FALSE, // AttachToYourAvatar
  155. FALSE, // ReleaseOwnership,
  156. FALSE, // LinkAndDelink,
  157. FALSE, // AddAndRemoveJoints
  158. FALSE, // ChangePermissions
  159. FALSE, // TrackYourCamera,
  160. FALSE // ControlYourCamera
  161. };
  162. bool friendship_offer_callback(const LLSD& notification, const LLSD& response)
  163. {
  164. S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
  165. LLMessageSystem* msg = gMessageSystem;
  166. const LLSD& payload = notification["payload"];
  167. // add friend to recent people list
  168. LLRecentPeople::instance().add(payload["from_id"]);
  169. switch(option)
  170. {
  171. case 0:
  172. {
  173. // accept
  174. LLAvatarTracker::formFriendship(payload["from_id"]);
  175. const LLUUID fid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD);
  176. // This will also trigger an onlinenotification if the user is online
  177. msg->newMessageFast(_PREHASH_AcceptFriendship);
  178. msg->nextBlockFast(_PREHASH_AgentData);
  179. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  180. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  181. msg->nextBlockFast(_PREHASH_TransactionBlock);
  182. msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]);
  183. msg->nextBlockFast(_PREHASH_FolderData);
  184. msg->addUUIDFast(_PREHASH_FolderID, fid);
  185. msg->sendReliable(LLHost(payload["sender"].asString()));
  186. LLSD payload = notification["payload"];
  187. payload["SUPPRESS_TOAST"] = true;
  188. LLNotificationsUtil::add("FriendshipAcceptedByMe",
  189. notification["substitutions"], payload);
  190. break;
  191. }
  192. case 1: // Decline
  193. {
  194. LLSD payload = notification["payload"];
  195. payload["SUPPRESS_TOAST"] = true;
  196. LLNotificationsUtil::add("FriendshipDeclinedByMe",
  197. notification["substitutions"], payload);
  198. }
  199. // fall-through
  200. case 2: // Send IM - decline and start IM session
  201. {
  202. // decline
  203. // We no longer notify other viewers, but we DO still send
  204. // the rejection to the simulator to delete the pending userop.
  205. msg->newMessageFast(_PREHASH_DeclineFriendship);
  206. msg->nextBlockFast(_PREHASH_AgentData);
  207. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  208. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  209. msg->nextBlockFast(_PREHASH_TransactionBlock);
  210. msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]);
  211. msg->sendReliable(LLHost(payload["sender"].asString()));
  212. // start IM session
  213. if(2 == option)
  214. {
  215. LLAvatarActions::startIM(payload["from_id"].asUUID());
  216. }
  217. }
  218. default:
  219. // close button probably, possibly timed out
  220. break;
  221. }
  222. return false;
  223. }
  224. static LLNotificationFunctorRegistration friendship_offer_callback_reg("OfferFriendship", friendship_offer_callback);
  225. static LLNotificationFunctorRegistration friendship_offer_callback_reg_nm("OfferFriendshipNoMessage", friendship_offer_callback);
  226. //const char BUSY_AUTO_RESPONSE[] = "The Resident you messaged is in 'busy mode' which means they have "
  227. // "requested not to be disturbed. Your message will still be shown in their IM "
  228. // "panel for later viewing.";
  229. //
  230. // Functions
  231. //
  232. void give_money(const LLUUID& uuid, LLViewerRegion* region, S32 amount, BOOL is_group,
  233. S32 trx_type, const std::string& desc)
  234. {
  235. if(0 == amount || !region) return;
  236. amount = abs(amount);
  237. LL_INFOS("Messaging") << "give_money(" << uuid << "," << amount << ")"<< LL_ENDL;
  238. if(can_afford_transaction(amount))
  239. {
  240. // gStatusBar->debitBalance(amount);
  241. LLMessageSystem* msg = gMessageSystem;
  242. msg->newMessageFast(_PREHASH_MoneyTransferRequest);
  243. msg->nextBlockFast(_PREHASH_AgentData);
  244. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  245. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  246. msg->nextBlockFast(_PREHASH_MoneyData);
  247. msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID() );
  248. msg->addUUIDFast(_PREHASH_DestID, uuid);
  249. msg->addU8Fast(_PREHASH_Flags, pack_transaction_flags(FALSE, is_group));
  250. msg->addS32Fast(_PREHASH_Amount, amount);
  251. msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY);
  252. msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY);
  253. msg->addS32Fast(_PREHASH_TransactionType, trx_type );
  254. msg->addStringFast(_PREHASH_Description, desc);
  255. msg->sendReliable(region->getHost());
  256. }
  257. else
  258. {
  259. LLStringUtil::format_map_t args;
  260. args["AMOUNT"] = llformat("%d", amount);
  261. LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("giving", args), amount );
  262. }
  263. }
  264. void send_complete_agent_movement(const LLHost& sim_host)
  265. {
  266. LLMessageSystem* msg = gMessageSystem;
  267. msg->newMessageFast(_PREHASH_CompleteAgentMovement);
  268. msg->nextBlockFast(_PREHASH_AgentData);
  269. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  270. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  271. msg->addU32Fast(_PREHASH_CircuitCode, msg->mOurCircuitCode);
  272. msg->sendReliable(sim_host);
  273. }
  274. void process_logout_reply(LLMessageSystem* msg, void**)
  275. {
  276. // The server has told us it's ok to quit.
  277. LL_DEBUGS("Messaging") << "process_logout_reply" << LL_ENDL;
  278. LLUUID agent_id;
  279. msg->getUUID("AgentData", "AgentID", agent_id);
  280. LLUUID session_id;
  281. msg->getUUID("AgentData", "SessionID", session_id);
  282. if((agent_id != gAgent.getID()) || (session_id != gAgent.getSessionID()))
  283. {
  284. LL_WARNS("Messaging") << "Bogus Logout Reply" << LL_ENDL;
  285. }
  286. LLInventoryModel::update_map_t parents;
  287. S32 count = msg->getNumberOfBlocksFast( _PREHASH_InventoryData );
  288. for(S32 i = 0; i < count; ++i)
  289. {
  290. LLUUID item_id;
  291. msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id, i);
  292. if( (1 == count) && item_id.isNull() )
  293. {
  294. // Detect dummy item. Indicates an empty list.
  295. break;
  296. }
  297. // We do not need to track the asset ids, just account for an
  298. // updated inventory version.
  299. LL_INFOS("Messaging") << "process_logout_reply itemID=" << item_id << LL_ENDL;
  300. LLInventoryItem* item = gInventory.getItem( item_id );
  301. if( item )
  302. {
  303. parents[item->getParentUUID()] = 0;
  304. gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item_id);
  305. }
  306. else
  307. {
  308. LL_INFOS("Messaging") << "process_logout_reply item not found: " << item_id << LL_ENDL;
  309. }
  310. }
  311. LLAppViewer::instance()->forceQuit();
  312. }
  313. void process_layer_data(LLMessageSystem *mesgsys, void **user_data)
  314. {
  315. LLViewerRegion *regionp = LLWorld::getInstance()->getRegion(mesgsys->getSender());
  316. if(!regionp)
  317. {
  318. llwarns << "Invalid region for layer data." << llendl;
  319. return;
  320. }
  321. S32 size;
  322. S8 type;
  323. mesgsys->getS8Fast(_PREHASH_LayerID, _PREHASH_Type, type);
  324. size = mesgsys->getSizeFast(_PREHASH_LayerData, _PREHASH_Data);
  325. if (0 == size)
  326. {
  327. LL_WARNS("Messaging") << "Layer data has zero size." << LL_ENDL;
  328. return;
  329. }
  330. if (size < 0)
  331. {
  332. // getSizeFast() is probably trying to tell us about an error
  333. LL_WARNS("Messaging") << "getSizeFast() returned negative result: "
  334. << size
  335. << LL_ENDL;
  336. return;
  337. }
  338. U8 *datap = new U8[size];
  339. mesgsys->getBinaryDataFast(_PREHASH_LayerData, _PREHASH_Data, datap, size);
  340. LLVLData *vl_datap = new LLVLData(regionp, type, datap, size);
  341. if (mesgsys->getReceiveCompressedSize())
  342. {
  343. gVLManager.addLayerData(vl_datap, mesgsys->getReceiveCompressedSize());
  344. }
  345. else
  346. {
  347. gVLManager.addLayerData(vl_datap, mesgsys->getReceiveSize());
  348. }
  349. }
  350. // S32 exported_object_count = 0;
  351. // S32 exported_image_count = 0;
  352. // S32 current_object_count = 0;
  353. // S32 current_image_count = 0;
  354. // extern LLNotifyBox *gExporterNotify;
  355. // extern LLUUID gExporterRequestID;
  356. // extern std::string gExportDirectory;
  357. // extern LLUploadDialog *gExportDialog;
  358. // std::string gExportedFile;
  359. // std::map<LLUUID, std::string> gImageChecksums;
  360. // void export_complete()
  361. // {
  362. // LLUploadDialog::modalUploadFinished();
  363. // gExporterRequestID.setNull();
  364. // gExportDirectory = "";
  365. // LLFILE* fXML = LLFile::fopen(gExportedFile, "rb"); /* Flawfinder: ignore */
  366. // fseek(fXML, 0, SEEK_END);
  367. // long length = ftell(fXML);
  368. // fseek(fXML, 0, SEEK_SET);
  369. // U8 *buffer = new U8[length + 1];
  370. // size_t nread = fread(buffer, 1, length, fXML);
  371. // if (nread < (size_t) length)
  372. // {
  373. // LL_WARNS("Messaging") << "Short read" << LL_ENDL;
  374. // }
  375. // buffer[nread] = '\0';
  376. // fclose(fXML);
  377. // char *pos = (char *)buffer;
  378. // while ((pos = strstr(pos+1, "<sl:image ")) != 0)
  379. // {
  380. // char *pos_check = strstr(pos, "checksum=\"");
  381. // if (pos_check)
  382. // {
  383. // char *pos_uuid = strstr(pos_check, "\">");
  384. // if (pos_uuid)
  385. // {
  386. // char image_uuid_str[UUID_STR_SIZE]; /* Flawfinder: ignore */
  387. // memcpy(image_uuid_str, pos_uuid+2, UUID_STR_SIZE-1); /* Flawfinder: ignore */
  388. // image_uuid_str[UUID_STR_SIZE-1] = 0;
  389. // LLUUID image_uuid(image_uuid_str);
  390. // LL_INFOS("Messaging") << "Found UUID: " << image_uuid << LL_ENDL;
  391. // std::map<LLUUID, std::string>::iterator itor = gImageChecksums.find(image_uuid);
  392. // if (itor != gImageChecksums.end())
  393. // {
  394. // LL_INFOS("Messaging") << "Replacing with checksum: " << itor->second << LL_ENDL;
  395. // if (!itor->second.empty())
  396. // {
  397. // memcpy(&pos_check[10], itor->second.c_str(), 32); /* Flawfinder: ignore */
  398. // }
  399. // }
  400. // }
  401. // }
  402. // }
  403. // LLFILE* fXMLOut = LLFile::fopen(gExportedFile, "wb"); /* Flawfinder: ignore */
  404. // if (fwrite(buffer, 1, length, fXMLOut) != length)
  405. // {
  406. // LL_WARNS("Messaging") << "Short write" << LL_ENDL;
  407. // }
  408. // fclose(fXMLOut);
  409. // delete [] buffer;
  410. // }
  411. // void exported_item_complete(const LLTSCode status, void *user_data)
  412. // {
  413. // //std::string *filename = (std::string *)user_data;
  414. // if (status < LLTS_OK)
  415. // {
  416. // LL_WARNS("Messaging") << "Export failed!" << LL_ENDL;
  417. // }
  418. // else
  419. // {
  420. // ++current_object_count;
  421. // if (current_image_count == exported_image_count && current_object_count == exported_object_count)
  422. // {
  423. // LL_INFOS("Messaging") << "*** Export complete ***" << LL_ENDL;
  424. // export_complete();
  425. // }
  426. // else
  427. // {
  428. // gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count));
  429. // }
  430. // }
  431. // }
  432. // struct exported_image_info
  433. // {
  434. // LLUUID image_id;
  435. // std::string filename;
  436. // U32 image_num;
  437. // };
  438. // void exported_j2c_complete(const LLTSCode status, void *user_data)
  439. // {
  440. // exported_image_info *info = (exported_image_info *)user_data;
  441. // LLUUID image_id = info->image_id;
  442. // U32 image_num = info->image_num;
  443. // std::string filename = info->filename;
  444. // delete info;
  445. // if (status < LLTS_OK)
  446. // {
  447. // LL_WARNS("Messaging") << "Image download failed!" << LL_ENDL;
  448. // }
  449. // else
  450. // {
  451. // LLFILE* fIn = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */
  452. // if (fIn)
  453. // {
  454. // LLPointer<LLImageJ2C> ImageUtility = new LLImageJ2C;
  455. // LLPointer<LLImageTGA> TargaUtility = new LLImageTGA;
  456. // fseek(fIn, 0, SEEK_END);
  457. // S32 length = ftell(fIn);
  458. // fseek(fIn, 0, SEEK_SET);
  459. // U8 *buffer = ImageUtility->allocateData(length);
  460. // if (fread(buffer, 1, length, fIn) != length)
  461. // {
  462. // LL_WARNS("Messaging") << "Short read" << LL_ENDL;
  463. // }
  464. // fclose(fIn);
  465. // LLFile::remove(filename);
  466. // // Convert to TGA
  467. // LLPointer<LLImageRaw> image = new LLImageRaw();
  468. // ImageUtility->updateData();
  469. // ImageUtility->decode(image, 100000.0f);
  470. // TargaUtility->encode(image);
  471. // U8 *data = TargaUtility->getData();
  472. // S32 data_size = TargaUtility->getDataSize();
  473. // std::string file_path = gDirUtilp->getDirName(filename);
  474. // std::string output_file = llformat("%s/image-%03d.tga", file_path.c_str(), image_num);//filename;
  475. // //S32 name_len = output_file.length();
  476. // //strcpy(&output_file[name_len-3], "tga");
  477. // LLFILE* fOut = LLFile::fopen(output_file, "wb"); /* Flawfinder: ignore */
  478. // char md5_hash_string[33]; /* Flawfinder: ignore */
  479. // strcpy(md5_hash_string, "00000000000000000000000000000000"); /* Flawfinder: ignore */
  480. // if (fOut)
  481. // {
  482. // if (fwrite(data, 1, data_size, fOut) != data_size)
  483. // {
  484. // LL_WARNS("Messaging") << "Short write" << LL_ENDL;
  485. // }
  486. // fseek(fOut, 0, SEEK_SET);
  487. // fclose(fOut);
  488. // fOut = LLFile::fopen(output_file, "rb"); /* Flawfinder: ignore */
  489. // LLMD5 my_md5_hash(fOut);
  490. // my_md5_hash.hex_digest(md5_hash_string);
  491. // }
  492. // gImageChecksums.insert(std::pair<LLUUID, std::string>(image_id, md5_hash_string));
  493. // }
  494. // }
  495. // ++current_image_count;
  496. // if (current_image_count == exported_image_count && current_object_count == exported_object_count)
  497. // {
  498. // LL_INFOS("Messaging") << "*** Export textures complete ***" << LL_ENDL;
  499. // export_complete();
  500. // }
  501. // else
  502. // {
  503. // gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count));
  504. // }
  505. //}
  506. void process_derez_ack(LLMessageSystem*, void**)
  507. {
  508. if(gViewerWindow) gViewerWindow->getWindow()->decBusyCount();
  509. }
  510. void process_places_reply(LLMessageSystem* msg, void** data)
  511. {
  512. LLUUID query_id;
  513. msg->getUUID("AgentData", "QueryID", query_id);
  514. if (query_id.isNull())
  515. {
  516. LLFloaterLandHoldings::processPlacesReply(msg, data);
  517. }
  518. else if(gAgent.isInGroup(query_id))
  519. {
  520. LLPanelGroupLandMoney::processPlacesReply(msg, data);
  521. }
  522. else
  523. {
  524. LL_WARNS("Messaging") << "Got invalid PlacesReply message" << LL_ENDL;
  525. }
  526. }
  527. void send_sound_trigger(const LLUUID& sound_id, F32 gain)
  528. {
  529. if (sound_id.isNull() || gAgent.getRegion() == NULL)
  530. {
  531. // disconnected agent or zero guids don't get sent (no sound)
  532. return;
  533. }
  534. LLMessageSystem* msg = gMessageSystem;
  535. msg->newMessageFast(_PREHASH_SoundTrigger);
  536. msg->nextBlockFast(_PREHASH_SoundData);
  537. msg->addUUIDFast(_PREHASH_SoundID, sound_id);
  538. // Client untrusted, ids set on sim
  539. msg->addUUIDFast(_PREHASH_OwnerID, LLUUID::null );
  540. msg->addUUIDFast(_PREHASH_ObjectID, LLUUID::null );
  541. msg->addUUIDFast(_PREHASH_ParentID, LLUUID::null );
  542. msg->addU64Fast(_PREHASH_Handle, gAgent.getRegion()->getHandle());
  543. LLVector3 position = gAgent.getPositionAgent();
  544. msg->addVector3Fast(_PREHASH_Position, position);
  545. msg->addF32Fast(_PREHASH_Gain, gain);
  546. gAgent.sendMessage();
  547. }
  548. bool join_group_response(const LLSD& notification, const LLSD& response)
  549. {
  550. S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
  551. BOOL delete_context_data = TRUE;
  552. bool accept_invite = false;
  553. LLUUID group_id = notification["payload"]["group_id"].asUUID();
  554. LLUUID transaction_id = notification["payload"]["transaction_id"].asUUID();
  555. std::string name = notification["payload"]["name"].asString();
  556. std::string message = notification["payload"]["message"].asString();
  557. S32 fee = notification["payload"]["fee"].asInteger();
  558. if (option == 2 && !group_id.isNull())
  559. {
  560. LLGroupActions::show(group_id);
  561. LLSD args;
  562. args["MESSAGE"] = message;
  563. LLNotificationsUtil::add("JoinGroup", args, notification["payload"]);
  564. return false;
  565. }
  566. if(option == 0 && !group_id.isNull())
  567. {
  568. // check for promotion or demotion.
  569. S32 max_groups = gMaxAgentGroups;
  570. if(gAgent.isInGroup(group_id)) ++max_groups;
  571. if(gAgent.mGroups.count() < max_groups)
  572. {
  573. accept_invite = true;
  574. }
  575. else
  576. {
  577. delete_context_data = FALSE;
  578. LLSD args;
  579. args["NAME"] = name;
  580. LLNotificationsUtil::add("JoinedTooManyGroupsMember", args, notification["payload"]);
  581. }
  582. }
  583. if (accept_invite)
  584. {
  585. // If there is a fee to join this group, make
  586. // sure the user is sure they want to join.
  587. if (fee > 0)
  588. {
  589. delete_context_data = FALSE;
  590. LLSD args;
  591. args["COST"] = llformat("%d", fee);
  592. // Set the fee for next time to 0, so that we don't keep
  593. // asking about a fee.
  594. LLSD next_payload = notification["payload"];
  595. next_payload["fee"] = 0;
  596. LLNotificationsUtil::add("JoinGroupCanAfford",
  597. args,
  598. next_payload);
  599. }
  600. else
  601. {
  602. send_improved_im(group_id,
  603. std::string("name"),
  604. std::string("message"),
  605. IM_ONLINE,
  606. IM_GROUP_INVITATION_ACCEPT,
  607. transaction_id);
  608. }
  609. }
  610. else
  611. {
  612. send_improved_im(group_id,
  613. std::string("name"),
  614. std::string("message"),
  615. IM_ONLINE,
  616. IM_GROUP_INVITATION_DECLINE,
  617. transaction_id);
  618. }
  619. return false;
  620. }
  621. static void highlight_inventory_objects_in_panel(const std::vector<LLUUID>& items, LLInventoryPanel *inventory_panel)
  622. {
  623. if (NULL == inventory_panel) return;
  624. for (std::vector<LLUUID>::const_iterator item_iter = items.begin();
  625. item_iter != items.end();
  626. ++item_iter)
  627. {
  628. const LLUUID& item_id = (*item_iter);
  629. if(!highlight_offered_object(item_id))
  630. {
  631. continue;
  632. }
  633. LLInventoryObject* item = gInventory.getObject(item_id);
  634. llassert(item);
  635. if (!item) {
  636. continue;
  637. }
  638. LL_DEBUGS("Inventory_Move") << "Highlighting inventory item: " << item->getName() << ", " << item_id << LL_ENDL;
  639. LLFolderView* fv = inventory_panel->getRootFolder();
  640. if (fv)
  641. {
  642. LLFolderViewItem* fv_item = fv->getItemByID(item_id);
  643. if (fv_item)
  644. {
  645. LLFolderViewItem* fv_folder = fv_item->getParentFolder();
  646. if (fv_folder)
  647. {
  648. // Parent folders can be different in case of 2 consecutive drag and drop
  649. // operations when the second one is started before the first one completes.
  650. LL_DEBUGS("Inventory_Move") << "Open folder: " << fv_folder->getName() << LL_ENDL;
  651. fv_folder->setOpen(TRUE);
  652. if (fv_folder->isSelected())
  653. {
  654. fv->changeSelection(fv_folder, FALSE);
  655. }
  656. }
  657. fv->changeSelection(fv_item, TRUE);
  658. }
  659. }
  660. }
  661. }
  662. static LLNotificationFunctorRegistration jgr_1("JoinGroup", join_group_response);
  663. static LLNotificationFunctorRegistration jgr_2("JoinedTooManyGroupsMember", join_group_response);
  664. static LLNotificationFunctorRegistration jgr_3("JoinGroupCanAfford", join_group_response);
  665. //-----------------------------------------------------------------------------
  666. // Instant Message
  667. //-----------------------------------------------------------------------------
  668. class LLOpenAgentOffer : public LLInventoryFetchItemsObserver
  669. {
  670. public:
  671. LLOpenAgentOffer(const LLUUID& object_id,
  672. const std::string& from_name) :
  673. LLInventoryFetchItemsObserver(object_id),
  674. mFromName(from_name) {}
  675. /*virtual*/ void startFetch()
  676. {
  677. for (uuid_vec_t::const_iterator it = mIDs.begin(); it < mIDs.end(); ++it)
  678. {
  679. LLViewerInventoryCategory* cat = gInventory.getCategory(*it);
  680. if (cat)
  681. {
  682. mComplete.push_back((*it));
  683. }
  684. }
  685. LLInventoryFetchItemsObserver::startFetch();
  686. }
  687. /*virtual*/ void done()
  688. {
  689. open_inventory_offer(mComplete, mFromName);
  690. gInventory.removeObserver(this);
  691. delete this;
  692. }
  693. private:
  694. std::string mFromName;
  695. };
  696. /**
  697. * Class to observe adding of new items moved from the world to user's inventory to select them in inventory.
  698. *
  699. * We can't create it each time items are moved because "drop" event is sent separately for each
  700. * element even while multi-dragging. We have to have the only instance of the observer. See EXT-4347.
  701. */
  702. class LLViewerInventoryMoveFromWorldObserver : public LLInventoryAddItemByAssetObserver
  703. {
  704. public:
  705. LLViewerInventoryMoveFromWorldObserver()
  706. : LLInventoryAddItemByAssetObserver()
  707. {
  708. }
  709. void setMoveIntoFolderID(const LLUUID& into_folder_uuid) {mMoveIntoFolderID = into_folder_uuid; }
  710. private:
  711. /*virtual */void onAssetAdded(const LLUUID& asset_id)
  712. {
  713. // Store active Inventory panel.
  714. if (LLInventoryPanel::getActiveInventoryPanel())
  715. {
  716. mActivePanel = LLInventoryPanel::getActiveInventoryPanel()->getHandle();
  717. }
  718. // Store selected items (without destination folder)
  719. mSelectedItems.clear();
  720. if (LLInventoryPanel::getActiveInventoryPanel())
  721. {
  722. mSelectedItems = LLInventoryPanel::getActiveInventoryPanel()->getRootFolder()->getSelectionList();
  723. }
  724. mSelectedItems.erase(mMoveIntoFolderID);
  725. }
  726. /**
  727. * Selects added inventory items watched by their Asset UUIDs if selection was not changed since
  728. * all items were started to watch (dropped into a folder).
  729. */
  730. void done()
  731. {
  732. LLInventoryPanel* active_panel = dynamic_cast<LLInventoryPanel*>(mActivePanel.get());
  733. // if selection is not changed since watch started lets hightlight new items.
  734. if (active_panel && !isSelectionChanged())
  735. {
  736. LL_DEBUGS("Inventory_Move") << "Selecting new items..." << LL_ENDL;
  737. active_panel->clearSelection();
  738. highlight_inventory_objects_in_panel(mAddedItems, active_panel);
  739. }
  740. }
  741. /**
  742. * Returns true if selected inventory items were changed since moved inventory items were started to watch.
  743. */
  744. bool isSelectionChanged()
  745. {
  746. LLInventoryPanel* active_panel = dynamic_cast<LLInventoryPanel*>(mActivePanel.get());
  747. if (NULL == active_panel)
  748. {
  749. return true;
  750. }
  751. // get selected items (without destination folder)
  752. selected_items_t selected_items = active_panel->getRootFolder()->getSelectionList();
  753. selected_items.erase(mMoveIntoFolderID);
  754. // compare stored & current sets of selected items
  755. selected_items_t different_items;
  756. std::set_symmetric_difference(mSelectedItems.begin(), mSelectedItems.end(),
  757. selected_items.begin(), selected_items.end(), std::inserter(different_items, different_items.begin()));
  758. LL_DEBUGS("Inventory_Move") << "Selected firstly: " << mSelectedItems.size()
  759. << ", now: " << selected_items.size() << ", difference: " << different_items.size() << LL_ENDL;
  760. return different_items.size() > 0;
  761. }
  762. LLHandle<LLPanel> mActivePanel;
  763. typedef std::set<LLUUID> selected_items_t;
  764. selected_items_t mSelectedItems;
  765. /**
  766. * UUID of FolderViewFolder into which watched items are moved.
  767. *
  768. * Destination FolderViewFolder becomes selected while mouse hovering (when dragged items are dropped).
  769. *
  770. * If mouse is moved out it set unselected and number of selected items is changed
  771. * even if selected items in Inventory stay the same.
  772. * So, it is used to update stored selection list.
  773. *
  774. * @see onAssetAdded()
  775. * @see isSelectionChanged()
  776. */
  777. LLUUID mMoveIntoFolderID;
  778. };
  779. LLViewerInventoryMoveFromWorldObserver* gInventoryMoveObserver = NULL;
  780. void set_dad_inventory_item(LLInventoryItem* inv_item, const LLUUID& into_folder_uuid)
  781. {
  782. start_new_inventory_observer();
  783. gInventoryMoveObserver->setMoveIntoFolderID(into_folder_uuid);
  784. gInventoryMoveObserver->watchAsset(inv_item->getAssetUUID());
  785. }
  786. /**
  787. * Class to observe moving of items and to select them in inventory.
  788. *
  789. * Used currently for dragging from inbox to regular inventory folders
  790. */
  791. class LLViewerInventoryMoveObserver : public LLInventoryObserver
  792. {
  793. public:
  794. LLViewerInventoryMoveObserver(const LLUUID& object_id)
  795. : LLInventoryObserver()
  796. , mObjectID(object_id)
  797. {
  798. if (LLInventoryPanel::getActiveInventoryPanel())
  799. {
  800. mActivePanel = LLInventoryPanel::getActiveInventoryPanel()->getHandle();
  801. }
  802. }
  803. virtual ~LLViewerInventoryMoveObserver() {}
  804. virtual void changed(U32 mask);
  805. private:
  806. LLUUID mObjectID;
  807. LLHandle<LLPanel> mActivePanel;
  808. };
  809. void LLViewerInventoryMoveObserver::changed(U32 mask)
  810. {
  811. LLInventoryPanel* active_panel = dynamic_cast<LLInventoryPanel*>(mActivePanel.get());
  812. if (NULL == active_panel)
  813. {
  814. gInventory.removeObserver(this);
  815. return;
  816. }
  817. if((mask & (LLInventoryObserver::STRUCTURE)) != 0)
  818. {
  819. const std::set<LLUUID>& changed_items = gInventory.getChangedIDs();
  820. std::set<LLUUID>::const_iterator id_it = changed_items.begin();
  821. std::set<LLUUID>::const_iterator id_end = changed_items.end();
  822. for (;id_it != id_end; ++id_it)
  823. {
  824. if ((*id_it) == mObjectID)
  825. {
  826. active_panel->clearSelection();
  827. std::vector<LLUUID> items;
  828. items.push_back(mObjectID);
  829. highlight_inventory_objects_in_panel(items, active_panel);
  830. active_panel->getRootFolder()->scrollToShowSelection();
  831. gInventory.removeObserver(this);
  832. break;
  833. }
  834. }
  835. }
  836. }
  837. void set_dad_inbox_object(const LLUUID& object_id)
  838. {
  839. LLViewerInventoryMoveObserver* move_observer = new LLViewerInventoryMoveObserver(object_id);
  840. gInventory.addObserver(move_observer);
  841. }
  842. //unlike the FetchObserver for AgentOffer, we only make one
  843. //instance of the AddedObserver for TaskOffers
  844. //and it never dies. We do this because we don't know the UUID of
  845. //task offers until they are accepted, so we don't wouldn't
  846. //know what to watch for, so instead we just watch for all additions.
  847. class LLOpenTaskOffer : public LLInventoryAddedObserver
  848. {
  849. protected:
  850. /*virtual*/ void done()
  851. {
  852. for (uuid_vec_t::iterator it = mAdded.begin(); it != mAdded.end();)
  853. {
  854. const LLUUID& item_uuid = *it;
  855. bool was_moved = false;
  856. LLInventoryObject* added_object = gInventory.getObject(item_uuid);
  857. if (added_object)
  858. {
  859. // cast to item to get Asset UUID
  860. LLInventoryItem* added_item = dynamic_cast<LLInventoryItem*>(added_object);
  861. if (added_item)
  862. {
  863. const LLUUID& asset_uuid = added_item->getAssetUUID();
  864. if (gInventoryMoveObserver->isAssetWatched(asset_uuid))
  865. {
  866. LL_DEBUGS("Inventory_Move") << "Found asset UUID: " << asset_uuid << LL_ENDL;
  867. was_moved = true;
  868. }
  869. }
  870. }
  871. if (was_moved)
  872. {
  873. it = mAdded.erase(it);
  874. }
  875. else ++it;
  876. }
  877. open_inventory_offer(mAdded, "");
  878. mAdded.clear();
  879. }
  880. };
  881. class LLOpenTaskGroupOffer : public LLInventoryAddedObserver
  882. {
  883. protected:
  884. /*virtual*/ void done()
  885. {
  886. open_inventory_offer(mAdded, "group_offer");
  887. mAdded.clear();
  888. gInventory.removeObserver(this);
  889. delete this;
  890. }
  891. };
  892. //one global instance to bind them
  893. LLOpenTaskOffer* gNewInventoryObserver=NULL;
  894. class LLNewInventoryHintObserver : public LLInventoryAddedObserver
  895. {
  896. protected:
  897. /*virtual*/ void done()
  898. {
  899. LLFirstUse::newInventory();
  900. }
  901. };
  902. LLNewInventoryHintObserver* gNewInventoryHintObserver=NULL;
  903. void start_new_inventory_observer()
  904. {
  905. if (!gNewInventoryObserver) //task offer observer
  906. {
  907. // Observer is deleted by gInventory
  908. gNewInventoryObserver = new LLOpenTaskOffer;
  909. gInventory.addObserver(gNewInventoryObserver);
  910. }
  911. if (!gInventoryMoveObserver) //inventory move from the world observer
  912. {
  913. // Observer is deleted by gInventory
  914. gInventoryMoveObserver = new LLViewerInventoryMoveFromWorldObserver;
  915. gInventory.addObserver(gInventoryMoveObserver);
  916. }
  917. if (!gNewInventoryHintObserver)
  918. {
  919. // Observer is deleted by gInventory
  920. gNewInventoryHintObserver = new LLNewInventoryHintObserver();
  921. gInventory.addObserver(gNewInventoryHintObserver);
  922. }
  923. }
  924. class LLDiscardAgentOffer : public LLInventoryFetchItemsObserver
  925. {
  926. LOG_CLASS(LLDiscardAgentOffer);
  927. public:
  928. LLDiscardAgentOffer(const LLUUID& folder_id, const LLUUID& object_id) :
  929. LLInventoryFetchItemsObserver(object_id),
  930. mFolderID(folder_id),
  931. mObjectID(object_id) {}
  932. virtual void done()
  933. {
  934. LL_DEBUGS("Messaging") << "LLDiscardAgentOffer::done()" << LL_ENDL;
  935. // We're invoked from LLInventoryModel::notifyObservers().
  936. // If we now try to remove the inventory item, it will cause a nested
  937. // notifyObservers() call, which won't work.
  938. // So defer moving the item to trash until viewer gets idle (in a moment).
  939. LLAppViewer::instance()->addOnIdleCallback(boost::bind(&LLInventoryModel::removeItem, &gInventory, mObjectID));
  940. gInventory.removeObserver(this);
  941. delete this;
  942. }
  943. protected:
  944. LLUUID mFolderID;
  945. LLUUID mObjectID;
  946. };
  947. //Returns TRUE if we are OK, FALSE if we are throttled
  948. //Set check_only true if you want to know the throttle status
  949. //without registering a hit
  950. bool check_offer_throttle(const std::string& from_name, bool check_only)
  951. {
  952. static U32 throttle_count;
  953. static bool throttle_logged;
  954. LLChat chat;
  955. std::string log_message;
  956. if (!gSavedSettings.getBOOL("ShowNewInventory"))
  957. return false;
  958. if (check_only)
  959. {
  960. return gThrottleTimer.hasExpired();
  961. }
  962. if(gThrottleTimer.checkExpirationAndReset(OFFER_THROTTLE_TIME))
  963. {
  964. LL_DEBUGS("Messaging") << "Throttle Expired" << LL_ENDL;
  965. throttle_count=1;
  966. throttle_logged=false;
  967. return true;
  968. }
  969. else //has not expired
  970. {
  971. LL_DEBUGS("Messaging") << "Throttle Not Expired, Count: " << throttle_count << LL_ENDL;
  972. // When downloading the initial inventory we get a lot of new items
  973. // coming in and can't tell that from spam.
  974. if (LLStartUp::getStartupState() >= STATE_STARTED
  975. && throttle_count >= OFFER_THROTTLE_MAX_COUNT)
  976. {
  977. if (!throttle_logged)
  978. {
  979. // Use the name of the last item giver, who is probably the person
  980. // spamming you.
  981. LLStringUtil::format_map_t arg;
  982. std::string log_msg;
  983. std::ostringstream time ;
  984. time<<OFFER_THROTTLE_TIME;
  985. arg["APP_NAME"] = LLAppViewer::instance()->getSecondLifeTitle();
  986. arg["TIME"] = time.str();
  987. if (!from_name.empty())
  988. {
  989. arg["FROM_NAME"] = from_name;
  990. log_msg = LLTrans::getString("ItemsComingInTooFastFrom", arg);
  991. }
  992. else
  993. {
  994. log_msg = LLTrans::getString("ItemsComingInTooFast", arg);
  995. }
  996. //this is kinda important, so actually put it on screen
  997. LLSD args;
  998. args["MESSAGE"] = log_msg;
  999. LLNotificationsUtil::add("SystemMessage", args);
  1000. throttle_logged=true;
  1001. }
  1002. return false;
  1003. }
  1004. else
  1005. {
  1006. throttle_count++;
  1007. return true;
  1008. }
  1009. }
  1010. }
  1011. void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_name)
  1012. {
  1013. for (uuid_vec_t::const_iterator obj_iter = objects.begin();
  1014. obj_iter != objects.end();
  1015. ++obj_iter)
  1016. {
  1017. const LLUUID& obj_id = (*obj_iter);
  1018. if(!highlight_offered_object(obj_id))
  1019. {
  1020. continue;
  1021. }
  1022. const LLInventoryObject *obj = gInventory.getObject(obj_id);
  1023. if (!obj)
  1024. {
  1025. llwarns << "Cannot find object [ itemID:" << obj_id << " ] to open." << llendl;
  1026. continue;
  1027. }
  1028. const LLAssetType::EType asset_type = obj->getActualType();
  1029. // Either an inventory item or a category.
  1030. const LLInventoryItem* item = dynamic_cast<const LLInventoryItem*>(obj);
  1031. if (item)
  1032. {
  1033. ////////////////////////////////////////////////////////////////////////////////
  1034. // Special handling for various types.
  1035. if (check_offer_throttle(from_name, false)) // If we are throttled, don't display
  1036. {
  1037. LL_DEBUGS("Messaging") << "Highlighting inventory item: " << item->getUUID() << LL_ENDL;
  1038. // If we opened this ourselves, focus it
  1039. const BOOL take_focus = from_name.empty() ? TAKE_FOCUS_YES : TAKE_FOCUS_NO;
  1040. switch(asset_type)
  1041. {
  1042. case LLAssetType::AT_NOTECARD:
  1043. {
  1044. LLFloaterReg::showInstance("preview_notecard", LLSD(obj_id), take_focus);
  1045. break;
  1046. }
  1047. case LLAssetType::AT_LANDMARK:
  1048. {
  1049. LLInventoryCategory* parent_folder = gInventory.getCategory(item->getParentUUID());
  1050. if ("inventory_handler" == from_name)
  1051. {
  1052. LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "landmark").with("id", item->getUUID()));
  1053. }
  1054. else if("group_offer" == from_name)
  1055. {
  1056. // "group_offer" is passed by LLOpenTaskGroupOffer
  1057. // Notification about added landmark will be generated under the "from_name.empty()" called from LLOpenTaskOffer::done().
  1058. LLSD args;
  1059. args["type"] = "landmark";
  1060. args["id"] = obj_id;
  1061. LLFloaterSidePanelContainer::showPanel("places", args);
  1062. continue;
  1063. }
  1064. else if(from_name.empty())
  1065. {
  1066. std::string folder_name;
  1067. if (parent_folder)
  1068. {
  1069. // Localize folder name.
  1070. // *TODO: share this code?
  1071. folder_name = parent_folder->getName();
  1072. if (LLFolderType::lookupIsProtectedType(parent_folder->getPreferredType()))
  1073. {
  1074. LLTrans::findString(folder_name, "InvFolder " + folder_name);
  1075. }
  1076. }
  1077. else
  1078. {
  1079. folder_name = LLTrans::getString("Unknown");
  1080. }
  1081. // we receive a message from LLOpenTaskOffer, it mean that new landmark has been added.
  1082. LLSD args;
  1083. args["LANDMARK_NAME"] = item->getName();
  1084. args["FOLDER_NAME"] = folder_name;
  1085. LLNotificationsUtil::add("LandmarkCreated", args);
  1086. }
  1087. }
  1088. break;
  1089. case LLAssetType::AT_TEXTURE:
  1090. {
  1091. LLFloaterReg::showInstance("preview_texture", LLSD(obj_id), take_focus);
  1092. break;
  1093. }
  1094. case LLAssetType::AT_ANIMATION:
  1095. LLFloaterReg::showInstance("preview_anim", LLSD(obj_id), take_focus);
  1096. break;
  1097. case LLAssetType::AT_SCRIPT:
  1098. LLFloaterReg::showInstance("preview_script", LLSD(obj_id), take_focus);
  1099. break;
  1100. case LLAssetType::AT_SOUND:
  1101. LLFloaterReg::showInstance("preview_sound", LLSD(obj_id), take_focus);
  1102. break;
  1103. default:
  1104. break;
  1105. }
  1106. }
  1107. }
  1108. ////////////////////////////////////////////////////////////////////////////////
  1109. // Highlight item
  1110. const BOOL auto_open =
  1111. gSavedSettings.getBOOL("ShowInInventory") && // don't open if showininventory is false
  1112. !from_name.empty(); // don't open if it's not from anyone.
  1113. LLInventoryPanel::openInventoryPanelAndSetSelection(auto_open, obj_id);
  1114. }
  1115. }
  1116. bool highlight_offered_object(const LLUUID& obj_id)
  1117. {
  1118. const LLInventoryObject* obj = gInventory.getObject(obj_id);
  1119. if(!obj)
  1120. {
  1121. LL_WARNS("Messaging") << "Unable to show inventory item: " << obj_id << LL_ENDL;
  1122. return false;
  1123. }
  1124. ////////////////////////////////////////////////////////////////////////////////
  1125. // Don't highlight if it's in certain "quiet" folders which don't need UI
  1126. // notification (e.g. trash, cof, lost-and-found).
  1127. if(!gAgent.getAFK())
  1128. {
  1129. const LLViewerInventoryCategory *parent = gInventory.getFirstNondefaultParent(obj_id);
  1130. if (parent)
  1131. {
  1132. const LLFolderType::EType parent_type = parent->getPreferredType();
  1133. if (LLViewerFolderType::lookupIsQuietType(parent_type))
  1134. {
  1135. return false;
  1136. }
  1137. }
  1138. }
  1139. return true;
  1140. }
  1141. void inventory_offer_mute_callback(const LLUUID& blocked_id,
  1142. const std::string& full_name,
  1143. bool is_group)
  1144. {
  1145. // *NOTE: blocks owner if the offer came from an object
  1146. LLMute::EType mute_type = is_group ? LLMute::GROUP : LLMute::AGENT;
  1147. LLMute mute(blocked_id, full_name, mute_type);
  1148. if (LLMuteList::getInstance()->add(mute))
  1149. {
  1150. LLPanelBlockedList::showPanelAndSelect(blocked_id);
  1151. }
  1152. // purge the message queue of any previously queued inventory offers from the same source.
  1153. class OfferMatcher : public LLNotificationsUI::LLScreenChannel::Matcher
  1154. {
  1155. public:
  1156. OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) {}
  1157. bool matches(const LLNotificationPtr notification) const
  1158. {
  1159. if(notification->getName() == "ObjectGiveItem"
  1160. || notification->getName() == "OwnObjectGiveItem"
  1161. || notification->getName() == "UserGiveItem")
  1162. {
  1163. return (notification->getPayload()["from_id"].asUUID() == blocked_id);
  1164. }
  1165. return FALSE;
  1166. }
  1167. private:
  1168. const LLUUID& blocked_id;
  1169. };
  1170. LLNotificationsUI::LLChannelManager::getInstance()->killToastsFromChannel(LLUUID(
  1171. gSavedSettings.getString("NotificationChannelUUID")), OfferMatcher(blocked_id));
  1172. }
  1173. LLOfferInfo::LLOfferInfo()
  1174. : LLNotificationResponderInterface()
  1175. , mFromGroup(FALSE)
  1176. , mFromObject(FALSE)
  1177. , mIM(IM_NOTHING_SPECIAL)
  1178. , mType(LLAssetType::AT_NONE)
  1179. , mPersist(false)
  1180. {
  1181. }
  1182. LLOfferInfo::LLOfferInfo(const LLSD& sd)
  1183. {
  1184. mIM = (EInstantMessage)sd["im_type"].asInteger();
  1185. mFromID = sd["from_id"].asUUID();
  1186. mFromGroup = sd["from_group"].asBoolean();
  1187. mFromObject = sd["from_object"].asBoolean();
  1188. mTransactionID = sd["transaction_id"].asUUID();
  1189. mFolderID = sd["folder_id"].asUUID();
  1190. mObjectID = sd["object_id"].asUUID();
  1191. mType = LLAssetType::lookup(sd["type"].asString().c_str());
  1192. mFromName = sd["from_name"].asString();
  1193. mDesc = sd["description"].asString();
  1194. mHost = LLHost(sd["sender"].asString());
  1195. mPersist = sd["persist"].asBoolean();
  1196. }
  1197. LLOfferInfo::LLOfferInfo(const LLOfferInfo& info)
  1198. {
  1199. mIM = info.mIM;
  1200. mFromID = info.mFromID;
  1201. mFromGroup = info.mFromGroup;
  1202. mFromObject = info.mFromObject;
  1203. mTransactionID = info.mTransactionID;
  1204. mFolderID = info.mFolderID;
  1205. mObjectID = info.mObjectID;
  1206. mType = info.mType;
  1207. mFromName = info.mFromName;
  1208. mDesc = info.mDesc;
  1209. mHost = info.mHost;
  1210. mPersist = info.mPersist;
  1211. }
  1212. LLSD LLOfferInfo::asLLSD()
  1213. {
  1214. LLSD sd;
  1215. sd["im_type"] = mIM;
  1216. sd["from_id"] = mFromID;
  1217. sd["from_group"] = mFromGroup;
  1218. sd["from_object"] = mFromObject;
  1219. sd["transaction_id"] = mTransactionID;
  1220. sd["folder_id"] = mFolderID;
  1221. sd["object_id"] = mObjectID;
  1222. sd["type"] = LLAssetType::lookup(mType);
  1223. sd["from_name"] = mFromName;
  1224. sd["description"] = mDesc;
  1225. sd["sender"] = mHost.getIPandPort();
  1226. sd["persist"] = mPersist;
  1227. return sd;
  1228. }
  1229. void LLOfferInfo::fromLLSD(const LLSD& params)
  1230. {
  1231. *this = params;
  1232. }
  1233. void LLOfferInfo::send_auto_receive_response(void)
  1234. {
  1235. LLMessageSystem* msg = gMessageSystem;
  1236. msg->newMessageFast(_PREHASH_ImprovedInstantMessage);
  1237. msg->nextBlockFast(_PREHASH_AgentData);
  1238. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  1239. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  1240. msg->nextBlockFast(_PREHASH_MessageBlock);
  1241. msg->addBOOLFast(_PREHASH_FromGroup, FALSE);
  1242. msg->addUUIDFast(_PREHASH_ToAgentID, mFromID);
  1243. msg->addU8Fast(_PREHASH_Offline, IM_ONLINE);
  1244. msg->addUUIDFast(_PREHASH_ID, mTransactionID);
  1245. msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary
  1246. std::string name;
  1247. LLAgentUI::buildFullname(name);
  1248. msg->addStringFast(_PREHASH_FromAgentName, name);
  1249. msg->addStringFast(_PREHASH_Message, "");
  1250. msg->addU32Fast(_PREHASH_ParentEstateID, 0);
  1251. msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null);
  1252. msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent());
  1253. // Auto Receive Message. The math for the dialog works, because the accept
  1254. // for inventory_offered, task_inventory_offer or
  1255. // group_notice_inventory is 1 greater than the offer integer value.
  1256. // Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED,
  1257. // or IM_GROUP_NOTICE_INVENTORY_ACCEPTED
  1258. msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 1));
  1259. msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(mFolderID.mData),
  1260. sizeof(mFolderID.mData));
  1261. // send the message
  1262. msg->sendReliable(mHost);
  1263. if(IM_INVENTORY_OFFERED == mIM)
  1264. {
  1265. // add buddy to recent people list
  1266. LLRecentPeople::instance().add(mFromID);
  1267. }
  1268. }
  1269. void LLOfferInfo::handleRespond(const LLSD& notification, const LLSD& response)
  1270. {
  1271. initRespondFunctionMap();
  1272. const std::string name = notification["name"].asString();
  1273. if(mRespondFunctions.find(name) == mRespondFunctions.end())
  1274. {
  1275. llwarns << "Unexpected notification name : " << name << llendl;
  1276. llassert(!"Unexpected notification name");
  1277. return;
  1278. }
  1279. mRespondFunctions[name](notification, response);
  1280. }
  1281. bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& response)
  1282. {
  1283. LLChat chat;
  1284. std::string log_message;
  1285. S32 button = LLNotificationsUtil::getSelectedOption(notification, response);
  1286. LLInventoryObserver* opener = NULL;
  1287. LLViewerInventoryCategory* catp = NULL;
  1288. catp = (LLViewerInventoryCategory*)gInventory.getCategory(mObjectID);
  1289. LLViewerInventoryItem* itemp = NULL;
  1290. if(!catp)
  1291. {
  1292. itemp = (LLViewerInventoryItem*)gInventory.getItem(mObjectID);
  1293. }
  1294. // For muting, we need to add the mute, then decline the offer.
  1295. // This must be done here because:
  1296. // * callback may be called immediately,
  1297. // * adding the mute sends a message,
  1298. // * we can't build two messages at once.
  1299. if (2 == button) // Block
  1300. {
  1301. LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID());
  1302. llassert(notification_ptr != NULL);
  1303. if (notification_ptr != NULL)
  1304. {
  1305. gCacheName->get(mFromID, mFromGroup, boost::bind(&inventory_offer_mute_callback, _1, _2, _3));
  1306. }
  1307. }
  1308. std::string from_string; // Used in the pop-up.
  1309. std::string chatHistory_string; // Used in chat history.
  1310. // TODO: when task inventory offers can also be handled the new way, migrate the code that sets these strings here:
  1311. from_string = chatHistory_string = mFromName;
  1312. bool busy = gAgent.getBusy();
  1313. switch(button)
  1314. {
  1315. case IOR_SHOW:
  1316. // we will want to open this item when it comes back.
  1317. LL_DEBUGS("Messaging") << "Initializing an opener for tid: " << mTransactionID
  1318. << LL_ENDL;
  1319. switch (mIM)
  1320. {
  1321. case IM_INVENTORY_OFFERED:
  1322. {
  1323. // This is an offer from an agent. In this case, the back
  1324. // end has already copied the items into your inventory,
  1325. // so we can fetch it out of our inventory.
  1326. if (gSavedSettings.getBOOL("ShowOfferedInventory"))
  1327. {
  1328. LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(mObjectID, from_string);
  1329. open_agent_offer->startFetch();
  1330. if(catp || (itemp && itemp->isFinished()))
  1331. {
  1332. open_agent_offer->done();
  1333. }
  1334. else
  1335. {
  1336. opener = open_agent_offer;
  1337. }
  1338. }
  1339. }
  1340. break;
  1341. case IM_GROUP_NOTICE:
  1342. opener = new LLOpenTaskGroupOffer;
  1343. send_auto_receive_response();
  1344. break;
  1345. case IM_TASK_INVENTORY_OFFERED:
  1346. case IM_GROUP_NOTICE_REQUESTED:
  1347. // This is an offer from a task or group.
  1348. // We don't use a new instance of an opener
  1349. // We instead use the singular observer gOpenTaskOffer
  1350. // Since it already exists, we don't need to actually do anything
  1351. break;
  1352. default:
  1353. LL_WARNS("Messaging") << "inventory_offer_callback: unknown offer type" << LL_ENDL;
  1354. break;
  1355. }
  1356. break;
  1357. // end switch (mIM)
  1358. case IOR_ACCEPT:
  1359. //don't spam them if they are getting flooded
  1360. if (check_offer_throttle(mFromName, true))
  1361. {
  1362. log_message = chatHistory_string + " " + LLTrans::getString("InvOfferGaveYou") + " " + mDesc + LLTrans::getString(".");
  1363. LLSD args;
  1364. args["MESSAGE"] = log_message;
  1365. LLNotificationsUtil::add("SystemMessageTip", args);
  1366. }
  1367. break;
  1368. case IOR_MUTE:
  1369. // MUTE falls through to decline
  1370. case IOR_DECLINE:
  1371. {
  1372. {
  1373. LLStringUtil::format_map_t log_message_args;
  1374. log_message_args["DESC"] = mDesc;
  1375. log_message_args["NAME"] = mFromName;
  1376. log_message = LLTrans::getString("InvOfferDecline", log_message_args);
  1377. }
  1378. chat.mText = log_message;
  1379. if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::getInstance()->isLinden(mFromName) ) // muting for SL-42269
  1380. {
  1381. chat.mMuted = TRUE;
  1382. }
  1383. // *NOTE dzaporozhan
  1384. // Disabled logging to old chat floater to fix crash in group notices - EXT-4149
  1385. // LLFloaterChat::addChatHistory(chat);
  1386. LLDiscardAgentOffer* discard_agent_offer = new LLDiscardAgentOffer(mFolderID, mObjectID);
  1387. discard_agent_offer->startFetch();
  1388. if (catp || (itemp && itemp->isFinished()))
  1389. {
  1390. discard_agent_offer->done();
  1391. }
  1392. else
  1393. {
  1394. opener = discard_agent_offer;
  1395. }
  1396. if (busy && (!mFromGroup && !mFromObject))
  1397. {
  1398. busy_message(gMessageSystem, mFromID);
  1399. }
  1400. break;
  1401. }
  1402. default:
  1403. // close button probably
  1404. // The item has already been fetched and is in your inventory, we simply won't highlight it
  1405. // OR delete it if the notification gets killed, since we don't want that to be a vector for
  1406. // losing inventory offers.
  1407. break;
  1408. }
  1409. if(opener)
  1410. {
  1411. gInventory.addObserver(opener);
  1412. }
  1413. if(!mPersist)
  1414. {
  1415. delete this;
  1416. }
  1417. return false;
  1418. }
  1419. bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const LLSD& response)
  1420. {
  1421. LLChat chat;
  1422. std::string log_message;
  1423. S32 button = LLNotification::getSelectedOption(notification, response);
  1424. // For muting, we need to add the mute, then decline the offer.
  1425. // This must be done here because:
  1426. // * callback may be called immediately,
  1427. // * adding the mute sends a message,
  1428. // * we can't build two messages at once.
  1429. if (2 == button)
  1430. {
  1431. LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID());
  1432. llassert(notification_ptr != NULL);
  1433. if (notification_ptr != NULL)
  1434. {
  1435. gCacheName->get(mFromID, mFromGroup, boost::bind(&inventory_offer_mute_callback, _1, _2, _3));
  1436. }
  1437. }
  1438. LLMessageSystem* msg = gMessageSystem;
  1439. msg->newMessageFast(_PREHASH_ImprovedInstantMessage);
  1440. msg->nextBlockFast(_PREHASH_AgentData);
  1441. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  1442. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  1443. msg->nextBlockFast(_PREHASH_MessageBlock);
  1444. msg->addBOOLFast(_PREHASH_FromGroup, FALSE);
  1445. msg->addUUIDFast(_PREHASH_ToAgentID, mFromID);
  1446. msg->addU8Fast(_PREHASH_Offline, IM_ONLINE);
  1447. msg->addUUIDFast(_PREHASH_ID, mTransactionID);
  1448. msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary
  1449. std::string name;
  1450. LLAgentUI::buildFullname(name);
  1451. msg->addStringFast(_PREHASH_FromAgentName, name);
  1452. msg->addStringFast(_PREHASH_Message, "");
  1453. msg->addU32Fast(_PREHASH_ParentEstateID, 0);
  1454. msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null);
  1455. msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent());
  1456. LLInventoryObserver* opener = NULL;
  1457. std::string from_string; // Used in the pop-up.
  1458. std::string chatHistory_string; // Used in chat history.
  1459. if (mFromObject == TRUE)
  1460. {
  1461. if (mFromGroup)
  1462. {
  1463. std::string group_name;
  1464. if (gCacheName->getGroupName(mFromID, group_name))
  1465. {
  1466. from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+"'"
  1467. + mFromName + LLTrans::getString("'") +" " + LLTrans::getString("InvOfferOwnedByGroup")
  1468. + " "+ "'" + group_name + "'";
  1469. chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByGroup")
  1470. + " " + group_name + "'";
  1471. }
  1472. else
  1473. {
  1474. from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+"'"
  1475. + mFromName +"'"+ " " + LLTrans::getString("InvOfferOwnedByUnknownGroup");
  1476. chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownGroup");
  1477. }
  1478. }
  1479. else
  1480. {
  1481. std::string full_name;
  1482. if (gCacheName->getFullName(mFromID, full_name))
  1483. {
  1484. from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+ LLTrans::getString("'") + mFromName
  1485. + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedBy") + full_name;
  1486. chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedBy") + " " + full_name;
  1487. }
  1488. else
  1489. {
  1490. from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+LLTrans::getString("'")
  1491. + mFromName + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedByUnknownUser");
  1492. chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownUser");
  1493. }
  1494. }
  1495. }
  1496. else
  1497. {
  1498. from_string = chatHistory_string = mFromName;
  1499. }
  1500. bool busy = gAgent.getBusy();
  1501. switch(button)
  1502. {
  1503. case IOR_ACCEPT:
  1504. // ACCEPT. The math for the dialog works, because the accept
  1505. // for inventory_offered, task_inventory_offer or
  1506. // group_notice_inventory is 1 greater than the offer integer value.
  1507. // Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED,
  1508. // or IM_GROUP_NOTICE_INVENTORY_ACCEPTED
  1509. msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 1));
  1510. msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(mFolderID.mData),
  1511. sizeof(mFolderID.mData));
  1512. // send the message
  1513. msg->sendReliable(mHost);
  1514. //don't spam them if they are getting flooded
  1515. if (check_offer_throttle(mFromName, true))
  1516. {
  1517. log_message = chatHistory_string + " " + LLTrans::getString("InvOfferGaveYou") + " " + mDesc + LLTrans::getString(".");
  1518. LLSD args;
  1519. args["MESSAGE"] = log_message;
  1520. LLNotificationsUtil::add("SystemMessageTip", args);
  1521. }
  1522. // we will want to open this item when it comes back.
  1523. LL_DEBUGS("Messaging") << "Initializing an opener for tid: " << mTransactionID
  1524. << LL_ENDL;
  1525. switch (mIM)
  1526. {
  1527. case IM_TASK_INVENTORY_OFFERED:
  1528. case IM_GROUP_NOTICE:
  1529. case IM_GROUP_NOTICE_REQUESTED:
  1530. {
  1531. // This is an offer from a task or group.
  1532. // We don't use a new instance of an opener
  1533. // We instead use the singular observer gOpenTaskOffer
  1534. // Since it already exists, we don't need to actually do anything
  1535. }
  1536. break;
  1537. default:
  1538. LL_WARNS("Messaging") << "inventory_offer_callback: unknown offer type" << LL_ENDL;
  1539. break;
  1540. } // end switch (mIM)
  1541. break;
  1542. case IOR_MUTE:
  1543. // MUTE falls through to decline
  1544. case IOR_DECLINE:
  1545. // DECLINE. The math for the dialog works, because the decline
  1546. // for inventory_offered, task_inventory_offer or
  1547. // group_notice_inventory is 2 greater than the offer integer value.
  1548. // Generates IM_INVENTORY_DECLINED, IM_TASK_INVENTORY_DECLINED,
  1549. // or IM_GROUP_NOTICE_INVENTORY_DECLINED
  1550. default:
  1551. // close button probably (or any of the fall-throughs from above)
  1552. msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 2));
  1553. msg->addBinaryDataFast(_PREHASH_BinaryBucket, EMPTY_BINARY_BUCKET, EMPTY_BINARY_BUCKET_SIZE);
  1554. // send the message
  1555. msg->sendReliable(mHost);
  1556. if (gSavedSettings.getBOOL("LogInventoryDecline"))
  1557. {
  1558. LLStringUtil::format_map_t log_message_args;
  1559. log_message_args["DESC"] = mDesc;
  1560. log_message_args["NAME"] = mFromName;
  1561. log_message = LLTrans::getString("InvOfferDecline", log_message_args);
  1562. LLSD args;
  1563. args["MESSAGE"] = log_message;
  1564. LLNotificationsUtil::add("SystemMessageTip", args);
  1565. }
  1566. if (busy && (!mFromGroup && !mFromObject))
  1567. {
  1568. busy_message(msg,mFromID);
  1569. }
  1570. break;
  1571. }
  1572. if(opener)
  1573. {
  1574. gInventory.addObserver(opener);
  1575. }
  1576. if(!mPersist)
  1577. {
  1578. delete this;
  1579. }
  1580. return false;
  1581. }
  1582. class LLPostponedOfferNotification: public LLPostponedNotification
  1583. {
  1584. protected:
  1585. /* virtual */
  1586. void modifyNotificationParams()
  1587. {
  1588. LLSD substitutions = mParams.substitutions;
  1589. substitutions["NAME"] = mName;
  1590. mParams.substitutions = substitutions;
  1591. }
  1592. };
  1593. void LLOfferInfo::initRespondFunctionMap()
  1594. {
  1595. if(mRespondFunctions.empty())
  1596. {
  1597. mRespondFunctions["ObjectGiveItem"] = boost::bind(&LLOfferInfo::inventory_task_offer_callback, this, _1, _2);
  1598. mRespondFunctions["OwnObjectGiveItem"] = boost::bind(&LLOfferInfo::inventory_task_offer_callback, this, _1, _2);
  1599. mRespondFunctions["UserGiveItem"] = boost::bind(&LLOfferInfo::inventory_offer_callback, this, _1, _2);
  1600. }
  1601. }
  1602. void inventory_offer_handler(LLOfferInfo* info)
  1603. {
  1604. // If muted, don't even go through the messaging stuff. Just curtail the offer here.
  1605. // Passing in a null UUID handles the case of where you have muted one of your own objects by_name.
  1606. // The solution for STORM-1297 seems to handle the cases where the object is owned by someone else.
  1607. if (LLMuteList::getInstance()->isMuted(info->mFromID, info->mFromName) ||
  1608. LLMuteList::getInstance()->isMuted(LLUUID::null, info->mFromName))
  1609. {
  1610. info->forceResponse(IOR_MUTE);
  1611. return;
  1612. }
  1613. // Avoid the Accept/Discard dialog if the user so desires. JC
  1614. if (gSavedSettings.getBOOL("AutoAcceptNewInventory")
  1615. && (info->mType == LLAssetType::AT_NOTECARD
  1616. || info->mType == LLAssetType::AT_LANDMARK
  1617. || info->mType == LLAssetType::AT_TEXTURE))
  1618. {
  1619. // For certain types, just accept the items into the inventory,
  1620. // and possibly open them on receipt depending upon "ShowNewInventory".
  1621. info->forceResponse(IOR_ACCEPT);
  1622. return;
  1623. }
  1624. // Strip any SLURL from the message display. (DEV-2754)
  1625. std::string msg = info->mDesc;
  1626. int indx = msg.find(" ( http://slurl.com/secondlife/");
  1627. if(indx == std::string::npos)
  1628. {
  1629. // try to find new slurl host
  1630. indx = msg.find(" ( http://maps.secondlife.com/secondlife/");
  1631. }
  1632. if(indx >= 0)
  1633. {
  1634. LLStringUtil::truncate(msg, indx);
  1635. }
  1636. LLSD args;
  1637. args["[OBJECTNAME]"] = msg;
  1638. LLSD payload;
  1639. // must protect against a NULL return from lookupHumanReadable()
  1640. std::string typestr = ll_safe_string(LLAssetType::lookupHumanReadable(info->mType));
  1641. if (!typestr.empty())
  1642. {
  1643. // human readable matches string name from strings.xml
  1644. // lets get asset type localized name
  1645. args["OBJECTTYPE"] = LLTrans::getString(typestr);
  1646. }
  1647. else
  1648. {
  1649. LL_WARNS("Messaging") << "LLAssetType::lookupHumanReadable() returned NULL - probably bad asset type: " << info->mType << LL_ENDL;
  1650. args["OBJECTTYPE"] = "";
  1651. // This seems safest, rather than propagating bogosity
  1652. LL_WARNS("Messaging") << "Forcing an inventory-decline for probably-bad asset type." << LL_ENDL;
  1653. info->forceResponse(IOR_DECLINE);
  1654. return;
  1655. }
  1656. // If mObjectID is null then generate the object_id based on msg to prevent
  1657. // multiple creation of chiclets for same object.
  1658. LLUUID object_id = info->mObjectID;
  1659. if (object_id.isNull())
  1660. object_id.generate(msg);
  1661. payload["from_id"] = info->mFromID;
  1662. // Needed by LLScriptFloaterManager to bind original notification with
  1663. // faked for toast one.
  1664. payload["object_id"] = object_id;
  1665. // Flag indicating that this notification is faked for toast.
  1666. payload["give_inventory_notification"] = FALSE;
  1667. args["OBJECTFROMNAME"] = info->mFromName;
  1668. args["NAME"] = info->mFromName;
  1669. if (info->mFromGroup)
  1670. {
  1671. args["NAME_SLURL"] = LLSLURL("group", info->mFromID, "about").getSLURLString();
  1672. }
  1673. else
  1674. {
  1675. args["NAME_SLURL"] = LLSLURL("agent", info->mFromID, "about").getSLURLString();
  1676. }
  1677. std::string verb = "select?name=" + LLURI::escape(msg);
  1678. args["ITEM_SLURL"] = LLSLURL("inventory", info->mObjectID, verb.c_str()).getSLURLString();
  1679. LLNotification::Params p;
  1680. // Object -> Agent Inventory Offer
  1681. if (info->mFromObject)
  1682. {
  1683. // Inventory Slurls don't currently work for non agent transfers, so only display the object name.
  1684. args["ITEM_SLURL"] = msg;
  1685. // Note: sets inventory_task_offer_callback as the callback
  1686. p.substitutions(args).payload(payload).functor.responder(LLNotificationResponderPtr(info));
  1687. info->mPersist = true;
  1688. // Offers from your own objects need a special notification template.
  1689. p.name = info->mFromID == gAgentID ? "OwnObjectGiveItem" : "ObjectGiveItem";
  1690. // Pop up inv offer chiclet and let the user accept (keep), or reject (and silently delete) the inventory.
  1691. LLPostponedNotification::add<LLPostponedOfferNotification>(p, info->mFromID, info->mFromGroup == TRUE);
  1692. }
  1693. else // Agent -> Agent Inventory Offer
  1694. {
  1695. p.responder = info;
  1696. // Note: sets inventory_offer_callback as the callback
  1697. // *TODO fix memory leak
  1698. // inventory_offer_callback() is not invoked if user received notification and
  1699. // closes viewer(without responding the notification)
  1700. p.substitutions(args).payload(payload).functor.responder(LLNotificationResponderPtr(info));
  1701. info->mPersist = true;
  1702. p.name = "UserGiveItem";
  1703. // Prefetch the item into your local inventory.
  1704. LLInventoryFetchItemsObserver* fetch_item = new LLInventoryFetchItemsObserver(info->mObjectID);
  1705. fetch_item->startFetch();
  1706. if(fetch_item->isFinished())
  1707. {
  1708. fetch_item->done();
  1709. }
  1710. else
  1711. {
  1712. gInventory.addObserver(fetch_item);
  1713. }
  1714. // In viewer 2 we're now auto receiving inventory offers and messaging as such (not sending reject messages).
  1715. info->send_auto_receive_response();
  1716. // Inform user that there is a script floater via toast system
  1717. {
  1718. payload["give_inventory_notification"] = TRUE;
  1719. p.payload = payload;
  1720. LLPostponedNotification::add<LLPostponedOfferNotification>(p, info->mFromID, false);
  1721. }
  1722. }
  1723. LLFirstUse::newInventory();
  1724. }
  1725. bool lure_callback(const LLSD& notification, const LLSD& response)
  1726. {
  1727. S32 option = 0;
  1728. if (response.isInteger())
  1729. {
  1730. option = response.asInteger();
  1731. }
  1732. else
  1733. {
  1734. option = LLNotificationsUtil::getSelectedOption(notification, response);
  1735. }
  1736. LLUUID from_id = notification["payload"]["from_id"].asUUID();
  1737. LLUUID lure_id = notification["payload"]["lure_id"].asUUID();
  1738. BOOL godlike = notification["payload"]["godlike"].asBoolean();
  1739. switch(option)
  1740. {
  1741. case 0:
  1742. {
  1743. // accept
  1744. gAgent.teleportViaLure(lure_id, godlike);
  1745. }
  1746. break;
  1747. case 1:
  1748. default:
  1749. // decline
  1750. send_simple_im(from_id,
  1751. LLStringUtil::null,
  1752. IM_LURE_DECLINED,
  1753. lure_id);
  1754. break;
  1755. }
  1756. return false;
  1757. }
  1758. static LLNotificationFunctorRegistration lure_callback_reg("TeleportOffered", lure_callback);
  1759. bool goto_url_callback(const LLSD& notification, const LLSD& response)
  1760. {
  1761. std::string url = notification["payload"]["url"].asString();
  1762. S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
  1763. if(1 == option)
  1764. {
  1765. LLWeb::loadURL(url);
  1766. }
  1767. return false;
  1768. }
  1769. static LLNotificationFunctorRegistration goto_url_callback_reg("GotoURL", goto_url_callback);
  1770. bool inspect_remote_object_callback(const LLSD& notification, const LLSD& response)
  1771. {
  1772. S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
  1773. if (0 == option)
  1774. {
  1775. LLFloaterReg::showInstance("inspect_remote_object", notification["payload"]);
  1776. }
  1777. return false;
  1778. }
  1779. static LLNotificationFunctorRegistration inspect_remote_object_callback_reg("ServerObjectMessage", inspect_remote_object_callback);
  1780. class LLPostponedServerObjectNotification: public LLPostponedNotification
  1781. {
  1782. protected:
  1783. /* virtual */
  1784. void modifyNotificationParams()
  1785. {
  1786. LLSD payload = mParams.payload;
  1787. mParams.payload = payload;
  1788. }
  1789. };
  1790. static bool parse_lure_bucket(const std::string& bucket,
  1791. U64& region_handle,
  1792. LLVector3& pos,
  1793. LLVector3& look_at,
  1794. U8& region_access)
  1795. {
  1796. // tokenize the bucket
  1797. typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
  1798. boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
  1799. tokenizer tokens(bucket, sep);
  1800. tokenizer::iterator iter = tokens.begin();
  1801. S32 gx,gy,rx,ry,rz,lx,ly,lz;
  1802. try
  1803. {
  1804. gx = boost::lexical_cast<S32>((*(iter)).c_str());
  1805. gy = boost::lexical_cast<S32>((*(++iter)).c_str());
  1806. rx = boost::lexical_cast<S32>((*(++iter)).c_str());
  1807. ry = boost::lexical_cast<S32>((*(++iter)).c_str());
  1808. rz = boost::lexical_cast<S32>((*(++iter)).c_str());
  1809. lx = boost::lexical_cast<S32>((*(++iter)).c_str());
  1810. ly = boost::lexical_cast<S32>((*(++iter)).c_str());
  1811. lz = boost::lexical_cast<S32>((*(++iter)).c_str());
  1812. }
  1813. catch( boost::bad_lexical_cast& )
  1814. {
  1815. LL_WARNS("parse_lure_bucket")
  1816. << "Couldn't parse lure bucket."
  1817. << LL_ENDL;
  1818. return false;
  1819. }
  1820. // Grab region access
  1821. region_access = SIM_ACCESS_MIN;
  1822. if (++iter != tokens.end())
  1823. {
  1824. std::string access_str((*iter).c_str());
  1825. LLStringUtil::trim(access_str);
  1826. if ( access_str == "A" )
  1827. {
  1828. region_access = SIM_ACCESS_ADULT;
  1829. }
  1830. else if ( access_str == "M" )
  1831. {
  1832. region_access = SIM_ACCESS_MATURE;
  1833. }
  1834. else if ( access_str == "PG" )
  1835. {
  1836. region_access = SIM_ACCESS_PG;
  1837. }
  1838. }
  1839. pos.setVec((F32)rx, (F32)ry, (F32)rz);
  1840. look_at.setVec((F32)lx, (F32)ly, (F32)lz);
  1841. region_handle = to_region_handle(gx, gy);
  1842. return true;
  1843. }
  1844. // Strip out "Resident" for display, but only if the message came from a user
  1845. // (rather than a script)
  1846. static std::string clean_name_from_im(const std::string& name, EInstantMessage type)
  1847. {
  1848. switch(type)
  1849. {
  1850. case IM_NOTHING_SPECIAL:
  1851. case IM_MESSAGEBOX:
  1852. case IM_GROUP_INVITATION:
  1853. case IM_INVENTORY_OFFERED:
  1854. case IM_INVENTORY_ACCEPTED:
  1855. case IM_INVENTORY_DECLINED:
  1856. case IM_GROUP_VOTE:
  1857. case IM_GROUP_MESSAGE_DEPRECATED:
  1858. //IM_TASK_INVENTORY_OFFERED
  1859. //IM_TASK_INVENTORY_ACCEPTED
  1860. //IM_TASK_INVENTORY_DECLINED
  1861. case IM_NEW_USER_DEFAULT:
  1862. case IM_SESSION_INVITE:
  1863. case IM_SESSION_P2P_INVITE:
  1864. case IM_SESSION_GROUP_START:
  1865. case IM_SESSION_CONFERENCE_START:
  1866. case IM_SESSION_SEND:
  1867. case IM_SESSION_LEAVE:
  1868. //IM_FROM_TASK
  1869. case IM_BUSY_AUTO_RESPONSE:
  1870. case IM_CONSOLE_AND_CHAT_HISTORY:
  1871. case IM_LURE_USER:
  1872. case IM_LURE_ACCEPTED:
  1873. case IM_LURE_DECLINED:
  1874. case IM_GODLIKE_LURE_USER:
  1875. case IM_YET_TO_BE_USED:
  1876. case IM_GROUP_ELECTION_DEPRECATED:
  1877. //IM_GOTO_URL
  1878. //IM_FROM_TASK_AS_ALERT
  1879. case IM_GROUP_NOTICE:
  1880. case IM_GROUP_NOTICE_INVENTORY_ACCEPTED:
  1881. case IM_GROUP_NOTICE_INVENTORY_DECLINED:
  1882. case IM_GROUP_INVITATION_ACCEPT:
  1883. case IM_GROUP_INVITATION_DECLINE:
  1884. case IM_GROUP_NOTICE_REQUESTED:
  1885. case IM_FRIENDSHIP_OFFERED:
  1886. case IM_FRIENDSHIP_ACCEPTED:
  1887. case IM_FRIENDSHIP_DECLINED_DEPRECATED:
  1888. //IM_TYPING_START
  1889. //IM_TYPING_STOP
  1890. return LLCacheName::cleanFullName(name);
  1891. default:
  1892. return name;
  1893. }
  1894. }
  1895. static std::string clean_name_from_task_im(const std::string& msg,
  1896. BOOL from_group)
  1897. {
  1898. boost::smatch match;
  1899. static const boost::regex returned_exp(
  1900. "(.*been returned to your inventory lost and found folder by )(.+)( (from|near).*)");
  1901. if (boost::regex_match(msg, match, returned_exp))
  1902. {
  1903. // match objects are 1-based for groups
  1904. std::string final = match[1].str();
  1905. std::string name = match[2].str();
  1906. // Don't try to clean up group names
  1907. if (!from_group)
  1908. {
  1909. if (LLAvatarNameCache::useDisplayNames())
  1910. {
  1911. // ...just convert to username
  1912. final += LLCacheName::buildUsername(name);
  1913. }
  1914. else
  1915. {
  1916. // ...strip out legacy "Resident" name
  1917. final += LLCacheName::cleanFullName(name);
  1918. }
  1919. }
  1920. final += match[3].str();
  1921. return final;
  1922. }
  1923. return msg;
  1924. }
  1925. void notification_display_name_callback(const LLUUID& id,
  1926. const LLAvatarName& av_name,
  1927. const std::string& name,
  1928. LLSD& substitutions,
  1929. const LLSD& payload)
  1930. {
  1931. substitutions["NAME"] = av_name.mDisplayName;
  1932. LLNotificationsUtil::add(name, substitutions, payload);
  1933. }
  1934. class LLPostponedIMSystemTipNotification: public LLPostponedNotification
  1935. {
  1936. protected:
  1937. /* virtual */
  1938. void modifyNotificationParams()
  1939. {
  1940. LLSD payload = mParams.payload;
  1941. payload["SESSION_NAME"] = mName;
  1942. mParams.payload = payload;
  1943. }
  1944. };
  1945. // Callback for name resolution of a god/estate message
  1946. void god_message_name_cb(const LLAvatarName& av_name, LLChat chat, std::string message)
  1947. {
  1948. LLSD args;
  1949. args["NAME"] = av_name.getCompleteName();
  1950. args["MES