Create Your MSN Messenger Bot Using Bitlbee
| November 21st, 2008I recently had to create a messenger bot for some of the leading Instant messengers such as MSN, Yahoo and Gtalk. After some googling I realized the best way to do it would be using Bitlbee, an open source IRC to other chat networks gateway. Bitlbee helps in managing other chat networks such as MSN, Yahoo, GTalk, ICQ, AIM and Jabber. from an IRC channel.
I do not intend to make this an introduction to Bitlbee, my aim is to provide you an insight into bot development using bitlbee and PHP.
If you are new to Bitlbee I would reccomend you to read http://quark.humbug.org.au/publications/internet/bitlbee.pdf
You can find other documents at bitlbee.org
So lets get into the bot development. After you set up your bitlbee account you can use the following PHP code
<code lang=”php”>
< ?php
/*
Bitlbee - IRC MSN Bot by Amal R S
*/
/* Variables that determine server, channel, etc */
$CONFIG = array();
$CONFIG['server'] = ‘im.bitlbee.org’; // server (i.e. 127.0.0.1 if using localhost)
$CONFIG['nick'] = ‘msnbot’; // nick (i.e. username used to loginto bitlbee)
$CONFIG['port'] = 6667; // port (standard: 6667)
$CONFIG['channel'] = ”; // leave this as it is
$CONFIG['name'] = ‘msnbot’; // bot name
$CONFIG['admin_pass'] = ”; //do not use any password here
/* Let it run forever (no timeouts) */
set_time_limit(0);
/* The connection */
$con = array();
/* start the bot… */
init();
function init()
{
global $con, $CONFIG;
/* We need this to see if we need to JOIN (the channel) during
the first iteration of the main loop */
$firstTime = true;
$logged_in = false;
/* Connect to the irc server */
$con['socket'] = fsockopen($CONFIG['server'], $CONFIG['port']);
/* Check that we have connected */
if (!$con['socket']) {
print (”Could not connect to: “. $CONFIG['server'] .” on port “. $CONFIG['port']);
} else {
/* Send the username and nick */
cmd_send(”USER “. $CONFIG['nick'] .” devUnite devunite.com :”. $CONFIG['name']);
cmd_send(”NICK “. $CONFIG['nick'] .” devunite.com”);
/* Here is the loop. Read the incoming data (from the socket connection) */
while (!feof($con['socket']))
{
/* Think of $con['buffer']['all'] as a line of chat messages.
We are getting a ‘line’ and getting rid of whitespace around it. */
$con['buffer']['all'] = trim(fgets($con['socket'], 4096));
/* Pring the line/buffer to the console
I used <- to identify incoming data, -> for outgoing. This is so that
you can identify messages that appear in the console. */
print date(”[d/m @ H:i]”).”< - “.$con['buffer']['all'] .”\n”;
/* If the server is PINGing, then PONG. This is to tell the server that
we are still here, and have not lost the connection */
if(substr($con['buffer']['all'], 0, 6) == ‘PING :’) {
/* PONG : is followed by the line that the server
sent us when PINGing */
cmd_send(’PONG :’.substr($con['buffer']['all'], 6));
/* If this is the first time we have reached this point,
then JOIN the channel */
if ($firstTime == true){
cmd_send(”JOIN “. $CONFIG['channel']);
/* The next time we get here, it will NOT be the firstTime */
$firstTime = false;
}
/* Make sure that we have a NEW line of chats to analyse. If we don’t,
there is no need to parse the data again */
} elseif ($old_buffer != $con['buffer']['all']) {
/* Determine the patterns to be passed
to parse_buffer(). buffer is in the form:
:username!~identd@hostname JOIN :#php
:username!~identd@hostname PRIVMSG #PHP :action text
:username!~identd@hostname command channel :text */
// log the buffer to “log.txt” (file must have
// already been created).
// log_to_file($con['buffer']['all']);
// make sense of the buffer
parse_buffer();
// now process any commands issued to the bot
process_commands();
//find whether logged in or not
$find = strpos($con['buffer']['text'],”in other folders”);
//if logged in set flag $logged_in to true
if($find !== false){
$logged_in=true;
$inputComing = false;
}
//check whether its from the root and contains the final intro message to pass identify
$find = strpos($con['buffer']['text'],”If you’ve never used BitlBee before, please do read the help information using the”);
if($find !== false){
if($con['buffer']['username']== “root”){
cmd_send(”PRIVMSG &bitlbee :identify password”); // the password for your bitlbee account
}
}
//checks whether the incoming request is to add the bot to the buddy list
$find = strpos($con['buffer']['text'],”wants to add you to his/her buddy list”);
if($find !== false){
//set request to true to accept the friend request, if not accepted the user wont be able to send messagess(especially in MSN)
$request = true;
}
//checks whether the request is to add the user to bot friend list
$find = strpos($con['buffer']['text'],”Do you want to add him/her now”);
if($find !== false){
//set request to false to not add the user into the bot’s contact list
$request = false;
}
//checks whether a yes/no question is asked
$find = strpos($con['buffer']['text'],”commands to accept/reject this request”);
if($find !== false){
if($con['buffer']['username']== “root”){
if($request == true){
//accept the request to be friends
cmd_send(”PRIVMSG &bitlbee :yes”);
}else{
//prevent the user from being added to the contact list
cmd_send(”PRIVMSG &bitlbee :no”);
}
}
}
//get messaged from other users except root and add it into db only if its a private message
if($con['buffer']['username']!=”root” and $con['buffer']['hostname']!=”im.bitlbee.org” and $con['buffer']['private'] == true and $con['buffer']['username']!= “” and $con['buffer']['text']!=””){
//send notification to the sender
$command = “PRIVMSG “.$con['buffer']['username'].” : Your Message was received!”;
cmd_send($command);
/* This is where you can write the code to update your mySQL table.
* $user contains the complete email address of the user who sent the message
* $message contains the message sent by the user
* All you need to do is just add them to your mySQL table.
*/
$user = $con['buffer']['identd'].”@”.$con['buffer']['hostname'];
$message = $con['buffer']['text'];
}
}
$old_buffer = $con['buffer']['all'];
}
}
}
/* Accepts the command as an argument, sends the command
to the server, and then displays the command in the console
for debugging */
function cmd_send($command)
{
global $con, $time, $CONFIG;
/* Send the command. Think of it as writing to a file. */
fputs($con['socket'], $command.”\n”);
/* Display the command locally, for the sole purpose
of checking output. (line is not actually not needed) */
print (date(”[d/m @ H:i]“) .”-> “. $command. “\n\r”);
}
function log_to_file ($data)
{
$filename = “log.txt”;
$data .= “\n”;
// open the log file
if ($fp = fopen($filename, “ab”))
{
// now write to the file
if ((fwrite($fp, $data) === FALSE))
{
echo “Could not write to file.
“;
}
}
else
{
echo “File could not be opened.
“;
}
}
function process_commands()
{
global $con, $CONFIG;
/* TIME */
if(strtoupper($con[’buffer’][’text’]) == ‘.TIME’) {
cmd_send(prep_text(”Time”, date(”F j, Y, g:i a”, time())));
}
/* NICK */
if (substr(strtoupper($con[’buffer’][’text’]), 0, 5) == “.NICK”){
$args = explode(” “, $con[’buffer’][’text’]);
if (count($args) < 3)
cmd_send(prep_text(”Nick”, “Syntax: .nick admin_pass new_nick”));
else
{
if ($args[1] == $CONFIG['admin_pass'])
cmd_send(”NICK “. $args[2]);
else
cmd_send(prep_text(”Nick”, “Invalid password”));
}
}
/* Noob */
if(strtoupper(substr($con['buffer']['text'], 0, 5)) == ‘.NOOB’) {
$args = explode(” “, $con['buffer']['text'], 2);
$name = (!empty($args[1]))?$args[1]:”beginner”;
cmd_send(prep_text(”Beginner Help”, “Welcome, “.$name.”, to PHP! Some tutorials: www.codedemons.net, www.zend.com, www.phpbuilder.com, www.php.net”));
}
/* No PMs */
if(strtoupper(substr($con['buffer']['text'], 0, 5)) == ‘.PM’) {
cmd_send(prep_text(”please”,” Please do not send PMs to ops/peons unless you have asked first.”));
}
}
function parse_buffer()
{
/*
:username!~identd@hostname JOIN :#php
:username!~identd@hostname PRIVMSG #PHP :action text
:username!~identd@hostname command channel :text
*/
global $con, $CONFIG;
$buffer = $con['buffer']['all'];
$buffer = explode(” “, $buffer, 4);
//set private to false
$buffer['private'] = false;
/* Get username */
$buffer['username'] = substr($buffer[0], 1, strpos($buffer['0'], “!”)-1);
/* Get identd */
$posExcl = strpos($buffer[0], “!”);
$posAt = strpos($buffer[0], “@”);
$buffer['identd'] = substr($buffer[0], $posExcl+1, $posAt-$posExcl-1);
$buffer['hostname'] = substr($buffer[0], strpos($buffer[0], “@”)+1);
/* The user and the host, the whole shabang */
$buffer['user_host'] = substr($buffer[0],1);
/* Isolate the command the user is sending from
the “general” text that is sent to the channel
This is privmsg to the channel we are talking about.
We also format $buffer['text'] so that it can be logged nicely.
*/
switch (strtoupper($buffer[1]))
{
case “JOIN”:
$buffer['text'] = “*JOINS: “. $buffer['username'].” ( “.$buffer['user_host'].” )”;
$buffer['command'] = “JOIN”;
$buffer['channel'] = $CONFIG['channel'];
break;
case “QUIT”:
$buffer['text'] = “*QUITS: “. $buffer['username'].” ( “.$buffer['user_host'].” )”;
$buffer['command'] = “QUIT”;
$buffer['channel'] = $CONFIG['channel'];
break;
case “NOTICE”:
$buffer['text'] = “*NOTICE: “. $buffer['username'];
$buffer['command'] = “NOTICE”;
$buffer['channel'] = substr($buffer[2], 1);
break;
case “PART”:
$buffer['text'] = “*PARTS: “. $buffer['username'].” ( “.$buffer['user_host'].” )”;
$buffer['command'] = “PART”;
$buffer['channel'] = $CONFIG['channel'];
break;
case “MODE”:
$buffer['text'] = $buffer['username'].” sets mode: “.$buffer[3];
$buffer['command'] = “MODE”;
$buffer['channel'] = $buffer[2];
break;
case “NICK”:
$buffer['text'] = “*NICK: “.$buffer['username'].” => “.substr($buffer[2], 1).” ( “.$buffer[’user_host’].” )”;
$buffer[’command’] = “NICK”;
$buffer[’channel’] = $CONFIG[’channel’];
break;
default:
// it is probably a PRIVMSG
$buffer[’command’] = $buffer[1];
$buffer[’channel’] = $buffer[2];
$buffer[’text’] = substr($buffer[3], 1);
$buffer[’private’] = true; //sets the message as private not a command, which should be captured
break;
}
$con[’buffer’] = $buffer;
}
function prep_text($type, $message)
{
global $con;
return (’PRIVMSG ‘. $con[’buffer’][’channel’] .’ :[’.$type.’]’.$message);
}
?>
</code>
The lines you’ll need to edit are the bot name and password. Remember not to use any administrative password. The place where you want to provide your password is
<code lang=”php”>
if($find !== false){
if($con[’buffer’][’username’]== “root”){
cmd_send(”PRIVMSG &bitlbee :identify password”); // the password for your bitlbee account
}
}
</code>
Thats all you need to get your MSN bot running. If you want to create bots for other chat networks try digging more… Enjoy the bot.