llviewermessage.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:176k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llviewermessage.cpp
  3.  * @brief Dumping ground for viewer-side message system callbacks.
  4.  *
  5.  * $LicenseInfo:firstyear=2002&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2002-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llviewermessage.h"
  34. #include "llanimationstates.h"
  35. #include "llaudioengine.h" 
  36. #include "llavataractions.h"
  37. #include "lscript_byteformat.h"
  38. #include "lleconomy.h"
  39. #include "lleventtimer.h"
  40. #include "llfloaterreg.h"
  41. #include "llfollowcamparams.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 "llcallingcard.h"
  52. //#include "llfirstuse.h"
  53. #include "llfloaterbuycurrency.h"
  54. #include "llfloaterbuyland.h"
  55. #include "llfloaterland.h"
  56. #include "llfloaterregioninfo.h"
  57. #include "llfloaterlandholdings.h"
  58. #include "llfloaterpostcard.h"
  59. #include "llfloaterpreference.h"
  60. #include "llhudeffecttrail.h"
  61. #include "llhudmanager.h"
  62. #include "llinventoryobserver.h"
  63. #include "llinventorypanel.h"
  64. #include "llnearbychat.h"
  65. #include "llnotifications.h"
  66. #include "llnotificationsutil.h"
  67. #include "llpanelgrouplandmoney.h"
  68. #include "llpanelplaces.h"
  69. #include "llrecentpeople.h"
  70. #include "llscriptfloater.h"
  71. #include "llselectmgr.h"
  72. #include "llsidetray.h"
  73. #include "llstartup.h"
  74. #include "llsky.h"
  75. #include "llslurl.h"
  76. #include "llstatenums.h"
  77. #include "llstatusbar.h"
  78. #include "llimview.h"
  79. #include "llspeakers.h"
  80. #include "lltrans.h"
  81. #include "llviewerfoldertype.h"
  82. #include "lluri.h"
  83. #include "llviewergenericmessage.h"
  84. #include "llviewermenu.h"
  85. #include "llviewerobjectlist.h"
  86. #include "llviewerparcelmgr.h"
  87. #include "llviewerstats.h"
  88. #include "llviewertexteditor.h"
  89. #include "llviewerthrottle.h"
  90. #include "llviewerwindow.h"
  91. #include "llvlmanager.h"
  92. #include "llvoavatarself.h"
  93. #include "llvotextbubble.h"
  94. #include "llworld.h"
  95. #include "pipeline.h"
  96. #include "llfloaterworldmap.h"
  97. #include "llviewerdisplay.h"
  98. #include "llkeythrottle.h"
  99. #include "llgroupactions.h"
  100. #include "llagentui.h"
  101. #include "llpanelblockedlist.h"
  102. #include "llpanelplaceprofile.h"
  103. #include <boost/algorithm/string/split.hpp> //
  104. #if LL_WINDOWS // For Windows specific error handler
  105. #include "llwindebug.h" // For the invalid message handler
  106. #endif
  107. #include "llnotificationmanager.h" //
  108. //
  109. // Constants
  110. //
  111. const F32 BIRD_AUDIBLE_RADIUS = 32.0f;
  112. const F32 SIT_DISTANCE_FROM_TARGET = 0.25f;
  113. static const F32 LOGOUT_REPLY_TIME = 3.f; // Wait this long after LogoutReply before quitting.
  114. // Determine how quickly residents' scripts can issue question dialogs
  115. // Allow bursts of up to 5 dialogs in 10 seconds. 10*2=20 seconds recovery if throttle kicks in
  116. static const U32 LLREQUEST_PERMISSION_THROTTLE_LIMIT = 5;     // requests
  117. static const F32 LLREQUEST_PERMISSION_THROTTLE_INTERVAL = 10.0f; // seconds
  118. extern BOOL gDebugClicks;
  119. // function prototypes
  120. bool check_offer_throttle(const std::string& from_name, bool check_only);
  121. //inventory offer throttle globals
  122. LLFrameTimer gThrottleTimer;
  123. const U32 OFFER_THROTTLE_MAX_COUNT=5; //number of items per time period
  124. const F32 OFFER_THROTTLE_TIME=10.f; //time period in seconds
  125. //script permissions
  126. const std::string SCRIPT_QUESTIONS[SCRIPT_PERMISSION_EOF] = 
  127. "ScriptTakeMoney",
  128. "ActOnControlInputs",
  129. "RemapControlInputs",
  130. "AnimateYourAvatar",
  131. "AttachToYourAvatar",
  132. "ReleaseOwnership",
  133. "LinkAndDelink",
  134. "AddAndRemoveJoints",
  135. "ChangePermissions",
  136. "TrackYourCamera",
  137. "ControlYourCamera"
  138. };
  139. const BOOL SCRIPT_QUESTION_IS_CAUTION[SCRIPT_PERMISSION_EOF] = 
  140. {
  141. TRUE, // ScriptTakeMoney,
  142. FALSE, // ActOnControlInputs
  143. FALSE, // RemapControlInputs
  144. FALSE, // AnimateYourAvatar
  145. FALSE, // AttachToYourAvatar
  146. FALSE, // ReleaseOwnership,
  147. FALSE, // LinkAndDelink,
  148. FALSE, // AddAndRemoveJoints
  149. FALSE, // ChangePermissions
  150. FALSE, // TrackYourCamera,
  151. FALSE // ControlYourCamera
  152. };
  153. bool friendship_offer_callback(const LLSD& notification, const LLSD& response)
  154. {
  155. S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
  156. LLMessageSystem* msg = gMessageSystem;
  157. const LLSD& payload = notification["payload"];
  158. // add friend to recent people list
  159. LLRecentPeople::instance().add(payload["from_id"]);
  160. switch(option)
  161. {
  162. case 0:
  163. {
  164. // accept
  165. LLAvatarTracker::formFriendship(payload["from_id"]);
  166. const LLUUID fid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD);
  167. // This will also trigger an onlinenotification if the user is online
  168. msg->newMessageFast(_PREHASH_AcceptFriendship);
  169. msg->nextBlockFast(_PREHASH_AgentData);
  170. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  171. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  172. msg->nextBlockFast(_PREHASH_TransactionBlock);
  173. msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]);
  174. msg->nextBlockFast(_PREHASH_FolderData);
  175. msg->addUUIDFast(_PREHASH_FolderID, fid);
  176. msg->sendReliable(LLHost(payload["sender"].asString()));
  177. break;
  178. }
  179. case 1: // Decline
  180. case 2: // Send IM - decline and start IM session
  181. {
  182. // decline
  183. // We no longer notify other viewers, but we DO still send
  184. // the rejection to the simulator to delete the pending userop.
  185. msg->newMessageFast(_PREHASH_DeclineFriendship);
  186. msg->nextBlockFast(_PREHASH_AgentData);
  187. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  188. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  189. msg->nextBlockFast(_PREHASH_TransactionBlock);
  190. msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]);
  191. msg->sendReliable(LLHost(payload["sender"].asString()));
  192. // start IM session
  193. if(2 == option)
  194. {
  195. LLAvatarActions::startIM(payload["from_id"].asUUID());
  196. }
  197. }
  198. default:
  199. // close button probably, possibly timed out
  200. break;
  201. }
  202. return false;
  203. }
  204. static LLNotificationFunctorRegistration friendship_offer_callback_reg("OfferFriendship", friendship_offer_callback);
  205. static LLNotificationFunctorRegistration friendship_offer_callback_reg_nm("OfferFriendshipNoMessage", friendship_offer_callback);
  206. //const char BUSY_AUTO_RESPONSE[] = "The Resident you messaged is in 'busy mode' which means they have "
  207. // "requested not to be disturbed. Your message will still be shown in their IM "
  208. // "panel for later viewing.";
  209. //
  210. // Functions
  211. //
  212. void give_money(const LLUUID& uuid, LLViewerRegion* region, S32 amount, BOOL is_group,
  213. S32 trx_type, const std::string& desc)
  214. {
  215. if(0 == amount || !region) return;
  216. amount = abs(amount);
  217. LL_INFOS("Messaging") << "give_money(" << uuid << "," << amount << ")"<< LL_ENDL;
  218. if(can_afford_transaction(amount))
  219. {
  220. // gStatusBar->debitBalance(amount);
  221. LLMessageSystem* msg = gMessageSystem;
  222. msg->newMessageFast(_PREHASH_MoneyTransferRequest);
  223. msg->nextBlockFast(_PREHASH_AgentData);
  224. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  225.         msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  226. msg->nextBlockFast(_PREHASH_MoneyData);
  227. msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID() );
  228. msg->addUUIDFast(_PREHASH_DestID, uuid);
  229. msg->addU8Fast(_PREHASH_Flags, pack_transaction_flags(FALSE, is_group));
  230. msg->addS32Fast(_PREHASH_Amount, amount);
  231. msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY);
  232. msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY);
  233. msg->addS32Fast(_PREHASH_TransactionType, trx_type );
  234. msg->addStringFast(_PREHASH_Description, desc);
  235. msg->sendReliable(region->getHost());
  236. }
  237. else
  238. {
  239. LLFloaterBuyCurrency::buyCurrency("Giving", amount);
  240. }
  241. }
  242. void send_complete_agent_movement(const LLHost& sim_host)
  243. {
  244. LLMessageSystem* msg = gMessageSystem;
  245. msg->newMessageFast(_PREHASH_CompleteAgentMovement);
  246. msg->nextBlockFast(_PREHASH_AgentData);
  247. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  248. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  249. msg->addU32Fast(_PREHASH_CircuitCode, msg->mOurCircuitCode);
  250. msg->sendReliable(sim_host);
  251. }
  252. void process_logout_reply(LLMessageSystem* msg, void**)
  253. {
  254. // The server has told us it's ok to quit.
  255. LL_DEBUGS("Messaging") << "process_logout_reply" << LL_ENDL;
  256. LLUUID agent_id;
  257. msg->getUUID("AgentData", "AgentID", agent_id);
  258. LLUUID session_id;
  259. msg->getUUID("AgentData", "SessionID", session_id);
  260. if((agent_id != gAgent.getID()) || (session_id != gAgent.getSessionID()))
  261. {
  262. LL_WARNS("Messaging") << "Bogus Logout Reply" << LL_ENDL;
  263. }
  264. LLInventoryModel::update_map_t parents;
  265. S32 count = msg->getNumberOfBlocksFast( _PREHASH_InventoryData );
  266. for(S32 i = 0; i < count; ++i)
  267. {
  268. LLUUID item_id;
  269. msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id, i);
  270. if( (1 == count) && item_id.isNull() )
  271. {
  272. // Detect dummy item.  Indicates an empty list.
  273. break;
  274. }
  275. // We do not need to track the asset ids, just account for an
  276. // updated inventory version.
  277. LL_INFOS("Messaging") << "process_logout_reply itemID=" << item_id << LL_ENDL;
  278. LLInventoryItem* item = gInventory.getItem( item_id );
  279. if( item )
  280. {
  281. parents[item->getParentUUID()] = 0;
  282. gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item_id);
  283. }
  284. else
  285. {
  286. LL_INFOS("Messaging") << "process_logout_reply item not found: " << item_id << LL_ENDL;
  287. }
  288. }
  289.     LLAppViewer::instance()->forceQuit();
  290. }
  291. void process_layer_data(LLMessageSystem *mesgsys, void **user_data)
  292. {
  293. LLViewerRegion *regionp = LLWorld::getInstance()->getRegion(mesgsys->getSender());
  294. if (!regionp || gNoRender)
  295. {
  296. return;
  297. }
  298. S32 size;
  299. S8 type;
  300. mesgsys->getS8Fast(_PREHASH_LayerID, _PREHASH_Type, type);
  301. size = mesgsys->getSizeFast(_PREHASH_LayerData, _PREHASH_Data);
  302. if (0 == size)
  303. {
  304. LL_WARNS("Messaging") << "Layer data has zero size." << LL_ENDL;
  305. return;
  306. }
  307. if (size < 0)
  308. {
  309. // getSizeFast() is probably trying to tell us about an error
  310. LL_WARNS("Messaging") << "getSizeFast() returned negative result: "
  311. << size
  312. << LL_ENDL;
  313. return;
  314. }
  315. U8 *datap = new U8[size];
  316. mesgsys->getBinaryDataFast(_PREHASH_LayerData, _PREHASH_Data, datap, size);
  317. LLVLData *vl_datap = new LLVLData(regionp, type, datap, size);
  318. if (mesgsys->getReceiveCompressedSize())
  319. {
  320. gVLManager.addLayerData(vl_datap, mesgsys->getReceiveCompressedSize());
  321. }
  322. else
  323. {
  324. gVLManager.addLayerData(vl_datap, mesgsys->getReceiveSize());
  325. }
  326. }
  327. // S32 exported_object_count = 0;
  328. // S32 exported_image_count = 0;
  329. // S32 current_object_count = 0;
  330. // S32 current_image_count = 0;
  331. // extern LLNotifyBox *gExporterNotify;
  332. // extern LLUUID gExporterRequestID;
  333. // extern std::string gExportDirectory;
  334. // extern LLUploadDialog *gExportDialog;
  335. // std::string gExportedFile;
  336. // std::map<LLUUID, std::string> gImageChecksums;
  337. // void export_complete()
  338. // {
  339. //  LLUploadDialog::modalUploadFinished();
  340. //  gExporterRequestID.setNull();
  341. //  gExportDirectory = "";
  342. //  LLFILE* fXML = LLFile::fopen(gExportedFile, "rb"); /* Flawfinder: ignore */
  343. //  fseek(fXML, 0, SEEK_END);
  344. //  long length = ftell(fXML);
  345. //  fseek(fXML, 0, SEEK_SET);
  346. //  U8 *buffer = new U8[length + 1];
  347. //  size_t nread = fread(buffer, 1, length, fXML);
  348. //  if (nread < (size_t) length)
  349. //  {
  350. //  LL_WARNS("Messaging") << "Short read" << LL_ENDL;
  351. //  }
  352. //  buffer[nread] = '';
  353. //  fclose(fXML);
  354. //  char *pos = (char *)buffer;
  355. //  while ((pos = strstr(pos+1, "<sl:image ")) != 0)
  356. //  {
  357. //  char *pos_check = strstr(pos, "checksum="");
  358. //  if (pos_check)
  359. //  {
  360. //  char *pos_uuid = strstr(pos_check, "">");
  361. //  if (pos_uuid)
  362. //  {
  363. //  char image_uuid_str[UUID_STR_SIZE]; /* Flawfinder: ignore */
  364. //  memcpy(image_uuid_str, pos_uuid+2, UUID_STR_SIZE-1); /* Flawfinder: ignore */
  365. //  image_uuid_str[UUID_STR_SIZE-1] = 0;
  366. //  LLUUID image_uuid(image_uuid_str);
  367. //  LL_INFOS("Messaging") << "Found UUID: " << image_uuid << LL_ENDL;
  368. //  std::map<LLUUID, std::string>::iterator itor = gImageChecksums.find(image_uuid);
  369. //  if (itor != gImageChecksums.end())
  370. //  {
  371. //  LL_INFOS("Messaging") << "Replacing with checksum: " << itor->second << LL_ENDL;
  372. //  if (!itor->second.empty())
  373. //  {
  374. //  memcpy(&pos_check[10], itor->second.c_str(), 32); /* Flawfinder: ignore */
  375. //  }
  376. //  }
  377. //  }
  378. //  }
  379. //  }
  380. //  LLFILE* fXMLOut = LLFile::fopen(gExportedFile, "wb"); /* Flawfinder: ignore */
  381. //  if (fwrite(buffer, 1, length, fXMLOut) != length)
  382. //  {
  383. //  LL_WARNS("Messaging") << "Short write" << LL_ENDL;
  384. //  }
  385. //  fclose(fXMLOut);
  386. //  delete [] buffer;
  387. // }
  388. // void exported_item_complete(const LLTSCode status, void *user_data)
  389. // {
  390. //  //std::string *filename = (std::string *)user_data;
  391. //  if (status < LLTS_OK)
  392. //  {
  393. //  LL_WARNS("Messaging") << "Export failed!" << LL_ENDL;
  394. //  }
  395. //  else
  396. //  {
  397. //  ++current_object_count;
  398. //  if (current_image_count == exported_image_count && current_object_count == exported_object_count)
  399. //  {
  400. //  LL_INFOS("Messaging") << "*** Export complete ***" << LL_ENDL;
  401. //  export_complete();
  402. //  }
  403. //  else
  404. //  {
  405. //  gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count));
  406. //  }
  407. //  }
  408. // }
  409. // struct exported_image_info
  410. // {
  411. //  LLUUID image_id;
  412. //  std::string filename;
  413. //  U32 image_num;
  414. // };
  415. // void exported_j2c_complete(const LLTSCode status, void *user_data)
  416. // {
  417. //  exported_image_info *info = (exported_image_info *)user_data;
  418. //  LLUUID image_id = info->image_id;
  419. //  U32 image_num = info->image_num;
  420. //  std::string filename = info->filename;
  421. //  delete info;
  422. //  if (status < LLTS_OK)
  423. //  {
  424. //  LL_WARNS("Messaging") << "Image download failed!" << LL_ENDL;
  425. //  }
  426. //  else
  427. //  {
  428. //  LLFILE* fIn = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */
  429. //  if (fIn) 
  430. //  {
  431. //  LLPointer<LLImageJ2C> ImageUtility = new LLImageJ2C;
  432. //  LLPointer<LLImageTGA> TargaUtility = new LLImageTGA;
  433. //  fseek(fIn, 0, SEEK_END);
  434. //  S32 length = ftell(fIn);
  435. //  fseek(fIn, 0, SEEK_SET);
  436. //  U8 *buffer = ImageUtility->allocateData(length);
  437. //  if (fread(buffer, 1, length, fIn) != length)
  438. //  {
  439. //  LL_WARNS("Messaging") << "Short read" << LL_ENDL;
  440. //  }
  441. //  fclose(fIn);
  442. //  LLFile::remove(filename);
  443. //  // Convert to TGA
  444. //  LLPointer<LLImageRaw> image = new LLImageRaw();
  445. //  ImageUtility->updateData();
  446. //  ImageUtility->decode(image, 100000.0f);
  447. //  TargaUtility->encode(image);
  448. //  U8 *data = TargaUtility->getData();
  449. //  S32 data_size = TargaUtility->getDataSize();
  450. //  std::string file_path = gDirUtilp->getDirName(filename);
  451. //  std::string output_file = llformat("%s/image-%03d.tga", file_path.c_str(), image_num);//filename;
  452. //  //S32 name_len = output_file.length();
  453. //  //strcpy(&output_file[name_len-3], "tga");
  454. //  LLFILE* fOut = LLFile::fopen(output_file, "wb"); /* Flawfinder: ignore */
  455. //  char md5_hash_string[33]; /* Flawfinder: ignore */
  456. //  strcpy(md5_hash_string, "00000000000000000000000000000000"); /* Flawfinder: ignore */
  457. //  if (fOut)
  458. //  {
  459. //  if (fwrite(data, 1, data_size, fOut) != data_size)
  460. //  {
  461. //  LL_WARNS("Messaging") << "Short write" << LL_ENDL;
  462. //  }
  463. //  fseek(fOut, 0, SEEK_SET);
  464. //  fclose(fOut);
  465. //  fOut = LLFile::fopen(output_file, "rb"); /* Flawfinder: ignore */
  466. //  LLMD5 my_md5_hash(fOut);
  467. //  my_md5_hash.hex_digest(md5_hash_string);
  468. //  }
  469. //  gImageChecksums.insert(std::pair<LLUUID, std::string>(image_id, md5_hash_string));
  470. //  }
  471. //  }
  472. //  ++current_image_count;
  473. //  if (current_image_count == exported_image_count && current_object_count == exported_object_count)
  474. //  {
  475. //  LL_INFOS("Messaging") << "*** Export textures complete ***" << LL_ENDL;
  476. //  export_complete();
  477. //  }
  478. //  else
  479. //  {
  480. //  gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count));
  481. //  }
  482. //}
  483. void process_derez_ack(LLMessageSystem*, void**)
  484. {
  485. if(gViewerWindow) gViewerWindow->getWindow()->decBusyCount();
  486. }
  487. void process_places_reply(LLMessageSystem* msg, void** data)
  488. {
  489. LLUUID query_id;
  490. msg->getUUID("AgentData", "QueryID", query_id);
  491. if (query_id.isNull())
  492. {
  493. LLFloaterLandHoldings::processPlacesReply(msg, data);
  494. }
  495. else if(gAgent.isInGroup(query_id))
  496. {
  497. LLPanelGroupLandMoney::processPlacesReply(msg, data);
  498. }
  499. else
  500. {
  501. LL_WARNS("Messaging") << "Got invalid PlacesReply message" << LL_ENDL;
  502. }
  503. }
  504. void send_sound_trigger(const LLUUID& sound_id, F32 gain)
  505. {
  506. if (sound_id.isNull() || gAgent.getRegion() == NULL)
  507. {
  508. // disconnected agent or zero guids don't get sent (no sound)
  509. return;
  510. }
  511. LLMessageSystem* msg = gMessageSystem;
  512. msg->newMessageFast(_PREHASH_SoundTrigger);
  513. msg->nextBlockFast(_PREHASH_SoundData);
  514. msg->addUUIDFast(_PREHASH_SoundID, sound_id);
  515. // Client untrusted, ids set on sim
  516. msg->addUUIDFast(_PREHASH_OwnerID, LLUUID::null );
  517. msg->addUUIDFast(_PREHASH_ObjectID, LLUUID::null );
  518. msg->addUUIDFast(_PREHASH_ParentID, LLUUID::null );
  519. msg->addU64Fast(_PREHASH_Handle, gAgent.getRegion()->getHandle());
  520. LLVector3 position = gAgent.getPositionAgent();
  521. msg->addVector3Fast(_PREHASH_Position, position);
  522. msg->addF32Fast(_PREHASH_Gain, gain);
  523. gAgent.sendMessage();
  524. }
  525. bool join_group_response(const LLSD& notification, const LLSD& response)
  526. {
  527. S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
  528. BOOL delete_context_data = TRUE;
  529. bool accept_invite = false;
  530. LLUUID group_id = notification["payload"]["group_id"].asUUID();
  531. LLUUID transaction_id = notification["payload"]["transaction_id"].asUUID();
  532. std::string name = notification["payload"]["name"].asString();
  533. std::string message = notification["payload"]["message"].asString();
  534. S32 fee = notification["payload"]["fee"].asInteger();
  535. if (option == 2 && !group_id.isNull())
  536. {
  537. LLGroupActions::show(group_id);
  538. LLSD args;
  539. args["MESSAGE"] = message;
  540. LLNotificationsUtil::add("JoinGroup", args, notification["payload"]);
  541. return false;
  542. }
  543. if(option == 0 && !group_id.isNull())
  544. {
  545. // check for promotion or demotion.
  546. S32 max_groups = MAX_AGENT_GROUPS;
  547. if(gAgent.isInGroup(group_id)) ++max_groups;
  548. if(gAgent.mGroups.count() < max_groups)
  549. {
  550. accept_invite = true;
  551. }
  552. else
  553. {
  554. delete_context_data = FALSE;
  555. LLSD args;
  556. args["NAME"] = name;
  557. LLNotificationsUtil::add("JoinedTooManyGroupsMember", args, notification["payload"]);
  558. }
  559. }
  560. if (accept_invite)
  561. {
  562. // If there is a fee to join this group, make
  563. // sure the user is sure they want to join.
  564. if (fee > 0)
  565. {
  566. delete_context_data = FALSE;
  567. LLSD args;
  568. args["COST"] = llformat("%d", fee);
  569. // Set the fee for next time to 0, so that we don't keep
  570. // asking about a fee.
  571. LLSD next_payload = notification["payload"];
  572. next_payload["fee"] = 0;
  573. LLNotificationsUtil::add("JoinGroupCanAfford",
  574. args,
  575. next_payload);
  576. }
  577. else
  578. {
  579. send_improved_im(group_id,
  580.  std::string("name"),
  581.  std::string("message"),
  582. IM_ONLINE,
  583. IM_GROUP_INVITATION_ACCEPT,
  584. transaction_id);
  585. }
  586. }
  587. else
  588. {
  589. send_improved_im(group_id,
  590.  std::string("name"),
  591.  std::string("message"),
  592. IM_ONLINE,
  593. IM_GROUP_INVITATION_DECLINE,
  594. transaction_id);
  595. }
  596. return false;
  597. }
  598. static LLNotificationFunctorRegistration jgr_1("JoinGroup", join_group_response);
  599. static LLNotificationFunctorRegistration jgr_2("JoinedTooManyGroupsMember", join_group_response);
  600. static LLNotificationFunctorRegistration jgr_3("JoinGroupCanAfford", join_group_response);
  601. //-----------------------------------------------------------------------------
  602. // Instant Message
  603. //-----------------------------------------------------------------------------
  604. class LLOpenAgentOffer : public LLInventoryFetchObserver
  605. {
  606. public:
  607. LLOpenAgentOffer(const std::string& from_name) : mFromName(from_name) {}
  608. /*virtual*/ void done()
  609. {
  610. open_inventory_offer(mComplete, mFromName);
  611. gInventory.removeObserver(this);
  612. delete this;
  613. }
  614. private:
  615. std::string mFromName;
  616. };
  617. //unlike the FetchObserver for AgentOffer, we only make one 
  618. //instance of the AddedObserver for TaskOffers
  619. //and it never dies.  We do this because we don't know the UUID of 
  620. //task offers until they are accepted, so we don't wouldn't 
  621. //know what to watch for, so instead we just watch for all additions.
  622. class LLOpenTaskOffer : public LLInventoryAddedObserver
  623. {
  624. protected:
  625. /*virtual*/ void done()
  626. {
  627. open_inventory_offer(mAdded, "");
  628. mAdded.clear();
  629. }
  630.  };
  631. class LLOpenTaskGroupOffer : public LLInventoryAddedObserver
  632. {
  633. protected:
  634. /*virtual*/ void done()
  635. {
  636. open_inventory_offer(mAdded, "group_offer");
  637. mAdded.clear();
  638. gInventory.removeObserver(this);
  639. delete this;
  640. }
  641. };
  642. //one global instance to bind them
  643. LLOpenTaskOffer* gNewInventoryObserver=NULL;
  644. void start_new_inventory_observer()
  645. {
  646. if (!gNewInventoryObserver) //task offer observer 
  647. {
  648. // Observer is deleted by gInventory
  649. gNewInventoryObserver = new LLOpenTaskOffer;
  650. gInventory.addObserver(gNewInventoryObserver);
  651. }
  652. }
  653. class LLDiscardAgentOffer : public LLInventoryFetchComboObserver
  654. {
  655. LOG_CLASS(LLDiscardAgentOffer);
  656. public:
  657. LLDiscardAgentOffer(const LLUUID& folder_id, const LLUUID& object_id) :
  658. mFolderID(folder_id),
  659. mObjectID(object_id) {}
  660. virtual ~LLDiscardAgentOffer() {}
  661. virtual void done()
  662. {
  663. LL_DEBUGS("Messaging") << "LLDiscardAgentOffer::done()" << LL_ENDL;
  664. const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
  665. bool notify = false;
  666. if(trash_id.notNull() && mObjectID.notNull())
  667. {
  668. LLInventoryModel::update_list_t update;
  669. LLInventoryModel::LLCategoryUpdate old_folder(mFolderID, -1);
  670. update.push_back(old_folder);
  671. LLInventoryModel::LLCategoryUpdate new_folder(trash_id, 1);
  672. update.push_back(new_folder);
  673. gInventory.accountForUpdate(update);
  674. gInventory.moveObject(mObjectID, trash_id);
  675. LLInventoryObject* obj = gInventory.getObject(mObjectID);
  676. if(obj)
  677. {
  678. // no need to restamp since this is already a freshly
  679. // stamped item.
  680. obj->updateParentOnServer(FALSE);
  681. notify = true;
  682. }
  683. }
  684. else
  685. {
  686. LL_WARNS("Messaging") << "DiscardAgentOffer unable to find: "
  687. << (trash_id.isNull() ? "trash " : "")
  688. << (mObjectID.isNull() ? "object" : "") << LL_ENDL;
  689. }
  690. gInventory.removeObserver(this);
  691. if(notify)
  692. {
  693. gInventory.notifyObservers();
  694. }
  695. delete this;
  696. }
  697. protected:
  698. LLUUID mFolderID;
  699. LLUUID mObjectID;
  700. };
  701. //Returns TRUE if we are OK, FALSE if we are throttled
  702. //Set check_only true if you want to know the throttle status 
  703. //without registering a hit
  704. bool check_offer_throttle(const std::string& from_name, bool check_only)
  705. {
  706. static U32 throttle_count;
  707. static bool throttle_logged;
  708. LLChat chat;
  709. std::string log_message;
  710. if (!gSavedSettings.getBOOL("ShowNewInventory"))
  711. return false;
  712. if (check_only)
  713. {
  714. return gThrottleTimer.hasExpired();
  715. }
  716. if(gThrottleTimer.checkExpirationAndReset(OFFER_THROTTLE_TIME))
  717. {
  718. LL_DEBUGS("Messaging") << "Throttle Expired" << LL_ENDL;
  719. throttle_count=1;
  720. throttle_logged=false;
  721. return true;
  722. }
  723. else //has not expired
  724. {
  725. LL_DEBUGS("Messaging") << "Throttle Not Expired, Count: " << throttle_count << LL_ENDL;
  726. // When downloading the initial inventory we get a lot of new items
  727. // coming in and can't tell that from spam.
  728. if (LLStartUp::getStartupState() >= STATE_STARTED
  729. && throttle_count >= OFFER_THROTTLE_MAX_COUNT)
  730. {
  731. if (!throttle_logged)
  732. {
  733. // Use the name of the last item giver, who is probably the person
  734. // spamming you.
  735. std::ostringstream message;
  736. message << LLAppViewer::instance()->getSecondLifeTitle();
  737. if (!from_name.empty())
  738. {
  739. message << ": Items coming in too fast from " << from_name;
  740. }
  741. else
  742. {
  743. message << ": Items coming in too fast";
  744. }
  745. message << ", automatic preview disabled for "
  746. << OFFER_THROTTLE_TIME << " seconds.";
  747. //this is kinda important, so actually put it on screen
  748. std::string log_msg = message.str();
  749. LLSD args;
  750. args["MESSAGE"] = log_msg;
  751. LLNotificationsUtil::add("SystemMessage", args);
  752. throttle_logged=true;
  753. }
  754. return false;
  755. }
  756. else
  757. {
  758. throttle_count++;
  759. return true;
  760. }
  761. }
  762. }
  763.  
  764. void open_inventory_offer(const std::vector<LLUUID>& items, const std::string& from_name)
  765. {
  766. for (std::vector<LLUUID>::const_iterator item_iter = items.begin();
  767.  item_iter != items.end();
  768.  ++item_iter)
  769. {
  770. const LLUUID& item_id = (*item_iter);
  771. if(!highlight_offered_item(item_id))
  772. {
  773. continue;
  774. }
  775. LLInventoryItem* item = gInventory.getItem(item_id);
  776. llassert(item);
  777. if (!item) {
  778. continue;
  779. }
  780. ////////////////////////////////////////////////////////////////////////////////
  781. // Special handling for various types.
  782. const LLAssetType::EType asset_type = item->getType();
  783. if (check_offer_throttle(from_name, false)) // If we are throttled, don't display
  784. {
  785. LL_DEBUGS("Messaging") << "Highlighting inventory item: " << item->getUUID()  << LL_ENDL;
  786. // If we opened this ourselves, focus it
  787. const BOOL take_focus = from_name.empty() ? TAKE_FOCUS_YES : TAKE_FOCUS_NO;
  788. switch(asset_type)
  789. {
  790.   case LLAssetType::AT_NOTECARD:
  791.   {
  792.   LLFloaterReg::showInstance("preview_notecard", LLSD(item_id), take_focus);
  793.   break;
  794.   }
  795.   case LLAssetType::AT_LANDMARK:
  796.    {
  797. LLInventoryCategory* parent_folder = gInventory.getCategory(item->getParentUUID());
  798. if ("inventory_handler" == from_name)
  799. {
  800. //we have to filter inventory_handler messages to avoid notification displaying
  801. LLSideTray::getInstance()->showPanel("panel_places",
  802. LLSD().with("type", "landmark").with("id", item->getUUID()));
  803. }
  804. else if("group_offer" == from_name)
  805. {
  806. // do not open inventory when we open group notice attachment because 
  807. // we already opened landmark info panel
  808. // "group_offer" is passed by LLOpenTaskGroupOffer
  809. continue;
  810. }
  811. else if(from_name.empty())
  812. {
  813. // we receive a message from LLOpenTaskOffer, it mean that new landmark has been added.
  814. LLSD args;
  815. args["LANDMARK_NAME"] = item->getName();
  816. args["FOLDER_NAME"] = std::string(parent_folder ? parent_folder->getName() : "unknown");
  817. LLNotificationsUtil::add("LandmarkCreated", args);
  818. // Created landmark is passed to Places panel to allow its editing. In fact panel should be already displayed.
  819. // If the panel is closed we don't reopen it until created landmark is loaded.
  820. //TODO*:: dserduk(7/12/09) remove LLPanelPlaces dependency from here
  821. LLPanelPlaces *places_panel = dynamic_cast<LLPanelPlaces*>(LLSideTray::getInstance()->getPanel("panel_places"));
  822. if (places_panel)
  823. {
  824. // Landmark creation handling is moved to LLPanelPlaces::showAddedLandmarkInfo()
  825. // TODO* LLPanelPlaces dependency is going to be removed. See EXT-4347.
  826. //if("create_landmark" == places_panel->getPlaceInfoType() && !places_panel->getItem())
  827. //{
  828. // places_panel->setItem(item);
  829. //}
  830. //else
  831. // we are opening a group notice attachment
  832. if("create_landmark" != places_panel->getPlaceInfoType())
  833. {
  834. LLSD args;
  835. args["type"] = "landmark";
  836. args["id"] = item_id;
  837. LLSideTray::getInstance()->showPanel("panel_places", args);
  838. }
  839. }
  840. }
  841. }
  842. break;
  843.   case LLAssetType::AT_TEXTURE:
  844.   {
  845.   LLFloaterReg::showInstance("preview_texture", LLSD(item_id), take_focus);
  846.   break;
  847.   }
  848.   case LLAssetType::AT_ANIMATION:
  849.   LLFloaterReg::showInstance("preview_anim", LLSD(item_id), take_focus);
  850.   break;
  851.   case LLAssetType::AT_SCRIPT:
  852.   LLFloaterReg::showInstance("preview_script", LLSD(item_id), take_focus);
  853.   break;
  854.   case LLAssetType::AT_SOUND:
  855.   LLFloaterReg::showInstance("preview_sound", LLSD(item_id), take_focus);
  856.   break;
  857.   default:
  858. break;
  859. }
  860. }
  861. ////////////////////////////////////////////////////////////////////////////////
  862. // Highlight item if it's not in the trash, lost+found, or COF
  863. const BOOL auto_open = gSavedSettings.getBOOL("ShowInInventory") &&
  864. (asset_type != LLAssetType::AT_CALLINGCARD) &&
  865. (item->getInventoryType() != LLInventoryType::IT_ATTACHMENT) &&
  866. !from_name.empty();
  867. LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(auto_open);
  868. if(active_panel)
  869. {
  870. LL_DEBUGS("Messaging") << "Highlighting" << item_id  << LL_ENDL;
  871. LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus();
  872. active_panel->setSelection(item_id, TAKE_FOCUS_NO);
  873. gFocusMgr.setKeyboardFocus(focus_ctrl);
  874. }
  875. }
  876. }
  877. bool highlight_offered_item(const LLUUID& item_id)
  878. {
  879. LLInventoryItem* item = gInventory.getItem(item_id);
  880. if(!item)
  881. {
  882. LL_WARNS("Messaging") << "Unable to show inventory item: " << item_id << LL_ENDL;
  883. return false;
  884. }
  885. ////////////////////////////////////////////////////////////////////////////////
  886. // Don't highlight if it's in certain "quiet" folders which don't need UI
  887. // notification (e.g. trash, cof, lost-and-found).
  888. if(!gAgent.getAFK())
  889. {
  890. const LLViewerInventoryCategory *parent = gInventory.getFirstNondefaultParent(item_id);
  891. if (parent)
  892. {
  893. const LLFolderType::EType parent_type = parent->getPreferredType();
  894. if (LLViewerFolderType::lookupIsQuietType(parent_type))
  895. {
  896. return false;
  897. }
  898. }
  899. }
  900. return true;
  901. }
  902. void inventory_offer_mute_callback(const LLUUID& blocked_id,
  903.    const std::string& first_name,
  904.    const std::string& last_name,
  905.    BOOL is_group, LLOfferInfo* offer = NULL)
  906. {
  907. std::string from_name;
  908. LLMute::EType type;
  909. if (is_group)
  910. {
  911. type = LLMute::GROUP;
  912. from_name = first_name;
  913. }
  914. else if(offer && offer->mFromObject)
  915. {
  916. //we have to block object by name because blocked_id is an id of owner
  917. type = LLMute::BY_NAME;
  918. from_name = offer->mFromName;
  919. }
  920. else
  921. {
  922. type = LLMute::AGENT;
  923. from_name = first_name + " " + last_name;
  924. }
  925. // id should be null for BY_NAME mute, see  LLMuteList::add for details  
  926. LLMute mute(type == LLMute::BY_NAME ? LLUUID::null : blocked_id, from_name, type);
  927. if (LLMuteList::getInstance()->add(mute))
  928. {
  929. LLPanelBlockedList::showPanelAndSelect(blocked_id);
  930. }
  931. // purge the message queue of any previously queued inventory offers from the same source.
  932. class OfferMatcher : public LLNotificationsUI::LLScreenChannel::Matcher
  933. {
  934. public:
  935. OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) {}
  936. bool matches(const LLNotificationPtr notification) const
  937. {
  938. if(notification->getName() == "ObjectGiveItem" 
  939. || notification->getName() == "ObjectGiveItemUnknownUser"
  940. || notification->getName() == "UserGiveItem")
  941. {
  942. return (notification->getPayload()["from_id"].asUUID() == blocked_id);
  943. }
  944. return FALSE;
  945. }
  946. private:
  947. const LLUUID& blocked_id;
  948. };
  949. LLNotificationsUI::LLChannelManager::getInstance()->killToastsFromChannel(LLUUID(
  950. gSavedSettings.getString("NotificationChannelUUID")), OfferMatcher(blocked_id));
  951. }
  952. LLOfferInfo::LLOfferInfo(const LLSD& sd)
  953. {
  954. mIM = (EInstantMessage)sd["im_type"].asInteger();
  955. mFromID = sd["from_id"].asUUID();
  956. mFromGroup = sd["from_group"].asBoolean();
  957. mFromObject = sd["from_object"].asBoolean();
  958. mTransactionID = sd["transaction_id"].asUUID();
  959. mFolderID = sd["folder_id"].asUUID();
  960. mObjectID = sd["object_id"].asUUID();
  961. mType = LLAssetType::lookup(sd["type"].asString().c_str());
  962. mFromName = sd["from_name"].asString();
  963. mDesc = sd["description"].asString();
  964. mHost = LLHost(sd["sender"].asString());
  965. }
  966. LLSD LLOfferInfo::asLLSD()
  967. {
  968. LLSD sd;
  969. sd["im_type"] = mIM;
  970. sd["from_id"] = mFromID;
  971. sd["from_group"] = mFromGroup;
  972. sd["from_object"] = mFromObject;
  973. sd["transaction_id"] = mTransactionID;
  974. sd["folder_id"] = mFolderID;
  975. sd["object_id"] = mObjectID;
  976. sd["type"] = LLAssetType::lookup(mType);
  977. sd["from_name"] = mFromName;
  978. sd["description"] = mDesc;
  979. sd["sender"] = mHost.getIPandPort();
  980. return sd;
  981. }
  982. void LLOfferInfo::send_auto_receive_response(void)
  983. {
  984. LLMessageSystem* msg = gMessageSystem;
  985. msg->newMessageFast(_PREHASH_ImprovedInstantMessage);
  986. msg->nextBlockFast(_PREHASH_AgentData);
  987. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  988. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  989. msg->nextBlockFast(_PREHASH_MessageBlock);
  990. msg->addBOOLFast(_PREHASH_FromGroup, FALSE);
  991. msg->addUUIDFast(_PREHASH_ToAgentID, mFromID);
  992. msg->addU8Fast(_PREHASH_Offline, IM_ONLINE);
  993. msg->addUUIDFast(_PREHASH_ID, mTransactionID);
  994. msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary
  995. std::string name;
  996. LLAgentUI::buildFullname(name);
  997. msg->addStringFast(_PREHASH_FromAgentName, name);
  998. msg->addStringFast(_PREHASH_Message, ""); 
  999. msg->addU32Fast(_PREHASH_ParentEstateID, 0);
  1000. msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null);
  1001. msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent());
  1002. // Auto Receive Message. The math for the dialog works, because the accept
  1003. // for inventory_offered, task_inventory_offer or
  1004. // group_notice_inventory is 1 greater than the offer integer value.
  1005. // Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED, 
  1006. // or IM_GROUP_NOTICE_INVENTORY_ACCEPTED
  1007. msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 1));
  1008. msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(mFolderID.mData),
  1009.    sizeof(mFolderID.mData));
  1010. // send the message
  1011. msg->sendReliable(mHost);
  1012. if(IM_INVENTORY_OFFERED == mIM)
  1013. {
  1014. // add buddy to recent people list
  1015. LLRecentPeople::instance().add(mFromID);
  1016. }
  1017. }
  1018. bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& response)
  1019. {
  1020. LLChat chat;
  1021. std::string log_message;
  1022. S32 button = LLNotificationsUtil::getSelectedOption(notification, response);
  1023. LLInventoryObserver* opener = NULL;
  1024. LLViewerInventoryCategory* catp = NULL;
  1025. catp = (LLViewerInventoryCategory*)gInventory.getCategory(mObjectID);
  1026. LLViewerInventoryItem* itemp = NULL;
  1027. if(!catp)
  1028. {
  1029. itemp = (LLViewerInventoryItem*)gInventory.getItem(mObjectID);
  1030. }
  1031.  
  1032. // For muting, we need to add the mute, then decline the offer.
  1033. // This must be done here because:
  1034. // * callback may be called immediately,
  1035. // * adding the mute sends a message,
  1036. // * we can't build two messages at once.
  1037. if (2 == button) // Block
  1038. {
  1039. gCacheName->get(mFromID, mFromGroup, boost::bind(&inventory_offer_mute_callback,_1,_2,_3,_4,this));
  1040. }
  1041. std::string from_string; // Used in the pop-up.
  1042. std::string chatHistory_string;  // Used in chat history.
  1043. // TODO: when task inventory offers can also be handled the new way, migrate the code that sets these strings here:
  1044. from_string = chatHistory_string = mFromName;
  1045. bool busy=FALSE;
  1046. switch(button)
  1047. {
  1048. case IOR_SHOW:
  1049. // we will want to open this item when it comes back.
  1050. LL_DEBUGS("Messaging") << "Initializing an opener for tid: " << mTransactionID
  1051.  << LL_ENDL;
  1052. switch (mIM)
  1053. {
  1054. case IM_INVENTORY_OFFERED:
  1055. {
  1056. // This is an offer from an agent. In this case, the back
  1057. // end has already copied the items into your inventory,
  1058. // so we can fetch it out of our inventory.
  1059. LLInventoryFetchObserver::item_ref_t items;
  1060. items.push_back(mObjectID);
  1061. LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(from_string);
  1062. open_agent_offer->fetchItems(items);
  1063. if(catp || (itemp && itemp->isComplete()))
  1064. {
  1065. open_agent_offer->done();
  1066. }
  1067. else
  1068. {
  1069. opener = open_agent_offer;
  1070. }
  1071. }
  1072. break;
  1073. case IM_GROUP_NOTICE:
  1074. opener = new LLOpenTaskGroupOffer;
  1075. send_auto_receive_response();
  1076. break;
  1077. case IM_TASK_INVENTORY_OFFERED:
  1078. case IM_GROUP_NOTICE_REQUESTED:
  1079. // This is an offer from a task or group.
  1080. // We don't use a new instance of an opener
  1081. // We instead use the singular observer gOpenTaskOffer
  1082. // Since it already exists, we don't need to actually do anything
  1083. break;
  1084. default:
  1085. LL_WARNS("Messaging") << "inventory_offer_callback: unknown offer type" << LL_ENDL;
  1086. break;
  1087. }
  1088. break;
  1089. // end switch (mIM)
  1090. case IOR_ACCEPT:
  1091. //don't spam them if they are getting flooded
  1092. if (check_offer_throttle(mFromName, true))
  1093. {
  1094. log_message = chatHistory_string + " " + LLTrans::getString("InvOfferGaveYou") + " " + mDesc + LLTrans::getString(".");
  1095. LLSD args;
  1096. args["MESSAGE"] = log_message;
  1097. LLNotificationsUtil::add("SystemMessage", args);
  1098. }
  1099. break;
  1100. case IOR_BUSY:
  1101. //Busy falls through to decline.  Says to make busy message.
  1102. busy=TRUE;
  1103. case IOR_MUTE:
  1104. // MUTE falls through to decline
  1105. case IOR_DECLINE:
  1106. {
  1107. log_message = LLTrans::getString("InvOfferYouDecline") + " " + mDesc + " " + LLTrans::getString("InvOfferFrom") + " " + mFromName +".";
  1108. chat.mText = log_message;
  1109. if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::getInstance()->isLinden(mFromName) )  // muting for SL-42269
  1110. {
  1111. chat.mMuted = TRUE;
  1112. }
  1113. // *NOTE dzaporozhan
  1114. // Disabled logging to old chat floater to fix crash in group notices - EXT-4149
  1115. // LLFloaterChat::addChatHistory(chat);
  1116. LLInventoryFetchComboObserver::folder_ref_t folders;
  1117. LLInventoryFetchComboObserver::item_ref_t items;
  1118. items.push_back(mObjectID);
  1119. LLDiscardAgentOffer* discard_agent_offer;
  1120. discard_agent_offer = new LLDiscardAgentOffer(mFolderID, mObjectID);
  1121. discard_agent_offer->fetch(folders, items);
  1122. if(catp || (itemp && itemp->isComplete()))
  1123. {
  1124. discard_agent_offer->done();
  1125. }
  1126. else
  1127. {
  1128. opener = discard_agent_offer;
  1129. }
  1130. if (busy && (!mFromGroup && !mFromObject))
  1131. {
  1132. busy_message(gMessageSystem, mFromID);
  1133. }
  1134. break;
  1135. }
  1136. default:
  1137. // close button probably
  1138. // The item has already been fetched and is in your inventory, we simply won't highlight it
  1139. // OR delete it if the notification gets killed, since we don't want that to be a vector for 
  1140. // losing inventory offers.
  1141. break;
  1142. }
  1143. if(opener)
  1144. {
  1145. gInventory.addObserver(opener);
  1146. }
  1147. delete this;
  1148. return false;
  1149. }
  1150. bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const LLSD& response)
  1151. {
  1152. LLChat chat;
  1153. std::string log_message;
  1154. S32 button = LLNotification::getSelectedOption(notification, response);
  1155. // For muting, we need to add the mute, then decline the offer.
  1156. // This must be done here because:
  1157. // * callback may be called immediately,
  1158. // * adding the mute sends a message,
  1159. // * we can't build two messages at once.
  1160. if (2 == button)
  1161. {
  1162. gCacheName->get(mFromID, mFromGroup, boost::bind(&inventory_offer_mute_callback,_1,_2,_3,_4,this));
  1163. }
  1164. LLMessageSystem* msg = gMessageSystem;
  1165. msg->newMessageFast(_PREHASH_ImprovedInstantMessage);
  1166. msg->nextBlockFast(_PREHASH_AgentData);
  1167. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  1168. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  1169. msg->nextBlockFast(_PREHASH_MessageBlock);
  1170. msg->addBOOLFast(_PREHASH_FromGroup, FALSE);
  1171. msg->addUUIDFast(_PREHASH_ToAgentID, mFromID);
  1172. msg->addU8Fast(_PREHASH_Offline, IM_ONLINE);
  1173. msg->addUUIDFast(_PREHASH_ID, mTransactionID);
  1174. msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary
  1175. std::string name;
  1176. LLAgentUI::buildFullname(name);
  1177. msg->addStringFast(_PREHASH_FromAgentName, name);
  1178. msg->addStringFast(_PREHASH_Message, ""); 
  1179. msg->addU32Fast(_PREHASH_ParentEstateID, 0);
  1180. msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null);
  1181. msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent());
  1182. LLInventoryObserver* opener = NULL;
  1183. std::string from_string; // Used in the pop-up.
  1184. std::string chatHistory_string;  // Used in chat history.
  1185. if (mFromObject == TRUE)
  1186. {
  1187. if (mFromGroup)
  1188. {
  1189. std::string group_name;
  1190. if (gCacheName->getGroupName(mFromID, group_name))
  1191. {
  1192. from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+"'" 
  1193. + mFromName + LLTrans::getString("'") +" " + LLTrans::getString("InvOfferOwnedByGroup") 
  1194. + " "+ "'" + group_name + "'";
  1195. chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByGroup") 
  1196. + " " + group_name + "'";
  1197. }
  1198. else
  1199. {
  1200. from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+"'"
  1201. + mFromName +"'"+ " " + LLTrans::getString("InvOfferOwnedByUnknownGroup");
  1202. chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownGroup");
  1203. }
  1204. }
  1205. else
  1206. {
  1207. std::string first_name, last_name;
  1208. if (gCacheName->getName(mFromID, first_name, last_name))
  1209. {
  1210. from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+ LLTrans::getString("'") + mFromName 
  1211. + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedBy") + first_name + " " + last_name;
  1212. chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedBy") + " " + first_name + " " + last_name;
  1213. }
  1214. else
  1215. {
  1216. from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+LLTrans::getString("'") 
  1217. + mFromName + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedByUnknownUser");
  1218. chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownUser");
  1219. }
  1220. }
  1221. }
  1222. else
  1223. {
  1224. from_string = chatHistory_string = mFromName;
  1225. }
  1226. bool busy=FALSE;
  1227. switch(button)
  1228. {
  1229. case IOR_ACCEPT:
  1230. // ACCEPT. The math for the dialog works, because the accept
  1231. // for inventory_offered, task_inventory_offer or
  1232. // group_notice_inventory is 1 greater than the offer integer value.
  1233. // Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED, 
  1234. // or IM_GROUP_NOTICE_INVENTORY_ACCEPTED
  1235. msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 1));
  1236. msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(mFolderID.mData),
  1237.    sizeof(mFolderID.mData));
  1238. // send the message
  1239. msg->sendReliable(mHost);
  1240. //don't spam them if they are getting flooded
  1241. if (check_offer_throttle(mFromName, true))
  1242. {
  1243. log_message = chatHistory_string + " " + LLTrans::getString("InvOfferGaveYou") + " " + mDesc + LLTrans::getString(".");
  1244. LLSD args;
  1245. args["MESSAGE"] = log_message;
  1246. LLNotificationsUtil::add("SystemMessage", args);
  1247. }
  1248. // we will want to open this item when it comes back.
  1249. LL_DEBUGS("Messaging") << "Initializing an opener for tid: " << mTransactionID
  1250. << LL_ENDL;
  1251. switch (mIM)
  1252. {
  1253. case IM_TASK_INVENTORY_OFFERED:
  1254. case IM_GROUP_NOTICE:
  1255. case IM_GROUP_NOTICE_REQUESTED:
  1256. {
  1257. // This is an offer from a task or group.
  1258. // We don't use a new instance of an opener
  1259. // We instead use the singular observer gOpenTaskOffer
  1260. // Since it already exists, we don't need to actually do anything
  1261. }
  1262. break;
  1263. default:
  1264. LL_WARNS("Messaging") << "inventory_offer_callback: unknown offer type" << LL_ENDL;
  1265. break;
  1266. } // end switch (mIM)
  1267. break;
  1268. case IOR_BUSY:
  1269. //Busy falls through to decline.  Says to make busy message.
  1270. busy=TRUE;
  1271. case IOR_MUTE:
  1272. // MUTE falls through to decline
  1273. case IOR_DECLINE:
  1274. // DECLINE. The math for the dialog works, because the decline
  1275. // for inventory_offered, task_inventory_offer or
  1276. // group_notice_inventory is 2 greater than the offer integer value.
  1277. // Generates IM_INVENTORY_DECLINED, IM_TASK_INVENTORY_DECLINED,
  1278. // or IM_GROUP_NOTICE_INVENTORY_DECLINED
  1279. default:
  1280. // close button probably (or any of the fall-throughs from above)
  1281. msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 2));
  1282. msg->addBinaryDataFast(_PREHASH_BinaryBucket, EMPTY_BINARY_BUCKET, EMPTY_BINARY_BUCKET_SIZE);
  1283. // send the message
  1284. msg->sendReliable(mHost);
  1285. log_message = LLTrans::getString("InvOfferYouDecline") + " " + mDesc + " " + LLTrans::getString("InvOfferFrom") + " " + mFromName +".";
  1286. LLSD args;
  1287. args["MESSAGE"] = log_message;
  1288. LLNotificationsUtil::add("SystemMessage", args);
  1289. if (busy && (!mFromGroup && !mFromObject))
  1290. {
  1291. busy_message(msg,mFromID);
  1292. }
  1293. break;
  1294. }
  1295. if(opener)
  1296. {
  1297. gInventory.addObserver(opener);
  1298. }
  1299. delete this;
  1300. return false;
  1301. }
  1302. void inventory_offer_handler(LLOfferInfo* info)
  1303. {
  1304. //Until throttling is implmented, busy mode should reject inventory instead of silently
  1305. //accepting it.  SEE SL-39554
  1306. if (gAgent.getBusy())
  1307. {
  1308. info->forceResponse(IOR_BUSY);
  1309. return;
  1310. }
  1311. //If muted, don't even go through the messaging stuff.  Just curtail the offer here.
  1312. if (LLMuteList::getInstance()->isMuted(info->mFromID, info->mFromName))
  1313. {
  1314. info->forceResponse(IOR_MUTE);
  1315. return;
  1316. }
  1317. // Avoid the Accept/Discard dialog if the user so desires. JC
  1318. if (gSavedSettings.getBOOL("AutoAcceptNewInventory")
  1319. && (info->mType == LLAssetType::AT_NOTECARD
  1320. || info->mType == LLAssetType::AT_LANDMARK
  1321. || info->mType == LLAssetType::AT_TEXTURE))
  1322. {
  1323. // For certain types, just accept the items into the inventory,
  1324. // and possibly open them on receipt depending upon "ShowNewInventory".
  1325. info->forceResponse(IOR_ACCEPT);
  1326. return;
  1327. }
  1328. // Strip any SLURL from the message display. (DEV-2754)
  1329. std::string msg = info->mDesc;
  1330. int indx = msg.find(" ( http://slurl.com/secondlife/");
  1331. if(indx == std::string::npos)
  1332. {
  1333. // try to find new slurl host
  1334. indx = msg.find(" ( http://maps.secondlife.com/secondlife/");
  1335. }
  1336. if(indx >= 0)
  1337. {
  1338. LLStringUtil::truncate(msg, indx);
  1339. }
  1340. LLSD args;
  1341. args["[OBJECTNAME]"] = msg;
  1342. LLSD payload;
  1343. // must protect against a NULL return from lookupHumanReadable()
  1344. std::string typestr = ll_safe_string(LLAssetType::lookupHumanReadable(info->mType));
  1345. if (!typestr.empty())
  1346. {
  1347. args["OBJECTTYPE"] = typestr;
  1348. }
  1349. else
  1350. {
  1351. LL_WARNS("Messaging") << "LLAssetType::lookupHumanReadable() returned NULL - probably bad asset type: " << info->mType << LL_ENDL;
  1352. args["OBJECTTYPE"] = "";
  1353. // This seems safest, rather than propagating bogosity
  1354. LL_WARNS("Messaging") << "Forcing an inventory-decline for probably-bad asset type." << LL_ENDL;
  1355. info->forceResponse(IOR_DECLINE);
  1356. return;
  1357. }
  1358. // Name cache callbacks don't store userdata, so can't save
  1359. // off the LLOfferInfo.  Argh.
  1360. BOOL name_found = FALSE;
  1361. if (info->mFromGroup)
  1362. {
  1363. std::string group_name;
  1364. if (gCacheName->getGroupName(info->mFromID, group_name))
  1365. {
  1366. args["FIRST"] = group_name;
  1367. args["LAST"] = "";
  1368. name_found = TRUE;
  1369. }
  1370. }
  1371. else
  1372. {
  1373. std::string first_name, last_name;
  1374. if (gCacheName->getName(info->mFromID, first_name, last_name))
  1375. {
  1376. args["FIRST"] = first_name;
  1377. args["LAST"] = last_name;
  1378. name_found = TRUE;
  1379. }
  1380. }
  1381. // If mObjectID is null then generate the object_id based on msg to prevent
  1382. // multiple creation of chiclets for same object.
  1383. LLUUID object_id = info->mObjectID;
  1384. if (object_id.isNull())
  1385. object_id.generate(msg);
  1386. payload["from_id"] = info->mFromID;
  1387. // Needed by LLScriptFloaterManager to bind original notification with 
  1388. // faked for toast one.
  1389. payload["object_id"] = object_id;
  1390. // Flag indicating that this notification is faked for toast.
  1391. payload["give_inventory_notification"] = FALSE;
  1392. args["OBJECTFROMNAME"] = info->mFromName;
  1393. args["NAME"] = info->mFromName;
  1394. args["NAME_SLURL"] = LLSLURL::buildCommand("agent", info->mFromID, "about");
  1395. std::string verb = "select?name=" + LLURI::escape(msg);
  1396. args["ITEM_SLURL"] = LLSLURL::buildCommand("inventory", info->mObjectID, verb.c_str());
  1397. LLNotification::Params p("ObjectGiveItem");
  1398. // Object -> Agent Inventory Offer
  1399. if (info->mFromObject)
  1400. {
  1401. // Inventory Slurls don't currently work for non agent transfers, so only display the object name.
  1402. args["ITEM_SLURL"] = msg;
  1403. // Note: sets inventory_task_offer_callback as the callback
  1404. p.substitutions(args).payload(payload).functor.function(boost::bind(&LLOfferInfo::inventory_task_offer_callback, info, _1, _2));
  1405. p.name = name_found ? "ObjectGiveItem" : "ObjectGiveItemUnknownUser";
  1406. // Pop up inv offer chiclet and let the user accept (keep), or reject (and silently delete) the inventory.
  1407. LLNotifications::instance().add(p);
  1408. }
  1409. else // Agent -> Agent Inventory Offer
  1410. {
  1411. // Note: sets inventory_offer_callback as the callback
  1412. p.substitutions(args).payload(payload).functor.function(boost::bind(&LLOfferInfo::inventory_offer_callback, info, _1, _2));
  1413. p.name = "UserGiveItem";
  1414. // Prefetch the item into your local inventory.
  1415. LLInventoryFetchObserver::item_ref_t items;
  1416. items.push_back(info->mObjectID);
  1417. LLInventoryFetchObserver* fetch_item = new LLInventoryFetchObserver();
  1418. fetch_item->fetchItems(items);
  1419. if(fetch_item->isEverythingComplete())
  1420. {
  1421. fetch_item->done();
  1422. }
  1423. else
  1424. {
  1425. gInventory.addObserver(fetch_item);
  1426. }
  1427. // In viewer 2 we're now auto receiving inventory offers and messaging as such (not sending reject messages).
  1428. info->send_auto_receive_response();
  1429. // Inform user that there is a script floater via toast system
  1430. {
  1431. payload["give_inventory_notification"] = TRUE;
  1432. LLNotificationPtr notification = LLNotifications::instance().add(p.payload(payload)); 
  1433. }
  1434. }
  1435. }
  1436. bool lure_callback(const LLSD& notification, const LLSD& response)
  1437. {
  1438. S32 option = 0;
  1439. if (response.isInteger()) 
  1440. {
  1441. option = response.asInteger();
  1442. }
  1443. else
  1444. {
  1445. option = LLNotificationsUtil::getSelectedOption(notification, response);
  1446. }
  1447. LLUUID from_id = notification["payload"]["from_id"].asUUID();
  1448. LLUUID lure_id = notification["payload"]["lure_id"].asUUID();
  1449. BOOL godlike = notification["payload"]["godlike"].asBoolean();
  1450. switch(option)
  1451. {
  1452. case 0:
  1453. {
  1454. // accept
  1455. gAgent.teleportViaLure(lure_id, godlike);
  1456. }
  1457. break;
  1458. case 1:
  1459. default:
  1460. // decline
  1461. send_simple_im(from_id,
  1462.    LLStringUtil::null,
  1463.    IM_LURE_DECLINED,
  1464.    lure_id);
  1465. break;
  1466. }
  1467. return false;
  1468. }
  1469. static LLNotificationFunctorRegistration lure_callback_reg("TeleportOffered", lure_callback);
  1470. bool goto_url_callback(const LLSD& notification, const LLSD& response)
  1471. {
  1472. std::string url = notification["payload"]["url"].asString();
  1473. S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
  1474. if(1 == option)
  1475. {
  1476. LLWeb::loadURL(url);
  1477. }
  1478. return false;
  1479. }
  1480. static LLNotificationFunctorRegistration goto_url_callback_reg("GotoURL", goto_url_callback);
  1481. bool inspect_remote_object_callback(const LLSD& notification, const LLSD& response)
  1482. {
  1483. S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
  1484. if (0 == option)
  1485. {
  1486. LLFloaterReg::showInstance("inspect_remote_object", notification["payload"]);
  1487. }
  1488. return false;
  1489. }
  1490. static LLNotificationFunctorRegistration inspect_remote_object_callback_reg("ServerObjectMessage", inspect_remote_object_callback);
  1491. void process_improved_im(LLMessageSystem *msg, void **user_data)
  1492. {
  1493. if (gNoRender)
  1494. {
  1495. return;
  1496. }
  1497. LLUUID from_id;
  1498. BOOL from_group;
  1499. LLUUID to_id;
  1500. U8 offline;
  1501. U8 d = 0;
  1502. LLUUID session_id;
  1503. U32 timestamp;
  1504. std::string name;
  1505. std::string message;
  1506. U32 parent_estate_id = 0;
  1507. LLUUID region_id;
  1508. LLVector3 position;
  1509. U8 binary_bucket[MTUBYTES];
  1510. S32 binary_bucket_size;
  1511. LLChat chat;
  1512. std::string buffer;
  1513. // *TODO: Translate - need to fix the full name to first/last (maybe)
  1514. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, from_id);
  1515. msg->getBOOLFast(_PREHASH_MessageBlock, _PREHASH_FromGroup, from_group);
  1516. msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ToAgentID, to_id);
  1517. msg->getU8Fast(  _PREHASH_MessageBlock, _PREHASH_Offline, offline);
  1518. msg->getU8Fast(  _PREHASH_MessageBlock, _PREHASH_Dialog, d);
  1519. msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ID, session_id);
  1520. msg->getU32Fast( _PREHASH_MessageBlock, _PREHASH_Timestamp, timestamp);
  1521. //msg->getData("MessageBlock", "Count", &count);
  1522. msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_FromAgentName, name);
  1523. msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_Message, message);
  1524. msg->getU32Fast(_PREHASH_MessageBlock, _PREHASH_ParentEstateID, parent_estate_id);
  1525. msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_RegionID, region_id);
  1526. msg->getVector3Fast(_PREHASH_MessageBlock, _PREHASH_Position, position);
  1527. msg->getBinaryDataFast(  _PREHASH_MessageBlock, _PREHASH_BinaryBucket, binary_bucket, 0, 0, MTUBYTES);
  1528. binary_bucket_size = msg->getSizeFast(_PREHASH_MessageBlock, _PREHASH_BinaryBucket);
  1529. EInstantMessage dialog = (EInstantMessage)d;
  1530.     // make sure that we don't have an empty or all-whitespace name
  1531. LLStringUtil::trim(name);
  1532. if (name.empty())
  1533. {
  1534.         name = LLTrans::getString("Unnamed");
  1535. }
  1536. BOOL is_busy = gAgent.getBusy();
  1537. BOOL is_muted = LLMuteList::getInstance()->isMuted(from_id, name, LLMute::flagTextChat);
  1538. BOOL is_linden = LLMuteList::getInstance()->isLinden(name);
  1539. BOOL is_owned_by_me = FALSE;
  1540. BOOL is_friend = (LLAvatarTracker::instance().getBuddyInfo(from_id) == NULL) ? false : true;
  1541. BOOL accept_im_from_only_friend = gSavedSettings.getBOOL("VoiceCallsFriendsOnly");
  1542. chat.mMuted = is_muted && !is_linden;
  1543. chat.mFromID = from_id;
  1544. chat.mFromName = name;
  1545. chat.mSourceType = (from_id.isNull() || (name == std::string(SYSTEM_FROM))) ? CHAT_SOURCE_SYSTEM : CHAT_SOURCE_AGENT;
  1546. LLViewerObject *source = gObjectList.findObject(session_id); //Session ID is probably the wrong thing.
  1547. if (source)
  1548. {
  1549. is_owned_by_me = source->permYouOwner();
  1550. }
  1551. std::string separator_string(": ");
  1552. LLSD args;
  1553. switch(dialog)
  1554. {
  1555. case IM_CONSOLE_AND_CHAT_HISTORY:
  1556. // These are used for system messages, hence don't need the name,
  1557. // as it is always "Second Life".
  1558.    // *TODO: Translate
  1559. args["MESSAGE"] = message;
  1560. // Note: don't put the message in the IM history, even though was sent
  1561. // via the IM mechanism.
  1562. LLNotificationsUtil::add("SystemMessageTip",args);
  1563. break;
  1564. case IM_NOTHING_SPECIAL: 
  1565. // Don't show dialog, just do IM
  1566. if (!gAgent.isGodlike()
  1567. && gAgent.getRegion()->isPrelude() 
  1568. && to_id.isNull() )
  1569. {
  1570. // do nothing -- don't distract newbies in
  1571. // Prelude with global IMs
  1572. }
  1573. else if (offline == IM_ONLINE && !is_linden && is_busy && name != SYSTEM_FROM)
  1574. {
  1575. // return a standard "busy" message, but only do it to online IM 
  1576. // (i.e. not other auto responses and not store-and-forward IM)
  1577. if (!gIMMgr->hasSession(session_id))
  1578. {
  1579. // if there is not a panel for this conversation (i.e. it is a new IM conversation
  1580. // initiated by the other party) then...
  1581. std::string my_name;
  1582. LLAgentUI::buildFullname(my_name);
  1583. std::string response = gSavedPerAccountSettings.getString("BusyModeResponse2");
  1584. pack_instant_message(
  1585. gMessageSystem,
  1586. gAgent.getID(),
  1587. FALSE,
  1588. gAgent.getSessionID(),
  1589. from_id,
  1590. my_name,
  1591. response,
  1592. IM_ONLINE,
  1593. IM_BUSY_AUTO_RESPONSE,
  1594. session_id);
  1595. gAgent.sendReliableMessage();
  1596. }
  1597. // now store incoming IM in chat history
  1598. buffer = message;
  1599. LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL;
  1600. // add to IM panel, but do not bother the user
  1601. gIMMgr->addMessage(
  1602. session_id,
  1603. from_id,
  1604. name,
  1605. buffer,
  1606. LLStringUtil::null,
  1607. dialog,
  1608. parent_estate_id,
  1609. region_id,
  1610. position,
  1611. true);
  1612. }
  1613. else if (from_id.isNull())
  1614. {
  1615. LLSD args;
  1616. args["MESSAGE"] = message;
  1617. LLNotificationsUtil::add("SystemMessage", args);
  1618. }
  1619. else if (to_id.isNull())
  1620. {
  1621. // Message to everyone from GOD
  1622. args["NAME"] = name;
  1623. args["MESSAGE"] = message;
  1624. LLNotificationsUtil::add("GodMessage", args);
  1625. // Treat like a system message and put in chat history.
  1626. // Claim to be from a local agent so it doesn't go into
  1627. // console.
  1628. chat.mText = name + separator_string + message;
  1629. LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD());
  1630. if(nearby_chat)
  1631. {
  1632. nearby_chat->addMessage(chat);
  1633. }
  1634. }
  1635. else
  1636. {
  1637. // standard message, not from system
  1638. std::string saved;
  1639. if(offline == IM_OFFLINE)
  1640. {
  1641. saved = llformat("(Saved %s) ", formatted_time(timestamp).c_str());
  1642. }
  1643. buffer = saved + message;
  1644. LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL;
  1645. bool mute_im = is_muted;
  1646. if(accept_im_from_only_friend&&!is_friend)
  1647. {
  1648. mute_im = true;
  1649. }
  1650. if (!mute_im || is_linden) 
  1651. {
  1652. gIMMgr->addMessage(
  1653. session_id,
  1654. from_id,
  1655. name,
  1656. buffer,
  1657. LLStringUtil::null,
  1658. dialog,
  1659. parent_estate_id,
  1660. region_id,
  1661. position,
  1662. true);
  1663. }
  1664. else
  1665. {
  1666. /*
  1667. EXT-5099
  1668. currently there is no way to store in history only...
  1669. using  LLNotificationsUtil::add will add message to Nearby Chat
  1670. // muted user, so don't start an IM session, just record line in chat
  1671. // history.  Pretend the chat is from a local agent,
  1672. // so it will go into the history but not be shown on screen.
  1673. LLSD args;
  1674. args["MESSAGE"] = buffer;
  1675. LLNotificationsUtil::add("SystemMessageTip", args);
  1676. */
  1677. }
  1678. }
  1679. break;
  1680. case IM_TYPING_START:
  1681. {
  1682. LLPointer<LLIMInfo> im_info = new LLIMInfo(gMessageSystem);
  1683. gIMMgr->processIMTypingStart(im_info);
  1684. }
  1685. break;
  1686. case IM_TYPING_STOP:
  1687. {
  1688. LLPointer<LLIMInfo> im_info = new LLIMInfo(gMessageSystem);
  1689. gIMMgr->processIMTypingStop(im_info);
  1690. }
  1691. break;
  1692. case IM_MESSAGEBOX:
  1693. {
  1694. // This is a block, modeless dialog.
  1695. //*TODO: Translate
  1696. args["MESSAGE"] = message;
  1697. LLNotificationsUtil::add("SystemMessageTip", args);
  1698. }
  1699. break;
  1700. case IM_GROUP_NOTICE:
  1701. case IM_GROUP_NOTICE_REQUESTED:
  1702. {
  1703. LL_INFOS("Messaging") << "Received IM_GROUP_NOTICE message." << LL_ENDL;
  1704. // Read the binary bucket for more information.
  1705. struct notice_bucket_header_t
  1706. {
  1707. U8 has_inventory;
  1708. U8 asset_type;
  1709. LLUUID group_id;
  1710. };
  1711. struct notice_bucket_full_t
  1712. {
  1713. struct notice_bucket_header_t header;
  1714. U8 item_name[DB_INV_ITEM_NAME_BUF_SIZE];
  1715. }* notice_bin_bucket;
  1716. // Make sure the binary bucket is big enough to hold the header 
  1717. // and a null terminated item name.
  1718. if ( (binary_bucket_size < (S32)((sizeof(notice_bucket_header_t) + sizeof(U8))))
  1719. || (binary_bucket[binary_bucket_size - 1] != '') )
  1720. {
  1721. LL_WARNS("Messaging") << "Malformed group notice binary bucket" << LL_ENDL;
  1722. break;
  1723. }
  1724. notice_bin_bucket = (struct notice_bucket_full_t*) &binary_bucket[0];
  1725. U8 has_inventory = notice_bin_bucket->header.has_inventory;
  1726. U8 asset_type = notice_bin_bucket->header.asset_type;
  1727. LLUUID group_id = notice_bin_bucket->header.group_id;
  1728. std::string item_name = ll_safe_string((const char*) notice_bin_bucket->item_name);
  1729. // If there is inventory, give the user the inventory offer.
  1730. LLOfferInfo* info = NULL;
  1731. if (has_inventory)
  1732. {
  1733. info = new LLOfferInfo();
  1734. info->mIM = IM_GROUP_NOTICE;
  1735. info->mFromID = from_id;
  1736. info->mFromGroup = from_group;
  1737. info->mTransactionID = session_id;
  1738. info->mType = (LLAssetType::EType) asset_type;
  1739. info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType));
  1740. std::string from_name;
  1741. from_name += "A group member named ";
  1742. from_name += name;
  1743. info->mFromName = from_name;
  1744. info->mDesc = item_name;
  1745. info->mHost = msg->getSender();
  1746. }
  1747. std::string str(message);
  1748. // Tokenize the string.
  1749. // TODO: Support escaped tokens ("||" -> "|")
  1750. typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
  1751. boost::char_separator<char> sep("|","",boost::keep_empty_tokens);
  1752. tokenizer tokens(str, sep);
  1753. tokenizer::iterator iter = tokens.begin();
  1754. std::string subj(*iter++);
  1755. std::string mes(*iter++);
  1756. // Send the notification down the new path.
  1757. // For requested notices, we don't want to send the popups.
  1758. if (dialog != IM_GROUP_NOTICE_REQUESTED)
  1759. {
  1760. LLSD payload;
  1761. payload["subject"] = subj;
  1762. payload["message"] = mes;
  1763. payload["sender_name"] = name;
  1764. payload["group_id"] = group_id;
  1765. payload["inventory_name"] = item_name;
  1766. payload["inventory_offer"] = info ? info->asLLSD() : LLSD();
  1767. LLSD args;
  1768. args["SUBJECT"] = subj;
  1769. args["MESSAGE"] = mes;
  1770. LLNotifications::instance().add(LLNotification::Params("GroupNotice").substitutions(args).payload(payload).time_stamp(timestamp));
  1771. }
  1772. // Also send down the old path for now.
  1773. if (IM_GROUP_NOTICE_REQUESTED == dialog)
  1774. {
  1775. LLPanelGroup::showNotice(subj,mes,group_id,has_inventory,item_name,info);
  1776. }
  1777. else
  1778. {
  1779. delete info;
  1780. }
  1781. }
  1782. break;
  1783. case IM_GROUP_INVITATION:
  1784. {
  1785. //if (!is_linden && (is_busy || is_muted))
  1786. if ((is_busy || is_muted))
  1787. {
  1788. LLMessageSystem *msg = gMessageSystem;
  1789. busy_message(msg,from_id);
  1790. }
  1791. else
  1792. {
  1793. LL_INFOS("Messaging") << "Received IM_GROUP_INVITATION message." << LL_ENDL;
  1794. // Read the binary bucket for more information.
  1795. struct invite_bucket_t
  1796. {
  1797. S32 membership_fee;
  1798. LLUUID role_id;
  1799. }* invite_bucket;
  1800. // Make sure the binary bucket is the correct size.
  1801. if (binary_bucket_size != sizeof(invite_bucket_t))
  1802. {
  1803. LL_WARNS("Messaging") << "Malformed group invite binary bucket" << LL_ENDL;
  1804. break;
  1805. }
  1806. invite_bucket = (struct invite_bucket_t*) &binary_bucket[0];
  1807. S32 membership_fee = ntohl(invite_bucket->membership_fee);
  1808. LLSD payload;
  1809. payload["transaction_id"] = session_id;
  1810. payload["group_id"] = from_id;
  1811. payload["name"] = name;
  1812. payload["message"] = message;
  1813. payload["fee"] = membership_fee;
  1814. LLSD args;
  1815. args["MESSAGE"] = message;
  1816. LLNotificationsUtil::add("JoinGroup", args, payload, join_group_response);
  1817. }
  1818. }
  1819. break;
  1820. case IM_INVENTORY_OFFERED:
  1821. case IM_TASK_INVENTORY_OFFERED:
  1822. // Someone has offered us some inventory.
  1823. {
  1824. LLOfferInfo* info = new LLOfferInfo;
  1825. if (IM_INVENTORY_OFFERED == dialog)
  1826. {
  1827. struct offer_agent_bucket_t
  1828. {
  1829. S8 asset_type;
  1830. LLUUID object_id;
  1831. }* bucketp;
  1832. if (sizeof(offer_agent_bucket_t) != binary_bucket_size)
  1833. {
  1834. LL_WARNS("Messaging") << "Malformed inventory offer from agent" << LL_ENDL;
  1835. delete info;
  1836. break;
  1837. }
  1838. bucketp = (struct offer_agent_bucket_t*) &binary_bucket[0];
  1839. info->mType = (LLAssetType::EType) bucketp->asset_type;
  1840. info->mObjectID = bucketp->object_id;
  1841. }
  1842. else
  1843. {
  1844. if (sizeof(S8) != binary_bucket_size)
  1845. {
  1846. LL_WARNS("Messaging") << "Malformed inventory offer from object" << LL_ENDL;
  1847. delete info;
  1848. break;
  1849. }
  1850. info->mType = (LLAssetType::EType) binary_bucket[0];
  1851. info->mObjectID = LLUUID::null;
  1852. }
  1853. info->mIM = dialog;
  1854. info->mFromID = from_id;
  1855. info->mFromGroup = from_group;
  1856. info->mTransactionID = session_id;
  1857. info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType));
  1858. if (dialog == IM_TASK_INVENTORY_OFFERED)
  1859. {
  1860. info->mFromObject = TRUE;
  1861. }
  1862. else
  1863. {
  1864. info->mFromObject = FALSE;
  1865. }
  1866. info->mFromName = name;
  1867. info->mDesc = message;
  1868. info->mHost = msg->getSender();
  1869. //if (((is_busy && !is_owned_by_me) || is_muted))
  1870. if (is_muted)
  1871. {
  1872. // Prefetch the offered item so that it can be discarded by the appropriate observer. (EXT-4331)
  1873. LLInventoryFetchObserver::item_ref_t items;
  1874. items.push_back(info->mObjectID);
  1875. LLInventoryFetchObserver* fetch_item = new LLInventoryFetchObserver();
  1876. fetch_item->fetchItems(items);
  1877. delete fetch_item;
  1878. // Same as closing window
  1879. info->forceResponse(IOR_DECLINE);
  1880. }
  1881. else
  1882. {
  1883. inventory_offer_handler(info);
  1884. }
  1885. }
  1886. break;
  1887. case IM_INVENTORY_ACCEPTED:
  1888. {
  1889. args["NAME"] = name;
  1890. LLSD payload;
  1891. payload["from_id"] = from_id;
  1892. LLNotificationsUtil::add("InventoryAccepted", args, payload);
  1893. break;
  1894. }
  1895. case IM_INVENTORY_DECLINED:
  1896. {
  1897. args["NAME"] = name;
  1898. LLSD payload;
  1899. payload["from_id"] = from_id;
  1900. LLNotificationsUtil::add("InventoryDeclined", args, payload);
  1901. break;
  1902. }
  1903. // TODO: _DEPRECATED suffix as part of vote removal - DEV-24856
  1904. case IM_GROUP_VOTE:
  1905. {
  1906. LL_WARNS("Messaging") << "Received IM: IM_GROUP_VOTE_DEPRECATED" << LL_ENDL;
  1907. }
  1908. break;
  1909. case IM_GROUP_ELECTION_DEPRECATED:
  1910. {
  1911. LL_WARNS("Messaging") << "Received IM: IM_GROUP_ELECTION_DEPRECATED" << LL_ENDL;
  1912. }
  1913. break;
  1914. case IM_SESSION_SEND:
  1915. {
  1916. if (!is_linden && is_busy)
  1917. {
  1918. return;
  1919. }
  1920. // Only show messages if we have a session open (which
  1921. // should happen after you get an "invitation"
  1922. if ( !gIMMgr->hasSession(session_id) )
  1923. {
  1924. return;
  1925. }
  1926. // standard message, not from system
  1927. std::string saved;
  1928. if(offline == IM_OFFLINE)
  1929. {
  1930. saved = llformat("(Saved %s) ", formatted_time(timestamp).c_str());
  1931. }
  1932. buffer = saved + message;
  1933. BOOL is_this_agent = FALSE;
  1934. if(from_id == gAgentID)
  1935. {
  1936. is_this_agent = TRUE;
  1937. }
  1938. gIMMgr->addMessage(
  1939. session_id,
  1940. from_id,
  1941. name,
  1942. buffer,
  1943. ll_safe_string((char*)binary_bucket),
  1944. IM_SESSION_INVITE,
  1945. parent_estate_id,
  1946. region_id,
  1947. position,
  1948. true);
  1949. }
  1950. break;
  1951. case IM_FROM_TASK:
  1952. {
  1953. if (is_busy && !is_owned_by_me)
  1954. {
  1955. return;
  1956. }
  1957. // Build a link to open the object IM info window.
  1958. std::string location = ll_safe_string((char*)binary_bucket, binary_bucket_size-1);
  1959. if (session_id.notNull())
  1960. {
  1961. chat.mFromID = session_id;
  1962. }
  1963. else
  1964. {
  1965. // This message originated on a region without the updated code for task id and slurl information.
  1966. // We just need a unique ID for this object that isn't the owner ID.
  1967. // If it is the owner ID it will overwrite the style that contains the link to that owner's profile.
  1968. // This isn't ideal - it will make 1 style for all objects owned by the the same person/group.
  1969. // This works because the only thing we can really do in this case is show the owner name and link to their profile.
  1970. chat.mFromID = from_id ^ gAgent.getSessionID();
  1971. }
  1972. if(SYSTEM_FROM == name)
  1973. {
  1974. // System's UUID is NULL (fixes EXT-4766)
  1975. chat.mFromID = from_id = LLUUID::null;
  1976. }
  1977. LLSD query_string;
  1978. query_string["owner"] = from_id;
  1979. query_string["slurl"] = location;
  1980. query_string["name"] = name;
  1981. if (from_group)
  1982. {
  1983. query_string["groupowned"] = "true";
  1984. }
  1985. std::ostringstream link;
  1986. link << "secondlife:///app/objectim/" << session_id << LLURI::mapToQueryString(query_string);
  1987. chat.mURL = link.str();
  1988. chat.mText = message;
  1989. chat.mSourceType = CHAT_SOURCE_OBJECT;
  1990. // Note: lie to Nearby Chat, pretending that this is NOT an IM, because
  1991. // IMs from obejcts don't open IM sessions.
  1992. LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD());
  1993. if(nearby_chat)
  1994. {
  1995. LLSD args;
  1996. args["owner_id"] = from_id;
  1997. args["slurl"] = location;
  1998. nearby_chat->addMessage(chat, true, args);
  1999. }
  2000. //Object IMs send with from name: 'Second Life' need to be displayed also in notification toasts (EXT-1590)
  2001. if (SYSTEM_FROM != name) break;
  2002. LLSD substitutions;
  2003. substitutions["NAME"] = name;
  2004. substitutions["MSG"] = message;
  2005. LLSD payload;
  2006. payload["object_id"] = session_id;
  2007. payload["owner_id"] = from_id;
  2008. payload["from_id"] = from_id;
  2009. payload["slurl"] = location;
  2010. payload["name"] = name;
  2011. std::string session_name;
  2012. gCacheName->getFullName(from_id, session_name);
  2013. payload["SESSION_NAME"] = session_name;
  2014. if (from_group)
  2015. {
  2016. payload["group_owned"] = "true";
  2017. }
  2018. LLNotificationsUtil::add("ServerObjectMessage", substitutions, payload);
  2019. }
  2020. break;
  2021. case IM_FROM_TASK_AS_ALERT:
  2022. if (is_busy && !is_owned_by_me)
  2023. {
  2024. return;
  2025. }
  2026. {
  2027. // Construct a viewer alert for this message.
  2028. args["NAME"] = name;
  2029. args["MESSAGE"] = message;
  2030. LLNotificationsUtil::add("ObjectMessage", args);
  2031. }
  2032. break;
  2033. case IM_BUSY_AUTO_RESPONSE:
  2034. if (is_muted)
  2035. {
  2036. LL_DEBUGS("Messaging") << "Ignoring busy response from " << from_id << LL_ENDL;
  2037. return;
  2038. }
  2039. else
  2040. {
  2041. // TODO: after LLTrans hits release, get "busy response" into translatable file
  2042. buffer = llformat("%s (%s): %s", name.c_str(), "busy response", message.c_str());
  2043. gIMMgr->addMessage(session_id, from_id, name, buffer);
  2044. }
  2045. break;
  2046. case IM_LURE_USER:
  2047. {
  2048. if (is_muted)
  2049. return;
  2050. }
  2051. else if (is_busy) 
  2052. {
  2053. busy_message(msg,from_id);
  2054. }
  2055. else
  2056. {
  2057. LLSD args;
  2058. // *TODO: Translate -> [FIRST] [LAST] (maybe)
  2059. args["NAME"] = name;
  2060. args["MESSAGE"] = message;
  2061. LLSD payload;
  2062. payload["from_id"] = from_id;
  2063. payload["lure_id"] = session_id;
  2064. payload["godlike"] = FALSE;
  2065. LLNotificationsUtil::add("TeleportOffered", args, payload);
  2066. }
  2067. }
  2068. break;
  2069. case IM_GODLIKE_LURE_USER:
  2070. {
  2071. LLSD payload;
  2072. payload["from_id"] = from_id;
  2073. payload["lure_id"] = session_id;
  2074. payload["godlike"] = TRUE;
  2075. // do not show a message box, because you're about to be
  2076. // teleported.
  2077. LLNotifications::instance().forceResponse(LLNotification::Params("TeleportOffered").payload(payload), 0);
  2078. }
  2079. break;
  2080. case IM_GOTO_URL:
  2081. {
  2082. LLSD args;
  2083. // n.b. this is for URLs sent by the system, not for
  2084. // URLs sent by scripts (i.e. llLoadURL)
  2085. if (binary_bucket_size <= 0)
  2086. {
  2087. LL_WARNS("Messaging") << "bad binary_bucket_size: "
  2088. << binary_bucket_size
  2089. << " - aborting function." << LL_ENDL;
  2090. return;
  2091. }
  2092. std::string url;
  2093. url.assign((char*)binary_bucket, binary_bucket_size-1);
  2094. args["MESSAGE"] = message;
  2095. args["URL"] = url;
  2096. LLSD payload;
  2097. payload["url"] = url;
  2098. LLNotificationsUtil::add("GotoURL", args, payload );
  2099. }
  2100. break;
  2101. case IM_FRIENDSHIP_OFFERED:
  2102. {
  2103. LLSD payload;
  2104. payload["from_id"] = from_id;
  2105. payload["session_id"] = session_id;;
  2106. payload["online"] = (offline == IM_ONLINE);
  2107. payload["sender"] = msg->getSender().getIPandPort();
  2108. if (is_busy)
  2109. {
  2110. busy_message(msg, from_id);
  2111. LLNotifications::instance().forceResponse(LLNotification::Params("OfferFriendship").payload(payload), 1);
  2112. }
  2113. else if (is_muted)
  2114. {
  2115. LLNotifications::instance().forceResponse(LLNotification::Params("OfferFriendship").payload(payload), 1);
  2116. }
  2117. else
  2118. {
  2119. args["[NAME]"] = name;
  2120. if(message.empty())
  2121. {
  2122. //support for frienship offers from clients before July 2008
  2123.         LLNotificationsUtil::add("OfferFriendshipNoMessage", args, payload);
  2124. }
  2125. else
  2126. {
  2127. args["[MESSAGE]"] = message;
  2128.         LLNotificationsUtil::add("OfferFriendship", args, payload);
  2129. }
  2130. }
  2131. }
  2132. break;
  2133. case IM_FRIENDSHIP_ACCEPTED:
  2134. {
  2135. // In the case of an offline IM, the formFriendship() may be extraneous
  2136. // as the database should already include the relationship.  But it
  2137. // doesn't hurt for dupes.
  2138. LLAvatarTracker::formFriendship(from_id);
  2139. std::vector<std::string> strings;
  2140. strings.push_back(from_id.asString());
  2141. send_generic_message("requestonlinenotification", strings);
  2142. args["NAME"] = name;
  2143. LLSD payload;
  2144. payload["from_id"] = from_id;
  2145. LLNotificationsUtil::add("FriendshipAccepted", args, payload);
  2146. }
  2147. break;
  2148. case IM_FRIENDSHIP_DECLINED_DEPRECATED:
  2149. default:
  2150. LL_WARNS("Messaging") << "Instant message calling for unknown dialog "
  2151. << (S32)dialog << LL_ENDL;
  2152. break;
  2153. }
  2154. LLWindow* viewer_window = gViewerWindow->getWindow();
  2155. if (viewer_window && viewer_window->getMinimized())
  2156. {
  2157. viewer_window->flashIcon(5.f);
  2158. }
  2159. }
  2160. void busy_message (LLMessageSystem* msg, LLUUID from_id) 
  2161. {
  2162. if (gAgent.getBusy())
  2163. {
  2164. std::string my_name;
  2165. LLAgentUI::buildFullname(my_name);
  2166. std::string response = gSavedPerAccountSettings.getString("BusyModeResponse2");
  2167. pack_instant_message(
  2168. gMessageSystem,
  2169. gAgent.getID(),
  2170. FALSE,
  2171. gAgent.getSessionID(),
  2172. from_id,
  2173. my_name,
  2174. response,
  2175. IM_ONLINE,
  2176. IM_BUSY_AUTO_RESPONSE);
  2177. gAgent.sendReliableMessage();
  2178. }
  2179. }
  2180. bool callingcard_offer_callback(const LLSD& notification, const LLSD& response)
  2181. {
  2182. S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
  2183. LLUUID fid;
  2184. LLUUID from_id;
  2185. LLMessageSystem* msg = gMessageSystem;
  2186. switch(option)
  2187. {
  2188. case 0:
  2189. // accept
  2190. msg->newMessageFast(_PREHASH_AcceptCallingCard);
  2191. msg->nextBlockFast(_PREHASH_AgentData);
  2192. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  2193. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  2194. msg->nextBlockFast(_PREHASH_TransactionBlock);
  2195. msg->addUUIDFast(_PREHASH_TransactionID, notification["payload"]["transaction_id"].asUUID());
  2196. fid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD);
  2197. msg->nextBlockFast(_PREHASH_FolderData);
  2198. msg->addUUIDFast(_PREHASH_FolderID, fid);
  2199. msg->sendReliable(LLHost(notification["payload"]["sender"].asString()));
  2200. break;
  2201. case 1:
  2202. // decline
  2203. msg->newMessageFast(_PREHASH_DeclineCallingCard);
  2204. msg->nextBlockFast(_PREHASH_AgentData);
  2205. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  2206. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  2207. msg->nextBlockFast(_PREHASH_TransactionBlock);
  2208. msg->addUUIDFast(_PREHASH_TransactionID, notification["payload"]["transaction_id"].asUUID());
  2209. msg->sendReliable(LLHost(notification["payload"]["sender"].asString()));
  2210. busy_message(msg, notification["payload"]["source_id"].asUUID());
  2211. break;
  2212. default:
  2213. // close button probably, possibly timed out
  2214. break;
  2215. }
  2216. return false;
  2217. }
  2218. static LLNotificationFunctorRegistration callingcard_offer_cb_reg("OfferCallingCard", callingcard_offer_callback);
  2219. void process_offer_callingcard(LLMessageSystem* msg, void**)
  2220. {
  2221. // someone has offered to form a friendship
  2222. LL_DEBUGS("Messaging") << "callingcard offer" << LL_ENDL;
  2223. LLUUID source_id;
  2224. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, source_id);
  2225. LLUUID tid;
  2226. msg->getUUIDFast(_PREHASH_AgentBlock, _PREHASH_TransactionID, tid);
  2227. LLSD payload;
  2228. payload["transaction_id"] = tid;
  2229. payload["source_id"] = source_id;
  2230. payload["sender"] = msg->getSender().getIPandPort();
  2231. LLViewerObject* source = gObjectList.findObject(source_id);
  2232. LLSD args;
  2233. std::string source_name;
  2234. if(source && source->isAvatar())
  2235. {
  2236. LLNameValue* nvfirst = source->getNVPair("FirstName");
  2237. LLNameValue* nvlast  = source->getNVPair("LastName");
  2238. if (nvfirst && nvlast)
  2239. {
  2240. args["FIRST"] = nvfirst->getString();
  2241. args["LAST"] = nvlast->getString();
  2242. source_name = std::string(nvfirst->getString()) + " " + nvlast->getString();
  2243. }
  2244. }
  2245. if(!source_name.empty())
  2246. {
  2247. if (gAgent.getBusy() 
  2248. || LLMuteList::getInstance()->isMuted(source_id, source_name, LLMute::flagTextChat))
  2249. {
  2250. // automatically decline offer
  2251. LLNotifications::instance().forceResponse(LLNotification::Params("OfferCallingCard").payload(payload), 1);
  2252. }
  2253. else
  2254. {
  2255. LLNotificationsUtil::add("OfferCallingCard", args, payload);
  2256. }
  2257. }
  2258. else
  2259. {
  2260. LL_WARNS("Messaging") << "Calling card offer from an unknown source." << LL_ENDL;
  2261. }
  2262. }
  2263. void process_accept_callingcard(LLMessageSystem* msg, void**)
  2264. {
  2265. LLNotificationsUtil::add("CallingCardAccepted");
  2266. }
  2267. void process_decline_callingcard(LLMessageSystem* msg, void**)
  2268. {
  2269. LLNotificationsUtil::add("CallingCardDeclined");
  2270. }
  2271. void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
  2272. {
  2273. LLChat chat;
  2274. std::string mesg;
  2275. std::string from_name;
  2276. U8 source_temp;
  2277. U8 type_temp;
  2278. U8 audible_temp;
  2279. LLColor4 color(1.0f, 1.0f, 1.0f, 1.0f);
  2280. LLUUID from_id;
  2281. LLUUID owner_id;
  2282. BOOL is_owned_by_me = FALSE;
  2283. LLViewerObject* chatter;
  2284. msg->getString("ChatData", "FromName", from_name);
  2285. chat.mFromName = from_name;
  2286. msg->getUUID("ChatData", "SourceID", from_id);
  2287. chat.mFromID = from_id;
  2288. // Object owner for objects
  2289. msg->getUUID("ChatData", "OwnerID", owner_id);
  2290. msg->getU8Fast(_PREHASH_ChatData, _PREHASH_SourceType, source_temp);
  2291. chat.mSourceType = (EChatSourceType)source_temp;
  2292. msg->getU8("ChatData", "ChatType", type_temp);
  2293. chat.mChatType = (EChatType)type_temp;
  2294. msg->getU8Fast(_PREHASH_ChatData, _PREHASH_Audible, audible_temp);
  2295. chat.mAudible = (EChatAudible)audible_temp;
  2296. chat.mTime = LLFrameTimer::getElapsedSeconds();
  2297. BOOL is_busy = gAgent.getBusy();
  2298. BOOL is_muted = FALSE;
  2299. BOOL is_linden = FALSE;
  2300. is_muted = LLMuteList::getInstance()->isMuted(
  2301. from_id,
  2302. from_name,
  2303. LLMute::flagTextChat) 
  2304. || LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagTextChat);
  2305. is_linden = chat.mSourceType != CHAT_SOURCE_OBJECT &&
  2306. LLMuteList::getInstance()->isLinden(from_name);
  2307. BOOL is_audible = (CHAT_AUDIBLE_FULLY == chat.mAudible);
  2308. chatter = gObjectList.findObject(from_id);
  2309. if (chatter)
  2310. {
  2311. chat.mPosAgent = chatter->getPositionAgent();
  2312. // Make swirly things only for talking objects. (not script debug messages, though)
  2313. if (chat.mSourceType == CHAT_SOURCE_OBJECT 
  2314. && chat.mChatType != CHAT_TYPE_DEBUG_MSG)
  2315. {
  2316. LLPointer<LLViewerPartSourceChat> psc = new LLViewerPartSourceChat(chatter->getPositionAgent());
  2317. psc->setSourceObject(chatter);
  2318. psc->setColor(color);
  2319. //We set the particles to be owned by the object's owner, 
  2320. //just in case they should be muted by the mute list
  2321. psc->setOwnerUUID(owner_id);
  2322. LLViewerPartSim::getInstance()->addPartSource(psc);
  2323. }
  2324. // record last audible utterance
  2325. if (is_audible
  2326. && (is_linden || (!is_muted && !is_busy)))
  2327. {
  2328. if (chat.mChatType != CHAT_TYPE_START 
  2329. && chat.mChatType != CHAT_TYPE_STOP)
  2330. {
  2331. gAgent.heardChat(chat.mFromID);
  2332. }
  2333. }
  2334. is_owned_by_me = chatter->permYouOwner();
  2335. }
  2336. if (is_audible)
  2337. {
  2338. BOOL visible_in_chat_bubble = FALSE;
  2339. std::string verb;
  2340. color.setVec(1.f,1.f,1.f,1.f);
  2341. msg->getStringFast(_PREHASH_ChatData, _PREHASH_Message, mesg);
  2342. BOOL ircstyle = FALSE;
  2343. // Look for IRC-style emotes here so chatbubbles work
  2344. std::string prefix = mesg.substr(0, 4);
  2345. if (prefix == "/me " || prefix == "/me'")
  2346. {
  2347. ircstyle = TRUE;
  2348. }
  2349. chat.mText = mesg;
  2350. // Look for the start of typing so we can put "..." in the bubbles.
  2351. if (CHAT_TYPE_START == chat.mChatType)
  2352. {
  2353. LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, TRUE);
  2354. // Might not have the avatar constructed yet, eg on login.
  2355. if (chatter && chatter->isAvatar())
  2356. {
  2357. ((LLVOAvatar*)chatter)->startTyping();
  2358. }
  2359. return;
  2360. }
  2361. else if (CHAT_TYPE_STOP == chat.mChatType)
  2362. {
  2363. LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, FALSE);
  2364. // Might not have the avatar constructed yet, eg on login.
  2365. if (chatter && chatter->isAvatar())
  2366. {
  2367. ((LLVOAvatar*)chatter)->stopTyping();
  2368. }
  2369. return;
  2370. }
  2371. // Look for IRC-style emotes
  2372. if (ircstyle)
  2373. {
  2374. // set CHAT_STYLE_IRC to avoid adding Avatar Name as author of message. See EXT-656
  2375. chat.mChatStyle = CHAT_STYLE_IRC;
  2376. // Do nothing, ircstyle is fixed above for chat bubbles
  2377. }
  2378. else
  2379. {
  2380. switch(chat.mChatType)
  2381. {
  2382. case CHAT_TYPE_WHISPER:
  2383. verb = LLTrans::getString("whisper") + " ";
  2384. break;
  2385. case CHAT_TYPE_DEBUG_MSG:
  2386. case CHAT_TYPE_OWNER:
  2387. case CHAT_TYPE_NORMAL:
  2388. verb = "";
  2389. break;
  2390. case CHAT_TYPE_SHOUT:
  2391. verb = LLTrans::getString("shout") + " ";
  2392. break;
  2393. case CHAT_TYPE_START:
  2394. case CHAT_TYPE_STOP:
  2395. LL_WARNS("Messaging") << "Got chat type start/stop in main chat processing." << LL_ENDL;
  2396. break;
  2397. default:
  2398. LL_WARNS("Messaging") << "Unknown type " << chat.mChatType << " in chat!" << LL_ENDL;
  2399. verb = "";
  2400. break;
  2401. }
  2402. chat.mText = "";
  2403. chat.mText += verb;
  2404. chat.mText += mesg;
  2405. }
  2406. // We have a real utterance now, so can stop showing "..." and proceed.
  2407. if (chatter && chatter->isAvatar())
  2408. {
  2409. LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, FALSE);
  2410. ((LLVOAvatar*)chatter)->stopTyping();
  2411. if (!is_muted && !is_busy)
  2412. {
  2413. visible_in_chat_bubble = gSavedSettings.getBOOL("UseChatBubbles");
  2414. std::string formated_msg = "";
  2415. LLViewerChat::formatChatMsg(chat, formated_msg);
  2416. LLChat chat_bubble = chat;
  2417. chat_bubble.mText = formated_msg;
  2418. ((LLVOAvatar*)chatter)->addChat(chat_bubble);
  2419. }
  2420. }
  2421. if (chatter)
  2422. {
  2423. chat.mPosAgent = chatter->getPositionAgent();
  2424. }
  2425. // truth table:
  2426. // LINDEN BUSY MUTED OWNED_BY_YOU TASK DISPLAY STORE IN HISTORY
  2427. // F F F F * Yes Yes
  2428. // F F F T * Yes Yes
  2429. // F F T F * No No
  2430. // F F T T * No No
  2431. // F T F F * No Yes
  2432. // F T F T * Yes Yes
  2433. // F T T F * No No
  2434. // F T T T * No No
  2435. // T * * * F Yes Yes
  2436. chat.mMuted = is_muted && !is_linden;
  2437. // pass owner_id to chat so that we can display the remote
  2438. // object inspect for an object that is chatting with you
  2439. LLSD args;
  2440. args["type"] = LLNotificationsUI::NT_NEARBYCHAT;
  2441. args["owner_id"] = owner_id;
  2442. LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args);
  2443. }
  2444. }
  2445. // Simulator we're on is informing the viewer that the agent
  2446. // is starting to teleport (perhaps to another sim, perhaps to the 
  2447. // same sim). If we initiated the teleport process by sending some kind 
  2448. // of TeleportRequest, then this info is redundant, but if the sim 
  2449. // initiated the teleport (via a script call, being killed, etc.) 
  2450. // then this info is news to us.
  2451. void process_teleport_start(LLMessageSystem *msg, void**)
  2452. {
  2453. U32 teleport_flags = 0x0;
  2454. msg->getU32("Info", "TeleportFlags", teleport_flags);
  2455. if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL)
  2456. {
  2457. gViewerWindow->setProgressCancelButtonVisible(FALSE);
  2458. }
  2459. else
  2460. {
  2461. gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Cancel"));
  2462. }
  2463. // Freeze the UI and show progress bar
  2464. // Note: could add data here to differentiate between normal teleport and death.
  2465. if( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE )
  2466. {
  2467. gTeleportDisplay = TRUE;
  2468. gAgent.setTeleportState( LLAgent::TELEPORT_START );
  2469. make_ui_sound("UISndTeleportOut");
  2470. // Don't call LLFirstUse::useTeleport here because this could be
  2471. // due to being killed, which would send you home, not to a Telehub
  2472. }
  2473. }
  2474. void process_teleport_progress(LLMessageSystem* msg, void**)
  2475. {
  2476. LLUUID agent_id;
  2477. msg->getUUID("AgentData", "AgentID", agent_id);
  2478. if((gAgent.getID() != agent_id)
  2479.    || (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE))
  2480. {
  2481. LL_WARNS("Messaging") << "Unexpected teleport progress message." << LL_ENDL;
  2482. return;
  2483. }
  2484. U32 teleport_flags = 0x0;
  2485. msg->getU32("Info", "TeleportFlags", teleport_flags);
  2486. if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL)
  2487. {
  2488. gViewerWindow->setProgressCancelButtonVisible(FALSE);
  2489. }
  2490. else
  2491. {
  2492. gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Cancel"));
  2493. }
  2494. std::string buffer;
  2495. msg->getString("Info", "Message", buffer);
  2496. LL_DEBUGS("Messaging") << "teleport progress: " << buffer << LL_ENDL;
  2497. //Sorta hacky...default to using simulator raw messages
  2498. //if we don't find the coresponding mapping in our progress mappings
  2499. std::string message = buffer;
  2500. if (LLAgent::sTeleportProgressMessages.find(buffer) != 
  2501. LLAgent::sTeleportProgressMessages.end() )
  2502. {
  2503. message = LLAgent::sTeleportProgressMessages[buffer];
  2504. }
  2505. gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages[message]);
  2506. }
  2507. class LLFetchInWelcomeArea : public LLInventoryFetchDescendentsObserver
  2508. {
  2509. public:
  2510. LLFetchInWelcomeArea() {}
  2511. virtual void done()
  2512. {
  2513. LLIsType is_landmark(LLAssetType::AT_LANDMARK);
  2514. LLIsType is_card(LLAssetType::AT_CALLINGCARD);
  2515. LLInventoryModel::cat_array_t card_cats;
  2516. LLInventoryModel::item_array_t card_items;
  2517. LLInventoryModel::cat_array_t land_cats;
  2518. LLInventoryModel::item_array_t land_items;
  2519. folder_ref_t::iterator it = mCompleteFolders.begin();
  2520. folder_ref_t::iterator end = mCompleteFolders.end();
  2521. for(; it != end; ++it)
  2522. {
  2523. gInventory.collectDescendentsIf(
  2524. (*it),
  2525. land_cats,
  2526. land_items,
  2527. LLInventoryModel::EXCLUDE_TRASH,
  2528. is_landmark);
  2529. gInventory.collectDescendentsIf(
  2530. (*it),
  2531. card_cats,
  2532. card_items,
  2533. LLInventoryModel::EXCLUDE_TRASH,
  2534. is_card);
  2535. }
  2536. LLSD args;
  2537. if ( land_items.count() > 0 )
  2538. { // Show notification that they can now teleport to landmarks.  Use a random landmark from the inventory
  2539. S32 random_land = ll_rand( land_items.count() - 1 );
  2540. args["NAME"] = land_items[random_land]->getName();
  2541. LLNotificationsUtil::add("TeleportToLandmark",args);
  2542. }
  2543. if ( card_items.count() > 0 )
  2544. { // Show notification that they can now contact people.  Use a random calling card from the inventory
  2545. S32 random_card = ll_rand( card_items.count() - 1 );
  2546. args["NAME"] = card_items[random_card]->getName();
  2547. LLNotificationsUtil::add("TeleportToPerson",args);
  2548. }
  2549. gInventory.removeObserver(this);
  2550. delete this;
  2551. }
  2552. };
  2553. class LLPostTeleportNotifiers : public LLEventTimer 
  2554. {
  2555. public:
  2556. LLPostTeleportNotifiers();
  2557. virtual ~LLPostTeleportNotifiers();
  2558. //function to be called at the supplied frequency
  2559. virtual BOOL tick();
  2560. };
  2561. LLPostTeleportNotifiers::LLPostTeleportNotifiers() : LLEventTimer( 2.0 )
  2562. {
  2563. };
  2564. LLPostTeleportNotifiers::~LLPostTeleportNotifiers()
  2565. {
  2566. }
  2567. BOOL LLPostTeleportNotifiers::tick()
  2568. {
  2569. BOOL all_done = FALSE;
  2570. if ( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE )
  2571. {
  2572. // get callingcards and landmarks available to the user arriving.
  2573. LLInventoryFetchDescendentsObserver::folder_ref_t folders;
  2574. const LLUUID callingcard_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD);
  2575. if(callingcard_id.notNull()) 
  2576. folders.push_back(callingcard_id);
  2577. const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK);
  2578. if(folder_id.notNull()) 
  2579. folders.push_back(folder_id);
  2580. if(!folders.empty())
  2581. {
  2582. LLFetchInWelcomeArea* fetcher = new LLFetchInWelcomeArea;
  2583. fetcher->fetchDescendents(folders);
  2584. if(fetcher->isEverythingComplete())
  2585. {
  2586. fetcher->done();
  2587. }
  2588. else
  2589. {
  2590. gInventory.addObserver(fetcher);
  2591. }
  2592. }
  2593. all_done = TRUE;
  2594. }
  2595. return all_done;
  2596. }
  2597. // Teleport notification from the simulator
  2598. // We're going to pretend to be a new agent
  2599. void process_teleport_finish(LLMessageSystem* msg, void**)
  2600. {
  2601. LL_DEBUGS("Messaging") << "Got teleport location message" << LL_ENDL;
  2602. LLUUID agent_id;
  2603. msg->getUUIDFast(_PREHASH_Info, _PREHASH_AgentID, agent_id);
  2604. if (agent_id != gAgent.getID())
  2605. {
  2606. LL_WARNS("Messaging") << "Got teleport notification for wrong agent!" << LL_ENDL;
  2607. return;
  2608. }
  2609. // Do teleport effect for where you're leaving
  2610. // VEFFECT: TeleportStart
  2611. LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
  2612. effectp->setPositionGlobal(gAgent.getPositionGlobal());
  2613. effectp->setColor(LLColor4U(gAgent.getEffectColor()));
  2614. LLHUDManager::getInstance()->sendEffects();
  2615. U32 location_id;
  2616. U32 sim_ip;
  2617. U16 sim_port;
  2618. LLVector3 pos, look_at;
  2619. U64 region_handle;
  2620. msg->getU32Fast(_PREHASH_Info, _PREHASH_LocationID, location_id);
  2621. msg->getIPAddrFast(_PREHASH_Info, _PREHASH_SimIP, sim_ip);
  2622. msg->getIPPortFast(_PREHASH_Info, _PREHASH_SimPort, sim_port);
  2623. //msg->getVector3Fast(_PREHASH_Info, _PREHASH_Position, pos);
  2624. //msg->getVector3Fast(_PREHASH_Info, _PREHASH_LookAt, look_at);
  2625. msg->getU64Fast(_PREHASH_Info, _PREHASH_RegionHandle, region_handle);
  2626. U32 teleport_flags;
  2627. msg->getU32Fast(_PREHASH_Info, _PREHASH_TeleportFlags, teleport_flags);
  2628. std::string seedCap;
  2629. msg->getStringFast(_PREHASH_Info, _PREHASH_SeedCapability, seedCap);
  2630. // update home location if we are teleporting out of prelude - specific to teleporting to welcome area 
  2631. if((teleport_flags & TELEPORT_FLAGS_SET_HOME_TO_TARGET)
  2632.    && (!gAgent.isGodlike()))
  2633. {
  2634. gAgent.setHomePosRegion(region_handle, pos);
  2635. // Create a timer that will send notices when teleporting is all finished.  Since this is 
  2636. // based on the LLEventTimer class, it will be managed by that class and not orphaned or leaked.
  2637. new LLPostTeleportNotifiers();
  2638. }
  2639. LLHost sim_host(sim_ip, sim_port);
  2640. // Viewer trusts the simulator.
  2641. gMessageSystem->enableCircuit(sim_host, TRUE);
  2642. LLViewerRegion* regionp =  LLWorld::getInstance()->addRegion(region_handle, sim_host);
  2643. /*
  2644. // send camera update to new region
  2645. gAgent.updateCamera();
  2646. // likewise make sure the camera is behind the avatar
  2647. gAgent.resetView(TRUE);
  2648. LLVector3 shift_vector = regionp->getPosRegionFromGlobal(gAgent.getRegion()->getOriginGlobal());
  2649. gAgent.setRegion(regionp);
  2650. gObjectList.shiftObjects(shift_vector);
  2651. if (gAgent.getAvatarObject())
  2652. {
  2653. gAgent.getAvatarObject()->clearChatText();
  2654. gAgent.slamLookAt(look_at);
  2655. }
  2656. gAgent.setPositionAgent(pos);
  2657. gAssetStorage->setUpstream(sim);
  2658. gCacheName->setUpstream(sim);
  2659. */
  2660. // now, use the circuit info to tell simulator about us!
  2661. LL_INFOS("Messaging") << "process_teleport_finish() Enabling "
  2662. << sim_host << " with code " << msg->mOurCircuitCode << LL_ENDL;
  2663. msg->newMessageFast(_PREHASH_UseCircuitCode);
  2664. msg->nextBlockFast(_PREHASH_CircuitCode);
  2665. msg->addU32Fast(_PREHASH_Code, msg->getOurCircuitCode());
  2666. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  2667. msg->addUUIDFast(_PREHASH_ID, gAgent.getID());
  2668. msg->sendReliable(sim_host);
  2669. send_complete_agent_movement(sim_host);
  2670. gAgent.setTeleportState( LLAgent::TELEPORT_MOVING );
  2671. gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages["contacting"]);
  2672. regionp->setSeedCapability(seedCap);
  2673. // Don't send camera updates to the new region until we're
  2674. // actually there...
  2675. // Now do teleport effect for where you're going.
  2676. // VEFFECT: TeleportEnd
  2677. effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
  2678. effectp->setPositionGlobal(gAgent.getPositionGlobal());
  2679. effectp->setColor(LLColor4U(gAgent.getEffectColor()));
  2680. LLHUDManager::getInstance()->sendEffects();
  2681. // gTeleportDisplay = TRUE;
  2682. // gTeleportDisplayTimer.reset();
  2683. // gViewerWindow->setShowProgress(TRUE);
  2684. }
  2685. // stuff we have to do every time we get an AvatarInitComplete from a sim
  2686. /*
  2687. void process_avatar_init_complete(LLMessageSystem* msg, void**)
  2688. {
  2689. LLVector3 agent_pos;
  2690. msg->getVector3Fast(_PREHASH_AvatarData, _PREHASH_Position, agent_pos);
  2691. agent_movement_complete(msg->getSender(), agent_pos);
  2692. }
  2693. */
  2694. void process_agent_movement_complete(LLMessageSystem* msg, void**)
  2695. {
  2696. gAgentMovementCompleted = true;