Widened. Allow the chat mogrification to be turned off.

git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4494 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2006-12-23 19:33:18 +00:00
parent 7cea2a7088
commit 679030dc2c
@@ -63,16 +63,15 @@ import com.threerings.crowd.chat.data.UserMessage;
import com.threerings.crowd.chat.data.UserSystemMessage; import com.threerings.crowd.chat.data.UserSystemMessage;
/** /**
* The chat director is the client side coordinator of all chat related * The chat director is the client side coordinator of all chat related services. It handles both
* services. It handles both place constrained chat as well as direct * place constrained chat as well as direct messaging.
* messaging.
*/ */
public class ChatDirector extends BasicDirector public class ChatDirector extends BasicDirector
implements ChatCodes, LocationObserver, MessageListener implements ChatCodes, LocationObserver, MessageListener
{ {
/** /**
* An interface to receive information about the {@link #MAX_CHATTERS} * An interface to receive information about the {@link #MAX_CHATTERS} most recent users that
* most recent users that we've been chatting with. * we've been chatting with.
*/ */
public static interface ChatterObserver public static interface ChatterObserver
{ {
@@ -83,8 +82,8 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* An interface for those who would like to validate whether usernames * An interface for those who would like to validate whether usernames may be added to the
* may be added to the chatter list. * chatter list.
*/ */
public static interface ChatterValidator public static interface ChatterValidator
{ {
@@ -102,28 +101,23 @@ public class ChatDirector extends BasicDirector
/** /**
* Handles the specified chat command. * Handles the specified chat command.
* *
* @param speakSvc an optional SpeakService object representing * @param speakSvc an optional SpeakService object representing the object to send the chat
* the object to send the chat message on. * message on.
* @param command the slash command that was used to invoke this * @param command the slash command that was used to invoke this handler
* handler (e.g. <code>/tell</code>). * (e.g. <code>/tell</code>).
* @param args the arguments provided along with the command (e.g. * @param args the arguments provided along with the command (e.g. <code>Bob hello</code>)
* <code>Bob hello</code>) or <code>null</code> if no arguments * or <code>null</code> if no arguments were supplied.
* were supplied. * @param history an in/out parameter that allows the command to modify the text that will
* @param history an in/out parameter that allows the command to * be appended to the chat history. If this is set to null, nothing will be appended.
* modify the text that will be appended to the chat history. If
* this is set to null, nothing will be appended.
* *
* @return an untranslated string that will be reported to the * @return an untranslated string that will be reported to the chat box to convey an error
* chat box to convey an error response to the user, or {@link * response to the user, or {@link ChatCodes#SUCCESS}.
* ChatCodes#SUCCESS}.
*/ */
public abstract String handleCommand ( public abstract String handleCommand (SpeakService speakSvc, String command, String args,
SpeakService speakSvc, String command, String args, String[] history);
String[] history);
/** /**
* Returns true if this user should have access to this chat * Returns true if this user should have access to this chat command.
* command.
*/ */
public boolean checkAccess (BodyObject user) public boolean checkAccess (BodyObject user)
{ {
@@ -132,14 +126,12 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* Creates a chat director and initializes it with the supplied * Creates a chat director and initializes it with the supplied context. The chat director will
* context. The chat director will register itself as a location * register itself as a location observer so that it can automatically process place
* observer so that it can automatically process place constrained * constrained chat.
* chat.
* *
* @param msgmgr the message manager via which we do our translations. * @param msgmgr the message manager via which we do our translations.
* @param bundle the message bundle from which we obtain our * @param bundle the message bundle from which we obtain our chat-related translation strings.
* chat-related translation strings.
*/ */
public ChatDirector (CrowdContext ctx, MessageManager msgmgr, String bundle) public ChatDirector (CrowdContext ctx, MessageManager msgmgr, String bundle)
{ {
@@ -169,9 +161,8 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* Adds the supplied chat display to the front of the chat display list. It * Adds the supplied chat display to the front of the chat display list. It will subsequently
* will subsequently be notified of incoming chat messages as well as tell * be notified of incoming chat messages as well as tell responses.
* responses.
*/ */
public void pushChatDisplay (ChatDisplay display) public void pushChatDisplay (ChatDisplay display)
{ {
@@ -179,9 +170,8 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* Adds the supplied chat display to the end of the chat display list. It * Adds the supplied chat display to the end of the chat display list. It will subsequently be
* will subsequently be notified of incoming chat messages as well as tell * notified of incoming chat messages as well as tell responses.
* responses.
*/ */
public void addChatDisplay (ChatDisplay display) public void addChatDisplay (ChatDisplay display)
{ {
@@ -189,8 +179,8 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* Removes the specified chat display from the chat display list. The * Removes the specified chat display from the chat display list. The display will no longer
* display will no longer receive chat related notifications. * receive chat related notifications.
*/ */
public void removeChatDisplay (ChatDisplay display) public void removeChatDisplay (ChatDisplay display)
{ {
@@ -198,9 +188,8 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* Adds the specified chat filter to the list of filters. All * Adds the specified chat filter to the list of filters. All chat requests and receipts will
* chat requests and receipts will be filtered with all filters * be filtered with all filters before they being sent or dispatched locally.
* before they being sent or dispatched locally.
*/ */
public void addChatFilter (ChatFilter filter) public void addChatFilter (ChatFilter filter)
{ {
@@ -216,8 +205,7 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* Adds an observer that watches the chatters list, and updates it * Adds an observer that watches the chatters list, and updates it immediately.
* immediately.
*/ */
public void addChatterObserver (ChatterObserver co) public void addChatterObserver (ChatterObserver co)
{ {
@@ -234,27 +222,36 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* Sets the validator that decides if a username is valid to be * Sets the validator that decides if a username is valid to be added to the chatter list, or
* added to the chatter list, or null if no such filtering is desired. * null if no such filtering is desired.
*/ */
public void setChatterValidator (ChatterValidator validator) public void setChatterValidator (ChatterValidator validator)
{ {
_chatterValidator = validator; _chatterValidator = validator;
} }
/**
* Enables or disables the chat mogrifier. The mogrifier converts chat speak like LOL, WTF,
* etc. into phrases, words and can also transform them into emotes. The mogrifier is
* configured via the <code>x.mogrifies</code> and <code>x.transforms</code> translation
* properties.
*/
public void setMogrifyChat (boolean mogrifyChat)
{
_mogrifyChat = mogrifyChat;
}
/** /**
* Registers a chat command handler. * Registers a chat command handler.
* *
* @param msg the message bundle via which the slash command will be * @param msg the message bundle via which the slash command will be translated (as
* translated (as <code>c.</code><i>command</i>). If no translation * <code>c.</code><i>command</i>). If no translation exists the command will be
* exists the command will be <code>/</code><i>command</i>. * <code>/</code><i>command</i>.
* @param command the name of the command that will be used to invoke * @param command the name of the command that will be used to invoke this handler
* this handler (e.g. <code>tell</code> if the command will be invoked * (e.g. <code>tell</code> if the command will be invoked as <code>/tell</code>).
* as <code>/tell</code>).
* @param handler the chat command handler itself. * @param handler the chat command handler itself.
*/ */
public void registerCommandHandler ( public void registerCommandHandler (MessageBundle msg, String command, CommandHandler handler)
MessageBundle msg, String command, CommandHandler handler)
{ {
String key = "c." + command; String key = "c." + command;
if (msg.exists(key)) { if (msg.exists(key)) {
@@ -277,8 +274,7 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* Get the chat history entry at the specified index, * Get the chat history entry at the specified index, with 0 being the oldest.
* with 0 being the oldest.
*/ */
public String getCommandHistory (int index) public String getCommandHistory (int index)
{ {
@@ -307,11 +303,11 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* Display a system INFO message as if it had come from the server. * Display a system INFO message as if it had come from the server. The localtype of the
* The localtype of the message will be PLACE_CHAT_TYPE. * message will be PLACE_CHAT_TYPE.
* *
* Info messages are sent when something happens that was neither * Info messages are sent when something happens that was neither directly triggered by the
* directly triggered by the user, nor requires direct action. * user, nor requires direct action.
*/ */
public void displayInfo (String bundle, String message) public void displayInfo (String bundle, String message)
{ {
@@ -321,8 +317,8 @@ public class ChatDirector extends BasicDirector
/** /**
* Display a system INFO message as if it had come from the server. * Display a system INFO message as if it had come from the server.
* *
* Info messages are sent when something happens that was neither * Info messages are sent when something happens that was neither directly triggered by the
* directly triggered by the user, nor requires direct action. * user, nor requires direct action.
*/ */
public void displayInfo (String bundle, String message, String localtype) public void displayInfo (String bundle, String message, String localtype)
{ {
@@ -330,29 +326,27 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* Display a system FEEDBACK message as if it had come from the server. * Display a system FEEDBACK message as if it had come from the server. The localtype of the
* The localtype of the message will be PLACE_CHAT_TYPE. * message will be PLACE_CHAT_TYPE.
* *
* Feedback messages are sent in direct response to a user action, * Feedback messages are sent in direct response to a user action, usually to indicate success
* usually to indicate success or failure of the user's action. * or failure of the user's action.
*/ */
public void displayFeedback (String bundle, String message) public void displayFeedback (String bundle, String message)
{ {
displaySystem( displaySystem(bundle, message, SystemMessage.FEEDBACK, PLACE_CHAT_TYPE);
bundle, message, SystemMessage.FEEDBACK, PLACE_CHAT_TYPE);
} }
/** /**
* Display a system ATTENTION message as if it had come from the server. * Display a system ATTENTION message as if it had come from the server. The localtype of the
* The localtype of the message will be PLACE_CHAT_TYPE. * message will be PLACE_CHAT_TYPE.
* *
* Attention messages are sent when something requires user action * Attention messages are sent when something requires user action that did not result from
* that did not result from direct action by the user. * direct action by the user.
*/ */
public void displayAttention (String bundle, String message) public void displayAttention (String bundle, String message)
{ {
displaySystem( displaySystem(bundle, message, SystemMessage.ATTENTION, PLACE_CHAT_TYPE);
bundle, message, SystemMessage.ATTENTION, PLACE_CHAT_TYPE);
} }
/** /**
@@ -365,21 +359,18 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* Parses and delivers the supplied chat message. Slash command * Parses and delivers the supplied chat message. Slash command processing and mogrification
* processing and mogrification are performed and the message is added * are performed and the message is added to the chat history if appropriate.
* to the chat history if appropriate.
* *
* @param speakSvc the SpeakService representing the target dobj of * @param speakSvc the SpeakService representing the target dobj of the speak or null if we
* the speak or null if we should speak in the "default" way. * should speak in the "default" way.
* @param text the text to be parsed and sent. * @param text the text to be parsed and sent.
* @param record if text is a command, should it be added to the history? * @param record if text is a command, should it be added to the history?
* *
* @return <code>ChatCodes#SUCCESS</code> if the message was parsed * @return <code>ChatCodes#SUCCESS</code> if the message was parsed and sent correctly, a
* and sent correctly, a translatable error string if there was some * translatable error string if there was some problem.
* problem.
*/ */
public String requestChat ( public String requestChat (SpeakService speakSvc, String text, boolean record)
SpeakService speakSvc, String text, boolean record)
{ {
if (text.startsWith("/")) { if (text.startsWith("/")) {
// split the text up into a command and arguments // split the text up into a command and arguments
@@ -392,13 +383,11 @@ public class ChatDirector extends BasicDirector
args = text.substring(sidx+1).trim(); args = text.substring(sidx+1).trim();
} }
HashMap<String,CommandHandler> possibleCommands = HashMap<String,CommandHandler> possibleCommands = getCommandHandlers(command);
getCommandHandlers(command);
switch (possibleCommands.size()) { switch (possibleCommands.size()) {
case 0: case 0:
StringTokenizer tok = new StringTokenizer(text); StringTokenizer tok = new StringTokenizer(text);
return MessageBundle.tcompose( return MessageBundle.tcompose("m.unknown_command", tok.nextToken());
"m.unknown_command", tok.nextToken());
case 1: case 1:
Map.Entry<String,CommandHandler> entry = Map.Entry<String,CommandHandler> entry =
@@ -406,8 +395,7 @@ public class ChatDirector extends BasicDirector
String cmdName = entry.getKey(); String cmdName = entry.getKey();
CommandHandler cmd = entry.getValue(); CommandHandler cmd = entry.getValue();
String result = cmd.handleCommand( String result = cmd.handleCommand(speakSvc, cmdName, args, hist);
speakSvc, cmdName, args, hist);
if (!result.equals(ChatCodes.SUCCESS)) { if (!result.equals(ChatCodes.SUCCESS)) {
return result; return result;
} }
@@ -416,8 +404,7 @@ public class ChatDirector extends BasicDirector
// get the final history-ready command string // get the final history-ready command string
hist[0] = "/" + ((hist[0] == null) ? command : hist[0]); hist[0] = "/" + ((hist[0] == null) ? command : hist[0]);
// remove from history if it was present and // remove from history if it was present and add it to the end
// add it to the end
addToHistory(hist[0]); addToHistory(hist[0]);
} }
@@ -425,13 +412,11 @@ public class ChatDirector extends BasicDirector
default: default:
String alternativeCommands = ""; String alternativeCommands = "";
Iterator<String> itr = Collections.getSortedIterator( Iterator<String> itr = Collections.getSortedIterator(possibleCommands.keySet());
possibleCommands.keySet());
while (itr.hasNext()) { while (itr.hasNext()) {
alternativeCommands += " /" + itr.next(); alternativeCommands += " /" + itr.next();
} }
return MessageBundle.tcompose( return MessageBundle.tcompose("m.unspecific_command", alternativeCommands);
"m.unspecific_command", alternativeCommands);
} }
} }
@@ -446,21 +431,18 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* Requests that a speak message with the specified mode be generated * Requests that a speak message with the specified mode be generated and delivered via the
* and delivered via the supplied speak service instance (which will * supplied speak service instance (which will be associated with a particular "speak
* be associated with a particular "speak object"). The message will * object"). The message will first be validated by all registered {@link ChatFilter}s (and
* first be validated by all registered {@link ChatFilter}s (and
* possibly vetoed) before being dispatched. * possibly vetoed) before being dispatched.
* *
* @param speakService the speak service to use when generating the * @param speakService the speak service to use when generating the speak request or null if we
* speak request or null if we should speak in the current "place". * should speak in the current "place".
* @param message the contents of the speak message. * @param message the contents of the speak message.
* @param mode a speech mode that will be interpreted by the {@link * @param mode a speech mode that will be interpreted by the {@link ChatDisplay}
* ChatDisplay} implementations that eventually display this speak * implementations that eventually display this speak message.
* message.
*/ */
public void requestSpeak ( public void requestSpeak (SpeakService speakService, String message, byte mode)
SpeakService speakService, String message, byte mode)
{ {
if (speakService == null) { if (speakService == null) {
if (_place == null) { if (_place == null) {
@@ -488,33 +470,25 @@ public class ChatDirector extends BasicDirector
{ {
message = filter(message, null, true); message = filter(message, null, true);
if (message == null) { if (message == null) {
displayFeedback(_bundle, displayFeedback(_bundle, MessageBundle.compose("m.broadcast_failed", "m.filtered"));
MessageBundle.compose("m.broadcast_failed", "m.filtered"));
return; return;
} }
_cservice.broadcast(_ctx.getClient(), message, new ChatService.InvocationListener() {
_cservice.broadcast( public void requestFailed (String reason) {
_ctx.getClient(), message, new ChatService.InvocationListener() { reason = MessageBundle.compose("m.broadcast_failed", reason);
public void requestFailed (String reason) { displayFeedback(_bundle, reason);
reason = MessageBundle.compose( }
"m.broadcast_failed", reason); });
displayFeedback(_bundle, reason);
}
});
} }
/** /**
* Requests that a tell message be delivered to the specified target * Requests that a tell message be delivered to the specified target user.
* user.
* *
* @param target the username of the user to which the tell message * @param target the username of the user to which the tell message should be delivered.
* should be delivered.
* @param msg the contents of the tell message. * @param msg the contents of the tell message.
* @param rl an optional result listener if you'd like to be notified * @param rl an optional result listener if you'd like to be notified of success or failure.
* of success or failure.
*/ */
public void requestTell (final Name target, String msg, public void requestTell (final Name target, String msg, final ResultListener<Name> rl)
final ResultListener<Name> rl)
{ {
// make sure they can say what they want to say // make sure they can say what they want to say
final String message = filter(msg, target, true); final String message = filter(msg, target, true);
@@ -528,15 +502,13 @@ public class ChatDirector extends BasicDirector
// create a listener that will report success or failure // create a listener that will report success or failure
ChatService.TellListener listener = new ChatService.TellListener() { ChatService.TellListener listener = new ChatService.TellListener() {
public void tellSucceeded (long idletime, String awayMessage) { public void tellSucceeded (long idletime, String awayMessage) {
success(xlate(_bundle, MessageBundle.tcompose( success(xlate(_bundle, MessageBundle.tcompose("m.told_format", target, message)));
"m.told_format", target, message)));
// if they have an away message, report that // if they have an away message, report that
if (awayMessage != null) { if (awayMessage != null) {
awayMessage = filter(awayMessage, target, false); awayMessage = filter(awayMessage, target, false);
if (awayMessage != null) { if (awayMessage != null) {
String msg = MessageBundle.tcompose( String msg = MessageBundle.tcompose("m.recipient_afk", target, awayMessage);
"m.recipient_afk", target, awayMessage);
displayFeedback(_bundle, msg); displayFeedback(_bundle, msg);
} }
} }
@@ -544,8 +516,7 @@ public class ChatDirector extends BasicDirector
// if they are idle, report that // if they are idle, report that
if (idletime > 0L) { if (idletime > 0L) {
// adjust by the time it took them to become idle // adjust by the time it took them to become idle
idletime += _ctx.getConfig().getValue( idletime += _ctx.getConfig().getValue(IDLE_TIME_KEY, DEFAULT_IDLE_TIME);
IDLE_TIME_KEY, DEFAULT_IDLE_TIME);
String msg = MessageBundle.compose( String msg = MessageBundle.compose(
"m.recipient_idle", MessageBundle.taint(target), "m.recipient_idle", MessageBundle.taint(target),
TimeUtil.getTimeOrderString(idletime, TimeUtil.MINUTE)); TimeUtil.getTimeOrderString(idletime, TimeUtil.MINUTE));
@@ -575,17 +546,15 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* Configures a message that will be automatically reported to anyone * Configures a message that will be automatically reported to anyone that sends a tell message
* that sends a tell message to this client to indicate that we are * to this client to indicate that we are busy or away from the keyboard.
* busy or away from the keyboard.
*/ */
public void setAwayMessage (String message) public void setAwayMessage (String message)
{ {
if (message != null) { if (message != null) {
message = filter(message, null, true); message = filter(message, null, true);
if (message == null) { if (message == null) {
// they filtered away their own away message.. // they filtered away their own away message.. change it to something
// change it to something
message = "..."; message = "...";
} }
} }
@@ -594,13 +563,12 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* Adds an additional object via which chat messages may arrive. The * Adds an additional object via which chat messages may arrive. The chat director assumes the
* chat director assumes the caller will be managing the subscription * caller will be managing the subscription to this object and will remain subscribed to it for
* to this object and will remain subscribed to it for as long as it * as long as it remains in effect as an auxiliary chat source.
* remains in effect as an auxiliary chat source.
* *
* @param localtype a type to be associated with all chat messages * @param localtype a type to be associated with all chat messages that arrive on the specified
* that arrive on the specified DObject. * DObject.
*/ */
public void addAuxiliarySource (DObject source, String localtype) public void addAuxiliarySource (DObject source, String localtype)
{ {
@@ -699,8 +667,7 @@ public class ChatDirector extends BasicDirector
addChatter(speaker); addChatter(speaker);
// note whether or not we have an auto-response // note whether or not we have an auto-response
BodyObject self = (BodyObject) BodyObject self = (BodyObject)_ctx.getClient().getClientObject();
_ctx.getClient().getClientObject();
if (!StringUtil.isBlank(self.awayMessage)) { if (!StringUtil.isBlank(self.awayMessage)) {
autoResponse = self.awayMessage; autoResponse = self.awayMessage;
} }
@@ -770,43 +737,38 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* Called to determine whether we are permitted to post the supplied * Called to determine whether we are permitted to post the supplied chat message. Derived
* chat message. Derived classes may wish to throttle chat or restrict * classes may wish to throttle chat or restrict certain types in certain circumstances for
* certain types in certain circumstances for whatever reason. * whatever reason.
* *
* @return null if the chat is permitted, SUCCESS if the chat is permitted * @return null if the chat is permitted, SUCCESS if the chat is permitted and has already been
* and has already been dealt with, or a translatable string * dealt with, or a translatable string indicating the reason for rejection if not.
* indicating the reason for rejection if not.
*/ */
protected String checkCanChat ( protected String checkCanChat (SpeakService speakSvc, String message, byte mode)
SpeakService speakSvc, String message, byte mode)
{ {
return null; return null;
} }
/** /**
* Delivers a plain chat message (not a slash command) on the * Delivers a plain chat message (not a slash command) on the specified speak service in the
* specified speak service in the specified mode. The message will be * specified mode. The message will be mogrified and filtered prior to delivery.
* mogrified and filtered prior to delivery.
* *
* @return {@link ChatCodes#SUCCESS} if the message was delivered or a * @return {@link ChatCodes#SUCCESS} if the message was delivered or a string indicating why it
* string indicating why it failed. * failed.
*/ */
protected String deliverChat ( protected String deliverChat (SpeakService speakSvc, String message, byte mode)
SpeakService speakSvc, String message, byte mode)
{ {
// run the message through our mogrification process // run the message through our mogrification process
message = mogrifyChat(message, true, mode != ChatCodes.EMOTE_MODE); message = mogrifyChat(message, true, mode != ChatCodes.EMOTE_MODE);
// mogrification may result in something being turned into a slash // mogrification may result in something being turned into a slash command, in which case
// command, in which case we have to run everything through again // we have to run everything through again from the start
// from the start
if (message.startsWith("/")) { if (message.startsWith("/")) {
return requestChat(speakSvc, message, false); return requestChat(speakSvc, message, false);
} }
// make sure this client is not restricted from performing this // make sure this client is not restricted from performing this chat message for some
// chat message for some reason or other // reason or other
String errmsg = checkCanChat(speakSvc, message, mode); String errmsg = checkCanChat(speakSvc, message, mode);
if (errmsg != null) { if (errmsg != null) {
return errmsg; return errmsg;
@@ -819,7 +781,7 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* Add the specified command to the history. * Adds the specified command to the history.
*/ */
protected void addToHistory (String cmd) protected void addToHistory (String cmd)
{ {
@@ -836,13 +798,12 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* Mogrify common literary crutches into more appealing chat or * Mogrifies common literary crutches into more appealing chat or commands.
* commands.
* *
* @param transformsAllowed if true, the chat may transformed into a * @param transformsAllowed if true, the chat may transformed into a different mode. (lol ->
* different mode. (lol -> /emote laughs) * /emote laughs)
* @param capFirst if true, the first letter of the text is * @param capFirst if true, the first letter of the text is capitalized. This is not desired if
* capitalized. This is not desired if the chat is already an emote. * the chat is already an emote.
*/ */
protected String mogrifyChat ( protected String mogrifyChat (
String text, boolean transformsAllowed, boolean capFirst) String text, boolean transformsAllowed, boolean capFirst)
@@ -876,12 +837,14 @@ public class ChatDirector extends BasicDirector
protected StringBuffer mogrifyChat ( protected StringBuffer mogrifyChat (
StringBuffer buf, boolean transformsAllowed, boolean capFirst) StringBuffer buf, boolean transformsAllowed, boolean capFirst)
{ {
// do the generic mogrifications and translations if (_mogrifyChat) {
buf = translatedReplacements("x.mogrifies", buf); // do the generic mogrifications and translations
buf = translatedReplacements("x.mogrifies", buf);
// perform themed expansions and transformations // perform themed expansions and transformations
if (transformsAllowed) { if (transformsAllowed) {
buf = translatedReplacements("x.transforms", buf); buf = translatedReplacements("x.transforms", buf);
}
} }
/* /*
@@ -906,8 +869,8 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* Do all the replacements (mogrifications) specified in the * Do all the replacements (mogrifications) specified in the translation string specified by
* translation string specified by the key. * the key.
*/ */
protected StringBuffer translatedReplacements (String key, StringBuffer buf) protected StringBuffer translatedReplacements (String key, StringBuffer buf)
{ {
@@ -920,8 +883,7 @@ public class ChatDirector extends BasicDirector
while (st.hasMoreTokens()) { while (st.hasMoreTokens()) {
String pattern = st.nextToken(); String pattern = st.nextToken();
String replace = st.nextToken(); String replace = st.nextToken();
Matcher m = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE). Matcher m = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE).matcher(buf);
matcher(buf);
if (m.find()) { if (m.find()) {
buf = new StringBuffer(); buf = new StringBuffer();
m.appendReplacement(buf, replace); m.appendReplacement(buf, replace);
@@ -945,14 +907,12 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* Returns a hashmap containing all command handlers that match the * Returns a hashmap containing all command handlers that match the specified command (i.e. the
* specified command (i.e. the specified command is a prefix of their * specified command is a prefix of their registered command string).
* registered command string).
*/ */
protected HashMap<String,CommandHandler> getCommandHandlers (String command) protected HashMap<String,CommandHandler> getCommandHandlers (String command)
{ {
HashMap<String,CommandHandler> matches = HashMap<String,CommandHandler> matches = new HashMap<String,CommandHandler>();
new HashMap<String,CommandHandler>();
BodyObject user = (BodyObject)_ctx.getClient().getClientObject(); BodyObject user = (BodyObject)_ctx.getClient().getClientObject();
for (Map.Entry<String,CommandHandler> entry : _handlers.entrySet()) { for (Map.Entry<String,CommandHandler> entry : _handlers.entrySet()) {
String cmd = entry.getKey(); String cmd = entry.getKey();
@@ -974,26 +934,22 @@ public class ChatDirector extends BasicDirector
protected void addChatter (Name name) protected void addChatter (Name name)
{ {
// check to see if the chatter validator approves.. // check to see if the chatter validator approves..
if ((_chatterValidator != null) && if ((_chatterValidator != null) && (!_chatterValidator.isChatterValid(name))) {
(!_chatterValidator.isChatterValid(name))) {
return; return;
} }
boolean wasthere = _chatters.remove(name); boolean wasthere = _chatters.remove(name);
_chatters.addFirst(name); _chatters.addFirst(name);
if (!wasthere) { if (!wasthere) {
if (_chatters.size() > MAX_CHATTERS) { if (_chatters.size() > MAX_CHATTERS) {
_chatters.removeLast(); _chatters.removeLast();
} }
notifyChatterObservers(); notifyChatterObservers();
} }
} }
/** /**
* Notifies all registered {@link ChatterObserver}s that the list of * Notifies all registered {@link ChatterObserver}s that the list of chatters has changed.
* chatters has changed.
*/ */
protected void notifyChatterObservers () protected void notifyChatterObservers ()
{ {
@@ -1013,9 +969,8 @@ public class ChatDirector extends BasicDirector
if (bundle != null && _msgmgr != null) { if (bundle != null && _msgmgr != null) {
MessageBundle msgb = _msgmgr.getBundle(bundle); MessageBundle msgb = _msgmgr.getBundle(bundle);
if (msgb == null) { if (msgb == null) {
Log.warning( Log.warning("No message bundle available to translate message " +
"No message bundle available to translate message " + "[bundle=" + bundle + ", message=" + message + "].");
"[bundle=" + bundle + ", message=" + message + "].");
} else { } else {
message = msgb.xlate(message); message = msgb.xlate(message);
} }
@@ -1026,11 +981,9 @@ public class ChatDirector extends BasicDirector
/** /**
* Display the specified system message as if it had come from the server. * Display the specified system message as if it had come from the server.
*/ */
protected void displaySystem ( protected void displaySystem (String bundle, String message, byte attLevel, String localtype)
String bundle, String message, byte attLevel, String localtype)
{ {
// nothing should be untranslated, so pass the default bundle if need // nothing should be untranslated, so pass the default bundle if need be.
// be.
if (bundle == null) { if (bundle == null) {
bundle = _bundle; bundle = _bundle;
} }
@@ -1041,8 +994,7 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* Looks up and returns the message type associated with the specified * Looks up and returns the message type associated with the specified oid.
* oid.
*/ */
protected String getLocalType (int oid) protected String getLocalType (int oid)
{ {
@@ -1058,8 +1010,8 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* An operation that checks with all chat filters to properly filter * An operation that checks with all chat filters to properly filter a message prior to sending
* a message prior to sending to the server or displaying. * to the server or displaying.
*/ */
protected static class FilterMessageOp protected static class FilterMessageOp
implements ObserverList.ObserverOp<ChatFilter> implements ObserverList.ObserverOp<ChatFilter>
@@ -1136,8 +1088,7 @@ public class ChatDirector extends BasicDirector
} }
// handle "/help help" and "/help someboguscommand" // handle "/help help" and "/help someboguscommand"
HashMap<String,CommandHandler> possibleCommands = HashMap<String,CommandHandler> possibleCommands = getCommandHandlers(hcmd);
getCommandHandlers(hcmd);
if (hcmd.equals("help") || possibleCommands.isEmpty()) { if (hcmd.equals("help") || possibleCommands.isEmpty()) {
possibleCommands = getCommandHandlers(""); possibleCommands = getCommandHandlers("");
possibleCommands.remove("help"); // remove help from the list possibleCommands.remove("help"); // remove help from the list
@@ -1147,9 +1098,8 @@ public class ChatDirector extends BasicDirector
switch (possibleCommands.size()) { switch (possibleCommands.size()) {
case 1: case 1:
Iterator<String> itr = possibleCommands.keySet().iterator(); Iterator<String> itr = possibleCommands.keySet().iterator();
// this is a little funny, but we display the feeback // this is a little funny, but we display the feeback message by hand and return
// message by hand and return SUCCESS so that the chat // SUCCESS so that the chat entry field doesn't think that we've failed and
// entry field doesn't think that we've failed and
// preserve our command text // preserve our command text
displayFeedback(null, "m.usage_" + itr.next()); displayFeedback(null, "m.usage_" + itr.next());
return ChatCodes.SUCCESS; return ChatCodes.SUCCESS;
@@ -1227,9 +1177,8 @@ public class ChatDirector extends BasicDirector
/** Implements <code>/tell</code>. */ /** Implements <code>/tell</code>. */
protected class TellHandler extends CommandHandler protected class TellHandler extends CommandHandler
{ {
public String handleCommand ( public String handleCommand (SpeakService speakSvc, final String command,
SpeakService speakSvc, final String command, String args, String args, String[] history)
String[] history)
{ {
if (StringUtil.isBlank(args)) { if (StringUtil.isBlank(args)) {
return "m.usage_tell"; return "m.usage_tell";
@@ -1275,19 +1224,15 @@ public class ChatDirector extends BasicDirector
// store the full command in the history, even if it was mistyped // store the full command in the history, even if it was mistyped
final String histEntry = command + " " + final String histEntry = command + " " +
(useQuotes ? ("\"" + target + "\"") : target.toString()) + (useQuotes ? ("\"" + target + "\"") : target.toString()) + " " + message;
" " + message;
history[0] = histEntry; history[0] = histEntry;
// request to send this text as a tell message // request to send this text as a tell message
requestTell(target, escapeMessage(message), requestTell(target, escapeMessage(message), new ResultListener<Name>() {
new ResultListener<Name>() {
public void requestCompleted (Name target) { public void requestCompleted (Name target) {
// replace the full one in the history with just: // replace the full one in the history with just: /tell "<handle>"
// /tell "<handle>"
String newEntry = "/" + command + " " + String newEntry = "/" + command + " " +
(useQuotes ? ("\"" + target + "\"") (useQuotes ? ("\"" + target + "\"") : String.valueOf(target)) + " ";
: String.valueOf(target)) + " ";
_history.remove(newEntry); _history.remove(newEntry);
int dex = _history.lastIndexOf("/" + histEntry); int dex = _history.lastIndexOf("/" + histEntry);
if (dex >= 0) { if (dex >= 0) {
@@ -1305,8 +1250,8 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* Parse the tell into two strings, handle and message. If either * Parse the tell into two strings, handle and message. If either one is null then the
* one is null then the parsing did not succeed. * parsing did not succeed.
*/ */
protected String[] parseTell (String args) protected String[] parseTell (String args)
{ {
@@ -1331,9 +1276,9 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* Turn the user-entered string into a Name object, doing * Turn the user-entered string into a Name object, doing any particular normalization we
* any particular normalization we want to do along the way * want to do along the way so that "/tell Bob" and "/tell BoB" don't both show up in
* so that "/tell Bob" and "/tell BoB" don't both show up in history. * history.
*/ */
protected Name normalizeAsName (String handle) protected Name normalizeAsName (String handle)
{ {
@@ -1341,8 +1286,7 @@ public class ChatDirector extends BasicDirector
} }
/** /**
* Escape or otherwise do any final processing on the message * Escape or otherwise do any final processing on the message prior to sending it.
* prior to sending it.
*/ */
protected String escapeMessage (String msg) protected String escapeMessage (String msg)
{ {
@@ -1400,6 +1344,9 @@ public class ChatDirector extends BasicDirector
/** The client object that we're listening to for tells. */ /** The client object that we're listening to for tells. */
protected ClientObject _clobj; protected ClientObject _clobj;
/** Whether or not to run chat through the mogrifier. */
protected boolean _mogrifyChat= true;
/** A list of registered chat displays. */ /** A list of registered chat displays. */
protected ObserverList<ChatDisplay> _displays = protected ObserverList<ChatDisplay> _displays =
new ObserverList<ChatDisplay>(ObserverList.SAFE_IN_ORDER_NOTIFY); new ObserverList<ChatDisplay>(ObserverList.SAFE_IN_ORDER_NOTIFY);