- Refactored ChatValidator into ChatFilter, which can invalidate a message

by returning null instead of a filtered version.
- Changed the MuteDirector to implement ChatFilter.
- ChatDirector no longer needs a reference to the MuteDirector because
  the outgoing mute-checking is now handled by the standard filtering code.
- Fixed a bug introduced by Walter back in December that caused the
  MuteDirector to be _removed_ as a validator the first time you try to
  /tell to a player that you've muted. How we never detected this, I'll
  stay awake at night wondering...


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@2795 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Ray Greenwell
2003-09-15 21:11:40 +00:00
parent cd6f38ee3d
commit ac52342b17
4 changed files with 92 additions and 107 deletions
@@ -1,5 +1,5 @@
// //
// $Id: ChatDirector.java,v 1.47 2003/06/26 19:57:24 mdb Exp $ // $Id: ChatDirector.java,v 1.48 2003/09/15 21:11:40 ray Exp $
package com.threerings.crowd.chat.client; package com.threerings.crowd.chat.client;
@@ -83,17 +83,6 @@ public class ChatDirector extends BasicDirector
_ctx.getLocationDirector().addLocationObserver(this); _ctx.getLocationDirector().addLocationObserver(this);
} }
/**
* Sets the mute director, if one is desired.
*/
public void setMuteDirector (MuteDirector muter)
{
if (_muter == null) {
_muter = muter;
_muter.setChatDirector(this);
}
}
/** /**
* Adds the supplied chat display to the chat display list. It will * Adds the supplied chat display to the chat display list. It will
* subsequently be notified of incoming chat messages as well as tell * subsequently be notified of incoming chat messages as well as tell
@@ -114,21 +103,21 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* Adds the specified chat validator to the list of validators. All * Adds the specified chat filter to the list of filters. All
* chat requests will be validated with all validators before they may * chat requests and receipts will be filtered with all filters
* be accepted. * before they being sent or dispatched locally.
*/ */
public void addChatValidator (ChatValidator validator) public void addChatFilter (ChatFilter filter)
{ {
_validators.add(validator); _filters.add(filter);
} }
/** /**
* Removes the specified chat validator from the list of chat validators. * Removes the specified chat validator from the list of chat validators.
*/ */
public void removeChatValidator (ChatValidator validator) public void removeChatFilter (ChatFilter filter)
{ {
_validators.remove(validator); _filters.remove(filter);
} }
/** /**
@@ -317,9 +306,8 @@ public class ChatDirector extends BasicDirector
SpeakService speakService, String message, byte mode) SpeakService speakService, String message, byte mode)
{ {
// make sure they can say what they want to say // make sure they can say what they want to say
_validateMessageOp.setMessage(message); message = filter(message, null, true);
_validators.apply(_validateMessageOp); if (message == null) {
if (!_validateMessageOp.isValid()) {
return; return;
} }
@@ -334,6 +322,13 @@ public class ChatDirector extends BasicDirector
*/ */
public void requestBroadcast (String message) public void requestBroadcast (String message)
{ {
message = filter(message, null, true);
if (message == null) {
displayFeedback(_bundle,
MessageBundle.compose("m.broadcast_failed", "m.filtered"));
return;
}
_cservice.broadcast( _cservice.broadcast(
_ctx.getClient(), message, new ChatService.InvocationListener() { _ctx.getClient(), message, new ChatService.InvocationListener() {
public void requestFailed (String reason) { public void requestFailed (String reason) {
@@ -355,12 +350,11 @@ public class ChatDirector extends BasicDirector
* of success or failure. * of success or failure.
*/ */
public void requestTell ( public void requestTell (
final String target, final String message, final ResultListener rl) final String target, String msg, final ResultListener rl)
{ {
// make sure they can say what they want to say // make sure they can say what they want to say
_validateMessageOp.setMessage(target, message); final String message = filter(msg, target, true);
_validators.apply(_validateMessageOp); if (message == null) {
if (!_validateMessageOp.isValid()) {
if (rl != null) { if (rl != null) {
rl.requestFailed(null); rl.requestFailed(null);
} }
@@ -468,12 +462,13 @@ public class ChatDirector extends BasicDirector
if (CHAT_NOTIFICATION.equals(event.getName())) { if (CHAT_NOTIFICATION.equals(event.getName())) {
ChatMessage msg = (ChatMessage) event.getArgs()[0]; ChatMessage msg = (ChatMessage) event.getArgs()[0];
String localtype = getLocalType(event.getTargetOid()); String localtype = getLocalType(event.getTargetOid());
String message = msg.message;
// if the message came from a user, make sure we want to hear it // if the message came from a user, make sure we want to hear it
if (msg instanceof UserMessage) { if (msg instanceof UserMessage) {
String speaker = ((UserMessage) msg).speaker; String speaker = ((UserMessage) msg).speaker;
if (isBlocked(speaker)) { message = filter(message, speaker, false);
// ack! block that message if (message == null) {
return; return;
} else if (USER_CHAT_TYPE.equals(localtype)) { } else if (USER_CHAT_TYPE.equals(localtype)) {
@@ -483,7 +478,7 @@ public class ChatDirector extends BasicDirector
} }
// initialize the client-specific fields of the message // initialize the client-specific fields of the message
msg.setClientInfo(xlate(msg.bundle, msg.message), localtype); msg.setClientInfo(xlate(msg.bundle, message), localtype);
// and send it off! // and send it off!
dispatchMessage(msg); dispatchMessage(msg);
@@ -527,14 +522,6 @@ public class ChatDirector extends BasicDirector
return (type == null) ? PLACE_CHAT_TYPE : type; return (type == null) ? PLACE_CHAT_TYPE : type;
} }
/**
* Returns whether chat from the specified user is to be distributed.
*/
protected boolean isBlocked (String username)
{
return (_muter != null) && _muter.isMuted(username);
}
/** /**
* Used to assign unique ids to all speak requests. * Used to assign unique ids to all speak requests.
*/ */
@@ -587,42 +574,44 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* An operation that checks with all chat validators to determine * Run a message through all the currently registered filters.
* whether chat messages are valid for display.
*/ */
protected static class ValidateMessageOp implements ObserverList.ObserverOp protected String filter (String msg, String otherUser, boolean outgoing)
{ {
public boolean isValid () _filterMessageOp.setMessage(msg, otherUser, outgoing);
{ _filters.apply(_filterMessageOp);
return _valid; return _filterMessageOp.getMessage();
} }
public void setMessage (String message) /**
* An operation that checks with all chat filters to properly filter
* a message prior to sending to the server or displaying.
*/
protected static class FilterMessageOp implements ObserverList.ObserverOp
{
public void setMessage (String msg, String otherUser, boolean outgoing)
{ {
setMessage(null, message); _msg = msg;
} _otherUser = otherUser;
_out = outgoing;
public void setMessage (String target, String message)
{
_target = target;
_message = message;
_valid = true;
} }
public boolean apply (Object observer) public boolean apply (Object observer)
{ {
if (_target == null) { if (_msg != null) {
_valid = ((ChatValidator)observer).validateSpeak(_message); _msg = ((ChatFilter) observer).filter(_msg, _otherUser, _out);
} else {
_valid = ((ChatValidator)observer).validateTell(
_target, _message);
} }
return _valid; return true;
} }
protected String _target; public String getMessage ()
protected String _message; {
protected boolean _valid; return _msg;
}
protected String _otherUser;
protected String _msg;
protected boolean _out;
} }
/** /**
@@ -666,17 +655,14 @@ public class ChatDirector extends BasicDirector
protected ObserverList _displays = protected ObserverList _displays =
new ObserverList(ObserverList.FAST_UNSAFE_NOTIFY); new ObserverList(ObserverList.FAST_UNSAFE_NOTIFY);
/** A list of registered chat validators. */ /** A list of registered chat filters. */
protected ObserverList _validators = protected ObserverList _filters =
new ObserverList(ObserverList.FAST_UNSAFE_NOTIFY); new ObserverList(ObserverList.FAST_UNSAFE_NOTIFY);
/** A mapping from auxiliary chat objects to the types under which /** A mapping from auxiliary chat objects to the types under which
* they are registered. */ * they are registered. */
protected HashIntMap _auxes = new HashIntMap(); protected HashIntMap _auxes = new HashIntMap();
/** An optionally present mutelist director. */
protected MuteDirector _muter;
/** Validator of who may be added to the chatters list. */ /** Validator of who may be added to the chatters list. */
protected ChatterValidator _chatterValidator; protected ChatterValidator _chatterValidator;
@@ -690,8 +676,8 @@ public class ChatDirector extends BasicDirector
/** Used by {@link #nextRequestId}. */ /** Used by {@link #nextRequestId}. */
protected int _requestId; protected int _requestId;
/** Operation used to validate chat messages for display. */ /** Operation used to filter chat messages. */
protected ValidateMessageOp _validateMessageOp = new ValidateMessageOp(); protected FilterMessageOp _filterMessageOp = new FilterMessageOp();
/** Operation used to display chat messages. */ /** Operation used to display chat messages. */
protected DisplayMessageOp _displayMessageOp = new DisplayMessageOp(); protected DisplayMessageOp _displayMessageOp = new DisplayMessageOp();
@@ -0,0 +1,22 @@
//
// $Id: ChatFilter.java,v 1.1 2003/09/15 21:11:40 ray Exp $
package com.threerings.crowd.chat.client;
/**
* Filters messages chat messages to or from the server.
*/
public interface ChatFilter
{
/**
* Filter a chat message.
* @param msg the message text to be filtered.
* @param otherUser an optional argument that represents the target or the
* speaker, depending on 'outgoing', and can be considered in filtering if
* it is provided.
* @param outgoing true if the message is going out to the server.
*
* @return the filtered message, or null to block it completely.
*/
public String filter (String msg, String otherUser, boolean outgoing);
}
@@ -1,22 +0,0 @@
//
// $Id: ChatValidator.java,v 1.2 2003/06/03 21:41:33 ray Exp $
package com.threerings.crowd.chat.client;
/**
* A chat validator validates chat messages before they are sent to the
* server. By default, each method returns true, it is assumed that
* validators will be added that override at least one of the methods.
*/
public interface ChatValidator
{
/**
* Validate that the specified speak message may be sent.
*/
public boolean validateSpeak (String msg);
/**
* Validate that the specified tell message may be sent.
*/
public boolean validateTell (String target, String msg);
}
@@ -1,5 +1,5 @@
// //
// $Id: MuteDirector.java,v 1.9 2003/06/04 02:50:18 ray Exp $ // $Id: MuteDirector.java,v 1.10 2003/09/15 21:11:40 ray Exp $
package com.threerings.crowd.chat.client; package com.threerings.crowd.chat.client;
@@ -20,7 +20,7 @@ import com.threerings.presents.client.Client;
* TODO: This class right now is pretty much just a placeholder. * TODO: This class right now is pretty much just a placeholder.
*/ */
public class MuteDirector extends BasicDirector public class MuteDirector extends BasicDirector
implements ChatValidator implements ChatFilter
{ {
/** /**
* An interface that can be registered with the MuteDirector to * An interface that can be registered with the MuteDirector to
@@ -61,8 +61,7 @@ public class MuteDirector extends BasicDirector
{ {
if (_chatdir == null) { if (_chatdir == null) {
_chatdir = chatdir; _chatdir = chatdir;
_chatdir.addChatValidator(this); _chatdir.addChatFilter(this);
_chatdir.setMuteDirector(this);
} }
} }
@@ -113,21 +112,21 @@ public class MuteDirector extends BasicDirector
return (String[]) _mutelist.toArray(new String[_mutelist.size()]); return (String[]) _mutelist.toArray(new String[_mutelist.size()]);
} }
// documentation inherited from interface ChatValidator // documentation inherited from interface ChatFilter
public boolean validateSpeak (String msg) public String filter (String msg, String otherUser, boolean outgoing)
{ {
return true; // sure! // we are only concerned with filtering things going to or coming
} // from muted users
if ((otherUser != null) && isMuted(otherUser)) {
// documentation inherited from interface ChatValidator // if it was outgoing, explain the dropped message, otherwise
public boolean validateTell (String target, String msg) // silently drop
{ if (outgoing) {
if (isMuted(target)) { _chatdir.displayFeedback(null, "m.no_tell_mute");
_chatdir.displayFeedback(null, "m.no_tell_mute"); }
return false; return null;
} }
return true; // let it go through.. return msg;
} }
/** /**