+// Listen to when the script was successfully loaded and connect to an IRC network
+function onScriptLoaded()
+ // Add an administrator
+ g_Irc.SetStaff("SLC", IrcAuthority.SystemOperator);
+ // Connect to a network
+ g_Irc.Connect("irc.liberty-unleashed.co.uk", 6667, "SquirrelBot");
+SqCore.Bind(SqEvent.ScriptLoaded, this, onScriptLoaded);
/* ------------------------------------------------------------------------------------------------
* Class responsible for managing an IRC session session.
- /* ----------------------------------------------------------------------------------
- * Table used to hold the command listeners.
/* --------------------------------------------------------------------------------------------
base.Bind(SqIrcEvent.Numeric, this, onNumeric);
// Save the name used in identifying where the output came from.
- // Initialize the staff list as a table with key as name and value as authority level
- m_Staff = {"SLC" : IrcAuthority.SystemOperator};
- // Initialize the command list
- m_Commands = { /* ... */ };
- /* --------------------------------------------------------------------------------------------
- function ProcessCommand(origin, channel, text)
- // See if this user from where the command originated can talk to us
- if (!m_Staff.rawin(origin))
- // Send a PM to this user to let him know he cannot talk to us
- base.CmdMsg(origin, "You do not have the privilege to talk to me!");
- // Just abort this command
- else if (IsSpace(text[0]))
- // Send a PM to this user to let him know he specified an invalid command
- base.CmdMsg(origin, "The command name cannot be preceded by any space characters!");
- // Just abort this command
- // Find the first space character
- local pos = SqStr.FirstSpace(text);
- // Was there any space located?
- // Send a PM to this user to let him know he must enter a valid command name
- base.CmdMsgF(origin, "Cannot execute invalid command (%s)", text);
- // Just abort this command
- // Separate the command name from the arguments
- local name = text.slice(0, pos), args = text.slice(pos+1);
- // Make sure that this command exists
- if (!m_Commands.rawin(name))
- // Send a PM to this user to let him know he entered an unknown command
- base.CmdMsgF(origin, "Cannot execute unknown command (%s)", name);
- // Just abort this command
- // Obtain the command data
- local cmd = m_Commands.rawget(name);
- // Make sure that the user has access to it
- if (m_Staff.rawget(origin) < cmd.Auth)
- // Send a PM to this user to let him know he does not have the privileges to execute this command
- base.CmdMsgF(origin, "You do not have access to this command! (%s)", name);
- // Just abort this command
- // Attempt to execute the command
- // Execute the command and check to see if the execution succeeded
- if (!cmd.Func.call(cmd.Env, origin, channel, args))
- // Send a PM to this user to let him know the command failed to execute
- base.CmdMsgF(origin, "Unable to execute command (%s). Check syntax: %s", command, cmd.Syntax.tostring());
- // Just abort this command
- // Send a PM to this user to let him know the command failed to execute
- base.CmdMsgF(origin, "Error occurred while executing command (%s) : %s", name, e.tostring());
- // Just abort this command
- // At this point the command was executed successfully
+ // Initialize the staff to an empty table
+ m_Staff = { /* ... */ };
function onConnect(event, origin, params)
- ProcessCommand(origin, params[0], params[1].slice(1));
+ g_Ircmd.Run({"origin" : origin, "channel" : params[0]}, params[1].slice(1));
- ProcessCommand(origin, params[0], params[1].slice(1));
+ g_Ircmd.Run({"origin" : origin, "channel" : origin}, params[1].slice(1));
function onCtcpReq(event, origin, params)
+ // Not yet implemented...
function onCtcpRep(event, origin, params)
+ // Not yet implemented...
function onCtcpAction(event, origin, params)
+ // Not yet implemented...
function onUnknown(event, origin, params)
print("Received RPL_UMODEIS from server");
foreach (idx, val in params)
- printf(origin, "=> Arg %d contains: '%s'", idx, val);
+ printf("=> Arg %d contains: '%s'", idx, val);
- /* ----------------------------------------------------------------------------------
- * Attach a new command.
- function AttachCommand(name, env, func, auth, syntax, info)
+ function SetStaff(name, level)
- // Validate the specified argument
- if (typeof(name) != "string" || typeof(func) != "function")
- SqLog.Err("Unknown or unsupported argument type");
- SqLog.Inf("=> Expected: (string), (function) Got: (%s), (%s)", typeof(name), typeof(func));
- // Store the specified information
- m_Commands.rawset(name, {Env = env, Func = func, Auth = auth, Syntax = syntax, Info = info});
- // Specify that we could attach this command
+ m_Staff.rawset(name.tostring(), level.tointeger());
- /* ----------------------------------------------------------------------------------
- * Detach an existing command.
- function DetachCommand(name)
+ function GetStaff(name)
- // Validate the specified argument
- if (typeof(name) != "string")
- SqLog.Err("Unknown or unsupported argument type");
- SqLog.Inf("=> Expected: (string) Got: (%s)", typeof(name));
+ name = name.tostring();
+ if (m_Staff.rawin(name))
- // Perform the required action
- m_Commands.rawdelete(name);
- // Specify that we could detach this command
+ return m_Staff.rawget(name);
- /* ----------------------------------------------------------------------------------
- * See if a certain command exists.
- function CommandExists(name)
- // Return the required information
- return m_Commands.rawin(name);
+ return IrcAuthority.Guest;
- /* ----------------------------------------------------------------------------------
- * Retrieve the syntax of a certain command name.
- function CommandSyntax(name)
+ function RemoveStaff(name)
- // Validate the specified argument
- if (typeof name != "string")
- SqLog.Err("Unknown or unsupported argument type");
- SqLog.Inf("=> Expected: (string) Got: (%s)", typeof(name));
- // Return the required information if available
- else if (m_Commands.rawin(name))
+ name = name.tostring();
+ if (m_Staff.rawin(name))
- return m_Commands.rawget(name).Syntax;
+ n_Staff.rawdelete(name);
- // Fall back to an empty value
- /* ----------------------------------------------------------------------------------
- * Retrieve the information of a certain command name.
- function CommandInfo(name)
+// Create an uninitialized instance of our IRC manager
+g_Irc <- MyIRC("SquirrelBot");
+/* ------------------------------------------------------------------------------------------------
+ * The main IRC related command manager.
+g_Ircmd <- SqCmd.Manager();
+/* ------------------------------------------------------------------------------------------------
+ * Bind a function to handle command errors.
+g_Ircmd.BindFail(this, function(type, msg, payload) {
+ // Retrieve the origin of the invocation
+ local origin = g_Ircmd.Invoker.origin;
+ // See if the invoker even exists
+ if (!origin || typeof(origin) != "string")
- // Validate the specified argument
- if (typeof name != "string")
- SqLog.Err("Unknown or unsupported argument type");
- SqLog.Inf("=> Expected: (string) Got: (%s)", typeof(name));
- // Return the required information if available
- else if (m_Commands.rawin(name))
- return m_Commands.rawget(name).Info;
- // Fall back to an empty value
+ return; // No one to report!
+ // Identify the error type
+ // The command failed for unknown reasons
+ g_Irc.CmdMsg(origin, "Unable to execute the command for reasons unknown");
+ g_Irc.CmdMsg(origin, "=> Please contact the owner: no_email@to.me");
+ // The command failed to execute because there was nothing to execute
+ case SqCmdErr.EmptyCommand:
+ g_Irc.CmdMsg(origin, "Cannot execute an empty command");
+ // The command failed to execute because the command name was invalid after processing
+ case SqCmdErr.InvalidCommand:
+ g_Irc.CmdMsg(origin, "The specified command name is invalid");
+ // The command failed to execute because there was a syntax error in the arguments
+ case SqCmdErr.SyntaxError:
+ g_Irc.CmdMsg(origin, "There was a syntax error in one of the command arguments");
+ // The command failed to execute because there was no such command
+ case SqCmdErr.UnknownCommand:
+ g_Irc.CmdMsg(origin, "The specified command does no exist");
+ // The command failed to execute because the it's currently suspended
+ case SqCmdErr.ListenerSuspended:
+ g_Irc.CmdMsg(origin, "The requested command is currently suspended");
+ // The command failed to execute because the invoker does not have the proper authority
+ case SqCmdErr.InsufficientAuth:
+ g_Irc.CmdMsg(origin, "You don't have the proper authority to execute this command");
+ // The command failed to execute because there was no callback to handle the execution
+ case SqCmdErr.MissingExecuter:
+ g_Irc.CmdMsg(origin, "The specified command is not being processed");
+ // The command was unable to execute because the argument limit was not reached
+ case SqCmdErr.IncompleteArgs:
+ g_Irc.CmdMsgF(origin, "The specified command requires at least %d arguments", payload);
+ // The command was unable to execute because the argument limit was exceeded
+ case SqCmdErr.ExtraneousArgs:
+ g_Irc.CmdMsgF(origin, "The specified command can allows up to %d arguments", payload);
+ // Command was unable to execute due to argument type mismatch
+ case SqCmdErr.UnsupportedArg:
+ g_Irc.CmdMsgF(origin, "Argument %d requires a different type than the one you specified", payload);
+ // The command arguments contained more data than the internal buffer can handle
+ case SqCmdErr.BufferOverflow:
+ g_Irc.CmdMsg(origin, "An internal error occurred and the execution was aborted");
+ g_Irc.CmdMsg(origin, "=> Please contact the owner: no_email@to.me");
+ // The command failed to complete execution due to a runtime exception
+ case SqCmdErr.ExecutionFailed:
+ g_Irc.CmdMsg(origin, "The command failed to complete the execution properly");
+ g_Irc.CmdMsg(origin, "=> Please contact the owner: no_email@to.me");
+ // The command completed the execution but returned a negative result
+ case SqCmdErr.ExecutionAborted:
+ g_Irc.CmdMsg(origin, "The command execution was aborted and therefore had no effect");
+ // The post execution callback failed to execute due to a runtime exception
+ case SqCmdErr.PostProcessingFailed:
+ g_Irc.CmdMsg(origin, "The command post-processing stage failed to complete properly");
+ g_Irc.CmdMsg(origin, "=> Please contact the owner: no_email@to.me");
+ // The callback that was supposed to deal with the failure also failed due to a runtime exception
+ case SqCmdErr.UnresolvedFailure:
+ g_Irc.CmdMsg(origin, "Unable to resolve the failures during command execution");
+ g_Irc.CmdMsg(origin, "=> Please contact the owner: no_email@to.me");
+ // Something bad happened and no one knows what
+ g_Irc.CmdMsgF(origin, "Command failed to execute because [%s]", msg);
- /* ----------------------------------------------------------------------------------
- * Retrieve the information of a certain command name.
- function CommandAuthority(name)
+/* ------------------------------------------------------------------------------------------------
+ * Bind a function to handle command authority inspection.
+g_Ircmd.BindAuth(this, function(invoker, command) {
+ // Is the command something that we can check against?
+ if (typeof(command) != "SqCmdListener")
- // Validate the specified argument
- if (typeof name != "string")
- _Log.Err("Unknown or unsupported argument type");
- _Log.Inf("=> Expected: (string) Got: (%s)", typeof(name));
- // Return the required information if available
- else if (m_Commands.rawin(name))
- return m_Commands.rawget(name).Auth;
- // Fall back to an invalid value
+ return true; // Not our kind? Not our problem!
+ // The specified invoker must be a table with 2 elements 'origin' and 'channel'
+ else if (typeof(invoker) != "table" || !invoker.rawin("origin") || !invoker.rawin("channel"))
+ return false; // Missing information
+ // Is the specified invoker something of a known type?
+ else if (typeof(invoker.origin) != "string" || typeof(invoker.channel) != "string")
+ return false; // What is this thing?
+ // Use the default authority system to make the call
+ return (g_Irc.GetStaff(invoker.origin) >= command.Authority);
-// Create an uninitialized instance of our IRC manager
-g_IRC <- MyIRC("SquirrelBot");
-// --------------------------------------------------------------------------------------
-g_IRC.AttachCommand("eval", this, function(origin, channel, args)
+/* ------------------------------------------------------------------------------------------------
+ * Global table used to scope IRC commands.
+/* ------------------------------------------------------------------------------------------------
+ * Evaluate a piece of code on the server.
+_Ircmd.Eval <- g_Ircmd.Create("eval", "g", ["code"], 1, 1, IrcAuthority.SystemOperator, true, true);
+// ------------------------------------------------------------------------------------------------
+_Ircmd.Eval.Help = "Evaluate the specified code";
+// ------------------------------------------------------------------------------------------------
+_Ircmd.Eval.BindExec(_Ircmd.Eval, function(invoker, args)
+ // Attempt to compile and execute the specified code
- // Attempt to compile and execute the specified code
- g_IRC.CmdMsg(origin, e.tostring());
- // Specify that this command was successfully executed
+ ::compilestring(args.code)();
-}, IrcAuthority.SystemOperator, "eval <code>", "Evaluate the specified code");
+ g_Irc.CmdMsg(invoker.origin, e.tostring());
+ // Specify that this command was successfully executed
-// --------------------------------------------------------------------------------------
-g_IRC.AttachCommand("say", this, function(origin, channel, args)
+/* ------------------------------------------------------------------------------------------------
+ * Say a certain message on the server.
+_Ircmd.Say <- g_Ircmd.Create("say", "g", ["text"], 1, 1, IrcAuthority.Moderator, true, true);
+// ------------------------------------------------------------------------------------------------
+_Ircmd.Say.Help = "Say the specified message";
+// ------------------------------------------------------------------------------------------------
+_Ircmd.Say.BindExec(_Ircmd.Say, function(invoker, args)
// Say the message back to to the origin
- g_IRC.CmdMsg(channel, args);
+ g_Irc.CmdMsg(invoker.channel, args.text);
// Specify that this command was successfully executed
-}, IrcAuthority.Moderator, "say <message>", "Say the specified message");
+/* ------------------------------------------------------------------------------------------------
+ * Say a certain message on the server with the /me command.
+_Ircmd.Me <- g_Ircmd.Create("me", "g", ["text"], 1, 1, IrcAuthority.Moderator, true, true);
-// --------------------------------------------------------------------------------------
-g_IRC.AttachCommand("me", this, function(origin, channel, args)
+// ------------------------------------------------------------------------------------------------
+_Ircmd.Me.Help = "Say the specified /me message";
+// ------------------------------------------------------------------------------------------------
+_Ircmd.Me.BindExec(_Ircmd.Me, function(invoker, args)
- // Say the /me message back to to the origin
- g_IRC.CmdMe(channel, args);
+ // Say the message back to to the origin
+ g_Irc.CmdMe(invoker.channel, args.text);
// Specify that this command was successfully executed
-}, IrcAuthority.Moderator, "me <message>", "Say the specified /me message");
-// --------------------------------------------------------------------------------------
-g_IRC.AttachCommand("mode", this, function(origin, channel, args)
+/* ------------------------------------------------------------------------------------------------
+ * Retrieve the modes of a certain user or channel.
+_Ircmd.Mode <- g_Ircmd.Create("mode", "s", ["name"], 1, 1, IrcAuthority.User, true, true);
+// ------------------------------------------------------------------------------------------------
+_Ircmd.Mode.Help = "Retrieve the modes of a user or channel";
+// ------------------------------------------------------------------------------------------------
+_Ircmd.Mode.BindExec(_Ircmd.Mode, function(invoker, args)
// Say the raw MODE <#channel/nick> command to retrieve the modes of a user/channel
- g_IRC.SendRaw("MODE " + args);
+ g_Irc.SendRaw("MODE " + args.name);
// Specify that this command was successfully executed
-}, IrcAuthority.Moderator, "mode <#channel/nick>", "Retrieve the modes of a user or channel");
-function onScriptLoaded()
- g_IRC.Connect("irc.liberty-unleashed.co.uk", 6667, "SquirrelBot");
-SqCore.Bind(SqEvent.ScriptLoaded, this, onScriptLoaded);