Add IpyBot to the public repository

git-svn-id: https://source.geekisp.com/bleep/trunk/IpyBot@259 a256dd88-e320-0410-9161-d397f098afaa
This commit is contained in:
tyler 2008-03-15 09:18:37 +00:00
commit 37fb1310f6
4 changed files with 439 additions and 0 deletions

BIN
contrib/Meebey.SmartIrc4net.dll Executable file

Binary file not shown.

39
ipybot.build Normal file
View File

@ -0,0 +1,39 @@
<?xml version="1.0"?>
<project name="IpyBot" default="release" basedir=".">
<description>
Very basic build file for IpyBot
</description>
<property name="debug" value="true" overwrite="false" />
<property name="project.name" value="IpyBot"/>
<property name="project.version" value="1.0.0"/>
<tstamp property="build.date" pattern="yyyyMMdd" verbose="true" />
<!-- These are being definde for posterity's sake, as they may change in the future -->
<property name="base_dir" value="${path::get-full-path('.')}"/>
<property name="bin_dir" value="${base_dir}/bin"/>
<property name="src_dir" value="${base_dir}/source"/>
<property name="lib_dir" value="${base_dir}/contrib"/>
<target name="release" description="'Release' the IronPython code and DLLs">
<copy todir="${bin_dir}">
<fileset basedir="${lib_dir}">
<include name="**.dll"/>
</fileset>
</copy>
<copy todir="${bin_dir}">
<fileset basedir="${src_dir}">
<include name="**.py"/>
</fileset>
</copy>
</target>
<target name="run" description="'Release' and run the bot" depends="release">
<echo message="Running the IpyBot"/>
<exec workingdir="${bin_dir}" program="ipy">
<arg value="IpyBot.py"/>
</exec>
</target>
</project>

198
source/IpyBot.py Normal file
View File

@ -0,0 +1,198 @@
import clr
clr.AddReference('System.Data')
clr.AddReference('Mono.Data.SqliteClient')
clr.AddReferenceToFile('Meebey.SmartIrc4net.dll')
import System
from System import *
from System.Collections import *
from System.Data import *
from System.IO import *
from System.Net import *
from System.Text import *
from System.Threading import *
from Meebey.SmartIrc4net import *
from Mono.Data.SqliteClient import *
VERSION_STRING = 'IpyBot v0.1-dev'
DEFAULT_NICK = 'IpyBotDev'
DEFAULT_SERVER = 'chat.freenode.net'
DEFAULT_PORT = 8001
DEFAULT_CHANNELS = ['#ipybot']
DEFAULT_AUTHORIZED = ['rtyler', 'zachallia']
DEFAULT_COMMAND = '!'
class IpyBot(object):
server = None
port = 0
channel = None
client = None
db = None
def OnQueryMessage(self, sender, args):
t = args.Data.MessageArray[0]
if t == 'dump_channel':
req = e.Data.MessageArray[1]
chan = self.client.GetChannel(req)
self.client.SendMessage(SendType.Message, e.Data.Nick, 'Topic: %s' % (chan.Topic))
def OnError(self, sender, args):
self.Print('*** ERROR! : %s' % args.ErrorMessage)
Environment.Exit(1)
def OnRawMessage(self, sender, args):
if 'PRIVMSG' in args.Data.RawMessage:
contents = args.Data.RawMessage.split(':')
who = contents[1].split('!')[0]
if contents[2].strip() == DEFAULT_NICK:
self.OnMessageToMe(who, contents)
elif len(contents) >= 3:
self.OnMessageToChannel(who, contents)
def OnMessageToMe(self, who, data):
self.Print('%s said to me: %s' % (who, data))
def OnMessageToChannel(self, who, data):
message = ':'.join(data[2:])
if message.startswith(DEFAULT_COMMAND) and len(message) > len(DEFAULT_COMMAND):
message = message[1:].split(' ')
if len(message):
getattr(self, 'IpyBotCommand_%s_Handler' % (message[0]), self.IpyBotCommand_Default_Handler)(who, message)
################################################
## IpyBot Command Handlers
def CheckAuthorized(self, who):
return who in DEFAULT_AUTHORIZED
def IpyBotCommand_learn_Handler(self, who, data):
if not len(data) >= 4 or not data[2] == 'is' or not self.CheckAuthorized(who):
return
command = data[1]
contents = ' '.join(data[3:])
self.Print('Learning that %s is %s' % (command, contents))
self.Store_Command(command, contents)
def IpyBotCommand_version_Handler(self, who, data):
self.client.SendMessage(SendType.Action, self.channel, 'is %s' % VERSION_STRING)
def IpyBotCommand_Default_Handler(self, who, message):
if not len(message):
return
target = ''
if len(message) == 3 and message[1] == '@':
target = message[2] + ': '
val = self.Fetch_Command(message[0])
if not val:
self.client.SendMessage(SendType.Message, self.channel, '"%s" is an invalid IpyBot command :(' % (message[0]))
else:
self.client.SendMessage(SendType.Message, self.channel, '%s%s is %s' % (target, message[0], val))
################################################
################################################
## IpyBot Sqlite Layer
def Store_Command(self, command, contents):
sql = '''
INSERT INTO %s (command, contents)
VALUES (:cmd, :cnts)
''' % (self.CurrentChannel())
c = self.db.CreateCommand()
c.CommandText = sql
c.Parameters.Add('cmd', command)
c.Parameters.Add('cnts', contents)
try:
c.ExecuteNonQuery()
return True
except Exception, ex:
self.Print(ex)
return False
def Fetch_Command(self, command):
self.Print('Finding %s' % command)
sql = '''
SELECT contents FROM %s WHERE command = "%s"
''' % (self.CurrentChannel(), command)
c = self.db.CreateCommand()
c.CommandText = sql
try:
return c.ExecuteScalar()
except Exception, ex:
self.Print(ex)
return None
################################################
def Print(self, message):
print '<%s> %s' % (Thread.CurrentThread.Name, message)
def CurrentChannel(self):
return self.channel.replace('#', '')
def __CreateBotTable(self, name):
sql = '''
CREATE TABLE %s (
command TEXT PRIMARY KEY,
contents TEXT);
''' % (name)
command = self.db.CreateCommand()
command.CommandText = sql
try:
command.ExecuteNonQuery()
except Exception, ex:
pass
def __init__(self, *args, **kwargs):
self.server = kwargs.get('server')
self.port = kwargs.get('port')
self.channel = kwargs.get('channel')
assert self.server and self.port and self.channel, 'Missing arguments for IpyBot() constructor!'
self.client = IrcClient()
self.client.Encoding = Text.Encoding.UTF8
self.client.SendDelay = 200
self.client.ActiveChannelSyncing = True
connection = 'URI=file:%s_ipybot.db' % (self.CurrentChannel())
self.db = SqliteConnection(connection)
self.db.Open()
self.__CreateBotTable(self.CurrentChannel())
self.client.OnQueryMessage += IrcEventHandler(self.OnQueryMessage)
self.client.OnError += IrcEventHandler(self.OnError)
self.client.OnRawMessage += IrcEventHandler(self.OnRawMessage)
def __del__(self):
if self.db:
self.db.Close()
def ReadCommands(self):
while True:
self.client.WriteLine(Console.ReadLine())
def Run(self):
try:
self.client.Connect(self.server, self.port)
except ConnectionException, ex:
self.Print("Couldn't connect! %s" % ex.Message)
return
try:
self.client.Login(DEFAULT_NICK, 'IpyBot LOLZ!', 0, 'IpyBot')
self.client.RfcJoin(self.channel)
self.client.SendMessage(SendType.Action, self.channel, "clears its throat")
Thread(ThreadStart(self.ReadCommands)).Start()
self.client.Listen()
self.client.Disconnect()
except Exception, ex:
self.Print(ex)
return
if __name__ == '__main__':
for channel in DEFAULT_CHANNELS:
b = IpyBot(server=DEFAULT_SERVER, port=DEFAULT_PORT, channel=channel)
t = Thread(ThreadStart(b.Run))
t.Name = channel
t.Start()

202
source/Test.cs Normal file
View File

@ -0,0 +1,202 @@
/**
* $Id$
* $Revision$
* $Author$
* $Date$
*
* SmartIrc4net - the IRC library for .NET/C# <http://smartirc4net.sf.net>
* This is a simple test client for the library.
*
* Copyright (c) 2003-2004 Mirco Bauer <meebey@meebey.net> <http://www.meebey.net>
*
* Full LGPL License: <http://www.gnu.org/licenses/lgpl.txt>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
using System;
using System.Collections;
using System.Threading;
using Meebey.SmartIrc4net;
// This is an VERY basic example how your IRC application could be written
// its mainly for showing how to use the API, this program just connects sends
// a few message to a channel and waits for commands on the console
// (raw RFC commands though! it's later explained).
// There are also a few commands the IRC bot/client allows via private message.
public class Test
{
// make an instance of the high-level API
public static IrcClient irc = new IrcClient();
// this method we will use to analyse queries (also known as private messages)
public static void OnQueryMessage(object sender, IrcEventArgs e)
{
switch (e.Data.MessageArray[0]) {
// debug stuff
case "dump_channel":
string requested_channel = e.Data.MessageArray[1];
// getting the channel (via channel sync feature)
Channel channel = irc.GetChannel(requested_channel);
// here we send messages
irc.SendMessage(SendType.Message, e.Data.Nick, "<channel '"+requested_channel+"'>");
irc.SendMessage(SendType.Message, e.Data.Nick, "Name: '"+channel.Name+"'");
irc.SendMessage(SendType.Message, e.Data.Nick, "Topic: '"+channel.Topic+"'");
irc.SendMessage(SendType.Message, e.Data.Nick, "Mode: '"+channel.Mode+"'");
irc.SendMessage(SendType.Message, e.Data.Nick, "Key: '"+channel.Key+"'");
irc.SendMessage(SendType.Message, e.Data.Nick, "UserLimit: '"+channel.UserLimit+"'");
// here we go through all users of the channel and show their
// hashtable key and nickname
string nickname_list = "";
nickname_list += "Users: ";
foreach (DictionaryEntry de in channel.Users) {
string key = (string)de.Key;
ChannelUser channeluser = (ChannelUser)de.Value;
nickname_list += "(";
if (channeluser.IsOp) {
nickname_list += "@";
}
if (channeluser.IsVoice) {
nickname_list += "+";
}
nickname_list += ")"+key+" => "+channeluser.Nick+", ";
}
irc.SendMessage(SendType.Message, e.Data.Nick, nickname_list);
irc.SendMessage(SendType.Message, e.Data.Nick, "</channel>");
break;
case "gc":
GC.Collect();
break;
// typical commands
case "join":
irc.RfcJoin(e.Data.MessageArray[1]);
break;
case "part":
irc.RfcPart(e.Data.MessageArray[1]);
break;
case "die":
Exit();
break;
}
}
// this method handles when we receive "ERROR" from the IRC server
public static void OnError(object sender, ErrorEventArgs e)
{
System.Console.WriteLine("Error: "+e.ErrorMessage);
Exit();
}
// this method will get all IRC messages
public static void OnRawMessage(object sender, IrcEventArgs e)
{
System.Console.WriteLine("Received: "+e.Data.RawMessage);
}
public static void Main(string[] args)
{
Thread.CurrentThread.Name = "Main";
// UTF-8 test
irc.Encoding = System.Text.Encoding.UTF8;
// wait time between messages, we can set this lower on own irc servers
irc.SendDelay = 200;
// we use channel sync, means we can use irc.GetChannel() and so on
irc.ActiveChannelSyncing = true;
// here we connect the events of the API to our written methods
// most have own event handler types, because they ship different data
irc.OnQueryMessage += new IrcEventHandler(OnQueryMessage);
irc.OnError += new ErrorEventHandler(OnError);
irc.OnRawMessage += new IrcEventHandler(OnRawMessage);
string[] serverlist;
// the server we want to connect to, could be also a simple string
serverlist = new string[] {"irc.freenode.org"};
int port = 6667;
string channel = "#smartirc-test";
try {
// here we try to connect to the server and exceptions get handled
irc.Connect(serverlist, port);
} catch (ConnectionException e) {
// something went wrong, the reason will be shown
System.Console.WriteLine("couldn't connect! Reason: "+e.Message);
Exit();
}
try {
// here we logon and register our nickname and so on
irc.Login("SmartIRC", "SmartIrc4net Test Bot");
// join the channel
irc.RfcJoin(channel);
for (int i = 0; i < 3; i++) {
// here we send just 3 different types of messages, 3 times for
// testing the delay and flood protection (messagebuffer work)
irc.SendMessage(SendType.Message, channel, "test message ("+i.ToString()+")");
irc.SendMessage(SendType.Action, channel, "thinks this is cool ("+i.ToString()+")");
irc.SendMessage(SendType.Notice, channel, "SmartIrc4net rocks ("+i.ToString()+")");
}
// spawn a new thread to read the stdin of the console, this we use
// for reading IRC commands from the keyboard while the IRC connection
// stays in its own thread
new Thread(new ThreadStart(ReadCommands)).Start();
// here we tell the IRC API to go into a receive mode, all events
// will be triggered by _this_ thread (main thread in this case)
// Listen() blocks by default, you can also use ListenOnce() if you
// need that does one IRC operation and then returns, so you need then
// an own loop
irc.Listen();
// when Listen() returns our IRC session is over, to be sure we call
// disconnect manually
irc.Disconnect();
} catch (ConnectionException) {
// this exception is handled because Disconnect() can throw a not
// connected exception
Exit();
} catch (Exception e) {
// this should not happen by just in case we handle it nicely
System.Console.WriteLine("Error occurred! Message: "+e.Message);
System.Console.WriteLine("Exception: "+e.StackTrace);
Exit();
}
}
public static void ReadCommands()
{
// here we read the commands from the stdin and send it to the IRC API
// WARNING, it uses WriteLine() means you need to enter RFC commands
// like "JOIN #test" and then "PRIVMSG #test :hello to you"
while (true) {
irc.WriteLine(System.Console.ReadLine());
}
}
public static void Exit()
{
// we are done, lets exit...
System.Console.WriteLine("Exiting...");
System.Environment.Exit(0);
}
}