added stats command
[ZNCAdmin.git] / zncadmin.php
1 <?php
2 /* czncadmin.php - main script - ZNCAdmin
3  * Copyright (C) 2011-2012  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 error_reporting(E_ALL & ~E_NOTICE);
20 require_once("zncadmin/HTTPConnector.class.php");
21 require_once("zncadmin/ZNCServer.class.php");
22 require_once("zncadmin/Table.class.php");
23
24 require_once("config.inc.php");
25
26 /*
27 $argv[1]   subcommand
28 */
29
30 function error($msg) {
31     echo"\00304ZNCAdmin error:\003 ".$msg."\n";
32 }
33
34 if(strtolower($argv[1]) == "force") {
35     $argv = array_slice($argv, 1);
36     $force = true;
37 } else
38     $force = false;
39
40 switch(strtolower($argv[1])) {
41     case "add":
42         zncadmin_add();
43         break;
44     case "del":
45         zncadmin_del();
46         break;
47     case "search":
48         zncadmin_search();
49         break;
50         case "seen":
51         zncadmin_seen();
52         break;
53     case "resetpass":
54         zncadmin_resetpass();
55         break;
56     case "simul":
57         zncadmin_simul();
58         break;
59     case "stats":
60         zncadmin_stats();
61         break;
62     default:
63         error("invalid subcommand '".$argv[1]."'");
64         break;
65 }
66
67 function preg_prepare($string,$wildcards = true,$pregstart = "#") {
68     $in = array("\\","^",".","$","|","(",")","[","]","+","?","{","}",",",$pregstart);
69     if(!$wildcards) array_push($in,"*");
70     $out = array();
71     foreach($in as $item) {
72         $out[] = "\\".$item;
73     }
74     if($wildcards) { 
75         array_push($in,"*");
76         array_push($out,"(.*)");
77     }
78     $string = str_replace($in,$out,$string);
79     return $string;
80 }
81
82 function generate_password() {
83     $password_chars = "abcdefghijklmnopqrstuvwxyz01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ";
84     $password_length = 10;
85     $password = 0;
86     srand();
87     for($i = 0; $i < $password_length; $i++) {
88         $password .= $password_chars[rand(0, strlen($password_chars))-1];
89     }
90     return $password;
91 }
92
93 function str2time($duration) {
94     $str="0";
95     $dur=0;
96     $mult=1;
97     for($i=0;$i<strlen($duration);$i++) {
98         if(is_numeric($duration[$i])) {
99             $str.=$duration[$i];
100         } else if($duration[$i] != " ") {
101             switch ($duration[$i]) {
102                 case "y":
103                     $mult=365*24*60*60;
104                     break;
105                 case "M":
106                     $mult=31*24*60*60;
107                     break;
108                 case "w":
109                     $mult=7*24*60*60;
110                     break;
111                 case "d":
112                     $mult=24*60*60;
113                     break;
114                 case "h":
115                     $mult=60*60;
116                     break;
117                 case "m":
118                     $mult=60;
119                     break;
120                 case "s":
121                     $mult=1;
122                     break;
123                 case "*":
124                     $mult=0;
125                     break;
126                 default:
127                     return null;
128                     break;
129             }
130             $dur=$dur+($str*$mult);
131             $str="0";
132         }
133     }
134     $dur=$dur+$str;
135     return $dur;
136 }
137
138 /***********************************************************
139  *                   ZNCAdmin SUBCOMMANDS                  *
140  ***********************************************************/
141
142 //SUBCOMMAND: search
143 function zncadmin_search() {
144     global $argv, $zncservers;
145     $mask = $argv[2];
146     if(!$mask) {
147         error("missing mask parameter");
148         return;
149     }
150     $extraflags = array();
151     if($argv[3]) {
152         $extraflags = explode(" ", $argv[3]);
153     }
154     $mask = preg_prepare($mask);
155     $table = new Table(5);
156     $table->add("Server", "User", "Clients", "Server", "Nick");
157     $count = 0;
158     foreach($zncservers as $zncserver) {
159         $zncserver['conn'] = new ZNCServer($zncserver['host'], $zncserver['port']);
160         $zncserver['conn']->login($zncserver['auser'], $zncserver['apass']);
161         foreach($zncserver['conn']->getUserList() as $user) {
162             $skip = false;
163             foreach($extraflags as $flag) {
164                 //some additional flags ;)
165                 if($flag[0] == '-') {
166                     $flag = substr($flag, 1);
167                     $positive = false;
168                 } else if($flag[0] == '+') {
169                     $flag = substr($flag, 1);
170                     $positive = true;
171                 } else
172                     $positive = true;
173                 $flag = explode("=", $flag, 2);
174                 $flagval = $flag[1];
175                 switch (strtolower($flag[0])) {
176                     case "online":
177                         $skip = (($user['clients'] > 0) != $positive);
178                         break;
179                     case "connected":
180                         $skip = (($user['server'] == "-N/A-") == $positive);
181                         break;
182                     case "server":
183                         $skip = (preg_match("#^".preg_prepare($flagval)."$#i", $user['server']) != $positive);
184                         break;
185                     case "server_regex":
186                         $skip = (preg_match("#^".$flagval."$#i", $user['server']) != $positive);
187                         break;
188                     case "nick":
189                         $skip = (preg_match("#^".preg_prepare($flagval)."$#i", $user['nick']) != $positive);
190                         break;
191                     case "nick_regex":
192                         $skip = (preg_match("#^".$flagval."$#i", $user['nick']) != $positive);
193                         break;
194                     case "znc":
195                         $skip = (preg_match("#^".preg_prepare($flagval)."$#i", $zncserver['name']) != $positive);
196                         break;
197                     default:
198                         
199                         break;
200                 }
201                 if($skip)
202                     break;
203             }
204             if($skip) continue;
205             if(preg_match("#^".$mask."$#i", $user['user'])) {
206                 $table->add($zncserver['name'], $user['user'], $user['clients'], $user['server'], $user['nick']);
207                 $count++;
208             }
209         }
210     }
211     if($count) {
212         foreach($table->end() as $line) {
213             echo$line."\n";
214         }
215         echo"Found \002".$count."\002 users.\n";
216     } else {
217         echo "no user matching \002".$argv[2]."\002 found.\n";
218     }
219 }
220
221 //SUBCOMMAND: search
222 function zncadmin_seen() {
223     global $argv, $zncservers;
224         $time = $argv[2];
225         $over_time = true;
226         if($time[0] == '>' || $time[0] == '<') {
227                 if($time[0] == '<') $over_time = false;
228                 $time = substr($time, 1);
229         }
230         $time = time() - str2time($time);
231     $mask = $argv[3];
232     if(!$time) {
233         error("missing time parameter");
234         return;
235     }
236     if($mask)
237         $mask = preg_prepare($mask);
238     else
239         $mask = "(.*)";
240     $table = new Table(4);
241     $table->add("Server", "User", "Seen", "Info");
242     $found = false;
243     foreach($zncservers as $zncserver) {
244         $zncserver['conn'] = new ZNCServer($zncserver['host'], $zncserver['port']);
245         $zncserver['conn']->login($zncserver['auser'], $zncserver['apass']);
246         foreach($zncserver['conn']->getSeenList() as $user) {
247             if(preg_match("#^".$mask."$#i", $user['user']) && (($over_time && $user['seen_unix'] < $time) || (!$over_time && $user['seen_unix'] > $time))) {
248                 $table->add($zncserver['name'], $user['user'], $user['seen'], $user['info']);
249                 $found = true;
250             }
251         }
252     }
253     if($found) {
254         foreach($table->end() as $line) {
255             echo$line."\n";
256         }
257     } else {
258         echo "no user matching \002".$argv[2]."\002 found.\n";
259     }
260 }
261
262 //SUBCOMMAND: del
263 function zncadmin_del() {
264     global $argv, $zncservers, $force;
265     $username = strtolower($argv[2]);
266     if(!$username) {
267         error("missing username");
268         return;
269     }
270     $delusers = array();
271     foreach($zncservers as $zncserver) {
272         if($argv[3] && (strtolower($argv[3]) != strtolower($zncserver['name']))) continue;
273         if($username == strtolower($zncserver['auser'])) continue;
274         $zncserver['conn'] = new ZNCServer($zncserver['host'], $zncserver['port']);
275         $zncserver['conn']->login($zncserver['auser'], $zncserver['apass']);
276         foreach($zncserver['conn']->getUserList() as $user) {
277             if(strtolower($user['user']) == $username) {
278                 $delusers[] = array("server" => $zncserver, "user" => $user);
279             }
280         }
281     }
282     if(count($delusers) > 1) {
283         error($argv[2]." exists on multiple servers! please add the server name, the user should be removed from.");
284         echo"Found User on following Servers:\n";
285         foreach($delusers as $server) {
286             echo "\002".$server['server']['name']."\002  Server: ".$server['user']['server']."  Nick: ".$server['user']['nick']."  Clients: ".$server['user']['clients']."\n";
287         }
288     } else if(count($delusers) == 0) {
289         error("Couldn't find an user called \002".$argv[2]."\002.");
290     } else if($delusers[0]['server']['protected'] && !$force) {
291         error("Access denied\n");
292     } else {
293         $deluser = $delusers[0];
294         $deluser['server']['conn']->delZNC($deluser['user']['user']);
295         echo "Deleted \002".$deluser['user']['user']."\002 from Server \002".$deluser['server']['name']."\002\n";
296         echo"/log\n";
297     }
298 }
299
300 //SUBCOMMAND: add
301 function zncadmin_add() {
302     global $argv, $zncservers, $add_settings, $force;
303     $username = strtolower($argv[2]);
304     if(!$username) {
305         error("missing username");
306         return;
307     }
308     $addserv = array();
309     $priority = 1;
310     foreach($zncservers as $zncserver) {
311         if($argv[3] && (strtolower($argv[3]) != strtolower($zncserver['name']))) continue;
312         if(!$argv[3] && $zncserver['priority'] < $priority) continue;
313         $zncserver['conn'] = new ZNCServer($zncserver['host'], $zncserver['port']);
314         $zncserver['conn']->login($zncserver['auser'], $zncserver['apass']);
315         $zncserver['users'] = $zncserver['conn']->getUserList();
316         $existing = false;
317         foreach($zncserver['users'] as $user) {
318             if(strtolower($user['user']) == $username) $existing = true;
319         }
320         if(!$existing && count($zncserver['users']) < $zncserver['maxznc']) {
321             if($zncserver['priority'] > $priority) {
322                 $priority = $zncserver['priority'];
323                 $addserv = array();
324             }
325             $addserv[] = $zncserver;
326         }
327     }
328     if(count($addserv) > 1) {
329         //select server with lowest user count
330         $usercount = count($addserv[0]['users']);
331         $selected = 0;
332         for($i = 1; $i < count($addserv); $i++) {
333             if(count($addserv[$i]['users']) < $usercount) {
334                 $usercount = count($addserv[$i]['users']);
335                 $selected = $i;
336             }
337         }
338         $addserv = $addserv[$selected];
339     } else if(count($addserv) == 0) {
340         error("Couldn't find a server the user could be added to.");
341         return;
342     } else {
343         $addserv = $addserv[0];
344     }
345     $password = generate_password();
346     $settings = array();
347     $settings['nick'] = $argv[2];
348     $settings['altnick'] = $argv[2]."`";
349     $settings['ident'] = $username;
350     $ret = $addserv['conn']->addZNC($argv[2], $password, $settings, $add_settings['servers'], $add_settings['modules'], $add_settings['other']);
351     if($ret) {
352         echo "Added user ".$argv[2]." to Server ".$addserv['name'].".\n";
353         echo "  Server Host: ".$addserv['public']."  Port: ".$addserv['port']."  SSL Port: ".$addserv['sslport']."\n";
354         echo "  Password: ".$password."\n";
355         echo "[mIRC]\n";
356         echo " /server -a ".$addserv['public']." -p ".$addserv['port']." -g KryptonZNC -w ".$argv[2].":".$password." -d KryptonZNC\n";
357         echo " /AS addmask *@*.free-bnc.de\n";
358         echo " /AS addmask *@*.krypton-bouncer.de\n";
359         echo " /server -m KryptonZNC\n";
360         echo"/log\n";
361         $addserv['conn']->addChan($argv[2], "#Krypton");
362     } else
363         error("Error while adding user.");
364 }
365
366 //SUBCOMMAND: resetpass
367 function zncadmin_resetpass() {
368     global $argv, $zncservers, $force;
369     $username = strtolower($argv[2]);
370     if(!$username) {
371         error("missing username");
372         return;
373     }
374     $delusers = array();
375     foreach($zncservers as $zncserver) {
376         if($argv[3] && (strtolower($argv[3]) != strtolower($zncserver['name']))) continue;
377         if($username == strtolower($zncserver['auser'])) continue;
378         $zncserver['conn'] = new ZNCServer($zncserver['host'], $zncserver['port']);
379         $zncserver['conn']->login($zncserver['auser'], $zncserver['apass']);
380         foreach($zncserver['conn']->getUserList() as $user) {
381             if(strtolower($user['user']) == $username) {
382                 $delusers[] = array("server" => $zncserver, "user" => $user);
383             }
384         }
385     }
386     if(count($delusers) > 1) {
387         error($argv[2]." exists on multiple servers! please add the server name the user, the password should be resetted, is on.");
388         echo"Found User on following Servers:\n";
389         foreach($delusers as $server) {
390             echo "\002".$server['server']['name']."\002  Server: ".$server['user']['server']."  Nick: ".$server['user']['nick']."  Clients: ".$server['user']['clients']."\n";
391         }
392     } else if(count($delusers) == 0) {
393         error("Couldn't find an user called \002".$argv[2]."\002.");
394     } else if($delusers[0]['server']['protected'] && !$force) {
395         error("Access denied\n");
396     } else {
397         $deluser = $delusers[0];
398         $password = generate_password();
399         $deluser['server']['conn']->editZNC($deluser['user']['user'], $password);
400         echo "Changed password of \002".$deluser['user']['user']."\002 on Server ".$deluser['server']['name']." to \002".$password."\002\n";
401         echo"/log\n";
402     }
403 }
404
405 //SUBCOMMAND: simul
406 function zncadmin_simul() {
407     global $argv, $zncservers, $force;
408     $username = strtolower($argv[2]);
409     $server = strtolower($argv[3]);
410     $raw = $argv[4];
411     if(!$username) {
412         error("missing username");
413         return;
414     }
415     if($server) {
416         $found = false;
417         foreach($zncservers as $zncserver) {
418             if(strtolower($server) == strtolower($zncserver['name'])) {
419                 $found = true;
420                 break;
421             }
422         }
423         if(!$found) {
424             $raw = $argv[3]." ".$raw;
425             $server = null;
426         }
427     }
428     if(!$raw) {
429         error("missing raw");
430         return;
431     }
432     $delusers = array();
433     foreach($zncservers as $zncserver) {
434         if($server && (strtolower($server) != strtolower($zncserver['name']))) continue;
435         if($username == strtolower($zncserver['auser'])) continue;
436         $zncserver['conn'] = new ZNCServer($zncserver['host'], $zncserver['port']);
437         $zncserver['conn']->login($zncserver['auser'], $zncserver['apass']);
438         foreach($zncserver['conn']->getUserList() as $user) {
439             if(strtolower($user['user']) == $username) {
440                 $delusers[] = array("server" => $zncserver, "user" => $user);
441             }
442         }
443     }
444     if(count($delusers) > 1) {
445         error($argv[2]." exists on multiple servers! please add the server name the user should be simuled on.");
446         echo"Found User on following Servers:\n";
447         foreach($delusers as $server) {
448             echo "\002".$server['server']['name']."\002  Server: ".$server['user']['server']."  Nick: ".$server['user']['nick']."  Clients: ".$server['user']['clients']."\n";
449         }
450     } else if(count($delusers) == 0) {
451         error("Couldn't find an user called \002".$argv[2]."\002.");
452     } else if($delusers[0]['server']['protected'] && !$force) {
453         error("Access denied\n");
454     } else {
455         $deluser = $delusers[0];
456         $deluser['server']['conn']->simulZNC($deluser['user']['user'], $raw);
457         echo "Simuled \002".$deluser['user']['user']."\002 on Server ".$deluser['server']['name'].": ".$raw."\n";
458         echo"/log\n";
459     }
460 }
461
462 //SUBCOMMAND: stats
463 function zncadmin_stats() {
464     global $argv, $zncservers;
465     $table = new Table(5);
466     $table->add("Server", "Port / SSL Port", "Total ZNC's", "Connected (IRC)", "Online (User)");
467     $count = 0;
468     foreach($zncservers as $zncserver) {
469         $total = 0;
470         $connected = 0;
471         $online = 0;
472         $zncserver['conn'] = new ZNCServer($zncserver['host'], $zncserver['port']);
473         $zncserver['conn']->login($zncserver['auser'], $zncserver['apass']);
474         foreach($zncserver['conn']->getUserList() as $user) {
475             if($user['server'] != "-N/A-") $connected++;
476             if($user['clients'] > 0) $online++;
477             $total++;
478         }
479         $table->add($zncserver['name'], $zncserver['port'].($zncserver['sslport'] ? "/".$zncserver['sslport'] : ""), $total.($zncserver['maxznc'] ? "/".$zncserver['maxznc'] : ""), $connected, $online);
480         $count++;
481     }
482     if($count) {
483         foreach($table->end() as $line) {
484             echo$line."\n";
485         }
486     } else {
487         echo "No Servers configured...\n";
488     }
489 }
490
491 ?>