00001
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048 #include "llviewerprecompiledheaders.h"
00049
00050 #include "llmutelist.h"
00051
00052 #include <boost/tokenizer.hpp>
00053
00054 #include "llcrc.h"
00055 #include "lldir.h"
00056 #include "lldispatcher.h"
00057 #include "llsdserialize.h"
00058 #include "llxfermanager.h"
00059 #include "message.h"
00060
00061 #include "llagent.h"
00062 #include "llviewergenericmessage.h"
00063 #include "llviewerwindow.h"
00064 #include "llworld.h"
00065 #include "llchat.h"
00066 #include "llfloaterchat.h"
00067 #include "llimpanel.h"
00068 #include "llimview.h"
00069 #include "llnotify.h"
00070 #include "lluistring.h"
00071 #include "llviewerobject.h"
00072 #include "llviewerobjectlist.h"
00073
00074
00075 std::map<LLUUID, F32> LLMuteList::sUserVolumeSettings;
00076
00077
00078
00079 class LLDispatchEmptyMuteList : public LLDispatchHandler
00080 {
00081 public:
00082 virtual bool operator()(
00083 const LLDispatcher* dispatcher,
00084 const std::string& key,
00085 const LLUUID& invoice,
00086 const sparam_t& strings)
00087 {
00088 LLMuteList::getInstance()->setLoaded();
00089 return true;
00090 }
00091 };
00092
00093 static LLDispatchEmptyMuteList sDispatchEmptyMuteList;
00094
00095
00096
00097
00098 const char BY_NAME_SUFFIX[] = " (by name)";
00099 const char AGENT_SUFFIX[] = " (resident)";
00100 const char OBJECT_SUFFIX[] = " (object)";
00101 const char GROUP_SUFFIX[] = " (group)";
00102
00103 LLString LLMute::getDisplayName() const
00104 {
00105 LLString name_with_suffix = mName;
00106 switch (mType)
00107 {
00108 case BY_NAME:
00109 default:
00110 name_with_suffix += BY_NAME_SUFFIX;
00111 break;
00112 case AGENT:
00113 name_with_suffix += AGENT_SUFFIX;
00114 break;
00115 case OBJECT:
00116 name_with_suffix += OBJECT_SUFFIX;
00117 break;
00118 case GROUP:
00119 name_with_suffix += GROUP_SUFFIX;
00120 break;
00121 }
00122 return name_with_suffix;
00123 }
00124
00125 void LLMute::setFromDisplayName(const LLString& display_name)
00126 {
00127 size_t pos = 0;
00128 mName = display_name;
00129
00130 pos = mName.rfind(GROUP_SUFFIX);
00131 if (pos != std::string::npos)
00132 {
00133 mName.erase(pos);
00134 mType = GROUP;
00135 return;
00136 }
00137
00138 pos = mName.rfind(OBJECT_SUFFIX);
00139 if (pos != std::string::npos)
00140 {
00141 mName.erase(pos);
00142 mType = OBJECT;
00143 return;
00144 }
00145
00146 pos = mName.rfind(AGENT_SUFFIX);
00147 if (pos != std::string::npos)
00148 {
00149 mName.erase(pos);
00150 mType = AGENT;
00151 return;
00152 }
00153
00154 pos = mName.rfind(BY_NAME_SUFFIX);
00155 if (pos != std::string::npos)
00156 {
00157 mName.erase(pos);
00158 mType = BY_NAME;
00159 return;
00160 }
00161
00162 llwarns << "Unable to set mute from display name " << display_name << llendl;
00163 return;
00164 }
00165
00166
00167 LLMuteList* LLMuteList::getInstance()
00168 {
00169
00170 static BOOL registered = FALSE;
00171 if( !registered && gMessageSystem != NULL)
00172 {
00173 registered = TRUE;
00174
00175 gMessageSystem->setHandlerFuncFast(_PREHASH_MuteListUpdate, processMuteListUpdate);
00176 gMessageSystem->setHandlerFuncFast(_PREHASH_UseCachedMuteList, processUseCachedMuteList);
00177 }
00178 return LLSingleton<LLMuteList>::getInstance();
00179 }
00180
00181
00182
00183
00184 LLMuteList::LLMuteList() :
00185 mIsLoaded(FALSE)
00186 {
00187 gGenericDispatcher.addHandler("emptymutelist", &sDispatchEmptyMuteList);
00188
00189
00190
00191 std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "volume_settings.xml");
00192
00193 LLSD settings_llsd;
00194 llifstream file;
00195 file.open(filename.c_str());
00196 if (file.is_open())
00197 {
00198 LLSDSerialize::fromXML(settings_llsd, file);
00199 }
00200
00201 for (LLSD::map_const_iterator iter = settings_llsd.beginMap();
00202 iter != settings_llsd.endMap(); ++iter)
00203 {
00204 sUserVolumeSettings.insert(std::make_pair(LLUUID(iter->first), (F32)iter->second.asReal()));
00205 }
00206 }
00207
00208
00209
00210
00211 LLMuteList::~LLMuteList()
00212 {
00213 std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "volume_settings.xml");
00214 LLSD settings_llsd;
00215
00216 for(user_volume_map_t::iterator iter = sUserVolumeSettings.begin(); iter != sUserVolumeSettings.end(); ++iter)
00217 {
00218 settings_llsd[iter->first.asString()] = iter->second;
00219 }
00220
00221 llofstream file;
00222 file.open(filename.c_str());
00223 LLSDSerialize::toPrettyXML(settings_llsd, file);
00224 }
00225
00226 BOOL LLMuteList::isLinden(const LLString& name) const
00227 {
00228 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
00229 boost::char_separator<char> sep(" ");
00230 tokenizer tokens(name, sep);
00231 tokenizer::iterator token_iter = tokens.begin();
00232
00233 if (token_iter == tokens.end()) return FALSE;
00234 token_iter++;
00235 if (token_iter == tokens.end()) return FALSE;
00236
00237 LLString last_name = *token_iter;
00238 return last_name == "Linden";
00239 }
00240
00241
00242 BOOL LLMuteList::add(const LLMute& mute, U32 flags)
00243 {
00244
00245 if ((mute.mType == LLMute::AGENT)
00246 && isLinden(mute.mName) && (flags & LLMute::flagTextChat || flags == 0))
00247 {
00248 gViewerWindow->alertXml("MuteLinden");
00249 return FALSE;
00250 }
00251
00252
00253 if (mute.mType == LLMute::AGENT
00254 && mute.mID == gAgent.getID())
00255 {
00256 return FALSE;
00257 }
00258
00259 if (mute.mType == LLMute::BY_NAME)
00260 {
00261
00262 if (mute.mName.empty())
00263 {
00264 llwarns << "Trying to mute empty string by-name" << llendl;
00265 return FALSE;
00266 }
00267
00268
00269 if (mute.mID.notNull())
00270 {
00271 llwarns << "Trying to add by-name mute with non-null id" << llendl;
00272 return FALSE;
00273 }
00274
00275 std::pair<string_set_t::iterator, bool> result = mLegacyMutes.insert(mute.mName);
00276 if (result.second)
00277 {
00278 llinfos << "Muting by name " << mute.mName << llendl;
00279 updateAdd(mute);
00280 notifyObservers();
00281 return TRUE;
00282 }
00283 else
00284 {
00285
00286 return FALSE;
00287 }
00288 }
00289 else
00290 {
00291
00292 LLMute localmute = mute;
00293
00294
00295 mute_set_t::iterator it = mMutes.find(localmute);
00296 if (it != mMutes.end())
00297 {
00298
00299 localmute.mFlags = it->mFlags;
00300
00301 mMutes.erase(it);
00302
00303 }
00304 else
00305 {
00306
00307 localmute.mFlags = LLMute::flagAll;
00308 }
00309
00310 if(flags)
00311 {
00312
00313 localmute.mFlags &= (~flags);
00314 }
00315 else
00316 {
00317
00318 localmute.mFlags = 0;
00319 }
00320
00321
00322 {
00323 std::pair<mute_set_t::iterator, bool> result = mMutes.insert(localmute);
00324 if (result.second)
00325 {
00326 llinfos << "Muting " << localmute.mName << " id " << localmute.mID << " flags " << localmute.mFlags << llendl;
00327 updateAdd(localmute);
00328 notifyObservers();
00329 if(!(localmute.mFlags & LLMute::flagParticles))
00330 {
00331
00332 if(localmute.mType == LLMute::AGENT || localmute.mType == LLMute::OBJECT)
00333 {
00334 LLViewerPartSim::getInstance()->clearParticlesByOwnerID(localmute.mID);
00335 }
00336 }
00337 return TRUE;
00338 }
00339 }
00340 }
00341
00342
00343 return FALSE;
00344 }
00345
00346 void LLMuteList::updateAdd(const LLMute& mute)
00347 {
00348
00349 LLMessageSystem* msg = gMessageSystem;
00350 msg->newMessageFast(_PREHASH_UpdateMuteListEntry);
00351 msg->nextBlockFast(_PREHASH_AgentData);
00352 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
00353 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
00354 msg->nextBlockFast(_PREHASH_MuteData);
00355 msg->addUUIDFast(_PREHASH_MuteID, mute.mID);
00356 msg->addStringFast(_PREHASH_MuteName, mute.mName);
00357 msg->addS32("MuteType", mute.mType);
00358 msg->addU32("MuteFlags", mute.mFlags);
00359 gAgent.sendReliableMessage();
00360
00361 mIsLoaded = TRUE;
00362 }
00363
00364
00365 BOOL LLMuteList::remove(const LLMute& mute, U32 flags)
00366 {
00367 BOOL found = FALSE;
00368
00369
00370 mute_set_t::iterator it = mMutes.find(mute);
00371 if (it != mMutes.end())
00372 {
00373 LLMute localmute = *it;
00374 bool remove = true;
00375 if(flags)
00376 {
00377
00378 localmute.mFlags |= flags;
00379
00380 if(localmute.mFlags == LLMute::flagAll)
00381 {
00382
00383
00384 }
00385 else
00386 {
00387
00388 remove = false;
00389 }
00390 }
00391 else
00392 {
00393
00394 }
00395
00396
00397 mMutes.erase(it);
00398
00399 if(remove)
00400 {
00401
00402 updateRemove(localmute);
00403 llinfos << "Unmuting " << localmute.mName << " id " << localmute.mID << " flags " << localmute.mFlags << llendl;
00404 }
00405 else
00406 {
00407
00408 mMutes.insert(localmute);
00409 updateAdd(localmute);
00410 llinfos << "Updating mute entry " << localmute.mName << " id " << localmute.mID << " flags " << localmute.mFlags << llendl;
00411 }
00412
00413
00414 setLoaded();
00415 }
00416
00417
00418 string_set_t::iterator legacy_it = mLegacyMutes.find(mute.mName);
00419 if (legacy_it != mLegacyMutes.end())
00420 {
00421
00422 LLMute mute(LLUUID::null, *legacy_it, LLMute::BY_NAME);
00423 updateRemove(mute);
00424 mLegacyMutes.erase(legacy_it);
00425
00426 setLoaded();
00427 }
00428
00429 return found;
00430 }
00431
00432
00433 void LLMuteList::updateRemove(const LLMute& mute)
00434 {
00435 LLMessageSystem* msg = gMessageSystem;
00436 msg->newMessageFast(_PREHASH_RemoveMuteListEntry);
00437 msg->nextBlockFast(_PREHASH_AgentData);
00438 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
00439 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
00440 msg->nextBlockFast(_PREHASH_MuteData);
00441 msg->addUUIDFast(_PREHASH_MuteID, mute.mID);
00442 msg->addString("MuteName", mute.mName);
00443 gAgent.sendReliableMessage();
00444 }
00445
00446 void notify_automute_callback(const LLUUID& agent_id, const char* first_name, const char* last_name, BOOL is_group, void* user_data)
00447 {
00448 U32 temp_data = (U32)user_data;
00449 LLMuteList::EAutoReason reason = (LLMuteList::EAutoReason)temp_data;
00450 LLUIString auto_message;
00451
00452 switch (reason)
00453 {
00454 default:
00455 case LLMuteList::AR_IM:
00456 auto_message = LLNotifyBox::getTemplateMessage("AutoUnmuteByIM");
00457 break;
00458 case LLMuteList::AR_INVENTORY:
00459 auto_message = LLNotifyBox::getTemplateMessage("AutoUnmuteByInventory");
00460 break;
00461 case LLMuteList::AR_MONEY:
00462 auto_message = LLNotifyBox::getTemplateMessage("AutoUnmuteByMoney");
00463 break;
00464 }
00465
00466 auto_message.setArg("[FIRST]", first_name);
00467 auto_message.setArg("[LAST]", last_name);
00468
00469 if (reason == LLMuteList::AR_IM)
00470 {
00471 LLFloaterIMPanel *timp = gIMMgr->findFloaterBySession(agent_id);
00472 if (timp)
00473 {
00474 timp->addHistoryLine(auto_message.getString());
00475 }
00476 }
00477
00478 LLChat auto_chat(auto_message.getString());
00479 LLFloaterChat::addChat(auto_chat, FALSE, FALSE);
00480 }
00481
00482
00483 BOOL LLMuteList::autoRemove(const LLUUID& agent_id, const EAutoReason reason, const LLString& first_name, const LLString& last_name)
00484 {
00485 BOOL removed = FALSE;
00486
00487 if (isMuted(agent_id))
00488 {
00489 LLMute automute(agent_id, "", LLMute::AGENT);
00490 removed = TRUE;
00491 remove(automute);
00492
00493 if (first_name.empty() && last_name.empty())
00494 {
00495 char cache_first[DB_FIRST_NAME_BUF_SIZE];
00496 char cache_last[DB_LAST_NAME_BUF_SIZE];
00497 if (gCacheName->getName(agent_id, cache_first, cache_last))
00498 {
00499
00500 notify_automute_callback(agent_id, cache_first, cache_last, FALSE, (void *)reason);
00501 }
00502 else
00503 {
00504
00505 gCacheName->get(agent_id, FALSE, notify_automute_callback, (void *)reason);
00506 }
00507 }
00508 else
00509 {
00510
00511 notify_automute_callback(agent_id, first_name.c_str(), last_name.c_str(), FALSE, (void *)reason);
00512 }
00513 }
00514
00515 return removed;
00516 }
00517
00518
00519 std::vector<LLMute> LLMuteList::getMutes() const
00520 {
00521 std::vector<LLMute> mutes;
00522
00523 for (mute_set_t::const_iterator it = mMutes.begin();
00524 it != mMutes.end();
00525 ++it)
00526 {
00527 mutes.push_back(*it);
00528 }
00529
00530 for (string_set_t::const_iterator it = mLegacyMutes.begin();
00531 it != mLegacyMutes.end();
00532 ++it)
00533 {
00534 LLMute legacy(LLUUID::null, *it);
00535 mutes.push_back(legacy);
00536 }
00537
00538 std::sort(mutes.begin(), mutes.end(), compare_by_name());
00539 return mutes;
00540 }
00541
00542
00543
00544
00545 BOOL LLMuteList::loadFromFile(const LLString& filename)
00546 {
00547 if(!filename.size())
00548 {
00549 llwarns << "Mute List Filename is Empty!" << llendl;
00550 return FALSE;
00551 }
00552
00553 LLFILE* fp = LLFile::fopen(filename.c_str(), "rb");
00554 if (!fp)
00555 {
00556 llwarns << "Couldn't open mute list " << filename << llendl;
00557 return FALSE;
00558 }
00559
00560
00561
00562 char id_buffer[MAX_STRING];
00563 char name_buffer[MAX_STRING];
00564 char buffer[MAX_STRING];
00565 while (!feof(fp)
00566 && fgets(buffer, MAX_STRING, fp))
00567 {
00568 id_buffer[0] = '\0';
00569 name_buffer[0] = '\0';
00570 S32 type = 0;
00571 U32 flags = 0;
00572 sscanf(
00573 buffer, " %d %254s %254[^|]| %u\n", &type, id_buffer, name_buffer,
00574 &flags);
00575 LLUUID id = LLUUID(id_buffer);
00576 LLMute mute(id, name_buffer, (LLMute::EType)type, flags);
00577 if (mute.mID.isNull()
00578 || mute.mType == LLMute::BY_NAME)
00579 {
00580 mLegacyMutes.insert(mute.mName);
00581 }
00582 else
00583 {
00584 mMutes.insert(mute);
00585 }
00586 }
00587 fclose(fp);
00588 setLoaded();
00589 return TRUE;
00590 }
00591
00592
00593
00594
00595 BOOL LLMuteList::saveToFile(const LLString& filename)
00596 {
00597 if(!filename.size())
00598 {
00599 llwarns << "Mute List Filename is Empty!" << llendl;
00600 return FALSE;
00601 }
00602
00603 LLFILE* fp = LLFile::fopen(filename.c_str(), "wb");
00604 if (!fp)
00605 {
00606 llwarns << "Couldn't open mute list " << filename << llendl;
00607 return FALSE;
00608 }
00609
00610 char id_string[UUID_STR_LENGTH];
00611 LLUUID::null.toString(id_string);
00612 for (string_set_t::iterator it = mLegacyMutes.begin();
00613 it != mLegacyMutes.end();
00614 ++it)
00615 {
00616 fprintf(fp, "%d %s %s|\n", (S32)LLMute::BY_NAME, id_string, it->c_str());
00617 }
00618 for (mute_set_t::iterator it = mMutes.begin();
00619 it != mMutes.end();
00620 ++it)
00621 {
00622 it->mID.toString(id_string);
00623 const LLString& name = it->mName;
00624 fprintf(fp, "%d %s %s|%u\n", (S32)it->mType, id_string, name.c_str(), it->mFlags);
00625 }
00626 fclose(fp);
00627 return TRUE;
00628 }
00629
00630
00631 BOOL LLMuteList::isMuted(const LLUUID& id, const LLString& name, U32 flags) const
00632 {
00633 LLUUID id_to_check = id;
00634
00635
00636 LLViewerObject *objectp = gObjectList.findObject(id);
00637 if ((objectp) && (!objectp->isAvatar()))
00638 {
00639 LLViewerObject *parentp = (LLViewerObject *)objectp->getParent();
00640 if (parentp)
00641 {
00642 id_to_check = parentp->getID();
00643 }
00644 }
00645
00646
00647 LLMute mute(id_to_check);
00648 mute_set_t::const_iterator mute_it = mMutes.find(mute);
00649 if (mute_it != mMutes.end())
00650 {
00651
00652 if(flags & mute_it->mFlags)
00653 {
00654 return FALSE;
00655 }
00656 return TRUE;
00657 }
00658
00659
00660 if (name.empty()) return FALSE;
00661
00662
00663 string_set_t::const_iterator legacy_it = mLegacyMutes.find(name);
00664 return legacy_it != mLegacyMutes.end();
00665 }
00666
00667
00668
00669
00670 void LLMuteList::requestFromServer(const LLUUID& agent_id)
00671 {
00672 char agent_id_string[UUID_STR_LENGTH];
00673 char filename[LL_MAX_PATH];
00674 agent_id.toString(agent_id_string);
00675 snprintf(filename, sizeof(filename), "%s.cached_mute", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,agent_id_string).c_str());
00676 LLCRC crc;
00677 crc.update(filename);
00678
00679 LLMessageSystem* msg = gMessageSystem;
00680 msg->newMessageFast(_PREHASH_MuteListRequest);
00681 msg->nextBlockFast(_PREHASH_AgentData);
00682 msg->addUUIDFast(_PREHASH_AgentID, agent_id);
00683 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
00684 msg->nextBlockFast(_PREHASH_MuteData);
00685 msg->addU32Fast(_PREHASH_MuteCRC, crc.getCRC());
00686 gAgent.sendReliableMessage();
00687 }
00688
00689
00690
00691
00692
00693 void LLMuteList::cache(const LLUUID& agent_id)
00694 {
00695
00696 if(mIsLoaded)
00697 {
00698 char agent_id_string[UUID_STR_LENGTH];
00699 char filename[LL_MAX_PATH];
00700 agent_id.toString(agent_id_string);
00701 snprintf(filename, sizeof(filename), "%s.cached_mute", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,agent_id_string).c_str());
00702 saveToFile(filename);
00703 }
00704 }
00705
00706 void LLMuteList::setSavedResidentVolume(const LLUUID& id, F32 volume)
00707 {
00708
00709 sUserVolumeSettings[id] = volume;
00710 }
00711
00712 F32 LLMuteList::getSavedResidentVolume(const LLUUID& id)
00713 {
00714 const F32 DEFAULT_VOLUME = 0.5f;
00715
00716 user_volume_map_t::iterator found_it = sUserVolumeSettings.find(id);
00717 if (found_it != sUserVolumeSettings.end())
00718 {
00719 return found_it->second;
00720 }
00721
00722 return DEFAULT_VOLUME;
00723 }
00724
00725
00726
00727
00728
00729
00730 void LLMuteList::processMuteListUpdate(LLMessageSystem* msg, void**)
00731 {
00732 llinfos << "LLMuteList::processMuteListUpdate()" << llendl;
00733 LLUUID agent_id;
00734 msg->getUUIDFast(_PREHASH_MuteData, _PREHASH_AgentID, agent_id);
00735 if(agent_id != gAgent.getID())
00736 {
00737 llwarns << "Got an mute list update for the wrong agent." << llendl;
00738 return;
00739 }
00740 char filename[MAX_STRING];
00741 filename[0] = '\0';
00742 msg->getStringFast(_PREHASH_MuteData, _PREHASH_Filename, MAX_STRING, filename);
00743
00744 std::string *local_filename_and_path = new std::string(gDirUtilp->getExpandedFilename( LL_PATH_CACHE, filename ));
00745 gXferManager->requestFile(local_filename_and_path->c_str(),
00746 filename,
00747 LL_PATH_CACHE,
00748 msg->getSender(),
00749 TRUE,
00750 onFileMuteList,
00751 (void**)local_filename_and_path,
00752 LLXferManager::HIGH_PRIORITY);
00753 }
00754
00755 void LLMuteList::processUseCachedMuteList(LLMessageSystem* msg, void**)
00756 {
00757 llinfos << "LLMuteList::processUseCachedMuteList()" << llendl;
00758
00759 char agent_id_string[UUID_STR_LENGTH];
00760 gAgent.getID().toString(agent_id_string);
00761 char filename[LL_MAX_PATH];
00762 snprintf(filename, sizeof(filename), "%s.cached_mute", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,agent_id_string).c_str());
00763 LLMuteList::getInstance()->loadFromFile(filename);
00764 }
00765
00766 void LLMuteList::onFileMuteList(void** user_data, S32 error_code, LLExtStat ext_status)
00767 {
00768 llinfos << "LLMuteList::processMuteListFile()" << llendl;
00769
00770 std::string *local_filename_and_path = (std::string*)user_data;
00771 if(local_filename_and_path && !local_filename_and_path->empty() && (error_code == 0))
00772 {
00773 LLMuteList::getInstance()->loadFromFile(local_filename_and_path->c_str());
00774 LLFile::remove(local_filename_and_path->c_str());
00775 }
00776 delete local_filename_and_path;
00777 }
00778
00779 void LLMuteList::addObserver(LLMuteListObserver* observer)
00780 {
00781 mObservers.insert(observer);
00782 }
00783
00784 void LLMuteList::removeObserver(LLMuteListObserver* observer)
00785 {
00786 mObservers.erase(observer);
00787 }
00788
00789 void LLMuteList::setLoaded()
00790 {
00791 mIsLoaded = TRUE;
00792 notifyObservers();
00793 }
00794
00795 void LLMuteList::notifyObservers()
00796 {
00797 for (observer_set_t::iterator it = mObservers.begin();
00798 it != mObservers.end();
00799 )
00800 {
00801 LLMuteListObserver* observer = *it;
00802 observer->onChange();
00803
00804 it = mObservers.upper_bound(observer);
00805 }
00806 }