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 "lldispatcher.h"
00056 #include "llxfermanager.h"
00057 #include "message.h"
00058 #include "lldir.h"
00059
00060 #include "llagent.h"
00061 #include "llfloatermute.h"
00062 #include "llviewergenericmessage.h"
00063 #include "llviewerwindow.h"
00064 #include "viewer.h"
00065 #include "llworld.h"
00066
00067 LLMuteList* gMuteListp = NULL;
00068
00069
00070 class LLDispatchEmptyMuteList : public LLDispatchHandler
00071 {
00072 public:
00073 virtual bool operator()(
00074 const LLDispatcher* dispatcher,
00075 const std::string& key,
00076 const LLUUID& invoice,
00077 const sparam_t& strings)
00078 {
00079 gMuteListp->setLoaded();
00080 return true;
00081 }
00082 };
00083
00084 static LLDispatchEmptyMuteList sDispatchEmptyMuteList;
00085
00086
00087
00088
00089 const char BY_NAME_SUFFIX[] = " (by name)";
00090 const char AGENT_SUFFIX[] = " (resident)";
00091 const char OBJECT_SUFFIX[] = " (object)";
00092 const char GROUP_SUFFIX[] = " (group)";
00093
00094 LLString LLMute::getDisplayName() const
00095 {
00096 LLString name_with_suffix = mName;
00097 switch (mType)
00098 {
00099 case BY_NAME:
00100 default:
00101 name_with_suffix += BY_NAME_SUFFIX;
00102 break;
00103 case AGENT:
00104 name_with_suffix += AGENT_SUFFIX;
00105 break;
00106 case OBJECT:
00107 name_with_suffix += OBJECT_SUFFIX;
00108 break;
00109 case GROUP:
00110 name_with_suffix += GROUP_SUFFIX;
00111 break;
00112 }
00113 return name_with_suffix;
00114 }
00115
00116 void LLMute::setFromDisplayName(const LLString& display_name)
00117 {
00118 size_t pos = 0;
00119 mName = display_name;
00120
00121 pos = mName.rfind(GROUP_SUFFIX);
00122 if (pos != std::string::npos)
00123 {
00124 mName.erase(pos);
00125 mType = GROUP;
00126 return;
00127 }
00128
00129 pos = mName.rfind(OBJECT_SUFFIX);
00130 if (pos != std::string::npos)
00131 {
00132 mName.erase(pos);
00133 mType = OBJECT;
00134 return;
00135 }
00136
00137 pos = mName.rfind(AGENT_SUFFIX);
00138 if (pos != std::string::npos)
00139 {
00140 mName.erase(pos);
00141 mType = AGENT;
00142 return;
00143 }
00144
00145 pos = mName.rfind(BY_NAME_SUFFIX);
00146 if (pos != std::string::npos)
00147 {
00148 mName.erase(pos);
00149 mType = BY_NAME;
00150 return;
00151 }
00152
00153 llwarns << "Unable to set mute from display name " << display_name << llendl;
00154 return;
00155 }
00156
00157
00158
00159
00160 LLMuteList::LLMuteList() :
00161 mIsLoaded(FALSE)
00162 {
00163 LLMessageSystem* msg = gMessageSystem;
00164
00165
00166 msg->setHandlerFuncFast(_PREHASH_MuteListUpdate, processMuteListUpdate);
00167 msg->setHandlerFuncFast(_PREHASH_UseCachedMuteList, processUseCachedMuteList);
00168
00169 gGenericDispatcher.addHandler("emptymutelist", &sDispatchEmptyMuteList);
00170 }
00171
00172
00173
00174
00175 LLMuteList::~LLMuteList()
00176 {
00177 }
00178
00179 BOOL LLMuteList::isLinden(const LLString& name) const
00180 {
00181 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
00182 boost::char_separator<char> sep(" ");
00183 tokenizer tokens(name, sep);
00184 tokenizer::iterator token_iter = tokens.begin();
00185
00186 if (token_iter == tokens.end()) return FALSE;
00187 token_iter++;
00188 if (token_iter == tokens.end()) return FALSE;
00189
00190 LLString last_name = *token_iter;
00191 return last_name == "Linden";
00192 }
00193
00194
00195 BOOL LLMuteList::add(const LLMute& mute, U32 flags)
00196 {
00197
00198 if ((mute.mType == LLMute::AGENT)
00199 && isLinden(mute.mName) && (flags & LLMute::flagTextChat || flags == 0))
00200 {
00201 gViewerWindow->alertXml("MuteLinden");
00202 return FALSE;
00203 }
00204
00205
00206 if (mute.mType == LLMute::AGENT
00207 && mute.mID == gAgent.getID())
00208 {
00209 return FALSE;
00210 }
00211
00212 if (mute.mType == LLMute::BY_NAME)
00213 {
00214
00215 if (mute.mName.empty())
00216 {
00217 llwarns << "Trying to mute empty string by-name" << llendl;
00218 return FALSE;
00219 }
00220
00221
00222 if (mute.mID.notNull())
00223 {
00224 llwarns << "Trying to add by-name mute with non-null id" << llendl;
00225 return FALSE;
00226 }
00227
00228 std::pair<string_set_t::iterator, bool> result = mLegacyMutes.insert(mute.mName);
00229 if (result.second)
00230 {
00231 llinfos << "Muting by name " << mute.mName << llendl;
00232 updateAdd(mute);
00233 notifyObservers();
00234 return TRUE;
00235 }
00236 else
00237 {
00238
00239 return FALSE;
00240 }
00241 }
00242 else
00243 {
00244
00245 LLMute localmute = mute;
00246
00247
00248 mute_set_t::iterator it = mMutes.find(localmute);
00249 if (it != mMutes.end())
00250 {
00251
00252 localmute.mFlags = it->mFlags;
00253
00254 mMutes.erase(it);
00255
00256 }
00257 else
00258 {
00259
00260 localmute.mFlags = LLMute::flagAll;
00261 }
00262
00263 if(flags)
00264 {
00265
00266 localmute.mFlags &= (~flags);
00267 }
00268 else
00269 {
00270
00271 localmute.mFlags = 0;
00272 }
00273
00274
00275 {
00276 std::pair<mute_set_t::iterator, bool> result = mMutes.insert(localmute);
00277 if (result.second)
00278 {
00279 llinfos << "Muting " << localmute.mName << " id " << localmute.mID << " flags " << localmute.mFlags << llendl;
00280 updateAdd(localmute);
00281 notifyObservers();
00282 if(!(localmute.mFlags & LLMute::flagParticles))
00283 {
00284
00285 if(localmute.mType == LLMute::AGENT || localmute.mType == LLMute::OBJECT)
00286 {
00287 gWorldPointer->mPartSim.clearParticlesByOwnerID(localmute.mID);
00288 }
00289 }
00290 return TRUE;
00291 }
00292 }
00293 }
00294
00295
00296 return FALSE;
00297 }
00298
00299 void LLMuteList::updateAdd(const LLMute& mute)
00300 {
00301
00302 LLMessageSystem* msg = gMessageSystem;
00303 msg->newMessageFast(_PREHASH_UpdateMuteListEntry);
00304 msg->nextBlockFast(_PREHASH_AgentData);
00305 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
00306 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
00307 msg->nextBlockFast(_PREHASH_MuteData);
00308 msg->addUUIDFast(_PREHASH_MuteID, mute.mID);
00309 msg->addStringFast(_PREHASH_MuteName, mute.mName);
00310 msg->addS32("MuteType", mute.mType);
00311 msg->addU32("MuteFlags", mute.mFlags);
00312 gAgent.sendReliableMessage();
00313
00314 mIsLoaded = TRUE;
00315 }
00316
00317
00318 BOOL LLMuteList::remove(const LLMute& mute, U32 flags)
00319 {
00320 BOOL found = FALSE;
00321
00322
00323 mute_set_t::iterator it = mMutes.find(mute);
00324 if (it != mMutes.end())
00325 {
00326 LLMute localmute = *it;
00327 bool remove = true;
00328 if(flags)
00329 {
00330
00331 localmute.mFlags |= flags;
00332
00333 if(localmute.mFlags == LLMute::flagAll)
00334 {
00335
00336
00337 }
00338 else
00339 {
00340
00341 remove = false;
00342 }
00343 }
00344 else
00345 {
00346
00347 }
00348
00349
00350 mMutes.erase(it);
00351
00352 if(remove)
00353 {
00354
00355 updateRemove(localmute);
00356 llinfos << "Unmuting " << localmute.mName << " id " << localmute.mID << " flags " << localmute.mFlags << llendl;
00357 }
00358 else
00359 {
00360
00361 mMutes.insert(localmute);
00362 updateAdd(localmute);
00363 llinfos << "Updating mute entry " << localmute.mName << " id " << localmute.mID << " flags " << localmute.mFlags << llendl;
00364 }
00365
00366
00367 notifyObservers();
00368 found = TRUE;
00369 }
00370
00371
00372 string_set_t::iterator legacy_it = mLegacyMutes.find(mute.mName);
00373 if (legacy_it != mLegacyMutes.end())
00374 {
00375
00376 LLMute mute(LLUUID::null, *legacy_it, LLMute::BY_NAME);
00377 updateRemove(mute);
00378 mLegacyMutes.erase(legacy_it);
00379
00380 notifyObservers();
00381 found = TRUE;
00382 }
00383
00384 return found;
00385 }
00386
00387
00388 void LLMuteList::updateRemove(const LLMute& mute)
00389 {
00390 LLMessageSystem* msg = gMessageSystem;
00391 msg->newMessageFast(_PREHASH_RemoveMuteListEntry);
00392 msg->nextBlockFast(_PREHASH_AgentData);
00393 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
00394 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
00395 msg->nextBlockFast(_PREHASH_MuteData);
00396 msg->addUUIDFast(_PREHASH_MuteID, mute.mID);
00397 msg->addString("MuteName", mute.mName);
00398 gAgent.sendReliableMessage();
00399 }
00400
00401
00402 std::vector<LLMute> LLMuteList::getMutes() const
00403 {
00404 std::vector<LLMute> mutes;
00405
00406 for (mute_set_t::const_iterator it = mMutes.begin();
00407 it != mMutes.end();
00408 ++it)
00409 {
00410 mutes.push_back(*it);
00411 }
00412
00413 for (string_set_t::const_iterator it = mLegacyMutes.begin();
00414 it != mLegacyMutes.end();
00415 ++it)
00416 {
00417 LLMute legacy(LLUUID::null, *it);
00418 mutes.push_back(legacy);
00419 }
00420
00421 std::sort(mutes.begin(), mutes.end(), compare_by_name());
00422 return mutes;
00423 }
00424
00425
00426
00427
00428 BOOL LLMuteList::loadFromFile(const LLString& filename)
00429 {
00430 if(!filename.size())
00431 {
00432 llwarns << "Mute List Filename is Empty!" << llendl;
00433 return FALSE;
00434 }
00435
00436 FILE* fp = LLFile::fopen(filename.c_str(), "rb");
00437 if (!fp)
00438 {
00439 llwarns << "Couldn't open mute list " << filename << llendl;
00440 return FALSE;
00441 }
00442
00443
00444
00445 char id_buffer[MAX_STRING];
00446 char name_buffer[MAX_STRING];
00447 char buffer[MAX_STRING];
00448 while (!feof(fp)
00449 && fgets(buffer, MAX_STRING, fp))
00450 {
00451 id_buffer[0] = '\0';
00452 name_buffer[0] = '\0';
00453 S32 type = 0;
00454 U32 flags = 0;
00455 sscanf(
00456 buffer, " %d %254s %254[^|]| %u\n", &type, id_buffer, name_buffer,
00457 &flags);
00458 LLUUID id = LLUUID(id_buffer);
00459 LLMute mute(id, name_buffer, (LLMute::EType)type, flags);
00460 if (mute.mID.isNull()
00461 || mute.mType == LLMute::BY_NAME)
00462 {
00463 mLegacyMutes.insert(mute.mName);
00464 }
00465 else
00466 {
00467 mMutes.insert(mute);
00468 }
00469 }
00470 fclose(fp);
00471 mIsLoaded = TRUE;
00472 notifyObservers();
00473 return TRUE;
00474 }
00475
00476
00477
00478
00479 BOOL LLMuteList::saveToFile(const LLString& filename)
00480 {
00481 if(!filename.size())
00482 {
00483 llwarns << "Mute List Filename is Empty!" << llendl;
00484 return FALSE;
00485 }
00486
00487 FILE* fp = LLFile::fopen(filename.c_str(), "wb");
00488 if (!fp)
00489 {
00490 llwarns << "Couldn't open mute list " << filename << llendl;
00491 return FALSE;
00492 }
00493
00494 char id_string[UUID_STR_LENGTH];
00495 LLUUID::null.toString(id_string);
00496 for (string_set_t::iterator it = mLegacyMutes.begin();
00497 it != mLegacyMutes.end();
00498 ++it)
00499 {
00500 fprintf(fp, "%d %s %s|\n", (S32)LLMute::BY_NAME, id_string, it->c_str());
00501 }
00502 for (mute_set_t::iterator it = mMutes.begin();
00503 it != mMutes.end();
00504 ++it)
00505 {
00506 it->mID.toString(id_string);
00507 const LLString& name = it->mName;
00508 fprintf(fp, "%d %s %s|%u\n", (S32)it->mType, id_string, name.c_str(), it->mFlags);
00509 }
00510 fclose(fp);
00511 return TRUE;
00512 }
00513
00514
00515 BOOL LLMuteList::isMuted(const LLUUID& id, const LLString& name, U32 flags) const
00516 {
00517
00518 LLMute mute(id);
00519 mute_set_t::const_iterator mute_it = mMutes.find(mute);
00520 if (mute_it != mMutes.end())
00521 {
00522
00523 if(flags & mute_it->mFlags)
00524 {
00525 return FALSE;
00526 }
00527 return TRUE;
00528 }
00529
00530
00531 if (name.empty()) return FALSE;
00532
00533
00534 string_set_t::const_iterator legacy_it = mLegacyMutes.find(name);
00535 return legacy_it != mLegacyMutes.end();
00536 }
00537
00538
00539
00540
00541 void LLMuteList::requestFromServer(const LLUUID& agent_id)
00542 {
00543 char agent_id_string[UUID_STR_LENGTH];
00544 char filename[LL_MAX_PATH];
00545 agent_id.toString(agent_id_string);
00546 snprintf(filename, sizeof(filename), "%s.cached_mute", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,agent_id_string).c_str());
00547 LLCRC crc;
00548 crc.update(filename);
00549
00550 LLMessageSystem* msg = gMessageSystem;
00551 msg->newMessageFast(_PREHASH_MuteListRequest);
00552 msg->nextBlockFast(_PREHASH_AgentData);
00553 msg->addUUIDFast(_PREHASH_AgentID, agent_id);
00554 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
00555 msg->nextBlockFast(_PREHASH_MuteData);
00556 msg->addU32Fast(_PREHASH_MuteCRC, crc.getCRC());
00557 gAgent.sendReliableMessage();
00558 }
00559
00560
00561
00562
00563
00564 void LLMuteList::cache(const LLUUID& agent_id)
00565 {
00566
00567 if(mIsLoaded)
00568 {
00569 char agent_id_string[UUID_STR_LENGTH];
00570 char filename[LL_MAX_PATH];
00571 agent_id.toString(agent_id_string);
00572 snprintf(filename, sizeof(filename), "%s.cached_mute", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,agent_id_string).c_str());
00573 saveToFile(filename);
00574 }
00575 }
00576
00577
00578
00579
00580
00581
00582 void LLMuteList::processMuteListUpdate(LLMessageSystem* msg, void**)
00583 {
00584 llinfos << "LLMuteList::processMuteListUpdate()" << llendl;
00585 LLUUID agent_id;
00586 msg->getUUIDFast(_PREHASH_MuteData, _PREHASH_AgentID, agent_id);
00587 if(agent_id != gAgent.getID())
00588 {
00589 llwarns << "Got an mute list update for the wrong agent." << llendl;
00590 return;
00591 }
00592 char filename[MAX_STRING];
00593 filename[0] = '\0';
00594 msg->getStringFast(_PREHASH_MuteData, _PREHASH_Filename, MAX_STRING, filename);
00595
00596 std::string *local_filename_and_path = new std::string(gDirUtilp->getExpandedFilename( LL_PATH_CACHE, filename ));
00597 gXferManager->requestFile(local_filename_and_path->c_str(),
00598 filename,
00599 LL_PATH_CACHE,
00600 msg->getSender(),
00601 TRUE,
00602 onFileMuteList,
00603 (void**)local_filename_and_path,
00604 LLXferManager::HIGH_PRIORITY);
00605 }
00606
00607 void LLMuteList::processUseCachedMuteList(LLMessageSystem* msg, void**)
00608 {
00609 llinfos << "LLMuteList::processUseCachedMuteList()" << llendl;
00610 if (!gMuteListp) return;
00611
00612 char agent_id_string[UUID_STR_LENGTH];
00613 gAgent.getID().toString(agent_id_string);
00614 char filename[LL_MAX_PATH];
00615 snprintf(filename, sizeof(filename), "%s.cached_mute", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,agent_id_string).c_str());
00616 gMuteListp->loadFromFile(filename);
00617 }
00618
00619 void LLMuteList::onFileMuteList(void** user_data, S32 error_code, LLExtStat ext_status)
00620 {
00621 llinfos << "LLMuteList::processMuteListFile()" << llendl;
00622 if (!gMuteListp) return;
00623
00624 std::string *local_filename_and_path = (std::string*)user_data;
00625 if(local_filename_and_path && !local_filename_and_path->empty() && (error_code == 0))
00626 {
00627 gMuteListp->loadFromFile(local_filename_and_path->c_str());
00628 LLFile::remove(local_filename_and_path->c_str());
00629 }
00630 delete local_filename_and_path;
00631 }
00632
00633 void LLMuteList::addObserver(LLMuteListObserver* observer)
00634 {
00635 mObservers.insert(observer);
00636 }
00637
00638 void LLMuteList::removeObserver(LLMuteListObserver* observer)
00639 {
00640 mObservers.erase(observer);
00641 }
00642
00643 void LLMuteList::setLoaded()
00644 {
00645 mIsLoaded = TRUE;
00646 notifyObservers();
00647 }
00648
00649 void LLMuteList::notifyObservers()
00650 {
00651
00652
00653
00654 if (gFloaterMute)
00655 {
00656 gFloaterMute->refreshMuteList();
00657 }
00658
00659 for (observer_set_t::iterator it = mObservers.begin();
00660 it != mObservers.end();
00661 )
00662 {
00663 LLMuteListObserver* observer = *it;
00664 observer->onChange();
00665
00666 it = mObservers.upper_bound(observer);
00667 }
00668 }