]> jfr.im git - irc/SurrealServices/srsv.git/blob - branches/erry-devel/modules/serviceslibs/adminserv.pm
My work on this so far....
[irc/SurrealServices/srsv.git] / branches / erry-devel / modules / serviceslibs / adminserv.pm
1 # This file is part of SurrealServices.
2 #
3 # SurrealServices is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
7 #
8 # SurrealServices is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License
14 # along with SurrealServices; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 package adminserv;
17
18 use strict;
19
20 use SrSv::Agent;
21
22 use SrSv::Text::Format qw(columnar);
23 use SrSv::Errors;
24
25 use SrSv::User qw(get_user_nick get_user_id);
26 use SrSv::User::Notice;
27 use SrSv::Help qw( sendhelp );
28
29 use SrSv::Log;
30
31 use SrSv::NickReg::Flags qw(NRF_NOHIGHLIGHT nr_chk_flag_user);
32
33 use SrSv::MySQL '$dbh';
34
35 use constant {
36 S_HELP => 1,
37 S_OPER => 2,
38 S_ADMIN => 3,
39 S_ROOT => 4,
40 };
41
42 # BE CAREFUL CHANGING THESE
43 my @flags = (
44 'SERVOP',
45 'FJOIN',
46 'SUPER',
47 'HOLD',
48 'FREEZE',
49 'BOT',
50 'QLINE',
51 'KILL',
52 'HELP',
53 );
54 my $allflags = (2**@flags) - 1;
55 my %flags;
56 for(my $i=0; $i<@flags; $i++) {
57 $flags{$flags[$i]} = 2**$i;
58 }
59
60 our $asnick_default = 'AdminServ';
61 our $asnick = $asnick_default;
62 our $asuser = { NICK => $asnick, ID => "123AAAAAG" };
63 our @levels = ('Normal User', 'HelpOp', 'Operator', 'Administrator', 'Root');
64 my @defflags = (
65 0, # Unused
66 $flags{HELP}, # HelpOp
67 $flags{HELP}|$flags{FJOIN}|$flags{QLINE}|$flags{SUPER}|$flags{FREEZE}|$flags{KILL}, # Operator
68 $flags{HELP}|$flags{FJOIN}|$flags{QLINE}|$flags{SUPER}|$flags{FREEZE}|$flags{HOLD}|$flags{BOT}|$flags{SERVOP}|$flags{KILL}, # Admin
69 $allflags # Root
70 );
71
72 our (
73 $create_svsop, $delete_svsop, $rename_svsop,
74
75 $get_svs_list, $get_all_svsops,
76
77 $get_svs_level, $set_svs_level, $get_best_svs_level,
78
79 $chk_pass, $get_pass, $set_pass
80 );
81
82 sub init() {
83 $create_svsop = $dbh->prepare("INSERT IGNORE INTO svsop SELECT id, NULL, NULL FROM nickreg WHERE nick=?");
84 $delete_svsop = $dbh->prepare("DELETE FROM svsop USING svsop, nickreg WHERE nickreg.nick=? AND svsop.nrid=nickreg.id");
85
86 $get_svs_list = $dbh->prepare("SELECT nickreg.nick, svsop.adder FROM svsop, nickreg WHERE svsop.level=? AND svsop.nrid=nickreg.id ORDER BY nickreg.nick");
87 $get_all_svsops = $dbh->prepare("SELECT nickreg.nick, svsop.level, svsop.adder FROM svsop, nickreg WHERE svsop.nrid=nickreg.id ORDER BY svsop.level, nickreg.nick");
88
89 $get_svs_level = $dbh->prepare("SELECT svsop.level FROM svsop, nickalias WHERE nickalias.alias=? AND svsop.nrid=nickalias.nrid");
90 $set_svs_level = $dbh->prepare("UPDATE svsop, nickreg SET svsop.level=?, svsop.adder=? WHERE nickreg.nick=? AND svsop.nrid=nickreg.id");
91 $get_best_svs_level = $dbh->prepare("SELECT svsop.level, nickreg.nick FROM nickid, nickreg, svsop WHERE nickid.nrid=nickreg.id AND svsop.nrid=nickreg.id AND nickid.id=? ORDER BY level DESC LIMIT 1");
92
93 $chk_pass = $dbh->prepare("SELECT 1 FROM ircop WHERE nick=? AND pass=?");
94 $get_pass = $dbh->prepare("SELECT pass FROM ircop WHERE nick=?");
95 $set_pass = $dbh->prepare("UPDATE ircop SET pass=? WHERE nick=?");
96 }
97
98 ### ADMINSERV COMMANDS ###
99
100 sub dispatch($$$) {
101 my ($user, $dstUser, $msg) = @_;
102 $msg =~ s/^\s+//;
103 my @args = split(/\s+/, $msg);
104 my $cmd = shift @args;
105 $user -> {AGENT} = $dstUser;
106 my $src = $user->{NICK};
107 return unless (lc $dstUser->{NICK} eq lc $asnick);
108 services::ulog($asuser, LOG_INFO(), "cmd: [$msg]", $user);
109
110 unless(is_svsop($user) or is_ircop($user)) {
111 notice($user, $err_deny);
112 ircd::globops($asuser, "\002$src\002 failed access to $asnick $msg");
113 return;
114 }
115
116 if($cmd =~ /^svsop$/i) {
117 my $cmd2 = shift @args;
118
119 if($cmd2 =~ /^add$/i) {
120 if(@args == 2 and $args[1] =~ /^[aoh]$/i) {
121 as_svs_add($user, $args[0], num_level($args[1]));
122 } else {
123 notice($user, 'Syntax: SVSOP ADD <nick> <A|O|H>');
124 }
125 }
126 elsif($cmd2 =~ /^del$/i) {
127 if(@args == 1) {
128 as_svs_del($user, $args[0]);
129 } else {
130 notice($user, 'Syntax: SVSOP DEL <nick>');
131 }
132 }
133 elsif($cmd2 =~ /^list$/i) {
134 if(@args == 1 and $args[0] =~ /^[raoh]$/i) {
135 as_svs_list($user, num_level($args[0]));
136 } else {
137 notice($user, 'Syntax: SVSOP LIST <R|A|O|H>');
138 }
139 }
140 else {
141 notice($user, 'Syntax: SVSOP <ADD|DEL|LIST> [...]');
142 }
143 }
144 elsif($cmd =~ /^whois$/i) {
145 if(@args == 1) {
146 as_whois($user, $args[0]);
147 } else {
148 notice($user, 'Syntax: WHOIS <nick>');
149 }
150 }
151 elsif($cmd =~ /^help$/i) {
152 sendhelp($user, 'adminserv', @args)
153 }
154 elsif($cmd =~ /^staff$/i) {
155 if(@args == 0) {
156 as_staff($user);
157 }
158 else {
159 notice($user, 'Syntax: STAFF');
160 }
161 }
162 else {
163 notice($user, "Unrecognized command. For help, type: \002/msg adminserv help\002");
164 }
165 }
166
167 sub as_svs_add($$$) {
168 my ($user, $nick, $level) = @_;
169 my $src = get_user_nick($user);
170
171 my ($root, $oper) = validate_chg($user, $nick);
172 return unless $oper;
173
174 if(get_svs_level($root) >= S_ROOT) {
175 notice($user, $err_deny);
176 return;
177 }
178
179 $create_svsop->execute($root);
180 $set_svs_level->execute($level, $oper, $root);
181
182 notice($user, "\002$nick\002 is now a \002Services $levels[$level]\002.");
183 wlog($asuser, LOG_INFO(), "$src added $root as a Services $levels[$level].");
184 }
185
186 sub as_svs_del($$) {
187 my ($user, $nick) = @_;
188 my $src = get_user_nick($user);
189
190 my ($root, $oper) = validate_chg($user, $nick);
191 return unless $oper;
192
193 if(get_svs_level($root) >= S_ROOT) {
194 notice($user, $err_deny);
195 return;
196 }
197
198 $delete_svsop->execute($root);
199 notice($user, "\002$nick\002 has been stripped of services rank.");
200 wlog($asuser, LOG_INFO(), "$src stripped $root of services rank.")
201 }
202
203 sub as_svs_list($$) {
204 my ($user, $level) = @_;
205 my (@data, @reply);
206
207 $get_svs_list->execute($level);
208
209 while(my ($nick, $adder) = $get_svs_list->fetchrow_array) {
210 push @data, [$nick, "($adder)"];
211 }
212
213 notice($user, columnar({TITLE => "Services $levels[$level] list:",
214 NOHIGHLIGHT => nr_chk_flag_user($user, NRF_NOHIGHLIGHT)}, @data));
215 }
216
217 sub as_whois($$) {
218 my ($user, $nick) = @_;
219
220 my ($level, $root) = get_best_svs_level({ NICK => $nick });
221 notice($user, "\002$nick\002 is a Services $levels[$level]".($level ? ' due to identification to the nick '."\002$root\002." : ''));
222 }
223
224 sub as_staff($) {
225 my ($user) = @_;
226 my (@data);
227
228 $get_all_svsops->execute();
229
230 while(my ($nick, $level, $adder) = $get_all_svsops->fetchrow_array) {
231 push @data, [$nick, $levels[$level], "($adder)"];
232 }
233
234 notice($user, columnar({TITLE => 'Staff list:',
235 NOHIGHLIGHT => nr_chk_flag_user($user, NRF_NOHIGHLIGHT)}, @data));
236 }
237
238
239 ### DATABASE UTILITY FUNCTIONS ###
240
241 sub validate_chg($$) {
242 my ($user, $nick) = @_;
243 my ($oper);
244
245 unless($oper = is_svsop($user, S_ROOT)) {
246 notice($user, $err_deny);
247 return undef;
248 }
249
250 my $root = nickserv::get_root_nick($nick);
251 unless($root) {
252 notice($user, "The nick \002$nick\002 is not registered.");
253 return undef;
254 }
255
256 return ($root, $oper);
257 }
258
259 sub can_do($$) {
260 my ($user, $flag) = @_;
261 my $nflag = $flags{$flag};
262
263 my ($level, $nick) = get_best_svs_level($user);
264 print ("LEVELS $defflags[$level] $nflag" . "\n");
265 if($defflags[$level] & $nflag) {
266 return $nick if (($nflag == $flags{'HELP'}) or is_ircop($user));
267 }
268
269 return undef;
270 }
271
272 sub is_svsop($;$) {
273 my ($user, $rlev) = @_;
274
275 my ($level, $nick) = get_best_svs_level($user);
276 return $nick if(defined($level) and !defined($rlev));
277
278 if($level >= $rlev) {
279 return $nick ; #if (($rlev == S_HELP) or is_ircop($user)) FIXME - erry
280 #Problem is inspircd has a gay way of identifying opers, instead of umode +o it sends OPERTYPE crap.
281 }
282
283 return undef;
284 }
285
286 sub is_ircop($) {
287 my ($user) = @_;
288
289 return undef if is_agent($user->{NICK});
290
291 return $user->{IRCOP} if(exists($user->{IRCOP}));
292
293 my %umodes = modes::splitumodes(nickserv::get_user_modes($user));
294
295 no warnings 'deprecated';
296 if(($umodes{'o'} eq '+') or ($umodes{'S'} eq '+')) {
297 $user->{IRCOP} = 1;
298 }
299 else {
300 $user->{IRCOP} = 0;
301 }
302
303 return $user->{IRCOP};
304 }
305
306 sub is_service($) {
307 # detect if a user belongs to another service like NeoStats. only works if they set umode +S
308 # is_ircop() includes is_service(), so no reason to call both.
309 my ($user) = @_;
310
311 return undef if is_agent($user->{NICK});
312
313 return $user->{SERVICE} if(exists($user->{SERVICE}));
314
315 my %umodes = modes::splitumodes(nickserv::get_user_modes($user));
316
317 if($umodes{'S'} eq '+') {
318 $user->{SERVICE} = 1;
319 $user->{IRCOP} = 1;
320 }
321 else {
322 $user->{SERVICE} = 0;
323 }
324
325 return $user->{SERVICE};
326 }
327
328 sub get_svs_level($) {
329 my ($nick) = @_;
330
331 return undef if is_agent($nick);
332
333 $get_svs_level->execute($nick);
334 my ($level) = $get_svs_level->fetchrow_array;
335
336 return $level or 0;
337 }
338
339 sub get_best_svs_level($) {
340 my ($user) = @_;
341
342 return undef if is_agent($user->{NICK});
343
344 if(exists($user->{SVSOP_LEVEL}) && exists($user->{SVSOP_NICK})) {
345 if(wantarray) {
346 return ($user->{SVSOP_LEVEL}, $user->{SVSOP_NICK});
347 } else {
348 return $user->{SVSOP_LEVEL};
349 }
350 }
351
352 my $uid = get_user_id($user);
353 $get_best_svs_level->execute($uid);
354 my ($level, $nick) = $get_best_svs_level->fetchrow_array;
355
356 $user->{SVSOP_LEVEL} = $level; $user->{SVSOP_NICK} = $nick;
357
358 if(wantarray) {
359 print "LEVEL $level\n";
360 return ($level, $nick);
361 } else {
362 return $level;
363 }
364 }
365
366 ### MISCELLANEA ###
367
368 sub num_level($) {
369 my ($x) = @_;
370 $x =~ tr/hoarHOAR/12341234/;
371 return $x;
372 }
373
374 ### IRC EVENTS ###
375
376 1;