added Perl debugger (PerlGod.class.php)
[PHP-P10.git] / Bots / PerlGod.class.php
1 <?php
2 /******************************* PHP-P10 v2 *****************************
3  * Copyright (C) 2011  Philipp Kreil (pk910)                            *
4  *                                                                      *
5  * This program is free software: you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation, either version 3 of the License, or    *
8  * (at your option) any later version.                                  *
9  *                                                                      * 
10  * This program is distributed in the hope that it will be useful,      *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
13  * GNU General Public License for more details.                         *
14  *                                                                      *
15  * You should have received a copy of the GNU General Public License    *
16  * along with this program. If not, see <http://www.gnu.org/licenses/>. *
17  *                                                                      *
18  ************************************************************************
19  * 
20  *  Bots/PerlGod.class.php
21  *
22  * simple Perl debugger...
23  *
24  */
25
26 class {$_NAME} extends Bot {
27         private $uplink;
28         private $bot, $execcache = array();
29         
30         public function load($uplink, $old = false) {
31                 $this->uplink = $uplink;
32                 if(!$old) {
33                         $nick = "Perl";
34                         $ident = "perl";
35                         $host = "Services.WebGamesNet.net";
36                         $ip = "0::0";
37                         $realname = "Perl Perl Perl Perl Perl";
38                         $modes = "ioknISD";
39                         $this->bot = $this->uplink->addUser($nick,$ident,$host,$ip,$modes,$realname);
40                         if(is_a($this->bot, "P10_User")) {
41                                 $this->uplink->join($this->bot, "#perl", (P10_Channel::USERPRIV_OPED | P10_Channel::USERPRIV_VOICE));
42                                 $this->uplink->join($this->bot, "#dev", P10_Channel::USERPRIV_VOICE);
43                         }
44                 } else {
45                         $this->bot = $old;
46                 }
47                 
48                 ModCMD::bind($this, BIND_CHANMSG, "recive_privmsg");
49                 ModCMD::bind($this, BIND_QUIT, "recive_quit");
50         }
51         
52         public function unload($rehash = false) {
53                 foreach($this->execcache as $id => $entry) {
54                         fclose($entry['pipes'][1]);
55                         fclose($entry['pipes'][2]);
56                         proc_terminate($entry['proc'],9);
57                 }
58                 $this->execcache = array();
59                 if($rehash) {
60                         return $this->bot;
61                 } else {
62                         $this->uplink->delUser($this->bot, "Bye.");
63                 }
64         }
65         
66         public function loop() {
67                 foreach($this->execcache as $id => $entry) {
68                         if(!$this->checkstate($entry)) {
69                                 unset($this->execcache[$id]);
70                         }
71                 }
72         }
73         
74         function recive_privmsg($user, $channel, $message) {
75                 $opOnPHPChannel = false;
76                 $entryChannel = P10_Channel::getChannelByName("#PHP");
77                 if($entryChannel) {
78                         $privs = $entryChannel->getUserPrivs($user);
79                         $opOnPHPChannel = ($privs & P10_Channel::USERPRIV_OPED);
80                 }
81                 if(!$user->getModes()->hasMode('o') && !$opOnPHPChannel) return 0;
82                 $exp=explode(" ", $message, 2);
83                 switch (strtolower($exp[0])) {
84                         case "~perl":
85                                 if(count($this->execcache) > 5) {
86                                         $this->uplink->notice($this->bot, $user, "too many running perl processes at the moment!");
87                                         return;
88                                 }
89                                 $entry=array();
90                                 $entry['channel'] = $channel;
91                                 $descriptor = array(0 => array("pipe", "r"),1 => array("pipe", "w"),2 => array("pipe", "w"));
92                                 $entry['proc'] = proc_open('perl', $descriptor, $entry['pipes']);
93                                 if(!is_resource($entry['proc'])) {
94                                         $this->uplink->notice($this->bot, $user, "error while loading perl!");
95                                         return;
96                                 }
97                                 $entry['time'] = time();
98                 if(preg_match("#pastebin\.com/([a-zA-Z0-9]*)$#i", $exp[1])) {
99                     $pasteid = explode("/", $exp[1]);
100                     $pasteid = $pasteid[count($pasteid)-1];
101                     $codecontent = file_get_contents("http://pastebin.com/download.php?i=".$pasteid);
102                     if(preg_match("#Unknown Paste ID!#i", $codecontent)) {
103                         $this->uplink->notice($this->bot, $user, "Unknown Paste ID!");
104                         return;
105                     }
106                     $code = $codecontent;
107                 } else {
108                     $code = $exp[1];
109                 }
110                                 fwrite($entry['pipes'][0], $code);
111                                 fclose($entry['pipes'][0]);
112                                 $this->execcache[] = $entry;
113                                 break;
114                 }
115         }
116         
117         function recive_quit($user, $reason) {
118                 if($user === $this->bot) {
119                         $this->load($this->uplink);
120                 }
121         }
122         
123         function checkstate($entry) {
124                 $data = proc_get_status($entry['proc']);
125                 if(!$data['running']) {
126                         $out="";
127                         while(!feof($entry['pipes'][1])) {
128                                 $out .= fgets($entry['pipes'][1], 128);
129                         }
130                         $eout="";
131                         while(!feof($entry['pipes'][2])) {
132                                 $eout .= fgets($entry['pipes'][2], 128);
133                         }
134                         if($out != "") {
135                                 $out=str_replace("\r","",$out);
136                                 $lines=explode("\n",$out);
137                                 $i=0;
138                                 foreach($lines as $line) {
139                                         $i++;
140                                         if($i>1000) {
141                                                 $this->uplink->privmsg($this->bot, $entry['channel'], "too many lines!");
142                                                 break; 
143                                         }
144                                         $this->uplink->privmsg($this->bot, $entry['channel'], $line);
145                                 }
146                         }
147                         if($eout != "") {
148                                 $eout=str_replace("\r","",$eout);
149                                 $lines=explode("\n",$eout);
150                                 $i=0;
151                                 foreach($lines as $line) {
152                                         $i++;
153                                         if($i>1000) { 
154                                                 $this->uplink->privmsg($this->bot, $entry['channel'], "too many lines!");
155                                                 break; 
156                                         }
157                                         $this->uplink->privmsg($this->bot, $entry['channel'], "\ 34".$line."\ 3");
158                                 }
159                         }
160                         fclose($entry['pipes'][1]);
161                         fclose($entry['pipes'][2]);
162                         proc_close($entry['proc']);
163                         return false;
164                 } else {
165                         if($entry['time']+10 > time()) {
166                                 return true;
167                         } else {
168                                 //TIMEOUT
169                                 if($entry['term']) {
170                                         fclose($entry['pipes'][1]);
171                                         fclose($entry['pipes'][2]);
172                                         proc_terminate($entry['proc'],9);
173                                         $this->uplink->privmsg($this->bot, $entry['channel'], "perl hard timeout. sending SIGKILL");
174                                         return false;
175                                 } else {
176                                         proc_terminate($entry['proc']);
177                                         $entry['term']=true;
178                                         $this->uplink->privmsg($this->bot, $entry['channel'], "perl timeout. (maximum of 10 seconds exceeded)  sending SIGTERM"); 
179                                         return true;
180                                 }
181                         }
182                 }
183         }
184         
185 }
186
187 ?>