![]() |
|
![]() |
|
|
Thread Tools | Display Modes |
|
|
#1 |
|
Hobbyist Programmer
|
Step-By-Step IRC Bot
I'm just getting back into perl, been a long while since I last messed with it (3+ years?). I'm starting with a simple IRC bot, that will slowly add on more features, so follow along if you want some very basic samples (and point out where I totally suck if you want
)First, mockerbot v 0.0000001 - using Net::IRC, connects to an IRC server, joins a channel and logs each message to a text file. (currently 'thegup' on #programmingforums) *lots of the code was found on O'reilly IRC hacks Import Net::IRC, declare our variables and create the IRC connection object !/usr/bin/perl -w
use Net::IRC;
use strict;
# create the IRC object
my $irc = new Net::IRC;
#log directory
my $logdir = "/home/thegupst/public_html/pfo_irc/";
my @thedate = localtime();
my $speaker = "";
my $quoted = "";
my $isSysMsg = 0;
# Create a connection object
my $conn = $irc->newconn(
Server => shift || 'irc.freenode.net',
Port => shift || '8001',
Nick => 'thegup',
Ircname => 'grlgrlgrl',
Username => 'humbug'
);
$conn->{channel} = shift || '#programmingforums';Open a file in append mode based on the log path and the date, the write in the message with html blocks based upon a regular message, part or join (this will be switched to a db query later) sub log_msg {
#open file and log the message
@thedate = localtime();
my $linein = "<font color=black><i>(" . $thedate[2] . ":" . $thedate[1] . ":" . $thedate[0] . ")</i></fon$
my $filename = $logdir . $thedate[4] . $thedate[3] . $thedate[5] . '.html';
open(LOGIN, ">>$filename");
flock (LOGIN,2);
if ($quoted eq 'dundundunleaves') {
$linein .= 'green';
$quoted = "sadly leaves";
}
if ($quoted eq 'dundundunjoins') {
$linein .= 'red';
$quoted = "joyfully enters";
}
if ($quoted ne 'joyfully enters' && $quoted ne 'sadly leaves') {
$linein .= 'blue';
}
$linein .= "'><b>" . $speaker . "</b> : " . $quoted . "</font><br>";
print LOGIN "$linein\n";
close(LOGIN);
}The next few are the handlers for specific events you'll see towards the bottom. Net::IRC has a huge list of events you can specific specific actions for sub on_privmsg {
#message was seen in channel, parse, log and react
my ($conn, $event) = @_;
$isSysMsg = 0;
$speaker = $event->{nick};
$quoted = $event->{args}[0];
log_msg();
}
sub on_connect {
# shift in our connection object that is passed automatically
my $conn = shift;
# when we connect, join our channel and greet it
$conn->join($conn->{channel});
$conn->privmsg($conn->{channel}, 'Hello everyone!');
$conn->{connected} = 1;
}
sub on_join {
# get our connection object and the event object, which is passed
# with this event automatically
my ($conn, $event) = @_;
# this is the nick that just joined
my $nick = $event->{nick};
$isSysMsg = 1;
$speaker = $nick;
$quoted = "dundundunjoins";
log_msg();
}
sub on_part {
# pretty much the same as above
my ($conn, $event) = @_;
my $nick = $event->{nick};
$isSysMsg = 1;
$speaker = $nick;
$quoted = "dundundunleaves";
log_msg();
}Next we add handlers to the connection object, so it knows what function to call when a certain event happens. A list of events are in perldoc Net::IRC::Events Once all that is setup, start the IRC connection, which puts it in a loop and leaves the action up to the handlers # add event handlers for join and part events
$conn->add_handler('join', \&on_join);
$conn->add_handler('part', \&on_part);
$conn->add_handler('public', \&on_privmsg);
# The end of MOTD (message of the day), numbered 376 signifies we've connect
$conn->add_handler('376', \&on_connect);
# start IRC
$irc->start();
__________________
#programmingforums relay - http://thegupstudio.com/cgi-bin/pforelay.cgi freelance scripts - http://ryanguthrie.com/index.html |
|
|
|
|
|
#2 |
|
Hobbyist Programmer
|
pfo_current
Now I'll show the quick cgi script I made that sits on my server and displays the #programmingforums log for anyone that is curious
pfo_current.cgi Set the values I'll be using - #!/usr/bin/perl my $logdir = "/home/thegupst/public_html/pfo_irc/"; my @thedate = localtime(); my $thetime = localtime(); my $filename = $logdir . $thedate[4] . $thedate[3] . $thedate[5] . ".html"; open todays log, print out the html headers and current time (so people know what the timestamps refer to), then print out each line of the file and close it open(FILEREAD, "< $filename") || die "could not open file";
print "Content-type: text/html\r\n\r\n";
print "<html><head><title>#programmingforums chat log</title></head><body>";
print "<b>#programmingforums current logs. Local time: " . $thetime . "</b><br><hr><br>";
while (<FILEREAD>) {
my $line = $_;
chomp($line);
print "$line\n";
}
close(FILEREAD);
print "</body></html>";aaannd done. Short and simple. It is online at http://thegupstudio.com/cgi-bin/pfo_current.cgi
__________________
#programmingforums relay - http://thegupstudio.com/cgi-bin/pforelay.cgi freelance scripts - http://ryanguthrie.com/index.html |
|
|
|
|
|
#3 |
|
Hobbyist Programmer
|
IRC Relay
Feel like I'm talking to myself,wee. Added a new relay feature. The bot now opens a socket that it monitors. Messages sent to that socket get relayed to the channel the bot is in.
Currently they relayed by a cgi-script. The pfo one is http://thegupstudio.com/cgi-bin/pforelay.cgi First pforelay.pl , the bot itself. Made some changes to the top. *note, the code below is not complete. Just snippets with the biggest changes* Took off strict to make it easier for subs like the socket handler to use the $conn object. Added and initialized the socket. Set some random variables. require "cgi-lib.pl"; use Net::IRC; #use strict; use IO::Socket::INET; my $MySocket = new IO::Socket::INET->new(LocalPort=>2345,Proto=>'udp'); my $irc = new Net::IRC; my @thedate = localtime(); my $logdir = "/home/thegupst/public_html/pfo_irc/"; #my @messagein; my $messagefrom = ""; my $inputstring = ""; my $lastsec = (localtime)[0]; #current seconds my $lastmin = (localtime)[1]; #current min logging and other functions are the same. Added the function to handle socket messages. Pretty basic stuff. Sets a time recieved. The message format is sent as username~message and stuff here , so I split it on ~, with the downside this would get messed up if that character is in the username or message. If there is less than 5 seconds between recieved messages it doesn't do anything to prevent flooding or spamming sub on_sockmsg {
#parse, send to irc
my $text = "";
my $cursec = (localtime)[0];
my $curmin = (localtime)[1];
$MySocket->recv($text,128);
my @msgin = split('\~', $text);
$text = "from " . $msgin[0] . " : " . $msgin[1];
if (($curmin == $lastmin) && (($cursec - $lastsec) < 5)){
#spamspam
}
else {
$conn->privmsg($conn->{channel}, $text );
$lastmin = $curmin;
$lastsec = $cursec;
$speaker = "m_" . $msgin[0];
$quoted = $msgin[1];
log_msg();
}
}Then the only other difference really is adding a file(and socket) handler to to the irc object so it knows what to do if it gets a message $irc->addfh($MySocket, \&on_sockmsg); **pforelay.cgi** Now for the cgi script that displays the last 15 messages and relays anything you enter to the bot left out some random declarations. Sets the log file path, and also it uses the 'tail' command to get the last 15 entries and the filepath it stores those lines at. Then sets up the socket so we can send stuff to the bot. require "cgi-lib.pl"; use IO::Socket::INET; my $logdir = "/home/thegupst/public_html/pfo_irc/"; my $filename = $logdir . $thedate[4] . $thedate[3] . $thedate[5] . ".html"; my $tmptail = $logdir . "tmptail"; my $tailcmd = "tail -15 " . $filename . " > " . $logdir . "tmptail"; &ReadParse(*input); $MySocket=new IO::Socket::INET->new(PeerPort=>2345,Proto=>'udp',PeerAddr=>'localhost'); If the script is sent any data, send it to the bot if (length($input{'ircmsg'}) > 1) {
#send message to socket
$inputstring = $input{'ircfrom'} . "~" . $input{'ircmsg'};
$MySocket->send($inputstring) || die "could not send";
}The rest just prints outthe html to the form. This is the code to read the last 15 lines of todays log system($tailcmd) == 0 || die "could not tail: $?";
open(TAILIN, $tmptail);
while(<TAILIN>){
my $line = $_;
chomp($line);
print "$line\n";
}
close(TAILIN);hope this is helpful/interesting or something. Feel free to use the url http://thegupstudio.com/cgi-bin/pforelay.cgi to check out #programmingforums irc channel (i'm kimochii on irc)
__________________
#programmingforums relay - http://thegupstudio.com/cgi-bin/pforelay.cgi freelance scripts - http://ryanguthrie.com/index.html |
|
|
|
|
|
#4 |
|
Hobbyist Programmer
Join Date: Nov 2004
Location: 1691 miles East of L.A.
Posts: 159
Rep Power: 4
![]() |
Nice work! Now to align the date/time, catch actions and maybe add some stats.
![]()
__________________
-- lostcauz Stepped in what?... Behind whose barn?... I didn't even know they had a cow! |
|
|
|
|
|
#5 |
|
Programming Guru
![]() ![]() |
yeah stats would be cool also
__________________
Profanity is the one language that all programmers understand. Check out my Blog <---updated Nov 30 2007! |
|
|
|
|
|
#6 |
|
Hobbyist Programmer
|
MockerBot going on
Woo, made a bunch of changes to my bot at work last night (slow night eh).
Some of the new things ---------- *Logs everything to a mysql database. Messages are logged with usernaem, userid, current datetime, and type. Usernames keep info for each user it has recorded as posting. Right now it just has a postcount, but there are fields for passwords and more info so it could serve as kinda a nickserv bot and keep profiles and authentic logged messages etc. *Added a bunch of commands! right now there is !quote random - displays a random quote from a quote file !quote add your quote here - adds the quote to the quote file !quote randomirc - displays a random entry in the irc logs !quote randomirc username - displays a random entry in the irc logs from that username !info postcount username - number of entries by that username It is 263 lines now so I put it in the pastebin. umm.. i'm feelnig lazy so I'll just link that. I'll break down the sections again later, shouldn't be too hard to follow. There are pretty messy areas because I'm learning perl as I go again and never used the DBI module. http://pfo.pastebin.com/716502 This is the exact script (except for db info) used for mockerbot, currently on #programmingforums irc channel. Next up is adding a way to track the current userlist, and then working on the relay script so you can see all the info and commands from there. *no comments on my variable names global $data1 and $data2 are horrible I know I know
__________________
#programmingforums relay - http://thegupstudio.com/cgi-bin/pforelay.cgi freelance scripts - http://ryanguthrie.com/index.html |
|
|
|
|
|
#7 |
|
Hobbyist Programmer
|
Woo, so I've added number of new things to my bot. I actually still need to update the help file so I'll try to list em all here for now
Logs the chat to a mysql database and keeps a postcount for each username Has a relay you can chat through http://thegupstudio.com/cgi-bin/pforelay.cgi You can search and view logs http://thegupstudio.com/cgi-bin/pfo_current.cgi Keeps an additional quote db that is added to manually The current commands are- !info postcount (LIKE) username !quote random|randomirc (LIKE) (username) - random uses quotedb, randomirc is random line from the log !help - pm's a brief help file !talk on|off (username) !define (DIC) word - users dict.org dictionaries, currently available : SPANISH ROM GERMAN FRENCH NLD DEVIL JARGON THES default is spanish !tran (LANG) phrase - uses google translate or freedict.com to translate GERMAN FRENCH ITALIAN ARABIC JAPANESE NIHONGO KOREAN CHINESE DEUTSCH FRANCAIS ESPANOL SPANISH(default). The native languages translate back to english !google phrase - gets first google result annd, the full source code is available. Kimobot runs on #programmingforums irc room (irc.freenode.net) if you want to test it. http://thegupstudio.com/pfo_irc/ircbot.html Let me know what you think I'm going to just keep adding to it, probably group the functions into modules. If you are interested in trying to use the source I'll include how I've setup the mysql tables and other files it uses.
__________________
#programmingforums relay - http://thegupstudio.com/cgi-bin/pforelay.cgi freelance scripts - http://ryanguthrie.com/index.html |
|
|
|
|
|
#8 |
|
Hobbyist Programmer
|
Slow night at work, got three more functions added to the bot
the first isnt really part of the bot, it is a quick php script that uses the GD library to generate an image of 3 random lines from irc http://thegupstudio.com/pfo_irc/randomirc_img2.php - refresh it a few times it is an image so you could do <img src="..etc"> and have it displayed it also takes 2 arguments, lines and names. http://thegupstudio.com/pfo_irc/rand...names=kimochii for example The next bot command is !random list of items here etc etc or !random number TO number The first way just choose a random item that comes after the command the second is a random int between the two numbers And this one took me a while, there is now a 'game' you can play !play quoteirc ON|OFF to turn the game on and off it will display a random irc quote and the first person to say the name of the speaker wins that round, it then adds a score and goes to the next one !skip - skips current round, displays answer and goes to the next !score - displays current score, works while game is off for last played game. New games reset the score If you dont skip and dont guess the name it will just wait until you do or you end the game I've had all of no interest in this so I probably will not post the source here anymore. Its still available, i'm just too lazy to update it.
__________________
#programmingforums relay - http://thegupstudio.com/cgi-bin/pforelay.cgi freelance scripts - http://ryanguthrie.com/index.html |
|
|
|
![]() |
| Bookmarks |
| Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
| Thread Tools | |
| Display Modes | |
|
|