#!/usr/bin/php4
<?php
//http://www.faqs.org/rfcs/rfc1459.html - Internet Relay Chat Protocol
//http://www.irchelp.org/irchelp/rfc/ctcpspec.html - The Client-To-Client Protocol (CTCP)

#########################################################
#
# Copyright (C) 2002  Sven Nierlein (sven@nierlein.org)
#
# This program 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 2
# of the License, or (at your option) any later version.
#
# This program 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 this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
#########################################################
#
# bot.phps,v 1.3 2002/11/22 19:42:51 sven Exp
#
#########################################################
# CONFIGURATION
$server       "irc.yournetworkhere.net";              # servername of irc server
$port         "6667";                                 # port of irc server
$nick         "yournamehere";                         # nickname of bot
$sec_nick     "yourothernamehere";                    # second nickname of bot
$channel      "#yourchannelhere";                     # name of channel
$realname     "yourrealnamehere";                     # realname of bot :)
$admins       = array("adminircnickhere");              # array of admin nicknames
$greeting_msg "";                                     # wanna say hello?
$auth_string  "AUTH authname authpass";               # type "/msg botname auth" if bot should auth himself
$auth_user    "AuthServ@Services.GamesNET.net";       # change this for non gamesnet servers
#########################################################
# global flags
$f_op    0;                   # is 1 if bot is channel operator
$f_voice 0;                   # is 1 if bot has voice
$f_con   0;                   # is 1 if connected to a server
$f_heise 1;                   # if 1 bot will display actual heise news
$f_autorejoin_after_kick 1;   # if 1, bot will try to rejoin after kick
$f_connecting 1;              # is 0 if connection is finished
$f_debug 0;                   # prints raw server responses

$dei_muddr_array = array("enter some abuses here",
                        );

#########################################################
#
# Don't need to change things below here
#
#########################################################
#$last_whois_rpl = array();
set_time_limit(0);
ignore_user_abort(1);
error_reporting(2047);
$last_heise_run 0;

list(
$usec$sec) = explode(' 'microtime());
$seed_init = (float) $sec + ((float) $usec 100000);
srand($seed_init);

#########################################################
# functionlist
#
# checkpong($zeile)
# checkline($zeile)
# check_response_code($server, $code, $user, $wert)
# check_join($server, $code, $user, $wert)
# check_channelmsg($server, $code, $user, $wert)
# check_channelmode($who, $mode)
# check_channelkick($who, $channel_user, $reason)
# check_channelnick($wer, $neuer_nick)
#
#
# do_something($what)
# do_heise($channel)
# cmd_say($target, $text)
# cmd_say_help($user)
# cmd_change_nick($nickname)
# cmd_join_channel($channel)
# cmd_action($action)
# disconnect($channel, $quit_message)
# unhtmlentities($string)
# change_nick($who, $zusatz)
# do_connect()
# do_auth()
#
#########################################################

#########################################################
# connect
list($fp$connect_time) = do_connect($server$port$errno$errstr$nick$realname);

#########################################################

$zeilen_counter 0;
while(!
feof($fp))
{
    if(
$f_con)
    {
        
do_heise($channel);
    }
    
$zeilen_counter++;
    
$zeile trim(fgets($fp,4096));
    
checkline($zeile$fp);
    if(
false)
    {
        
do_print("NOTICE: trying to join channel: ".$channel."\n");
        
cmd_join_channel($channel);
        
$f_con 1;
    }
    
sleep(1);
}

#########################################################

function checkpong($zeile)
{
    global 
$fp;

    
$tmp explode(":"$zeile);
    
fputs($fp"PONG ".$tmp[1]."\n");
}

#########################################################

function checkline($zeile)
{
    global 
$f_debug;
    if(
$f_debug == AND !empty($zeile))
    {
        
do_print("RAW: ".$zeile."\n");
    }
    if(
preg_match("/^PING/",$zeile))
    {
        
checkpong($zeile);
    }
    else
    {
        
$zeilen_array explode(":",$zeile3);
        
$zeilen_array array_pad($zeilen_array3"");
        
$test array_shift($zeilen_array); # remove the first (empty) element
        
list($server_command$wert) = $zeilen_array;
        
$server_response explode(" ",$server_command3);
        
$server_response[] = $wert;
        if(!isset(
$server_response[1]) OR empty($server_response[1]) OR empty($server_response[0]))
        {
            
#do_print("empty response from server\n");
        
}
        elseif(
is_numeric($server_response[1]))
        {
            
check_response_code($server_response[0], $server_response[1], $server_response[2], $server_response[3]);
        }
        elseif(
$server_response[1] == "JOIN")
        {
            
check_join($server_response[0], $server_response[1], $server_response[2], $server_response[3]);
        }
        elseif(
$server_response[1] == "PRIVMSG")
        {
            
check_channelmsg($server_response[0], $server_response[1], $server_response[2], $server_response[3]);
        }
        elseif(
$server_response[1] == "KICK")
        {
            
check_channelkick($server_response[0], $server_response[2], $server_response[3]);
        }
        elseif(
$server_response[1] == "MODE")
        {
            
check_channelmode($server_response[0], $server_response[2]);
        }
        elseif(
$server_response[1] == "NICK")
        {
            
check_channelnick($server_response[0], $server_response[3]);
        }
        elseif(
$server_response[1] == "NOTICE")
        {
            
do_print("SERVERNOTICE: ".$server_response[0]." notice : ".$server_response[3]."\n");
        }
        elseif(
$server_response[1] == "QUIT")
        {
            
do_print($server_response[0]." quits\n");
        }
        elseif(
$server_response[1] == "PART")
        {
            
do_print($server_response[0]." parts ".$server_response[2]."\n");
        }
        elseif(
$server_response[1] == "Link" AND $server_response[0] == "Closing")
        {
            
# needs reconnect
            
global $server$port$errno$errstr$nick$realname$fp;
            list(
$fp$egal) = do_connect($server$port$errno$errstr$nick$realname);
        }
        else
        {
            
do_print("WARNING: Unknown Server Response\n"1);
            
do_print("WARNING: ".$server_response1);
        }
    }
}

#########################################################

function check_response_code($server$code$user$wert)
{
    switch(
$code)
    {
        case 
001:  // Welcome
                   
do_print($wert."\n");
                   break;
        case 
002:  // kein Plan
                   
do_print($wert."\n");
                   break;
        case 
003:  // kein Plan
                   
do_print($wert."\n");
                   break;
        case 
004:  // kein Plan
                   
do_print($wert."\n");
                   break;
        case 
005:  // kein Plan
                   
do_print($wert."\n");
                   break;
        case 
251:  // RPL_LUSERCLIENT
                   
do_print($wert."\n");
                   break;
        case 
252:  // RPL_LUSEROP
                   
do_print($wert."\n");
                   break;
        case 
253:  // RPL_LUSERUNKNOWN
                   
do_print($wert."\n");
                   break;
        case 
254:  // RPL_LUSERCHANNELS
                   
do_print($wert."\n");
           global 
$channel;
           global 
$f_con;
                   
do_print("NOTICE: trying to join channel: ".$channel."\n");
                   
cmd_join_channel($channel);
                   
$f_con 1;
                   break;
        case 
255:  // RPL_LUSERME
                   
do_print($wert."\n");
                   break;
        case 
265:  // Current local users: 152 Max: 307
                   
do_print($wert."\n");
                   break;
        case 
266:  // Current global users: 524 Max: 785
                   
do_print($wert."\n");
                   break;
/*
        case 311:  //RPL_WHOISUSER
                   $last_whois_rpl[ident] = $action_info[4];
                   $last_whois_rpl[host] = $action_info[5];
                   $last_whois_rpl[nick] = $action_info[3];
                   $last_whois_rpl[realname] = chop($parameters);
                   break;
        case 312:  //RPL_WHOISSERVER
                   $last_whois_rpl[server_ip] = $action_info[4];
                   $last_whois_rpl[server_name] = chop($parameters);
                   break;
        case 319:  //Channels
                   $last_whois_rpl[channels] = chop(str_replace("*", "", $parameters));
                   break;
        case 317:  //RPL_WHOISIDLE
                   $last_whois_rpl[idle] = $action_info[4];
                   $last_whois_rpl[connect] = date("d.m.Y - H:i:s", $action_info[5]);
                   break;
        case 318:  //RPL_ENDOFWHOIS
                   cmd_say($channel, "$last_whois_rpl[nick] ($last_whois_rpl[ident]@$last_whois_rpl[host]) is on " . $last_whois_rpl[server_name] . " (" . $last_whois_rpl[server_ip] . ") since " . $last_whois_rpl[connect] . " (idle : " . $last_whois_rpl[idle] . " Seconds)");
                   break;
*/
        
case 332:  // RPL_TOPIC
                   
do_print("Topic is: ".$wert."\n");
                   break;
        case 
353:  // RPL_NAMREPLY
                   
do_print($wert."\n");
                   break;
        case 
366:  // RPL_ENDOFNAMES
                   
do_print($wert."\n");
                   break;
        case 
372:  // RPL_MOTD
                   #do_print($wert."\n");
                   
break;
        case 
375:  // RPL_MOTDSTART
                   #do_print($wert."\n");
                   
break;
        case 
376:  // RPL_ENDOFMOTD
                   #do_print($wert."\n");
                   
break;
/*
        case 391:  //TIME Reply
                   cmd_say($channel, "Server-time is : " . $parameters);
                   break;
*/
    # Error Replys
        
case 401:  // ERR_NOSUCHNICK
                   
do_print("ERR ".$code." ".$wert."\n");
                   break;
        case 
412:  // ERR_NOTEXTTOSEND
                   
do_print("ERR ".$code." ".$wert."\n");
                   break;
        case 
421:  // ERR_UNKNOWNCOMMAND
                   
do_print("ERR ".$code." ".$wert."\n");
                   break;
        case 
433:  //ERR_NICKNAMEINUSE
                   
global $sec_nick;
                   global 
$nick;
                   
do_print("ERR ".$code." ".$wert."\n");
                   global 
$f_connecting;
                   if(
$f_connecting == 1)
                   {
                      
cmd_change_nick($sec_nick);
                   }
                   break;
         default:  
do_print("*****Unknown Server Response Code\nServer: $server\nCode: $code\nUser: $user\nWert: $wert\n"1);
                   
do_print("*****\n"1);
    }
}

#########################################################

function check_join($server$code$user$wert)
{
    global 
$nick;

    list(
$j_user$tmp) = explode("!"$server);
    if(
$j_user == $nick)
    {
        global 
$f_connecting;
        global 
$greeting_msg;
        if(
$f_connecting == 1)
        {
            if(!empty(
$greeting_msg))
            {
                
cmd_say($wert$greeting_msg);
            }
            
$f_connecting 0;
        }
        
do_print("NOTICE: Bot joined ".$wert."\n");
    }
    else
    {
        
do_print("NOTICE: ".$j_user." joins ".$wert."\n");
    }
}

#########################################################

function check_channelmsg($user$code$channel$text)
{
    global 
$nick;
    
$text    trim($text);
    
$channel trim($channel);
    list(
$shortname$tmp) = explode("!"$user);

    if(
preg_match("/^\!/"$text))
    {
        
do_print("NOTICE: ".$shortname." gave chan. command: ".$text."\n");
        
do_something(substr($text,1), $channel$shortname);
    }
    elseif(
$channel == $nick)
    {
        if(!
do_something($text$user$shortname))
        {
            
cmd_say($user"hu?");
        }
        else
        {
            
do_print("NOTICE: ".$shortname." gave pers. command: ".$text."\n");
        }
    }
    else
    {
        
# Normal Users says something
        
do_print(str_pad($shortname12)." # ".$text."\n");
    }
}

#########################################################

function check_channelmode($who$modes)
{
    global 
$nick;

    list(
$channel$mode$whom) = explode(" "$modes." ");
    list(
$who$tmp) = explode("!"$who);

    if(empty(
$whom))
    {
        
do_print("NOTICE: ".$who." sets ".$mode." to ".$channel."\n");
    }
    else
    {
        if(
$mode == "+o" AND $whom == $nick# someone ops me
        
{
            global 
$f_op;
            
do_print("NOTICE: ".$who." gives Op to me\n");
            
$f_op 1;
        }
        elseif(
$mode == "-o" AND $whom == $nick# someone deops me
        
{
            global 
$f_op;
            
do_print("NOTICE: ".$who." removes Op from me\n");
            
$f_op 0;
        }
        elseif(
$mode == "+v" AND $whom == $nick# someone voices me
        
{
            global 
$f_voice;
            
do_print("NOTICE: ".$who." gives Voice to me\n");
            
$f_voice 1;
        }
        elseif(
$mode == "-v" AND $whom == $nick# someone devoices me
        
{
            global 
$f_voice;
            
do_print("NOTICE: ".$who." removes Voice from me\n");
            
$f_voice 0;
        }
        else
        {
            
do_print("NOTICE: ".$who." sets ".$mode." to ".$whom."\n");
        }
    }
}

#########################################################

/*
 * returns 1 if something done
 *         0 if action not found
 */
function do_something($what$channel$who)
{
    
$tmp explode(" "$what2);
    
$tmp array_pad($tmp2"");

    
$what strtolower($tmp[0]);
    
$zusatz $tmp[1];

    switch(
$what)
    {
        case 
"uptime" : global $connect_time;
                        
$time    time() - $connect_time;
                        
$tage    0;
                        
$stunden 0;
                        
$minuten 0;

                        if(
$time / (60*60*24) > 1) { $tage    floor($time / (60*60*24)); $time $time - ($tage    60*60*24);  }
                        if(
$time / (60*60   ) > 1) { $stunden floor($time / (60*60   )); $time $time - ($stunden 60*60);  }
                        if(
$time / (60      ) > 1) { $minuten floor($time / (60      )); $time $time - ($minuten 60);  }

                        if(
$tage 0)
                        {
                            
cmd_say($channel"Uptime: ".$tage." Tage und ".$stunden." Stunden ".$minuten." Minuten");
                        }
                        elseif(
$stunden 0)
                        {
                            
cmd_say($channel"Uptime: ".$stunden." Stunden ".$minuten." Minuten und ".$time." Sekunden");
                        }
                        elseif(
$minuten 0)
                        {
                            
cmd_say($channel"Uptime: ".$minuten." Minuten und ".$time." Sekunden");
                        }
                        else
                        {
                            
cmd_say($channel"Uptime: ".$time." Sekunden");
                        }
                        return(
1);
                        break;
        case 
"help"   cmd_say_help($who);
                        return(
1);
                        break;
        case 
"hilfe"  cmd_say_help($who);
                        return(
1);
                        break;
        case 
"exit"   disconnect($channel$who);
                        return(
1);
                        break;
        case 
"quit"   disconnect($channel$who);
                        return(
1);
                        break;
        case 
"heise"  do_heise($channel$zusatz);
                        return(
1);
                        break;
        case 
"sag"    : global $channel;
                        
cmd_say($channel$zusatz);
                        return(
1);
                        break;
        case 
"say"    : global $channel;
                        
cmd_say($channel$zusatz);
                        return(
1);
                        break;
        case 
"nick"   change_nick($who$zusatz);
                        return(
1);
                        break;
        case 
"action" cmd_action($zusatz);
                        return(
1);
                        break;
        case 
"plum"    : global $channel;
                        
cmd_say($channel"plum plum");
                        return(
1);
                        break;
        case 
"deimuddr" : global $channel;
                        global 
$dei_muddr_array;
                        
cmd_say($channel$dei_muddr_array[array_rand($dei_muddr_array)]);
                        return(
1);
                        break;
        case 
"maul"   : global $channel;
                        
cmd_say($channel"MAUL ".$zusatz);
                        return(
1);
                        break;
        case 
"auth"   do_auth();
                        return(
1);
                        break;
    case 
"debug"  : global $f_debug;
                    if(
$f_debug) {
                
$f_debug 0;
                
do_print("NOTICE: disabled debug\n");
            }else{
                
$f_debug 1;
                
do_print("NOTICE: enabled debug\n");
            }
            return(
1);
            break;
        default       : 
do_print("WARNING: Unknown command: Was: $what Channel: $channel Wer: $who\n");
                        return(
0);
                        break;
    }
}

#########################################################

function cmd_change_nick($nickname)
{
    global 
$fp;
    global 
$nick;
    
$nick $nickname;
    
fputs($fp"NICK $nickname\n");
}

#########################################################

function cmd_print_time($fp$channel) {

    
fputs($fp"TIME\n");

}

#########################################################

function cmd_change_topic($fp$channel$topic){

    
fputs($fp"TOPIC $channel : $topic\n");

}

#########################################################

function cmd_say($target$text)
{
    global 
$fp;
    
chop($text);
    
fputs($fp"PRIVMSG $target :$text\n");
}

#########################################################

function cmd_say_help($user)
{
    
cmd_say($user"Hilfe:");
    
CMD_SAY($user"Erlaubt ist entweder den Befehl mit \"/msg bot befehl\" oder mit \"!befehl\"");
    
cmd_say($user"einzugeben.");
    
cmd_say($user"Es gibt folgende Befehle: ");
    
cmd_say($user"action:       laesst den Bot eine Action ausfuehren");
    
cmd_say($user"heise:        sucht nach neuen Heise News");
    
cmd_say($user"help/hilfe:   zeigt diese Hilfe an");
    
cmd_say($user"nick:         aendert den Nick des Bots");
    
cmd_say($user"quit/exit:    beendet den bot");
    
cmd_say($user"say/sag:      sagt etwas im Channel");
    
cmd_say($user"uptime:       zeigt an wie lange der Bot schon aktiv ist");
}

#########################################################

function cmd_join_channel($channel_name)
{
    global 
$fp;
    
fputs($fp"JOIN $channel_name\n");
}

#########################################################

function cmd_action($action)
{
    global 
$fp;
    global 
$channel;
    
fputs($fp"PRIVMSG ".$channel." :\001ACTION ".$action."\001\n");
}

#########################################################

function disconnect($channel$who)
{
    global 
$fp;
    global 
$admins;

    if(
in_array(strtolower($who), $admins))
    {
        
fputs($fp"QUIT :I quit\n");
        die;
    }
    else
    {
        
cmd_say($who"Nicht erlaubt");
    }
}

#########################################################

function do_heise($channel$zusatz "")
{
    global 
$last_heise_run;
    global 
$f_heise;
    if(
$f_heise)
    {
        
$file_name "heise.txt";
        if(
$last_heise_run 300 time() AND $zusatz != "force")
        {
        }
        elseif((
$zusatz == "force") OR ($last_heise_run 300 time()))
        {
            
$last_heise_run time();

            
do_print("NOTICE: doing heise test\n");
            
exec("touch ".$file_name) or die("Cannot write to file: ".$file_name."\n");
            
$fp fopen("heise.txt""a");
            
$file  file($file_name);
            
$heise str_replace("\n"""join("",file("http://www.heise.de/newsticker/heise.rdf")));

            
preg_match_all ("/<item>.*?<title>(.*?)<\/title>.*?<link>(.*?)<\/link>.*?<\/item>/i",
                            
$heise,
                            
$outPREG_PATTERN_ORDER);
            
$nr 0;
            
$printed 0;
            foreach(
$out[2] as $tmp)
            {
                if(!
in_array(trim($out[2][$nr])."\n"$file))
                {
                    if(
$printed 3)
                    {
                        
cmd_say($channelunhtmlentities($out[1][$nr])." -> ".$out[2][$nr]);
                        
$printed++;
                    }
                    
fputs($fp$out[2][$nr]."\n");
                }
                
$nr++;
            }
            
fclose($fp);
            if(
$printed == 0)
            {
            
do_print("NOTICE: Nichts neues gefunden\n");
            }
        }
    }
}

#########################################################

function check_channelkick($who$channel_user$reason)
{
    global 
$nick;

    list(
$channel$user) = explode(" "$channel_user);
    list(
$who_short$who_host) = explode("!"$who);
    if(
$user == $nick)
    {
        global 
$f_con;
        
$f_con 0;

        
do_print("NOTICE: ".$who_short." kicks me from ".$channel." (".$reason.")...\n");
        global 
$f_autorejoin_after_kick;
        if(
$f_autorejoin_after_kick)
        {
            
do_print("NOTICE: trying to join channel: ".$channel." *****\n");
            
cmd_join_channel($channel);
            
$f_con 1;
        }
    }
    else
    {
        
do_print("NOTICE: ".$who_short." kicks ".$user." from ".$channel." (".$reason.")\n");
    }
}

#########################################################

function check_channelnick($wer$neuer_nick)
{
    list(
$short_nick$host) = explode("!"$wer);
    
do_print("NOTICE: ".$short_nick." changes nick to ".$neuer_nick."\n");
}

#########################################################

function unhtmlentities($string)
{
    
$trans_tbl get_html_translation_table (HTML_ENTITIES);
    
$trans_tbl array_flip ($trans_tbl);
    return 
strtr ($string$trans_tbl);
}

#########################################################

function do_print($string$log 0)
{
    if(
is_array($string))
    {
        
print_r($string);
    }
    else
    {
        print 
format_short_time(time())." ".$string;
    }
}

#########################################################

function format_short_time($timestamp)
{
    return(
date("H:i:s"$timestamp));
}

#########################################################

function change_nick($who$zusatz)
{
    global 
$admins;

    if(
in_array(strtolower($who), $admins))
    {
        
cmd_change_nick($zusatz);
    }
    else
    {
        
cmd_say($who"Nicht erlaubt");
    }
}

#########################################################

function do_connect($server$port, &$errno, &$errstr$nick$realname)
{
    
# connect
    
do_print("NOTICE: Connecting to Server: $server as User: $nick\n");
    
flush();
    
$fp fsockopen($server$port$errno$errstr) or die("cannot connect to host: ".$server."\n");
    
socket_set_blocking($fpFALSE);
    
$connect_time mktime();
    
fputs($fp"USER $nick 2 3 :$realname\n");
    
fputs($fp"NICK $nick\n");

    return(array(
$fp$connect_time));
}

#########################################################

function do_auth()
{
    
# Authen
    
global $auth_string;
    global 
$auth_user;
    if(!empty(
$auth_user) AND !empty($auth_string))
    {
        
cmd_say($auth_user$auth_string);
        
do_print("NOTICE: Authet\n");
    }
}

#########################################################

?>