PageRenderTime 352ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/newview/llmutelist.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 739 lines | 537 code | 86 blank | 116 comment | 96 complexity | e1d0ad97dbc648c2b274b9dc860c62db MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llmutelist.cpp
  3. * @author Richard Nelson, James Cook
  4. * @brief Management of list of muted players
  5. *
  6. * $LicenseInfo:firstyear=2003&license=viewerlgpl$
  7. * Second Life Viewer Source Code
  8. * Copyright (C) 2010, Linden Research, Inc.
  9. *
  10. * This library is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU Lesser General Public
  12. * License as published by the Free Software Foundation;
  13. * version 2.1 of the License only.
  14. *
  15. * This library is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. * Lesser General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Lesser General Public
  21. * License along with this library; if not, write to the Free Software
  22. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  23. *
  24. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  25. * $/LicenseInfo$
  26. */
  27. /*
  28. * How should muting work?
  29. * Mute an avatar
  30. * Mute a specific object (accidentally spamming)
  31. *
  32. * right-click avatar, mute
  33. * see list of recent chatters, mute
  34. * type a name to mute?
  35. *
  36. * show in list whether chatter is avatar or object
  37. *
  38. * need fast lookup by id
  39. * need lookup by name, doesn't have to be fast
  40. */
  41. #include "llviewerprecompiledheaders.h"
  42. #include "llmutelist.h"
  43. #include <boost/tokenizer.hpp>
  44. #include "lldispatcher.h"
  45. #include "llxfermanager.h"
  46. #include "llagent.h"
  47. #include "llviewergenericmessage.h" // for gGenericDispatcher
  48. #include "llworld.h" //for particle system banning
  49. #include "llimview.h"
  50. #include "llnotifications.h"
  51. #include "llviewerobjectlist.h"
  52. #include "lltrans.h"
  53. namespace
  54. {
  55. // This method is used to return an object to mute given an object id.
  56. // Its used by the LLMute constructor and LLMuteList::isMuted.
  57. LLViewerObject* get_object_to_mute_from_id(LLUUID object_id)
  58. {
  59. LLViewerObject *objectp = gObjectList.findObject(object_id);
  60. if ((objectp) && (!objectp->isAvatar()))
  61. {
  62. LLViewerObject *parentp = (LLViewerObject *)objectp->getParent();
  63. if (parentp && parentp->getID() != gAgent.getID())
  64. {
  65. objectp = parentp;
  66. }
  67. }
  68. return objectp;
  69. }
  70. }
  71. // "emptymutelist"
  72. class LLDispatchEmptyMuteList : public LLDispatchHandler
  73. {
  74. public:
  75. virtual bool operator()(
  76. const LLDispatcher* dispatcher,
  77. const std::string& key,
  78. const LLUUID& invoice,
  79. const sparam_t& strings)
  80. {
  81. LLMuteList::getInstance()->setLoaded();
  82. return true;
  83. }
  84. };
  85. static LLDispatchEmptyMuteList sDispatchEmptyMuteList;
  86. //-----------------------------------------------------------------------------
  87. // LLMute()
  88. //-----------------------------------------------------------------------------
  89. LLMute::LLMute(const LLUUID& id, const std::string& name, EType type, U32 flags)
  90. : mID(id),
  91. mName(name),
  92. mType(type),
  93. mFlags(flags)
  94. {
  95. // muting is done by root objects only - try to find this objects root
  96. LLViewerObject* mute_object = get_object_to_mute_from_id(id);
  97. if(mute_object && mute_object->getID() != id)
  98. {
  99. mID = mute_object->getID();
  100. LLNameValue* firstname = mute_object->getNVPair("FirstName");
  101. LLNameValue* lastname = mute_object->getNVPair("LastName");
  102. if (firstname && lastname)
  103. {
  104. mName = LLCacheName::buildFullName(
  105. firstname->getString(), lastname->getString());
  106. }
  107. mType = mute_object->isAvatar() ? AGENT : OBJECT;
  108. }
  109. }
  110. std::string LLMute::getDisplayType() const
  111. {
  112. switch (mType)
  113. {
  114. case BY_NAME:
  115. default:
  116. return LLTrans::getString("MuteByName");
  117. break;
  118. case AGENT:
  119. return LLTrans::getString("MuteAgent");
  120. break;
  121. case OBJECT:
  122. return LLTrans::getString("MuteObject");
  123. break;
  124. case GROUP:
  125. return LLTrans::getString("MuteGroup");
  126. break;
  127. case EXTERNAL:
  128. return LLTrans::getString("MuteExternal");
  129. break;
  130. }
  131. }
  132. /* static */
  133. LLMuteList* LLMuteList::getInstance()
  134. {
  135. // Register callbacks at the first time that we find that the message system has been created.
  136. static BOOL registered = FALSE;
  137. if( !registered && gMessageSystem != NULL)
  138. {
  139. registered = TRUE;
  140. // Register our various callbacks
  141. gMessageSystem->setHandlerFuncFast(_PREHASH_MuteListUpdate, processMuteListUpdate);
  142. gMessageSystem->setHandlerFuncFast(_PREHASH_UseCachedMuteList, processUseCachedMuteList);
  143. }
  144. return LLSingleton<LLMuteList>::getInstance(); // Call the "base" implementation.
  145. }
  146. //-----------------------------------------------------------------------------
  147. // LLMuteList()
  148. //-----------------------------------------------------------------------------
  149. LLMuteList::LLMuteList() :
  150. mIsLoaded(FALSE)
  151. {
  152. gGenericDispatcher.addHandler("emptymutelist", &sDispatchEmptyMuteList);
  153. }
  154. //-----------------------------------------------------------------------------
  155. // ~LLMuteList()
  156. //-----------------------------------------------------------------------------
  157. LLMuteList::~LLMuteList()
  158. {
  159. }
  160. BOOL LLMuteList::isLinden(const std::string& name) const
  161. {
  162. typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
  163. boost::char_separator<char> sep(" ");
  164. tokenizer tokens(name, sep);
  165. tokenizer::iterator token_iter = tokens.begin();
  166. if (token_iter == tokens.end()) return FALSE;
  167. token_iter++;
  168. if (token_iter == tokens.end()) return FALSE;
  169. std::string last_name = *token_iter;
  170. return last_name == "Linden";
  171. }
  172. BOOL LLMuteList::add(const LLMute& mute, U32 flags)
  173. {
  174. // Can't mute text from Lindens
  175. if ((mute.mType == LLMute::AGENT)
  176. && isLinden(mute.mName) && (flags & LLMute::flagTextChat || flags == 0))
  177. {
  178. LLNotifications::instance().add("MuteLinden", LLSD(), LLSD());
  179. return FALSE;
  180. }
  181. // Can't mute self.
  182. if (mute.mType == LLMute::AGENT
  183. && mute.mID == gAgent.getID())
  184. {
  185. return FALSE;
  186. }
  187. if (mute.mType == LLMute::BY_NAME)
  188. {
  189. // Can't mute empty string by name
  190. if (mute.mName.empty())
  191. {
  192. llwarns << "Trying to mute empty string by-name" << llendl;
  193. return FALSE;
  194. }
  195. // Null mutes must have uuid null
  196. if (mute.mID.notNull())
  197. {
  198. llwarns << "Trying to add by-name mute with non-null id" << llendl;
  199. return FALSE;
  200. }
  201. std::pair<string_set_t::iterator, bool> result = mLegacyMutes.insert(mute.mName);
  202. if (result.second)
  203. {
  204. llinfos << "Muting by name " << mute.mName << llendl;
  205. updateAdd(mute);
  206. notifyObservers();
  207. return TRUE;
  208. }
  209. else
  210. {
  211. // was duplicate
  212. return FALSE;
  213. }
  214. }
  215. else
  216. {
  217. // Need a local (non-const) copy to set up flags properly.
  218. LLMute localmute = mute;
  219. // If an entry for the same entity is already in the list, remove it, saving flags as necessary.
  220. mute_set_t::iterator it = mMutes.find(localmute);
  221. if (it != mMutes.end())
  222. {
  223. // This mute is already in the list. Save the existing entry's flags if that's warranted.
  224. localmute.mFlags = it->mFlags;
  225. mMutes.erase(it);
  226. // Don't need to call notifyObservers() here, since it will happen after the entry has been re-added below.
  227. }
  228. else
  229. {
  230. // There was no entry in the list previously. Fake things up by making it look like the previous entry had all properties unmuted.
  231. localmute.mFlags = LLMute::flagAll;
  232. }
  233. if(flags)
  234. {
  235. // The user passed some combination of flags. Make sure those flag bits are turned off (i.e. those properties will be muted).
  236. localmute.mFlags &= (~flags);
  237. }
  238. else
  239. {
  240. // The user passed 0. Make sure all flag bits are turned off (i.e. all properties will be muted).
  241. localmute.mFlags = 0;
  242. }
  243. // (re)add the mute entry.
  244. {
  245. std::pair<mute_set_t::iterator, bool> result = mMutes.insert(localmute);
  246. if (result.second)
  247. {
  248. llinfos << "Muting " << localmute.mName << " id " << localmute.mID << " flags " << localmute.mFlags << llendl;
  249. updateAdd(localmute);
  250. notifyObservers();
  251. if(!(localmute.mFlags & LLMute::flagParticles))
  252. {
  253. //Kill all particle systems owned by muted task
  254. if(localmute.mType == LLMute::AGENT || localmute.mType == LLMute::OBJECT)
  255. {
  256. LLViewerPartSim::getInstance()->clearParticlesByOwnerID(localmute.mID);
  257. }
  258. }
  259. return TRUE;
  260. }
  261. }
  262. }
  263. // If we were going to return success, we'd have done it by now.
  264. return FALSE;
  265. }
  266. void LLMuteList::updateAdd(const LLMute& mute)
  267. {
  268. // External mutes (e.g. Avaline callers) are local only, don't send them to the server.
  269. if (mute.mType == LLMute::EXTERNAL)
  270. {
  271. return;
  272. }
  273. // Update the database
  274. LLMessageSystem* msg = gMessageSystem;
  275. msg->newMessageFast(_PREHASH_UpdateMuteListEntry);
  276. msg->nextBlockFast(_PREHASH_AgentData);
  277. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  278. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  279. msg->nextBlockFast(_PREHASH_MuteData);
  280. msg->addUUIDFast(_PREHASH_MuteID, mute.mID);
  281. msg->addStringFast(_PREHASH_MuteName, mute.mName);
  282. msg->addS32("MuteType", mute.mType);
  283. msg->addU32("MuteFlags", mute.mFlags);
  284. gAgent.sendReliableMessage();
  285. mIsLoaded = TRUE; // why is this here? -MG
  286. }
  287. BOOL LLMuteList::remove(const LLMute& mute, U32 flags)
  288. {
  289. BOOL found = FALSE;
  290. // First, remove from main list.
  291. mute_set_t::iterator it = mMutes.find(mute);
  292. if (it != mMutes.end())
  293. {
  294. LLMute localmute = *it;
  295. bool remove = true;
  296. if(flags)
  297. {
  298. // If the user passed mute flags, we may only want to turn some flags on.
  299. localmute.mFlags |= flags;
  300. if(localmute.mFlags == LLMute::flagAll)
  301. {
  302. // Every currently available mute property has been masked out.
  303. // Remove the mute entry entirely.
  304. }
  305. else
  306. {
  307. // Only some of the properties are masked out. Update the entry.
  308. remove = false;
  309. }
  310. }
  311. else
  312. {
  313. // The caller didn't pass any flags -- just remove the mute entry entirely.
  314. }
  315. // Always remove the entry from the set -- it will be re-added with new flags if necessary.
  316. mMutes.erase(it);
  317. if(remove)
  318. {
  319. // The entry was actually removed. Notify the server.
  320. updateRemove(localmute);
  321. llinfos << "Unmuting " << localmute.mName << " id " << localmute.mID << " flags " << localmute.mFlags << llendl;
  322. }
  323. else
  324. {
  325. // Flags were updated, the mute entry needs to be retransmitted to the server and re-added to the list.
  326. mMutes.insert(localmute);
  327. updateAdd(localmute);
  328. llinfos << "Updating mute entry " << localmute.mName << " id " << localmute.mID << " flags " << localmute.mFlags << llendl;
  329. }
  330. // Must be after erase.
  331. setLoaded(); // why is this here? -MG
  332. }
  333. else
  334. {
  335. // Clean up any legacy mutes
  336. string_set_t::iterator legacy_it = mLegacyMutes.find(mute.mName);
  337. if (legacy_it != mLegacyMutes.end())
  338. {
  339. // Database representation of legacy mute is UUID null.
  340. LLMute mute(LLUUID::null, *legacy_it, LLMute::BY_NAME);
  341. updateRemove(mute);
  342. mLegacyMutes.erase(legacy_it);
  343. // Must be after erase.
  344. setLoaded(); // why is this here? -MG
  345. }
  346. }
  347. return found;
  348. }
  349. void LLMuteList::updateRemove(const LLMute& mute)
  350. {
  351. // External mutes are not sent to the server anyway, no need to remove them.
  352. if (mute.mType == LLMute::EXTERNAL)
  353. {
  354. return;
  355. }
  356. LLMessageSystem* msg = gMessageSystem;
  357. msg->newMessageFast(_PREHASH_RemoveMuteListEntry);
  358. msg->nextBlockFast(_PREHASH_AgentData);
  359. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  360. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  361. msg->nextBlockFast(_PREHASH_MuteData);
  362. msg->addUUIDFast(_PREHASH_MuteID, mute.mID);
  363. msg->addString("MuteName", mute.mName);
  364. gAgent.sendReliableMessage();
  365. }
  366. void notify_automute_callback(const LLUUID& agent_id, const std::string& full_name, bool is_group, LLMuteList::EAutoReason reason)
  367. {
  368. std::string notif_name;
  369. switch (reason)
  370. {
  371. default:
  372. case LLMuteList::AR_IM:
  373. notif_name = "AutoUnmuteByIM";
  374. break;
  375. case LLMuteList::AR_INVENTORY:
  376. notif_name = "AutoUnmuteByInventory";
  377. break;
  378. case LLMuteList::AR_MONEY:
  379. notif_name = "AutoUnmuteByMoney";
  380. break;
  381. }
  382. LLSD args;
  383. args["NAME"] = full_name;
  384. LLNotificationPtr notif_ptr = LLNotifications::instance().add(notif_name, args, LLSD());
  385. if (notif_ptr)
  386. {
  387. std::string message = notif_ptr->getMessage();
  388. if (reason == LLMuteList::AR_IM)
  389. {
  390. LLIMModel::getInstance()->addMessage(agent_id, SYSTEM_FROM, LLUUID::null, message);
  391. }
  392. }
  393. }
  394. BOOL LLMuteList::autoRemove(const LLUUID& agent_id, const EAutoReason reason)
  395. {
  396. BOOL removed = FALSE;
  397. if (isMuted(agent_id))
  398. {
  399. LLMute automute(agent_id, LLStringUtil::null, LLMute::AGENT);
  400. removed = TRUE;
  401. remove(automute);
  402. std::string full_name;
  403. if (gCacheName->getFullName(agent_id, full_name))
  404. {
  405. // name in cache, call callback directly
  406. notify_automute_callback(agent_id, full_name, false, reason);
  407. }
  408. else
  409. {
  410. // not in cache, lookup name from cache
  411. gCacheName->get(agent_id, false,
  412. boost::bind(&notify_automute_callback, _1, _2, _3, reason));
  413. }
  414. }
  415. return removed;
  416. }
  417. std::vector<LLMute> LLMuteList::getMutes() const
  418. {
  419. std::vector<LLMute> mutes;
  420. for (mute_set_t::const_iterator it = mMutes.begin();
  421. it != mMutes.end();
  422. ++it)
  423. {
  424. mutes.push_back(*it);
  425. }
  426. for (string_set_t::const_iterator it = mLegacyMutes.begin();
  427. it != mLegacyMutes.end();
  428. ++it)
  429. {
  430. LLMute legacy(LLUUID::null, *it);
  431. mutes.push_back(legacy);
  432. }
  433. std::sort(mutes.begin(), mutes.end(), compare_by_name());
  434. return mutes;
  435. }
  436. //-----------------------------------------------------------------------------
  437. // loadFromFile()
  438. //-----------------------------------------------------------------------------
  439. BOOL LLMuteList::loadFromFile(const std::string& filename)
  440. {
  441. if(!filename.size())
  442. {
  443. llwarns << "Mute List Filename is Empty!" << llendl;
  444. return FALSE;
  445. }
  446. LLFILE* fp = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/
  447. if (!fp)
  448. {
  449. llwarns << "Couldn't open mute list " << filename << llendl;
  450. return FALSE;
  451. }
  452. // *NOTE: Changing the size of these buffers will require changes
  453. // in the scanf below.
  454. char id_buffer[MAX_STRING]; /*Flawfinder: ignore*/
  455. char name_buffer[MAX_STRING]; /*Flawfinder: ignore*/
  456. char buffer[MAX_STRING]; /*Flawfinder: ignore*/
  457. while (!feof(fp)
  458. && fgets(buffer, MAX_STRING, fp))
  459. {
  460. id_buffer[0] = '\0';
  461. name_buffer[0] = '\0';
  462. S32 type = 0;
  463. U32 flags = 0;
  464. sscanf( /* Flawfinder: ignore */
  465. buffer, " %d %254s %254[^|]| %u\n", &type, id_buffer, name_buffer,
  466. &flags);
  467. LLUUID id = LLUUID(id_buffer);
  468. LLMute mute(id, std::string(name_buffer), (LLMute::EType)type, flags);
  469. if (mute.mID.isNull()
  470. || mute.mType == LLMute::BY_NAME)
  471. {
  472. mLegacyMutes.insert(mute.mName);
  473. }
  474. else
  475. {
  476. mMutes.insert(mute);
  477. }
  478. }
  479. fclose(fp);
  480. setLoaded();
  481. return TRUE;
  482. }
  483. //-----------------------------------------------------------------------------
  484. // saveToFile()
  485. //-----------------------------------------------------------------------------
  486. BOOL LLMuteList::saveToFile(const std::string& filename)
  487. {
  488. if(!filename.size())
  489. {
  490. llwarns << "Mute List Filename is Empty!" << llendl;
  491. return FALSE;
  492. }
  493. LLFILE* fp = LLFile::fopen(filename, "wb"); /*Flawfinder: ignore*/
  494. if (!fp)
  495. {
  496. llwarns << "Couldn't open mute list " << filename << llendl;
  497. return FALSE;
  498. }
  499. // legacy mutes have null uuid
  500. std::string id_string;
  501. LLUUID::null.toString(id_string);
  502. for (string_set_t::iterator it = mLegacyMutes.begin();
  503. it != mLegacyMutes.end();
  504. ++it)
  505. {
  506. fprintf(fp, "%d %s %s|\n", (S32)LLMute::BY_NAME, id_string.c_str(), it->c_str());
  507. }
  508. for (mute_set_t::iterator it = mMutes.begin();
  509. it != mMutes.end();
  510. ++it)
  511. {
  512. // Don't save external mutes as they are not sent to the server and probably won't
  513. //be valid next time anyway.
  514. if (it->mType != LLMute::EXTERNAL)
  515. {
  516. it->mID.toString(id_string);
  517. const std::string& name = it->mName;
  518. fprintf(fp, "%d %s %s|%u\n", (S32)it->mType, id_string.c_str(), name.c_str(), it->mFlags);
  519. }
  520. }
  521. fclose(fp);
  522. return TRUE;
  523. }
  524. BOOL LLMuteList::isMuted(const LLUUID& id, const std::string& name, U32 flags) const
  525. {
  526. // for objects, check for muting on their parent prim
  527. LLViewerObject* mute_object = get_object_to_mute_from_id(id);
  528. LLUUID id_to_check = (mute_object) ? mute_object->getID() : id;
  529. // don't need name or type for lookup
  530. LLMute mute(id_to_check);
  531. mute_set_t::const_iterator mute_it = mMutes.find(mute);
  532. if (mute_it != mMutes.end())
  533. {
  534. // If any of the flags the caller passed are set, this item isn't considered muted for this caller.
  535. if(flags & mute_it->mFlags)
  536. {
  537. return FALSE;
  538. }
  539. return TRUE;
  540. }
  541. // empty names can't be legacy-muted
  542. bool avatar = mute_object && mute_object->isAvatar();
  543. if (name.empty() || avatar) return FALSE;
  544. // Look in legacy pile
  545. string_set_t::const_iterator legacy_it = mLegacyMutes.find(name);
  546. return legacy_it != mLegacyMutes.end();
  547. }
  548. //-----------------------------------------------------------------------------
  549. // requestFromServer()
  550. //-----------------------------------------------------------------------------
  551. void LLMuteList::requestFromServer(const LLUUID& agent_id)
  552. {
  553. std::string agent_id_string;
  554. std::string filename;
  555. agent_id.toString(agent_id_string);
  556. filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,agent_id_string) + ".cached_mute";
  557. LLCRC crc;
  558. crc.update(filename);
  559. LLMessageSystem* msg = gMessageSystem;
  560. msg->newMessageFast(_PREHASH_MuteListRequest);
  561. msg->nextBlockFast(_PREHASH_AgentData);
  562. msg->addUUIDFast(_PREHASH_AgentID, agent_id);
  563. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  564. msg->nextBlockFast(_PREHASH_MuteData);
  565. msg->addU32Fast(_PREHASH_MuteCRC, crc.getCRC());
  566. gAgent.sendReliableMessage();
  567. }
  568. //-----------------------------------------------------------------------------
  569. // cache()
  570. //-----------------------------------------------------------------------------
  571. void LLMuteList::cache(const LLUUID& agent_id)
  572. {
  573. // Write to disk even if empty.
  574. if(mIsLoaded)
  575. {
  576. std::string agent_id_string;
  577. std::string filename;
  578. agent_id.toString(agent_id_string);
  579. filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,agent_id_string) + ".cached_mute";
  580. saveToFile(filename);
  581. }
  582. }
  583. //-----------------------------------------------------------------------------
  584. // Static message handlers
  585. //-----------------------------------------------------------------------------
  586. void LLMuteList::processMuteListUpdate(LLMessageSystem* msg, void**)
  587. {
  588. llinfos << "LLMuteList::processMuteListUpdate()" << llendl;
  589. LLUUID agent_id;
  590. msg->getUUIDFast(_PREHASH_MuteData, _PREHASH_AgentID, agent_id);
  591. if(agent_id != gAgent.getID())
  592. {
  593. llwarns << "Got an mute list update for the wrong agent." << llendl;
  594. return;
  595. }
  596. std::string unclean_filename;
  597. msg->getStringFast(_PREHASH_MuteData, _PREHASH_Filename, unclean_filename);
  598. std::string filename = LLDir::getScrubbedFileName(unclean_filename);
  599. std::string *local_filename_and_path = new std::string(gDirUtilp->getExpandedFilename( LL_PATH_CACHE, filename ));
  600. gXferManager->requestFile(*local_filename_and_path,
  601. filename,
  602. LL_PATH_CACHE,
  603. msg->getSender(),
  604. TRUE, // make the remote file temporary.
  605. onFileMuteList,
  606. (void**)local_filename_and_path,
  607. LLXferManager::HIGH_PRIORITY);
  608. }
  609. void LLMuteList::processUseCachedMuteList(LLMessageSystem* msg, void**)
  610. {
  611. llinfos << "LLMuteList::processUseCachedMuteList()" << llendl;
  612. std::string agent_id_string;
  613. gAgent.getID().toString(agent_id_string);
  614. std::string filename;
  615. filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,agent_id_string) + ".cached_mute";
  616. LLMuteList::getInstance()->loadFromFile(filename);
  617. }
  618. void LLMuteList::onFileMuteList(void** user_data, S32 error_code, LLExtStat ext_status)
  619. {
  620. llinfos << "LLMuteList::processMuteListFile()" << llendl;
  621. std::string* local_filename_and_path = (std::string*)user_data;
  622. if(local_filename_and_path && !local_filename_and_path->empty() && (error_code == 0))
  623. {
  624. LLMuteList::getInstance()->loadFromFile(*local_filename_and_path);
  625. LLFile::remove(*local_filename_and_path);
  626. }
  627. delete local_filename_and_path;
  628. }
  629. void LLMuteList::addObserver(LLMuteListObserver* observer)
  630. {
  631. mObservers.insert(observer);
  632. }
  633. void LLMuteList::removeObserver(LLMuteListObserver* observer)
  634. {
  635. mObservers.erase(observer);
  636. }
  637. void LLMuteList::setLoaded()
  638. {
  639. mIsLoaded = TRUE;
  640. notifyObservers();
  641. }
  642. void LLMuteList::notifyObservers()
  643. {
  644. for (observer_set_t::iterator it = mObservers.begin();
  645. it != mObservers.end();
  646. )
  647. {
  648. LLMuteListObserver* observer = *it;
  649. observer->onChange();
  650. // In case onChange() deleted an entry.
  651. it = mObservers.upper_bound(observer);
  652. }
  653. }