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