From a82a270b80a6bb9ed1a6bd1f70a42f4234197c36 Mon Sep 17 00:00:00 2001
From: Monroe Linden <monroe@lindenlab.com>
Date: Fri, 1 Oct 2010 17:43:27 -0700
Subject: More precise control of notifications using
 notification_visibility.xml.

Added a "name" property that lets a rule match a specific notification.
Added a "response" property that lets a rule specify a response when it matches.

Reviewed by Richard.
---
 indra/llui/llnotifications.cpp            | 84 +++++++++++++++++++++----------
 indra/llui/llnotificationvisibilityrule.h | 13 ++++-
 2 files changed, 70 insertions(+), 27 deletions(-)

diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index 289020fa3f..5b2e7590b1 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -182,28 +182,11 @@ bool defaultResponse(const LLSD& payload)
 	return false;
 }
 
-bool emptyResponse(const LLSD& payload)
+bool visibilityRuleMached(const LLSD& payload)
 {
-	if (payload["sigtype"].asString() == "add")
-	{
-		LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID());
-		if (pNotif) 
-		{
-			// supply empty response
-			pNotif->respond(pNotif->getResponseTemplate(LLNotification::WITHOUT_DEFAULT_BUTTON));
-		}
-	}
-	return false;
-}
-
-bool cancelNotification(const LLSD& payload)
-{
-	if (payload["sigtype"].asString() == "add")
-	{
-		// cancel this notification
-		LLNotifications::instance().cancel(LLNotifications::instance().find(payload["id"].asUUID()));
-	}
-	return false;
+	// This is needed because LLNotifications::isVisibleByRules may have cancelled the notification.
+	// Returning true here makes LLNotificationChannelBase::updateItem do an early out, which prevents things from happening in the wrong order.
+	return true;
 }
 
 
@@ -450,8 +433,10 @@ LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Par
 
 LLNotificationVisibilityRule::LLNotificationVisibilityRule(const LLNotificationVisibilityRule::Params &p)
 :	mVisible(p.visible),
+	mResponse(p.response),
 	mType(p.type),
-	mTag(p.tag)
+	mTag(p.tag),
+	mName(p.name)
 {
 }
 
@@ -1290,7 +1275,7 @@ void LLNotifications::createDefaultChannels()
 	LLNotifications::instance().getChannel("Ignore")->
 		connectFailedFilter(&handleIgnoredNotification);
 	LLNotifications::instance().getChannel("VisibilityRules")->
-		connectFailedFilter(&cancelNotification);
+		connectFailedFilter(&visibilityRuleMached);
 }
 
 bool LLNotifications::addTemplate(const std::string &name, 
@@ -1663,6 +1648,12 @@ bool LLNotifications::getIgnoreAllNotifications()
 
 bool LLNotifications::isVisibleByRules(LLNotificationPtr n)
 {
+	if(n->isRespondedTo())
+	{
+		// This avoids infinite recursion in the case where the filter calls respond()
+		return true;
+	}
+	
 	VisibilityRuleList::iterator it;
 	
 	for(it = mVisibilityRules.begin(); it != mVisibilityRules.end(); it++)
@@ -1687,15 +1678,56 @@ bool LLNotifications::isVisibleByRules(LLNotificationPtr n)
 				continue;
 			}
 		}
+
+		if(!(*it)->mName.empty())
+		{
+			lldebugs << "rule name = " << (*it)->mName << ", notification name = " << n->getName() << llendl;
+
+			// check this notification's name against the notification's name and continue if no match is found.
+			if((*it)->mName != n->getName())
+			{
+				// This rule's non-empty name didn't match the notification.  Skip this rule.
+				continue;
+			}
+		}
 		
 		// If we got here, the rule matches.  Don't evaluate subsequent rules.
-		return (*it)->mVisible;
+		if(!(*it)->mVisible)
+		{
+			// This notification is being hidden.
+			
+			if((*it)->mResponse.empty())
+			{
+				// Response property is empty.  Cancel this notification.
+				lldebugs << "cancelling notification " << n->getName() << llendl;
+
+				n->cancel();
+			}
+			else
+			{
+				// Response property is not empty.  Return the specified response.
+				LLSD response = n->getResponseTemplate(LLNotification::WITHOUT_DEFAULT_BUTTON);
+				// TODO: verify that the response template has an item with the correct name
+				response[(*it)->mResponse] = true;
+
+				lldebugs << "responding to notification " << n->getName() << " with response = " << response << llendl;
+				
+				n->respond(response);
+			}
+
+			return false;
+		}
+		
+		// If we got here, exit the loop and return true.
+		break;
 	}
 	
-	// Default for cases with no rules or incomplete rules is to show all notifications.
+	lldebugs << "allowing notification " << n->getName() << llendl;
+
 	return true;
 }
-													
+			
+
 // ---
 // END OF LLNotifications implementation
 // =========================================================
diff --git a/indra/llui/llnotificationvisibilityrule.h b/indra/llui/llnotificationvisibilityrule.h
index a98591c9d6..58a7eb6176 100644
--- a/indra/llui/llnotificationvisibilityrule.h
+++ b/indra/llui/llnotificationvisibilityrule.h
@@ -40,13 +40,17 @@ struct LLNotificationVisibilityRule
 	struct Params : public LLInitParam::Block<Params>
 	{
 		Mandatory<bool>	visible;
+		Optional<std::string> response;
 		Optional<std::string> type;
 		Optional<std::string> tag;
+		Optional<std::string> name;
 
 		Params()
 		:	visible("visible"),
+			response("response"),
 			type("type"),
-			tag("tag")
+			tag("tag"),
+			name("name")
 		{}
 	};
 
@@ -65,11 +69,18 @@ struct LLNotificationVisibilityRule
     // If true, this rule makes matching notifications visible.  Otherwise, it makes them invisible.
     bool mVisible;
 
+    // Which response to give when making a notification invisible.  An empty string means the notification should be cancelled instead of responded to.
+	std::string mResponse;
+
     // String to match against the notification's "type".  An empty string matches all notifications.
     std::string mType;
 	
     // String to match against the notification's tag(s).  An empty string matches all notifications.
 	std::string mTag;
+
+    // String to match against the notification's name.  An empty string matches all notifications.
+	std::string mName;
+	
 };
 
 #endif //LL_LLNOTIFICATION_VISIBILITY_RULE_H
-- 
cgit v1.2.3