diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 577cbed16..537a22a41 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -9,6 +9,17 @@
settings_rlv.xml
+ ScriptsCanShowUI
+
FloaterObjectBackuptRect
-
+ SGBlockGeneralSpam
+
+ SGBlockCardSpam
+
+ SGBlockChatSpam
+
+ SGBlockDialogSpam
+
+ SGSpamTime
+
+ SGSpamCount
+
+ SGChatSpamTime
+
+ SGChatSpamCount
+
+
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index a9fc5c5f8..aedd47d40 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -232,6 +232,75 @@ const BOOL SCRIPT_QUESTION_IS_CAUTION[SCRIPT_PERMISSION_EOF] =
FALSE // ControlYourCamera
};
+template
+class SH_SpamHandler
+{
+public:
+ SH_SpamHandler(const char *pToggleCtrl, const char *pDurCtrl, const char *pFreqCtrl) :
+ mDuration(pDurCtrl, 1.f),
+ mFrequency(pFreqCtrl, 5),
+ mEnabled(false)
+ {
+ gSavedSettings.getControl(pToggleCtrl)->getSignal()->connect(boost::bind(&SH_SpamHandler::CtrlToggle, this, _1));
+ CtrlToggle(gSavedSettings.getBOOL(pToggleCtrl));
+ }
+ bool CtrlToggle(const LLSD& newvalue)
+ {
+ bool on = newvalue.asBoolean();
+ if(on == mEnabled)
+ return true;
+ mEnabled = on;
+ mTimer.stop();
+ mActiveList.clear();
+ mBlockedList.clear();
+ return true;
+ }
+ bool isBlocked(const T &owner, const LLUUID &source_id, const char *pNotification, LLSD &args=LLSD())
+ {
+ if(!mEnabled || isAgent(owner))
+ return false;
+ if(mBlockedList.find(owner) != mBlockedList.end())
+ return true;
+ if(mTimer.getStarted() && mTimer.getElapsedTimeF32() < mDuration)
+ {
+ std::map::iterator it = mActiveList.insert(std::pair(owner,0)).first;
+ if(++(it->second)>=mFrequency)
+ {
+ mBlockedList.insert(owner);
+ if(pNotification)
+ {
+ args["OWNER"] = owner;
+ args["SOURCE"] = source_id;
+ LLNotifications::getInstance()->add(pNotification,args);
+ }
+ return true;
+ }
+ }
+ else
+ {
+ mActiveList.clear();
+ mTimer.start();
+ }
+ return false;
+ }
+private:
+ //Owner is either a key, or a name. Do not look up perms since object may be unknown.
+ bool isAgent(const T &owner) const;
+ bool mEnabled;
+ LLFrameTimer mTimer;
+ const LLCachedControl mDuration;
+ const LLCachedControl mFrequency;
+ std::map mActiveList;
+ std::set mBlockedList;
+};
+template<> bool SH_SpamHandler::isAgent(const LLUUID &owner) const { return gAgent.getID() == owner; }
+template<> bool SH_SpamHandler::isAgent(const std::string &owner) const
+{
+ std::string str;
+ gAgent.getName(str);
+ return str == owner;
+}
+
bool friendship_offer_callback(const LLSD& notification, const LLSD& response)
{
S32 option = LLNotification::getSelectedOption(notification, response);
@@ -1631,6 +1700,21 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
chat.mFromID = from_id;
chat.mFromName = name;
chat.mSourceType = (from_id.isNull() || (name == std::string(SYSTEM_FROM))) ? CHAT_SOURCE_SYSTEM : CHAT_SOURCE_AGENT;
+
+ if(chat.mSourceType == CHAT_SOURCE_AGENT)
+ {
+ LLSD args;
+ args["FULL_NAME"] = name;
+ static SH_SpamHandler avatar_spam_check("SGBlockGeneralSpam","SGSpamTime","SGSpamCount");
+ static SH_SpamHandler object_spam_check("SGBlockGeneralSpam","SGSpamTime","SGSpamCount");
+ if(d==IM_FROM_TASK||d==IM_GOTO_URL||d==IM_FROM_TASK_AS_ALERT||d==IM_TASK_INVENTORY_OFFERED||d==IM_TASK_INVENTORY_ACCEPTED||d==IM_TASK_INVENTORY_DECLINED)
+ {
+ if(object_spam_check.isBlocked(from_id,session_id,"BlockedGeneralObjects"),args)
+ return;
+ }
+ else if(avatar_spam_check.isBlocked(from_id,from_id,"BlockedGeneralAvatar"),args)
+ return;
+ }
LLViewerObject *source = gObjectList.findObject(session_id); //Session ID is probably the wrong thing.
if (source)
@@ -2812,6 +2896,9 @@ void process_offer_callingcard(LLMessageSystem* msg, void**)
}
else
{
+ static SH_SpamHandler spam_check("SGBlockCardSpam","SHSpamTime","SGSpamCount");
+ if(spam_check.isBlocked(source_id,source_id,"BlockedCards",args))
+ return;
LLNotifications::instance().add("OfferCallingCard", args, payload);
}
}
@@ -2985,6 +3072,14 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
//
if (chatter)
{
+ LLSD args;
+ args["FULL_NAME"] = from_name;
+ static SH_SpamHandler avatar_spam_check("SGBlockChatSpam","SGChatSpamTime","SGChatSpamCount");
+ static SH_SpamHandler object_spam_check("SGBlockChatSpam","SGChatSpamTime","SGChatSpamCount");
+ if( (chatter->isAvatar() && avatar_spam_check.isBlocked(from_id,from_id,"BlockedChatterAvatar",args)) ||
+ (!chatter->isAvatar() && object_spam_check.isBlocked(owner_id,from_id,"BlockedChatterObjects",args)) )
+ return;
+
chat.mPosAgent = chatter->getPositionAgent();
// Make swirly things only for talking objects. (not script debug messages, though)
@@ -6366,17 +6461,22 @@ static LLNotificationFunctorRegistration callback_script_dialog_reg_2("ScriptDia
void process_script_dialog(LLMessageSystem* msg, void**)
{
S32 i;
-
LLSD payload;
+ LLUUID object_id;
+ msg->getUUID("Data", "ObjectID", object_id);
+
+ if (LLMuteList::getInstance()->isMuted(object_id))
+ {
+ return;
+ }
+
std::string message;
std::string first_name;
std::string last_name;
std::string title;
- LLUUID object_id;
S32 chat_channel;
- msg->getUUID("Data", "ObjectID", object_id);
msg->getString("Data", "FirstName", first_name);
msg->getString("Data", "LastName", last_name);
msg->getString("Data", "ObjectName", title);
@@ -6437,6 +6537,10 @@ void process_script_dialog(LLMessageSystem* msg, void**)
args["FIRST"] = first_name;
args["LAST"] = last_name;
+ static SH_SpamHandler spam_check("SGBlockDialogSpam","SGSpamTime","SGSpamCount");
+ if(spam_check.isBlocked(first_name + " " + last_name,object_id,"BlockedDialogs",args))
+ return;
+
if (is_text_box)
{
args["DEFAULT"] = default_text;
@@ -6601,6 +6705,8 @@ void process_initiate_download(LLMessageSystem* msg, void**)
void process_script_teleport_request(LLMessageSystem* msg, void**)
{
+ if (!gSavedSettings.getBOOL("ScriptsCanShowUI")) return;
+
std::string object_name;
std::string sim_name;
LLVector3 pos;
diff --git a/indra/newview/skins/default/xui/en-us/notifications.xml b/indra/newview/skins/default/xui/en-us/notifications.xml
index ab432afd1..a89b0b0c0 100644
--- a/indra/newview/skins/default/xui/en-us/notifications.xml
+++ b/indra/newview/skins/default/xui/en-us/notifications.xml
@@ -6933,6 +6933,12 @@ No
For instructions, make a new template in the AO. Use the toolbar to toggle the AO on/off.
+ Blocked calling cards from [FIRST] [LAST] ([SOURCE])
+ Blocking all dialogs from [FIRST] [LAST]'s objects. (Origin: [SOURCE])
+ Blocked spam from avatar [FULL_NAME] ([SOURCE])
+ Blocked spam from objects owned by [OWNER] ([SOURCE])
+ Blocked chat-spam from avatar [FULL_NAME] ([SOURCE])
+ Blocked chat-spam from objects owned by [OWNER] ([SOURCE])