summaryrefslogtreecommitdiff
path: root/indra/newview/llmutelist.cpp
diff options
context:
space:
mode:
authorJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
committerJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
commit420b91db29485df39fd6e724e782c449158811cb (patch)
treeb471a94563af914d3ed3edd3e856d21cb1b69945 /indra/newview/llmutelist.cpp
Print done when done.
Diffstat (limited to 'indra/newview/llmutelist.cpp')
-rw-r--r--indra/newview/llmutelist.cpp553
1 files changed, 553 insertions, 0 deletions
diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp
new file mode 100644
index 0000000000..fc8ac0a372
--- /dev/null
+++ b/indra/newview/llmutelist.cpp
@@ -0,0 +1,553 @@
+/**
+ * @file llmutelist.cpp
+ * @author Richard Nelson, James Cook
+ * @brief Management of list of muted players
+ *
+ * Copyright (c) 2003-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+/*
+ * How should muting work?
+ * Mute an avatar
+ * Mute a specific object (accidentally spamming)
+ *
+ * right-click avatar, mute
+ * see list of recent chatters, mute
+ * type a name to mute?
+ *
+ * show in list whether chatter is avatar or object
+ *
+ * need fast lookup by id
+ * need lookup by name, doesn't have to be fast
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llmutelist.h"
+
+#include <boost/tokenizer.hpp>
+
+#include "llcrc.h"
+#include "lldispatcher.h"
+#include "llxfermanager.h"
+#include "message.h"
+#include "lldir.h"
+
+#include "llagent.h"
+#include "llfloatermute.h"
+#include "llviewermessage.h" // for gGenericDispatcher
+#include "llviewerwindow.h"
+#include "viewer.h"
+#include "llworld.h" //for particle system banning
+
+LLMuteList* gMuteListp = NULL;
+
+// "emptymutelist"
+class LLDispatchEmptyMuteList : public LLDispatchHandler
+{
+public:
+ virtual bool operator()(
+ const LLDispatcher* dispatcher,
+ const std::string& key,
+ const LLUUID& invoice,
+ const sparam_t& strings)
+ {
+ gMuteListp->setLoaded();
+ return true;
+ }
+};
+
+static LLDispatchEmptyMuteList sDispatchEmptyMuteList;
+
+//-----------------------------------------------------------------------------
+// LLMute()
+//-----------------------------------------------------------------------------
+const char BY_NAME_SUFFIX[] = " (by name)";
+const char AGENT_SUFFIX[] = " (resident)";
+const char OBJECT_SUFFIX[] = " (object)";
+const char GROUP_SUFFIX[] = " (group)";
+
+LLString LLMute::getDisplayName() const
+{
+ LLString name_with_suffix = mName;
+ switch (mType)
+ {
+ case BY_NAME:
+ default:
+ name_with_suffix += BY_NAME_SUFFIX;
+ break;
+ case AGENT:
+ name_with_suffix += AGENT_SUFFIX;
+ break;
+ case OBJECT:
+ name_with_suffix += OBJECT_SUFFIX;
+ break;
+ case GROUP:
+ name_with_suffix += GROUP_SUFFIX;
+ break;
+ }
+ return name_with_suffix;
+}
+
+void LLMute::setFromDisplayName(const LLString& display_name)
+{
+ size_t pos = 0;
+ mName = display_name;
+
+ pos = mName.rfind(GROUP_SUFFIX);
+ if (pos != std::string::npos)
+ {
+ mName.erase(pos);
+ mType = GROUP;
+ return;
+ }
+
+ pos = mName.rfind(OBJECT_SUFFIX);
+ if (pos != std::string::npos)
+ {
+ mName.erase(pos);
+ mType = OBJECT;
+ return;
+ }
+
+ pos = mName.rfind(AGENT_SUFFIX);
+ if (pos != std::string::npos)
+ {
+ mName.erase(pos);
+ mType = AGENT;
+ return;
+ }
+
+ pos = mName.rfind(BY_NAME_SUFFIX);
+ if (pos != std::string::npos)
+ {
+ mName.erase(pos);
+ mType = BY_NAME;
+ return;
+ }
+
+ llwarns << "Unable to set mute from display name " << display_name << llendl;
+ return;
+}
+
+//-----------------------------------------------------------------------------
+// LLMuteList()
+//-----------------------------------------------------------------------------
+LLMuteList::LLMuteList() :
+ mIsLoaded(FALSE)
+{
+ LLMessageSystem* msg = gMessageSystem;
+
+ // Register our various callbacks
+ msg->setHandlerFuncFast(_PREHASH_MuteListUpdate, processMuteListUpdate);
+ msg->setHandlerFuncFast(_PREHASH_UseCachedMuteList, processUseCachedMuteList);
+
+ gGenericDispatcher.addHandler("emptymutelist", &sDispatchEmptyMuteList);
+}
+
+//-----------------------------------------------------------------------------
+// ~LLMuteList()
+//-----------------------------------------------------------------------------
+LLMuteList::~LLMuteList()
+{
+}
+
+BOOL LLMuteList::isLinden(const LLString& name) const
+{
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ boost::char_separator<char> sep(" ");
+ tokenizer tokens(name, sep);
+ tokenizer::iterator token_iter = tokens.begin();
+
+ if (token_iter == tokens.end()) return FALSE;
+ token_iter++;
+ if (token_iter == tokens.end()) return FALSE;
+
+ LLString last_name = *token_iter;
+
+ if (last_name == "Linden")
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+BOOL LLMuteList::add(const LLMute& mute)
+{
+ // Can't mute Lindens
+ if ((mute.mType == LLMute::AGENT || mute.mType == LLMute::BY_NAME)
+ && isLinden(mute.mName))
+ {
+ gViewerWindow->alertXml("MuteLinden");
+ return FALSE;
+ }
+
+ // Can't mute self.
+ if (mute.mType == LLMute::AGENT
+ && mute.mID == gAgent.getID())
+ {
+ return FALSE;
+ }
+
+ if (mute.mType == LLMute::BY_NAME)
+ {
+ // Can't mute empty string by name
+ if (mute.mName.empty())
+ {
+ llwarns << "Trying to mute empty string by-name" << llendl;
+ return FALSE;
+ }
+
+ // Null mutes must have uuid null
+ if (mute.mID.notNull())
+ {
+ llwarns << "Trying to add by-name mute with non-null id" << llendl;
+ return FALSE;
+ }
+
+ std::pair<string_set_t::iterator, bool> result = mLegacyMutes.insert(mute.mName);
+ if (result.second)
+ {
+ llinfos << "Muting by name " << mute.mName << llendl;
+ updateAdd(mute);
+ notifyObservers();
+ return TRUE;
+ }
+ else
+ {
+ // was duplicate
+ return FALSE;
+ }
+ }
+ else
+ {
+ std::pair<mute_set_t::iterator, bool> result = mMutes.insert(mute);
+ if (result.second)
+ {
+ llinfos << "Muting " << mute.mName << " id " << mute.mID << llendl;
+ updateAdd(mute);
+ notifyObservers();
+ //Kill all particle systems owned by muted task
+ if(mute.mType == LLMute::AGENT || mute.mType == LLMute::OBJECT)
+ {
+ gWorldPointer->mPartSim.cleanMutedParticles(mute.mID);
+ }
+
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+}
+
+void LLMuteList::updateAdd(const LLMute& mute)
+{
+ // Update the database
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_UpdateMuteListEntry);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_MuteData);
+ msg->addUUIDFast(_PREHASH_MuteID, mute.mID);
+ msg->addStringFast(_PREHASH_MuteName, mute.mName);
+ msg->addS32("MuteType", mute.mType);
+ msg->addU32("MuteFlags", 0x0); // future
+ gAgent.sendReliableMessage();
+
+ mIsLoaded = TRUE;
+}
+
+
+BOOL LLMuteList::remove(const LLMute& mute)
+{
+ BOOL found = FALSE;
+
+ // First, remove from main list.
+ mute_set_t::iterator it = mMutes.find(mute);
+ if (it != mMutes.end())
+ {
+ updateRemove(*it);
+ mMutes.erase(it);
+ // Must be after erase.
+ notifyObservers();
+ found = TRUE;
+ }
+
+ // Clean up any legacy mutes
+ string_set_t::iterator legacy_it = mLegacyMutes.find(mute.mName);
+ if (legacy_it != mLegacyMutes.end())
+ {
+ // Database representation of legacy mute is UUID null.
+ LLMute mute(LLUUID::null, *legacy_it, LLMute::BY_NAME);
+ updateRemove(mute);
+ mLegacyMutes.erase(legacy_it);
+ // Must be after erase.
+ notifyObservers();
+ found = TRUE;
+ }
+
+ return found;
+}
+
+
+void LLMuteList::updateRemove(const LLMute& mute)
+{
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_RemoveMuteListEntry);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_MuteData);
+ msg->addUUIDFast(_PREHASH_MuteID, mute.mID);
+ msg->addString("MuteName", mute.mName);
+ gAgent.sendReliableMessage();
+}
+
+
+std::vector<LLMute> LLMuteList::getMutes() const
+{
+ std::vector<LLMute> mutes;
+
+ for (mute_set_t::const_iterator it = mMutes.begin();
+ it != mMutes.end();
+ ++it)
+ {
+ mutes.push_back(*it);
+ }
+
+ for (string_set_t::const_iterator it = mLegacyMutes.begin();
+ it != mLegacyMutes.end();
+ ++it)
+ {
+ LLMute legacy(LLUUID::null, *it);
+ mutes.push_back(legacy);
+ }
+
+ std::sort(mutes.begin(), mutes.end(), compare_by_name());
+ return mutes;
+}
+
+//-----------------------------------------------------------------------------
+// loadFromFile()
+//-----------------------------------------------------------------------------
+BOOL LLMuteList::loadFromFile(const LLString& filename)
+{
+ FILE* fp = LLFile::fopen(filename.c_str(), "rb");
+ if (!fp)
+ {
+ llwarns << "Couldn't open mute list " << filename << llendl;
+ return FALSE;
+ }
+
+ char id_buffer[MAX_STRING];
+ char name_buffer[MAX_STRING];
+ char buffer[MAX_STRING];
+ while (!feof(fp)
+ && fgets(buffer, MAX_STRING, fp))
+ {
+ id_buffer[0] = '\0';
+ name_buffer[0] = '\0';
+ S32 type = 0;
+ sscanf(buffer, " %d %s %[^|]", &type, id_buffer, name_buffer);
+ LLUUID id = LLUUID(id_buffer);
+ LLMute mute(id, name_buffer, (LLMute::EType)type);
+ if (mute.mID.isNull()
+ || mute.mType == LLMute::BY_NAME)
+ {
+ mLegacyMutes.insert(mute.mName);
+ }
+ else
+ {
+ mMutes.insert(mute);
+ }
+ }
+ fclose(fp);
+ mIsLoaded = TRUE;
+ notifyObservers();
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// saveToFile()
+//-----------------------------------------------------------------------------
+BOOL LLMuteList::saveToFile(const LLString& filename)
+{
+ FILE* fp = LLFile::fopen(filename.c_str(), "wb");
+ if (!fp)
+ {
+ llwarns << "Couldn't open mute list " << filename << llendl;
+ return FALSE;
+ }
+ // legacy mutes have null uuid
+ char id_string[UUID_STR_LENGTH];
+ LLUUID::null.toString(id_string);
+ for (string_set_t::iterator it = mLegacyMutes.begin();
+ it != mLegacyMutes.end();
+ ++it)
+ {
+ fprintf(fp, "%d %s %s|\n", (S32)LLMute::BY_NAME, id_string, it->c_str());
+ }
+ for (mute_set_t::iterator it = mMutes.begin();
+ it != mMutes.end();
+ ++it)
+ {
+ it->mID.toString(id_string);
+ const LLString& name = it->mName;
+ fprintf(fp, "%d %s %s|\n", (S32)it->mType, id_string, name.c_str());
+ }
+ fclose(fp);
+ return TRUE;
+}
+
+
+BOOL LLMuteList::isMuted(const LLUUID& id, const LLString& name) const
+{
+ // don't need name or type for lookup
+ LLMute mute(id);
+ mute_set_t::const_iterator mute_it = mMutes.find(mute);
+ if (mute_it != mMutes.end()) return TRUE;
+
+ // empty names can't be legacy-muted
+ if (name.empty()) return FALSE;
+
+ // Look in legacy pile
+ string_set_t::const_iterator legacy_it = mLegacyMutes.find(name);
+ return legacy_it != mLegacyMutes.end();
+}
+
+//-----------------------------------------------------------------------------
+// requestFromServer()
+//-----------------------------------------------------------------------------
+void LLMuteList::requestFromServer(const LLUUID& agent_id)
+{
+ char agent_id_string[UUID_STR_LENGTH];
+ char filename[LL_MAX_PATH];
+ agent_id.toString(agent_id_string);
+ sprintf(filename, "%s.cached_mute", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,agent_id_string).c_str());
+ LLCRC crc;
+ crc.update(filename);
+
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_MuteListRequest);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, agent_id);
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_MuteData);
+ msg->addU32Fast(_PREHASH_MuteCRC, crc.getCRC());
+ gAgent.sendReliableMessage();
+}
+
+//-----------------------------------------------------------------------------
+// cache()
+//-----------------------------------------------------------------------------
+
+void LLMuteList::cache(const LLUUID& agent_id)
+{
+ // Write to disk even if empty.
+ if(mIsLoaded)
+ {
+ char agent_id_string[UUID_STR_LENGTH];
+ char filename[LL_MAX_PATH];
+ agent_id.toString(agent_id_string);
+ sprintf(filename, "%s.cached_mute", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,agent_id_string).c_str());
+ saveToFile(filename);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Static message handlers
+//-----------------------------------------------------------------------------
+
+void LLMuteList::processMuteListUpdate(LLMessageSystem* msg, void**)
+{
+ llinfos << "LLMuteList::processMuteListUpdate()" << llendl;
+ LLUUID agent_id;
+ msg->getUUIDFast(_PREHASH_MuteData, _PREHASH_AgentID, agent_id);
+ if(agent_id != gAgent.getID())
+ {
+ llwarns << "Got an mute list update for the wrong agent." << llendl;
+ return;
+ }
+ char filename[MAX_STRING];
+ filename[0] = '\0';
+ msg->getStringFast(_PREHASH_MuteData, _PREHASH_Filename, MAX_STRING, filename);
+
+ std::string *local_filename_and_path = new std::string(gDirUtilp->getExpandedFilename( LL_PATH_CACHE, filename ));
+ gXferManager->requestFile(local_filename_and_path->c_str(),
+ filename,
+ LL_PATH_CACHE,
+ msg->getSender(),
+ TRUE, // make the remote file temporary.
+ onFileMuteList,
+ (void**)local_filename_and_path,
+ LLXferManager::HIGH_PRIORITY);
+}
+
+void LLMuteList::processUseCachedMuteList(LLMessageSystem* msg, void**)
+{
+ llinfos << "LLMuteList::processUseCachedMuteList()" << llendl;
+ if (!gMuteListp) return;
+
+ char agent_id_string[UUID_STR_LENGTH];
+ gAgent.getID().toString(agent_id_string);
+ char filename[LL_MAX_PATH];
+ sprintf(filename, "%s.cached_mute", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,agent_id_string).c_str());
+ gMuteListp->loadFromFile(filename);
+}
+
+void LLMuteList::onFileMuteList(void** user_data, S32 error_code)
+{
+ llinfos << "LLMuteList::processMuteListFile()" << llendl;
+ if (!gMuteListp) return;
+
+ std::string *local_filename_and_path = (std::string*)user_data;
+ if(local_filename_and_path && !local_filename_and_path->empty() && (error_code == 0))
+ {
+ gMuteListp->loadFromFile(local_filename_and_path->c_str());
+ LLFile::remove(local_filename_and_path->c_str());
+ }
+ delete local_filename_and_path;
+}
+
+void LLMuteList::addObserver(LLMuteListObserver* observer)
+{
+ mObservers.insert(observer);
+}
+
+void LLMuteList::removeObserver(LLMuteListObserver* observer)
+{
+ mObservers.erase(observer);
+}
+
+void LLMuteList::setLoaded()
+{
+ mIsLoaded = TRUE;
+ notifyObservers();
+}
+
+void LLMuteList::notifyObservers()
+{
+ // HACK: LLFloaterMute is constructed before LLMuteList,
+ // so it can't easily observe it. Changing this requires
+ // much reshuffling of the startup process. JC
+ if (gFloaterMute)
+ {
+ gFloaterMute->refreshMuteList();
+ }
+
+ for (observer_set_t::iterator it = mObservers.begin();
+ it != mObservers.end();
+ )
+ {
+ LLMuteListObserver* observer = *it;
+ observer->onChange();
+ // In case onChange() deleted an entry.
+ it = mObservers.upper_bound(observer);
+ }
+}