/*
This file is part of leafdigital leafChat.
leafChat is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
leafChat is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with leafChat. If not, see <http://www.gnu.org/licenses/>.
Copyright 2011 Samuel Marshall.
*/
package com.leafdigital.irc;
import java.util.regex.*;
import util.StringUtils;
import com.leafdigital.irc.api.*;
import com.leafdigital.prefs.api.*;
import leafchat.core.api.*;
/** Implementor of Commands interface to manage user-typed command handlers */
public class CommandsSingleton implements Commands,MsgOwner
{
private MessageDispatch mdp;
private PluginContext pc;
PluginContext getPluginContext() { return pc; }
CommandsSingleton(PluginContext pc)
{
this.pc=pc;
pc.registerMessageOwner(this);
}
// MessageOwner
@Override
public void init(MessageDispatch mdp)
{
this.mdp=mdp;
}
@Override
public String getFriendlyName()
{
return "User-typed commands";
}
@Override
public Class<? extends Msg> getMessageClass()
{
return UserCommandMsg.class;
}
@Override
public boolean registerTarget(Object oTarget, Class<? extends Msg> cMessage,
MessageFilter mf, int iRequestID, int iPriority)
{
return true;
}
@Override
public void unregisterTarget(Object oTarget, int iRequestID)
{
}
@Override
public void manualDispatch(Msg m)
{
}
@Override
public boolean allowExternalDispatch(Msg m)
{
return false;
}
/**
* Splits a command into the following components:
* 1. Optional server index prefix e.g. /2/msg (the /2 bit)
* 2. Actual command
* 3. Params of command
*/
private final static String COMMANDSPLIT=
"^(%[0-9]+(?=%))?(?:%([A-Za-z0-9]+)(?:\\ )*)?(.*)$";
private static String regexpRangeQuote(String s)
{
if(s.length()==0) return "";
char c=s.charAt(0);
switch(c)
{
case '\\':
case '-':
return "\\"+c;
default:
return ""+c;
}
}
@Override
public boolean isCommandCharacter(char c)
{
Preferences p=pc.getSingle(Preferences.class);
PreferencesGroup pg=p.getGroup(pc.getPlugin());
String extra=pg.get(IRCPrefs.PREF_EXTRACOMMANDCHAR,IRCPrefs.PREFDEFAULT_EXTRACOMMANDCHAR);
return (c=='/' || extra.indexOf(c)!=-1);
}
@Override
public void doCommand(String command,
Server contextServer,IRCUserAddress contextUser,String contextChan,MessageDisplay md,
boolean variables)
{
// Set up regular expression matcher to handle extra command character if provided
Preferences p=pc.getSingle(Preferences.class);
PreferencesGroup pg=p.getGroup(pc.getPlugin());
String commandCharacters="[/"+regexpRangeQuote(
pg.get(IRCPrefs.PREF_EXTRACOMMANDCHAR,IRCPrefs.PREFDEFAULT_EXTRACOMMANDCHAR))+
"]";
Matcher m=Pattern.compile(StringUtils.replace(COMMANDSPLIT,"%",commandCharacters),Pattern.DOTALL).matcher(command);
if(!m.matches()) throw new BugException("Command regexp didn't match: "+command);
// Handle server index
String serverIndex=m.group(1);
Server resolvedServer=contextServer;
if(serverIndex!=null && !serverIndex.equals(""))
{
// Get connections singleton
Connections c=pc.getSingle(Connections.class);
try
{
resolvedServer=c.getNumbered(Integer.parseInt(serverIndex.substring(1)));
}
catch(ArrayIndexOutOfBoundsException aioobe)
{
// Send off an error display already
md.showError("No connected server has index: <key>"+serverIndex.substring(1)+"</key>");
return;
}
}
// Set up other parts of resolved command
String resolvedCommand=m.group(2);
if(resolvedCommand!=null && resolvedCommand.equals("")) resolvedCommand=null;
if(resolvedCommand!=null) resolvedCommand=resolvedCommand.toLowerCase();
String resolvedParams=m.group(3);
// TODO Replace variables
// Construct message and dispatch it
mdp.dispatchMessage(
new UserCommandMsg(resolvedServer,resolvedCommand,resolvedParams,
contextChan,contextUser,md),
true);
}
}