line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# $Id: Util.pm,v 1.15 2001-07-27 09:06:13-04 roderick Exp $ |
2
|
|
|
|
|
|
|
# |
3
|
|
|
|
|
|
|
# Copyright (c) 1997-2000 Roderick Schertler. All rights reserved. |
4
|
|
|
|
|
|
|
# This program is free software; you can redistribute it and/or modify |
5
|
|
|
|
|
|
|
# it under the same terms as Perl itself. |
6
|
|
|
|
|
|
|
|
7
|
1
|
|
|
1
|
|
5
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
51
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
package Sirc::Util; |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=head1 NAME |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
Sirc::Util - Utility sirc functions |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=head1 SYNOPSIS |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
# sirc functions |
18
|
|
|
|
|
|
|
use Sirc::Util ':sirc'; |
19
|
|
|
|
|
|
|
# overrides: |
20
|
|
|
|
|
|
|
addhelp $cmd, $usage_line, $rest; |
21
|
|
|
|
|
|
|
timer $delay, $code_string_or_ref, [$reference]; |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
# user messages |
24
|
|
|
|
|
|
|
arg_count_error undef, $want, [@arg]; # or 1st arg $name |
25
|
|
|
|
|
|
|
tell_error $msg; |
26
|
|
|
|
|
|
|
tell_question $msg; |
27
|
|
|
|
|
|
|
xtell $msg; |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
# miscellaneous |
30
|
|
|
|
|
|
|
$pattern = ban_pattern $nick, $user, $host; |
31
|
|
|
|
|
|
|
$boolean = by_server [$who, $user, $host]; |
32
|
|
|
|
|
|
|
eval_this $code, [@arg]; |
33
|
|
|
|
|
|
|
eval_verbose $name, code$, [@arg]; |
34
|
|
|
|
|
|
|
$boolean = have_ops $channel; |
35
|
|
|
|
|
|
|
$boolean = have_ops_q $channel; |
36
|
|
|
|
|
|
|
$boolean = ieq $a, $b; |
37
|
|
|
|
|
|
|
$re = mask_to_re $mask; |
38
|
|
|
|
|
|
|
$unused_timer = newtimer; |
39
|
|
|
|
|
|
|
optional_channel or return; |
40
|
|
|
|
|
|
|
$boolean = plausible_channel $channel; |
41
|
|
|
|
|
|
|
$boolean = plausible_nick $nick; |
42
|
|
|
|
|
|
|
$arg = xgetarg; |
43
|
|
|
|
|
|
|
$restricted = xrestrict; |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# /settables |
46
|
|
|
|
|
|
|
settable name, $var_ref, $setter_ref; |
47
|
|
|
|
|
|
|
settable_boolean $name, $var_ref, [$validate_ref]; |
48
|
|
|
|
|
|
|
settable_int $name, $var_ref, [$validate_ref]; |
49
|
|
|
|
|
|
|
settable_str $name, $var_ref, [$validate_ref]; |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# hooks |
52
|
|
|
|
|
|
|
add_hook_type $name; |
53
|
|
|
|
|
|
|
add_hook $name, $code; |
54
|
|
|
|
|
|
|
run_hook $name, [@arg]; |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
=head1 DESCRIPTION |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
This module provides a bunch of utility functions for B. |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
It also allows you to import from it all of the standard sirc API |
61
|
|
|
|
|
|
|
functions, so that you can more simply write your script as a module. |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
Nothing is exported by default. |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=cut |
66
|
|
|
|
|
|
|
|
67
|
1
|
|
|
1
|
|
5
|
use vars qw($VERSION @ISA @EXPORT_OK %EXPORT_TAGS %Cmd $Debug %Hook); |
|
1
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
106
|
|
68
|
|
|
|
|
|
|
|
69
|
1
|
|
|
1
|
|
5
|
use Exporter (); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
42
|
|
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
# Supply dummy definitions for testing. |
72
|
|
|
|
|
|
|
BEGIN { |
73
|
1
|
50
|
33
|
1
|
|
706
|
eval q{ |
|
1
|
|
|
1
|
|
3
|
|
|
14
|
|
|
14
|
|
26
|
|
|
21
|
|
|
21
|
|
56
|
|
|
1
|
|
|
1
|
|
3
|
|
|
1
|
|
|
1
|
|
38
|
|
74
|
|
|
|
|
|
|
sub main::addhelp { } |
75
|
|
|
|
|
|
|
sub main::addhook { } |
76
|
|
|
|
|
|
|
sub main::addset { } |
77
|
|
|
|
|
|
|
sub main::docommand { } |
78
|
|
|
|
|
|
|
sub main::tell { print @_, "\n" } |
79
|
|
|
|
|
|
|
} unless $::version || $::version; |
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
# I need %EXPORT_TAGS in a BEGIN to get the list of symbols to import |
83
|
|
|
|
|
|
|
# from main, so just set all the globals at compile time. |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
BEGIN { |
86
|
|
|
|
|
|
|
# This first line is for MakeMaker, it extracts the version for the |
87
|
|
|
|
|
|
|
# whole distribution from here. |
88
|
1
|
|
|
1
|
|
2
|
$VERSION = '0.12'; |
89
|
1
|
|
|
|
|
8
|
$VERSION .= '-l' if 0; |
90
|
1
|
50
|
33
|
|
|
7
|
$::add_ons .= "+libsirc $VERSION" |
91
|
|
|
|
|
|
|
if !defined $::add_ons || $::add_ons !~ /\blibsirc\b/; |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
# This is the real version for this file. |
94
|
1
|
|
|
|
|
1
|
$VERSION = do{my@r=q$Revision: 1.15 $=~/\d+/g;sprintf '%d.'.'%03d'x$#r,@r}; |
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
10
|
|
95
|
1
|
50
|
|
|
|
6
|
$VERSION .= '-l' if q$Locker: $ =~ /: \S/; |
96
|
|
|
|
|
|
|
|
97
|
1
|
|
|
|
|
15
|
@ISA = qw(Exporter); |
98
|
1
|
|
|
|
|
5
|
@EXPORT_OK = qw( |
99
|
|
|
|
|
|
|
arg_count_error tell_error tell_question xtell |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
ban_pattern by_server eval_this eval_verbose have_ops |
102
|
|
|
|
|
|
|
have_ops_q ieq mask_to_re newtimer optional_channel |
103
|
|
|
|
|
|
|
plausible_channel plausible_nick xgetarg |
104
|
|
|
|
|
|
|
xrestrict |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
settable settable_boolean settable_int settable_str |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
add_hook add_hook_type run_hook |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
); |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
=head1 STANDARD SIRC FUNCTIONS |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
You can import the standard SIRC API functions individually or, using |
115
|
|
|
|
|
|
|
the tag B<:sirc>, as a group. The available functions are: |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
=over |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
=item |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
accept addcmd addhelp addhook addset connect deltimer describe docommand |
122
|
|
|
|
|
|
|
doset dosplat dostatus eq getarg getuserline getuserpass listen load me |
123
|
|
|
|
|
|
|
msg newfh notice print remhook remsel resolve say sl tell timer userhost |
124
|
|
|
|
|
|
|
yetonearg |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
=back |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
Some of these are actually enhanced versions of the routines that B |
129
|
|
|
|
|
|
|
provides, see below for information about them. |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
=cut |
132
|
|
|
|
|
|
|
|
133
|
1
|
|
|
|
|
7
|
%EXPORT_TAGS = ( |
134
|
|
|
|
|
|
|
'sirc' => [qw(accept addcmd addhelp addhook addset |
135
|
|
|
|
|
|
|
connect deltimer describe docommand doset dosplat |
136
|
|
|
|
|
|
|
dostatus eq getarg getuserline getuserpass listen |
137
|
|
|
|
|
|
|
load me msg newfh notice print remhook remsel |
138
|
|
|
|
|
|
|
resolve say sl tell timer userhost yetonearg)], |
139
|
|
|
|
|
|
|
); |
140
|
1
|
|
|
|
|
61
|
Exporter::export_ok_tags; |
141
|
|
|
|
|
|
|
|
142
|
1
|
|
|
|
|
37
|
$Debug = 0; |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
my $Old_w; |
146
|
1
|
|
|
1
|
|
3
|
BEGIN { $Old_w = $^W; $^W = 1 } |
|
1
|
|
|
|
|
24
|
|
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
# Import sirc's functions. |
149
|
|
|
|
|
|
|
BEGIN { |
150
|
1
|
|
|
1
|
|
6
|
no strict 'refs'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
135
|
|
151
|
1
|
|
|
1
|
|
2
|
for my $fn (grep { $_ !~ /^(addcmd|addhelp|timer|userhost)$/ } |
|
32
|
|
|
|
|
68
|
|
|
1
|
|
|
|
|
3
|
|
152
|
|
|
|
|
|
|
@{ $EXPORT_TAGS{'sirc'} }) { |
153
|
28
|
|
|
|
|
31
|
*$fn = \&{ "main::$fn" }; |
|
28
|
|
|
|
|
194
|
|
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
1
|
|
|
1
|
|
6998
|
use subs qw(tell_error xtell); |
|
1
|
|
|
|
|
31
|
|
|
1
|
|
|
|
|
5
|
|
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
sub debug { |
160
|
6
|
50
|
|
6
|
0
|
21
|
xtell "debug " . join '', @_ |
161
|
|
|
|
|
|
|
if $Debug; |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
=head1 STANDARD MESSAGE FORMS |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
These functions provide for a few standard message forms which are shown |
169
|
|
|
|
|
|
|
to the user via main::tell(). |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
=over |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
=item B I, I, [I...] |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
This prints an error appropriate to an incorrect number of arguments. |
176
|
|
|
|
|
|
|
I is the name to report as having been invoked incorrectly. If |
177
|
|
|
|
|
|
|
it's C (which is the usual case) it's set to the caller's |
178
|
|
|
|
|
|
|
function name. I is how many arguments were desired and the |
179
|
|
|
|
|
|
|
remaining I arguments are the arguments which were actually |
180
|
|
|
|
|
|
|
received. |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
=cut |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
sub arg_count_error { |
185
|
0
|
|
|
0
|
1
|
0
|
my ($fn, $want, @got) = @_; |
186
|
0
|
0
|
|
|
|
0
|
$fn = (caller 1)[3] if !defined $fn; |
187
|
0
|
|
|
|
|
0
|
tell_error "Wrong number of args to $fn, wanted $want got " |
188
|
|
|
|
|
|
|
. @got . ' (' . join(', ', @got) . ')'; |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
=item B I |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
This formats I as an error message and passes it to main::tell. |
194
|
|
|
|
|
|
|
It's appropriate for errors caused by the system or an invalid invocation |
195
|
|
|
|
|
|
|
of your code. |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
=cut |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
#'; |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
sub tell_error { |
202
|
1
|
50
|
|
1
|
|
6
|
unless (@_ == 1) { |
203
|
0
|
|
|
|
|
0
|
arg_count_error undef, 1, @_; |
204
|
0
|
|
|
|
|
0
|
return; |
205
|
|
|
|
|
|
|
} |
206
|
1
|
|
|
|
|
29
|
main::tell("*\cbE\cb* $_[0]"); |
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
=item B I |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
This formats I as an error message for something the user did |
212
|
|
|
|
|
|
|
wrong. The message is passed to main::tell. |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
=cut |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
sub tell_question { |
217
|
0
|
0
|
|
0
|
1
|
0
|
unless (@_ == 1) { |
218
|
0
|
|
|
|
|
0
|
arg_count_error undef, 1, @_; |
219
|
0
|
|
|
|
|
0
|
return; |
220
|
|
|
|
|
|
|
} |
221
|
0
|
|
|
|
|
0
|
main::tell("*\cb?\cb* $_[0]"); |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
=item B I |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
This is just C. |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
=cut |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
sub xtell { |
231
|
0
|
|
|
0
|
|
0
|
my $s = shift; |
232
|
0
|
|
|
|
|
0
|
main::tell("*** $s"); |
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
=back |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
=cut |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=head1 MISCELLANEOUS FUNCTIONS |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
These are some functions which don't fall nicely into groups like those |
244
|
|
|
|
|
|
|
following do. |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
=over |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
=item B I |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
This is an enhanced version of B's addcmd(). It lets you define |
251
|
|
|
|
|
|
|
commands whose names contain non-alphanumeric characters. |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
=cut |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
sub addcmd { |
256
|
6
|
50
|
|
6
|
1
|
19
|
@_ == 1 || arg_count_error undef, '1', @_; |
257
|
6
|
|
|
|
|
8
|
my ($cmd) = @_; |
258
|
|
|
|
|
|
|
|
259
|
6
|
|
|
|
|
11
|
(my $qcmd = $cmd) =~ s/(['\\])/\\$1/g; |
260
|
6
|
|
|
|
|
11
|
my $ucmd = uc $cmd; |
261
|
6
|
|
|
|
|
20
|
$::cmds{$ucmd} = "\&{'cmd_$qcmd'}();"; |
262
|
6
|
|
|
|
|
21
|
debug "command $cmd => $::cmds{$ucmd}"; |
263
|
|
|
|
|
|
|
} |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
=item B I, I |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
=item B I, I, I |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
This is an enhanced version of B's addhelp(). It arranges for the |
270
|
|
|
|
|
|
|
new command to appear in the master help list. |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
Additionally, there's a new 3-arg syntax. When called with 2 args it |
273
|
|
|
|
|
|
|
uses the regular addhelp() command. I hate the way this makes you |
274
|
|
|
|
|
|
|
hardcode the standard form for help info, though, so I added the second |
275
|
|
|
|
|
|
|
form. This form takes the usage info which appears after the command |
276
|
|
|
|
|
|
|
as its first arg, and the bulk of the help as its 3rd arg. |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
=cut |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
{ my (%seen_cmd, %seen_set); |
281
|
|
|
|
|
|
|
sub addhelp { |
282
|
1
|
50
|
33
|
1
|
1
|
19
|
@_ == 2 || @_ == 3 || arg_count_error undef, '2 or 3', @_; |
283
|
1
|
|
|
|
|
2
|
my $cmd = shift @_; |
284
|
1
|
50
|
|
|
|
8
|
my $text = @_ == 1 ? shift : ("Usage: \cB\U$cmd\E\cB " . join "\n", @_); |
285
|
|
|
|
|
|
|
|
286
|
1
|
|
|
|
|
2
|
my ($rseen, $seen_tag, $targ, $intro); |
287
|
1
|
50
|
|
|
|
10
|
if ($cmd =~ /^set (.*)/) { |
288
|
0
|
|
|
|
|
0
|
$rseen = \%seen_set; |
289
|
0
|
|
|
|
|
0
|
$seen_tag = uc $1; |
290
|
0
|
|
|
|
|
0
|
$targ = '@set'; |
291
|
0
|
|
|
|
|
0
|
$intro = "List of non-builtin SET variables:"; |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
else { |
294
|
1
|
|
|
|
|
3
|
$rseen = \%seen_cmd; |
295
|
1
|
|
|
|
|
2
|
$seen_tag = uc $cmd; |
296
|
1
|
|
|
|
|
2
|
$targ = '@main'; |
297
|
1
|
|
|
|
|
2
|
$intro = "List of non-builtin commands with help:"; |
298
|
|
|
|
|
|
|
} |
299
|
|
|
|
|
|
|
|
300
|
1
|
50
|
33
|
|
|
6
|
if (@::help && !$rseen->{$seen_tag}++) { |
301
|
|
|
|
|
|
|
# The help info is stored as an array of lines, then they're |
302
|
|
|
|
|
|
|
# scanned when you use /help! Entries are introduced with |
303
|
|
|
|
|
|
|
# "@name". |
304
|
|
|
|
|
|
|
|
305
|
0
|
|
|
|
|
0
|
my $state = 0; |
306
|
0
|
|
|
|
|
0
|
my $i = -1; |
307
|
0
|
|
|
|
|
0
|
my $first = undef; |
308
|
0
|
|
|
|
|
0
|
my $len = 0; |
309
|
|
|
|
|
|
|
|
310
|
0
|
|
|
|
|
0
|
for (@::help) { |
311
|
0
|
|
|
|
|
0
|
$i++; |
312
|
0
|
0
|
|
|
|
0
|
if ($state == 0) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
313
|
0
|
0
|
|
|
|
0
|
$state = 1 if $_ eq $targ; |
314
|
|
|
|
|
|
|
} |
315
|
|
|
|
|
|
|
elsif ($state == 1) { |
316
|
0
|
0
|
|
|
|
0
|
if ($_ eq $intro) { |
|
|
0
|
|
|
|
|
|
317
|
0
|
|
|
|
|
0
|
$first = $i; |
318
|
0
|
|
|
|
|
0
|
$len = 1; |
319
|
0
|
|
|
|
|
0
|
$state = 2; |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
elsif (/^@/) { |
322
|
0
|
|
|
|
|
0
|
$first = $i; |
323
|
0
|
|
|
|
|
0
|
$len = 0; |
324
|
0
|
|
|
|
|
0
|
last; |
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
elsif ($state == 2) { |
328
|
0
|
0
|
|
|
|
0
|
if (/^@/) { |
329
|
0
|
|
|
|
|
0
|
last; |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
else { |
332
|
0
|
|
|
|
|
0
|
$len++; |
333
|
|
|
|
|
|
|
} |
334
|
|
|
|
|
|
|
} |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
|
337
|
0
|
0
|
|
|
|
0
|
if (defined $first) { |
338
|
|
|
|
|
|
|
# I found the help entry, $first and $len are the splice() |
339
|
|
|
|
|
|
|
# indicators which for the part I've added to it. |
340
|
0
|
|
|
|
|
0
|
local $_; |
341
|
0
|
|
|
|
|
0
|
my @labels = sort keys %$rseen; |
342
|
0
|
|
|
|
|
0
|
my $l = 0; # max label length |
343
|
0
|
|
|
|
|
0
|
for (@labels) { |
344
|
0
|
0
|
|
|
|
0
|
$l = length if length > $l; |
345
|
|
|
|
|
|
|
} |
346
|
0
|
|
|
|
|
0
|
$l += 2; # spaces between |
347
|
0
|
|
|
|
|
0
|
my $w = 80 - 4; # XXX terminal width less wrap margin |
348
|
0
|
|
|
|
|
0
|
my @out = ($intro, ''); |
349
|
0
|
|
|
|
|
0
|
while (@labels) { |
350
|
0
|
|
|
|
|
0
|
my $this = sprintf "%-${l}s", shift @labels; |
351
|
0
|
0
|
|
|
|
0
|
if (length($out[$#out]) + length($this) > $w) { |
352
|
0
|
|
|
|
|
0
|
push @out, ''; |
353
|
|
|
|
|
|
|
} |
354
|
0
|
|
|
|
|
0
|
$out[$#out] .= $this; |
355
|
|
|
|
|
|
|
} |
356
|
0
|
0
|
|
|
|
0
|
if ($out[$#out] eq '') { |
357
|
0
|
|
|
|
|
0
|
pop @out; |
358
|
|
|
|
|
|
|
} |
359
|
0
|
|
|
|
|
0
|
splice @::help, $first, $len, @out; |
360
|
|
|
|
|
|
|
} |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
|
363
|
1
|
|
|
|
|
29
|
return main::addhelp $cmd, $text; |
364
|
|
|
|
|
|
|
} } |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
=item B I, I, I |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
This returns a pattern suitable for banning the given nick, user and host. |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
The current implementation is this: Any nick is always matched. If the |
371
|
|
|
|
|
|
|
user has a ~ at the start (that is, it didn't come from identd) all user |
372
|
|
|
|
|
|
|
names are matched, else just the one given matches. If the host is an |
373
|
|
|
|
|
|
|
IP address, it bans a class C sized chunk of IP space, otherwise |
374
|
|
|
|
|
|
|
part of it is wildcarded (how much depends on how many parts it has). |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
For example: |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
qw(Nick user 1.2.3.4) *!user@1.2.3.* |
379
|
|
|
|
|
|
|
qw(Nick ~user 1.2.3.4) *!*@1.2.3.* |
380
|
|
|
|
|
|
|
qw(Nick user host.foo.com) *!user@*.foo.com |
381
|
|
|
|
|
|
|
qw(Nick ~user host.foo.com) *!*@*.foo.com |
382
|
|
|
|
|
|
|
qw(Nick user foo.com) *!user@*foo.com |
383
|
|
|
|
|
|
|
qw(Nick ~user foo.com) *!*@*foo.com |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
=cut |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
sub ban_pattern { |
388
|
0
|
|
|
0
|
1
|
0
|
debug "ban_pattern @_"; |
389
|
0
|
0
|
|
|
|
0
|
unless (@_ == 3) { |
390
|
0
|
|
|
|
|
0
|
arg_count_error undef, 1, @_; |
391
|
0
|
|
|
|
|
0
|
return; |
392
|
|
|
|
|
|
|
} |
393
|
0
|
|
|
|
|
0
|
my ($n, $u, $h) = @_; |
394
|
|
|
|
|
|
|
|
395
|
0
|
|
|
|
|
0
|
$n = '*'; |
396
|
0
|
|
|
|
|
0
|
$u =~ s/^~.*/*/; |
397
|
|
|
|
|
|
|
# 1.2.3.4 => 1.2.3.* |
398
|
0
|
0
|
|
|
|
0
|
if ($h =~ /^(\d+\.\d+\.\d+)\.\d+$/) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
399
|
0
|
|
|
|
|
0
|
$h = "$1.*"; |
400
|
|
|
|
|
|
|
} |
401
|
|
|
|
|
|
|
# foo.bar.baz => *.bar.baz |
402
|
|
|
|
|
|
|
elsif ($h =~ /^[^.]+\.(.+\..+)$/) { |
403
|
0
|
|
|
|
|
0
|
$h = "*.$1"; |
404
|
|
|
|
|
|
|
} |
405
|
|
|
|
|
|
|
# foo.bar => *foo.bar |
406
|
|
|
|
|
|
|
elsif ($h =~ /^[^.]+\.[^.]+$/) { |
407
|
0
|
|
|
|
|
0
|
$h = "*$h"; |
408
|
|
|
|
|
|
|
} |
409
|
0
|
|
|
|
|
0
|
return "$n!$u\@$h"; |
410
|
|
|
|
|
|
|
} |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
=item by_server [I, I, I] |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
If the given I, I, I corresponds to a server rather |
415
|
|
|
|
|
|
|
than a user, return the server name, else return undef. If these aren't |
416
|
|
|
|
|
|
|
specified the global $::who, $::user, and $::host are used, which is |
417
|
|
|
|
|
|
|
what you usually want anyway. |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
=cut |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
sub by_server { |
422
|
0
|
0
|
0
|
0
|
1
|
0
|
unless (@_ == 0 || @_ == 3) { |
423
|
0
|
|
|
|
|
0
|
arg_count_error undef, '0 or 3', @_; |
424
|
0
|
|
|
|
|
0
|
return; |
425
|
|
|
|
|
|
|
} |
426
|
0
|
0
|
|
|
|
0
|
my ($n, $u, $h) = @_ ? @_ : ($::who, $::user, $::host); |
427
|
|
|
|
|
|
|
|
428
|
0
|
0
|
|
|
|
0
|
return $u eq '' ? $n : undef; |
429
|
|
|
|
|
|
|
} |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
=item B I, [I...] |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
This Bs I with I as arguments. The I can be |
434
|
|
|
|
|
|
|
either a code reference or a string. In either case the Is will be |
435
|
|
|
|
|
|
|
available in @_. The return value is whatever the I returns. |
436
|
|
|
|
|
|
|
$@ will be set if an exception was raised. |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
=cut |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
#'; |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
sub eval_this { |
443
|
0
|
|
|
0
|
1
|
0
|
debug "eval_this @_"; |
444
|
0
|
0
|
|
|
|
0
|
unless (@_ >= 1) { |
445
|
0
|
|
|
|
|
0
|
arg_count_error undef, '1 or more', @_; |
446
|
0
|
|
|
|
|
0
|
return; |
447
|
|
|
|
|
|
|
} |
448
|
0
|
|
|
|
|
0
|
my $code = shift; |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
package main; |
451
|
1
|
|
|
1
|
|
1774
|
no strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
996
|
|
452
|
0
|
0
|
|
|
|
0
|
return ref $code ? eval { $code->(@_) } : eval $code; |
|
0
|
|
|
|
|
0
|
|
453
|
|
|
|
|
|
|
} |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
=item B I, I, [I...] |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
This is like B except that if an exception is raised it is |
458
|
|
|
|
|
|
|
passed along to B (with a message indicating it's from |
459
|
|
|
|
|
|
|
B). |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
=cut |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
#'; |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
sub eval_verbose { |
466
|
0
|
0
|
|
0
|
1
|
0
|
unless (@_ >= 2) { |
467
|
0
|
|
|
|
|
0
|
arg_count_error undef, '2 or more', @_; |
468
|
0
|
|
|
|
|
0
|
return; |
469
|
|
|
|
|
|
|
} |
470
|
0
|
|
|
|
|
0
|
my ($what, $code, @arg) = @_; |
471
|
|
|
|
|
|
|
|
472
|
0
|
|
|
|
|
0
|
eval_this $code, @arg; |
473
|
0
|
0
|
|
|
|
0
|
if ($@) { |
474
|
0
|
|
|
|
|
0
|
chomp $@; |
475
|
0
|
|
|
|
|
0
|
tell_error "Error running code for $what: $@"; |
476
|
0
|
|
|
|
|
0
|
return 0; |
477
|
|
|
|
|
|
|
} |
478
|
0
|
|
|
|
|
0
|
return 1; |
479
|
|
|
|
|
|
|
} |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
=item B I |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
This function returns true if you have ops on the specified channel. If |
484
|
|
|
|
|
|
|
you don\'t have ops it prints an error message and returns false. |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
=cut |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
sub have_ops { |
489
|
0
|
0
|
|
0
|
1
|
0
|
unless (@_ == 1) { |
490
|
0
|
|
|
|
|
0
|
arg_count_error undef, 1, @_; |
491
|
0
|
|
|
|
|
0
|
return; |
492
|
|
|
|
|
|
|
} |
493
|
0
|
|
|
|
|
0
|
my ($c) = @_; |
494
|
|
|
|
|
|
|
|
495
|
0
|
0
|
|
|
|
0
|
if (!$::haveops{lc $c}) { |
496
|
0
|
|
|
|
|
0
|
tell_question "You don't have ops on $c"; |
497
|
0
|
|
|
|
|
0
|
return 0; |
498
|
|
|
|
|
|
|
} |
499
|
0
|
|
|
|
|
0
|
return 1; |
500
|
|
|
|
|
|
|
} |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
=item B I |
503
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
This is like B except that no message is printed, it just |
505
|
|
|
|
|
|
|
returns true or false depending on whether you have ops on the specified |
506
|
|
|
|
|
|
|
channel. |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
=cut |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
sub have_ops_q { |
511
|
0
|
0
|
|
0
|
1
|
0
|
unless (@_ == 1) { |
512
|
0
|
|
|
|
|
0
|
arg_count_error undef, 1, @_; |
513
|
0
|
|
|
|
|
0
|
return; |
514
|
|
|
|
|
|
|
} |
515
|
0
|
|
|
|
|
0
|
my ($c) = @_; |
516
|
|
|
|
|
|
|
|
517
|
0
|
|
|
|
|
0
|
return $::haveops{lc $c}; |
518
|
|
|
|
|
|
|
} |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
=item B $a, $b |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
This sub returns true if its two args are eq, ignoring case. |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
=cut |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
sub ieq { |
527
|
0
|
0
|
|
0
|
1
|
0
|
unless (@_ == 2) { |
528
|
0
|
|
|
|
|
0
|
arg_count_error undef, 2, @_; |
529
|
0
|
|
|
|
|
0
|
return; |
530
|
|
|
|
|
|
|
} |
531
|
0
|
|
|
|
|
0
|
return lc($_[0]) eq lc($_[1]); |
532
|
|
|
|
|
|
|
} |
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
=item B I |
535
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
Convert the given "mask" (an IRC-style glob pattern) to a regular |
537
|
|
|
|
|
|
|
expression. The only special characters in IRC masks are C<*> and |
538
|
|
|
|
|
|
|
C> (there's no way to escape one of these). The returned pattern |
539
|
|
|
|
|
|
|
always matches case insensitively and is anchored at the front and |
540
|
|
|
|
|
|
|
back (as IRC does it). |
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
=cut |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
sub mask_to_re { |
545
|
6
|
50
|
|
6
|
1
|
150
|
unless (@_ == 1) { |
546
|
0
|
|
|
|
|
0
|
arg_count_error undef, 1, @_; |
547
|
0
|
|
|
|
|
0
|
return; |
548
|
|
|
|
|
|
|
} |
549
|
6
|
|
|
|
|
8
|
my ($s) = @_; |
550
|
|
|
|
|
|
|
|
551
|
6
|
|
|
|
|
13
|
$s = quotemeta $s; |
552
|
6
|
|
|
|
|
13
|
$s =~ s/\\\*/.*/g; |
553
|
6
|
|
|
|
|
10
|
$s =~ s/\\\?/./g; |
554
|
6
|
|
|
|
|
20
|
return "(?is)^$s\$"; |
555
|
|
|
|
|
|
|
} |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
=item B |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
This sub examines $::args to see if the first word in it looks like a |
560
|
|
|
|
|
|
|
channel. If it doesn't then $::talkchannel is inserted there. If there |
561
|
|
|
|
|
|
|
was no channel present and you're not on a channel then an error message |
562
|
|
|
|
|
|
|
is printed and false is returned, otherwise true is returned. |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
Here's a replacement for /names which runs /names for your current |
565
|
|
|
|
|
|
|
channel if you don't provide any args. |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
sub main::cmd_names { |
568
|
|
|
|
|
|
|
optional_channel or return; |
569
|
|
|
|
|
|
|
docommand "/names $::args"; |
570
|
|
|
|
|
|
|
} |
571
|
|
|
|
|
|
|
addcmd 'names'; |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
=cut |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
sub optional_channel { |
576
|
0
|
0
|
|
0
|
1
|
0
|
unless (@_ == 0) { |
577
|
0
|
|
|
|
|
0
|
arg_count_error undef, 0, @_; |
578
|
0
|
|
|
|
|
0
|
$::args = "#invalid-optional_channel-invocation $::args"; |
579
|
0
|
|
|
|
|
0
|
return; |
580
|
|
|
|
|
|
|
} |
581
|
0
|
|
|
|
|
0
|
my $ret = 1; |
582
|
0
|
0
|
|
|
|
0
|
if ($::args !~ /^[\#&]/) { |
583
|
0
|
0
|
|
|
|
0
|
if (!$::talkchannel) { |
584
|
0
|
|
|
|
|
0
|
tell_question "Not on a channel"; |
585
|
0
|
|
|
|
|
0
|
$ret = 0; |
586
|
|
|
|
|
|
|
} |
587
|
0
|
|
0
|
|
|
0
|
$::args = ($::talkchannel || '#not-on-a-channel') . " $::args"; |
588
|
|
|
|
|
|
|
} |
589
|
0
|
|
|
|
|
0
|
return $ret; |
590
|
|
|
|
|
|
|
} |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
=item B |
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
Return an unused timer number. |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
=cut |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
sub newtimer { |
599
|
0
|
0
|
|
0
|
1
|
0
|
unless (@_ == 0) { |
600
|
0
|
|
|
|
|
0
|
arg_count_error undef, 1, @_; |
601
|
0
|
|
|
|
|
0
|
return; |
602
|
|
|
|
|
|
|
} |
603
|
|
|
|
|
|
|
|
604
|
0
|
|
|
|
|
0
|
while (1) { |
605
|
0
|
|
|
|
|
0
|
my $n = 1 + int rand 2**31; |
606
|
0
|
0
|
|
|
|
0
|
return $n unless grep { $_ == $n } @::trefs; |
|
0
|
|
|
|
|
0
|
|
607
|
|
|
|
|
|
|
} |
608
|
|
|
|
|
|
|
} |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
=item B I |
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
This returns true if I is syntactically valid as a channel |
613
|
|
|
|
|
|
|
name. |
614
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
=cut |
616
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
sub plausible_channel { |
618
|
0
|
0
|
|
0
|
1
|
0
|
unless (@_ == 1) { |
619
|
0
|
|
|
|
|
0
|
arg_count_error undef, 1, @_; |
620
|
0
|
|
|
|
|
0
|
return; |
621
|
|
|
|
|
|
|
} |
622
|
0
|
|
|
|
|
0
|
my ($c) = @_; |
623
|
0
|
|
|
|
|
0
|
return $c =~ /^[\#&][^ \a\0\012\015,]+$/; |
624
|
|
|
|
|
|
|
} |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
=item B I |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
This returns true if I is syntactically valid as a nick name. |
629
|
|
|
|
|
|
|
Originally I used the RFC 1459 definition here, but that turns out to be |
630
|
|
|
|
|
|
|
no longer valid. I don't know what definition modern IRC servers are |
631
|
|
|
|
|
|
|
using. This sub allows characters in the range [!-~]. |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
=cut |
634
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
#'; |
636
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
sub plausible_nick { |
638
|
0
|
0
|
|
0
|
1
|
0
|
unless (@_ == 1) { |
639
|
0
|
|
|
|
|
0
|
arg_count_error undef, 1, @_; |
640
|
0
|
|
|
|
|
0
|
return; |
641
|
|
|
|
|
|
|
} |
642
|
0
|
|
|
|
|
0
|
my ($n) = @_; |
643
|
|
|
|
|
|
|
#return $n =~ /^[a-z][a-z0-9\-\[\]\\\`^{}]*$/i; |
644
|
0
|
|
|
|
|
0
|
return $n =~ /^[!-~]+$/; |
645
|
|
|
|
|
|
|
} |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
=item B @args |
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
This is an enhanced version of B's timer(). It allows you to use |
650
|
|
|
|
|
|
|
a code reference as the code arg. |
651
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
=cut |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
#'; |
655
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
my $timer_name = 'timersub000'; |
657
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
sub timer { |
659
|
0
|
|
|
0
|
1
|
0
|
my @arg = @_; |
660
|
|
|
|
|
|
|
|
661
|
0
|
0
|
0
|
|
|
0
|
if (@arg > 1 && ref $arg[1]) { |
662
|
|
|
|
|
|
|
# The strategy here is to give a name to the code reference |
663
|
|
|
|
|
|
|
# and then call it via that name. After calling it the glob |
664
|
|
|
|
|
|
|
# containing the name is deleted to free memory. (You can't |
665
|
|
|
|
|
|
|
# just undef the &sub because that would leave the glob and CV |
666
|
|
|
|
|
|
|
# in existance.) |
667
|
1
|
|
|
1
|
|
6
|
no strict 'refs'; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
330
|
|
668
|
0
|
|
|
|
|
0
|
$timer_name++; |
669
|
0
|
|
|
|
|
0
|
my $pkg = __PACKAGE__; |
670
|
0
|
|
|
|
|
0
|
*{ "${pkg}::$timer_name" } = $arg[1]; |
|
0
|
|
|
|
|
0
|
|
671
|
0
|
|
|
|
|
0
|
$arg[1] = qq{${pkg}::$timer_name(); delete \$${pkg}::{"$timer_name"}}; |
672
|
|
|
|
|
|
|
} |
673
|
0
|
|
|
|
|
0
|
return main::timer(@arg); |
674
|
|
|
|
|
|
|
} |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
# Hack: Chantrack overrides userhost, so I have to call through here. |
677
|
|
|
|
|
|
|
# If I assign to *userhost at compile time I'll retain a reference to |
678
|
|
|
|
|
|
|
# the original sub. |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
sub userhost { |
681
|
0
|
|
|
0
|
0
|
0
|
goto &main::userhost; |
682
|
|
|
|
|
|
|
} |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
=item B |
685
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
This is like main::getarg, but it returns the new argument (in addition |
687
|
|
|
|
|
|
|
to setting $::newarg). |
688
|
|
|
|
|
|
|
|
689
|
|
|
|
|
|
|
=cut |
690
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
sub xgetarg { |
692
|
0
|
|
|
0
|
1
|
0
|
getarg; |
693
|
0
|
|
|
|
|
0
|
return $::newarg; |
694
|
|
|
|
|
|
|
} |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
=item B |
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
This just returns $::restrict. |
699
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
=cut |
701
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
sub xrestrict { |
703
|
0
|
|
|
0
|
1
|
0
|
return $::restrict; |
704
|
|
|
|
|
|
|
} |
705
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
=back |
707
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
=cut |
709
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
=head1 /SET COMMANDS |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
These commands provide a simplified interface to adding /set variables. |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
=over |
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
=item B I, I, I |
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
This sub adds a user-settable option. I is its name, I |
721
|
|
|
|
|
|
|
is a reference to the place it will be stored, and I is a |
722
|
|
|
|
|
|
|
reference to code to validate and save new values. The code will be |
723
|
|
|
|
|
|
|
called as C<$rsetter->($rvar, $name, $value)>. $name will be in upper |
724
|
|
|
|
|
|
|
case. The code needs to set both $$rvar and $::set{$name}. (The values |
725
|
|
|
|
|
|
|
in %set are user-visible.) |
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
=cut |
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
sub settable { |
730
|
21
|
|
|
21
|
1
|
28
|
my ($name, $rvar, $rsetter) = @_; |
731
|
21
|
|
|
|
|
34
|
my $subname = "main::set_$name"; |
732
|
21
|
|
|
|
|
35
|
my $uname = uc $name; |
733
|
|
|
|
|
|
|
my $closure = sub { |
734
|
0
|
|
|
0
|
|
0
|
my $val = shift; |
735
|
0
|
|
|
|
|
0
|
$rsetter->($rvar, $uname, $val); |
736
|
21
|
|
|
|
|
67
|
}; |
737
|
|
|
|
|
|
|
{ |
738
|
1
|
|
|
1
|
|
6
|
no strict 'refs'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
1101
|
|
|
21
|
|
|
|
|
26
|
|
739
|
21
|
|
|
|
|
125
|
*$subname = $closure; |
740
|
|
|
|
|
|
|
} |
741
|
|
|
|
|
|
|
# XXX 2nd arg is ignored |
742
|
21
|
|
|
|
|
575
|
addset $name, $name; |
743
|
|
|
|
|
|
|
} |
744
|
|
|
|
|
|
|
|
745
|
|
|
|
|
|
|
=item B I, I, [I] |
746
|
|
|
|
|
|
|
|
747
|
|
|
|
|
|
|
This adds a /settable boolean called I. I is a reference |
748
|
|
|
|
|
|
|
to the scalar which will store the value. |
749
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
I, if provided, will be called to validate a new value is |
751
|
|
|
|
|
|
|
legal. It will receive both the I and the new value (as a boolean, |
752
|
|
|
|
|
|
|
not as the user typed it) as arguments. It should return a boolean to |
753
|
|
|
|
|
|
|
indicate whether the value is okay. |
754
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
=cut |
756
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
sub settable_boolean { |
758
|
9
|
|
|
9
|
1
|
17
|
my ($name, $rvar, $rvalidate) = @_; |
759
|
|
|
|
|
|
|
my $closure = sub { |
760
|
0
|
|
|
0
|
|
0
|
my ($rvar, $name, $val) = @_; |
761
|
0
|
|
|
|
|
0
|
my $new = $$rvar; |
762
|
0
|
|
|
|
|
0
|
my $lval = lc $val; |
763
|
0
|
0
|
|
|
|
0
|
if ($lval eq 'on') { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
764
|
0
|
|
|
|
|
0
|
$new = 1; |
765
|
|
|
|
|
|
|
} |
766
|
|
|
|
|
|
|
elsif ($lval eq 'off') { |
767
|
0
|
|
|
|
|
0
|
$new = 0; |
768
|
|
|
|
|
|
|
} |
769
|
|
|
|
|
|
|
elsif ($lval eq 'toggle') { |
770
|
0
|
|
|
|
|
0
|
$new = !$new; |
771
|
|
|
|
|
|
|
} |
772
|
|
|
|
|
|
|
elsif ($lval eq 'nil') { |
773
|
|
|
|
|
|
|
# do nothing, for initial set |
774
|
|
|
|
|
|
|
} |
775
|
|
|
|
|
|
|
else { |
776
|
0
|
|
|
|
|
0
|
tell_question "Invalid value `$val' for $name"; |
777
|
0
|
|
|
|
|
0
|
return; |
778
|
|
|
|
|
|
|
} |
779
|
0
|
0
|
0
|
|
|
0
|
if ($rvalidate && !$rvalidate->($name, $new)) { |
780
|
0
|
|
|
|
|
0
|
tell_question "Invalid value `$val' for $name"; |
781
|
0
|
|
|
|
|
0
|
return; |
782
|
|
|
|
|
|
|
} |
783
|
0
|
|
|
|
|
0
|
$$rvar = $new; |
784
|
0
|
0
|
|
|
|
0
|
$::set{$name} = $$rvar ? 'on' : 'off'; |
785
|
9
|
|
|
|
|
48
|
}; |
786
|
9
|
|
|
|
|
20
|
settable $name, $rvar, $closure; |
787
|
9
|
100
|
|
|
|
52
|
$::set{uc $name} = $$rvar ? 'on' : 'off'; |
788
|
|
|
|
|
|
|
} |
789
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
=item B I, I, [I] |
791
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
This function adds a /settable integer called I. I is a |
793
|
|
|
|
|
|
|
reference to the scalar which will store the value. |
794
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
I, if provided, will be called to validate a new |
796
|
|
|
|
|
|
|
value is legal. It will receive both the I and the new value as |
797
|
|
|
|
|
|
|
arguments. Before it is called the new value will have been vetted for |
798
|
|
|
|
|
|
|
number-hood. It should return a boolean to indicate whether the value |
799
|
|
|
|
|
|
|
is okay. |
800
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
=cut |
802
|
|
|
|
|
|
|
|
803
|
|
|
|
|
|
|
sub settable_int { |
804
|
10
|
|
|
10
|
1
|
17
|
my ($name, $rvar, $rvalidate) = @_; |
805
|
|
|
|
|
|
|
my $closure = sub { |
806
|
0
|
|
|
0
|
|
0
|
my ($rvar, $name, $val) = @_; |
807
|
0
|
0
|
0
|
|
|
0
|
if (!defined $val) { |
|
|
0
|
0
|
|
|
|
|
808
|
0
|
|
|
|
|
0
|
tell_question "Can't set $name to undefined value"; |
809
|
|
|
|
|
|
|
} |
810
|
|
|
|
|
|
|
elsif ($val !~ /^-?\d+$/ |
811
|
|
|
|
|
|
|
|| ($rvalidate && !$rvalidate->($name, $val))) { |
812
|
0
|
|
|
|
|
0
|
tell_question "Invalid value `$val' for $name"; |
813
|
|
|
|
|
|
|
} |
814
|
|
|
|
|
|
|
else { |
815
|
0
|
|
|
|
|
0
|
$$rvar = $::set{$name} = $val; |
816
|
|
|
|
|
|
|
} |
817
|
10
|
|
|
|
|
55
|
}; |
818
|
10
|
|
|
|
|
21
|
settable $name, $rvar, $closure; |
819
|
10
|
|
50
|
|
|
24
|
$$rvar ||= 0; # must be defined for /set to work |
820
|
10
|
|
|
|
|
37
|
$::set{uc $name} = $$rvar; |
821
|
|
|
|
|
|
|
} |
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
=item B I, I, [I] |
824
|
|
|
|
|
|
|
|
825
|
|
|
|
|
|
|
This function adds a /settable called I. I is a reference |
826
|
|
|
|
|
|
|
to the scalar which will store the value. |
827
|
|
|
|
|
|
|
|
828
|
|
|
|
|
|
|
I, if provided, will be called to validate the a new |
829
|
|
|
|
|
|
|
value is legal. It will receive both the I and the new value as |
830
|
|
|
|
|
|
|
arguments. It should return a boolean to indicate whether the value is |
831
|
|
|
|
|
|
|
okay. |
832
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
=cut |
834
|
|
|
|
|
|
|
|
835
|
|
|
|
|
|
|
sub settable_str { |
836
|
2
|
|
|
2
|
1
|
4
|
my ($name, $rvar, $rvalidate) = @_; |
837
|
|
|
|
|
|
|
my $closure = sub { |
838
|
0
|
|
|
0
|
|
0
|
my ($rvar, $name, $val) = @_; |
839
|
0
|
0
|
0
|
|
|
0
|
if (!defined $val) { |
|
|
0
|
|
|
|
|
|
840
|
0
|
|
|
|
|
0
|
tell_question "Can't set $name to undefined value"; |
841
|
|
|
|
|
|
|
} |
842
|
|
|
|
|
|
|
elsif ($rvalidate && !$rvalidate->($name, $val)) { |
843
|
0
|
|
|
|
|
0
|
tell_question "Invalid value `$val' for $name"; |
844
|
|
|
|
|
|
|
} |
845
|
|
|
|
|
|
|
else { |
846
|
0
|
|
|
|
|
0
|
$$rvar = $::set{$name} = $val; |
847
|
|
|
|
|
|
|
} |
848
|
2
|
|
|
|
|
8
|
}; |
849
|
2
|
|
|
|
|
6
|
settable $name, $rvar, $closure; |
850
|
2
|
|
50
|
|
|
6
|
$$rvar ||= ''; # must be defined for /set to work |
851
|
2
|
|
|
|
|
7
|
$::set{uc $name} = $$rvar; |
852
|
|
|
|
|
|
|
} |
853
|
|
|
|
|
|
|
|
854
|
|
|
|
|
|
|
=back |
855
|
|
|
|
|
|
|
|
856
|
|
|
|
|
|
|
=cut |
857
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
859
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
#=head1 CHAINED COMMANDS |
861
|
|
|
|
|
|
|
# |
862
|
|
|
|
|
|
|
#=over |
863
|
|
|
|
|
|
|
# |
864
|
|
|
|
|
|
|
#=cut |
865
|
|
|
|
|
|
|
# |
866
|
|
|
|
|
|
|
#sub chain_cmd_runner { |
867
|
|
|
|
|
|
|
# my $type = shift; |
868
|
|
|
|
|
|
|
# for my $code (@{ $Cmd{$type} }) { |
869
|
|
|
|
|
|
|
# if (ref $code) { |
870
|
|
|
|
|
|
|
# eval { &$code }; |
871
|
|
|
|
|
|
|
# } |
872
|
|
|
|
|
|
|
# else { |
873
|
|
|
|
|
|
|
# eval $code; |
874
|
|
|
|
|
|
|
# } |
875
|
|
|
|
|
|
|
# die if $@; |
876
|
|
|
|
|
|
|
# } |
877
|
|
|
|
|
|
|
#} |
878
|
|
|
|
|
|
|
# |
879
|
|
|
|
|
|
|
#sub chain_cmd { |
880
|
|
|
|
|
|
|
# my ($type, $new) = @_; |
881
|
|
|
|
|
|
|
# $type = lc $type; |
882
|
|
|
|
|
|
|
# my $old = $main::cmds{$type}; |
883
|
|
|
|
|
|
|
# my $cmd = "chain_cmd_runner '$type'"; |
884
|
|
|
|
|
|
|
# if ($old && $old ne $cmd) { |
885
|
|
|
|
|
|
|
# push @{ $Cmd{$type} }, $old; |
886
|
|
|
|
|
|
|
# $main::cmds{$type} = $cmd; |
887
|
|
|
|
|
|
|
# } |
888
|
|
|
|
|
|
|
# push @{ $Cmd{$type} }, $new; |
889
|
|
|
|
|
|
|
#} |
890
|
|
|
|
|
|
|
# |
891
|
|
|
|
|
|
|
#=back |
892
|
|
|
|
|
|
|
# |
893
|
|
|
|
|
|
|
#=cut |
894
|
|
|
|
|
|
|
|
895
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
896
|
|
|
|
|
|
|
|
897
|
|
|
|
|
|
|
=head1 HOOKS |
898
|
|
|
|
|
|
|
|
899
|
|
|
|
|
|
|
Sirc::Util provides functionality for creating, adding code to and |
900
|
|
|
|
|
|
|
running hooks. |
901
|
|
|
|
|
|
|
|
902
|
|
|
|
|
|
|
=over |
903
|
|
|
|
|
|
|
|
904
|
|
|
|
|
|
|
=item B I |
905
|
|
|
|
|
|
|
|
906
|
|
|
|
|
|
|
This creates a new hook called I. |
907
|
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
=cut |
909
|
|
|
|
|
|
|
|
910
|
|
|
|
|
|
|
sub add_hook_type { |
911
|
6
|
50
|
|
6
|
1
|
15
|
unless (@_ == 1) { |
912
|
0
|
|
|
|
|
0
|
arg_count_error undef, 1, @_; |
913
|
0
|
|
|
|
|
0
|
return; |
914
|
|
|
|
|
|
|
} |
915
|
6
|
|
|
|
|
7
|
my ($hook) = @_; |
916
|
|
|
|
|
|
|
|
917
|
6
|
50
|
|
|
|
14
|
if (exists $Hook{$hook}) { |
918
|
0
|
|
|
|
|
0
|
tell_error "add_hook_type: Hook $hook already exists"; |
919
|
0
|
|
|
|
|
0
|
return; |
920
|
|
|
|
|
|
|
} |
921
|
6
|
|
|
|
|
16
|
$Hook{$hook} = []; |
922
|
|
|
|
|
|
|
} |
923
|
|
|
|
|
|
|
|
924
|
|
|
|
|
|
|
|
925
|
|
|
|
|
|
|
=item B I, I |
926
|
|
|
|
|
|
|
|
927
|
|
|
|
|
|
|
Add I to the I hook. The I must already have been |
928
|
|
|
|
|
|
|
created with add_hook_type(). The I can be either a string or a |
929
|
|
|
|
|
|
|
code reference. |
930
|
|
|
|
|
|
|
|
931
|
|
|
|
|
|
|
=cut |
932
|
|
|
|
|
|
|
|
933
|
|
|
|
|
|
|
sub add_hook { |
934
|
4
|
50
|
|
4
|
1
|
19
|
unless (@_ == 2) { |
935
|
0
|
|
|
|
|
0
|
arg_count_error undef, 2, @_; |
936
|
0
|
|
|
|
|
0
|
return; |
937
|
|
|
|
|
|
|
} |
938
|
4
|
|
|
|
|
7
|
my ($hook, $code) = @_; |
939
|
|
|
|
|
|
|
|
940
|
4
|
50
|
|
|
|
13
|
if (!exists $Hook{$hook}) { |
941
|
0
|
|
|
|
|
0
|
tell_error "add_hook: Invalid hook `$hook'"; |
942
|
0
|
|
|
|
|
0
|
return; |
943
|
|
|
|
|
|
|
} |
944
|
4
|
|
|
|
|
5
|
push @{ $Hook{$hook} }, $code; |
|
4
|
|
|
|
|
14
|
|
945
|
|
|
|
|
|
|
} |
946
|
|
|
|
|
|
|
|
947
|
|
|
|
|
|
|
=item B I, [I...] |
948
|
|
|
|
|
|
|
|
949
|
|
|
|
|
|
|
Run the I hook, passing the Is to each hook member via @_. |
950
|
|
|
|
|
|
|
|
951
|
|
|
|
|
|
|
=cut |
952
|
|
|
|
|
|
|
|
953
|
|
|
|
|
|
|
sub run_hook { |
954
|
0
|
0
|
|
0
|
1
|
|
unless (@_ >= 1) { |
955
|
0
|
|
|
|
|
|
arg_count_error undef, '1 or more', @_; |
956
|
0
|
|
|
|
|
|
return; |
957
|
|
|
|
|
|
|
} |
958
|
0
|
|
|
|
|
|
my ($hook, @arg) = @_; |
959
|
|
|
|
|
|
|
|
960
|
0
|
0
|
|
|
|
|
if (!exists $Hook{$hook}) { |
961
|
0
|
|
|
|
|
|
tell_error "run_hook: Invalid hook `$hook'"; |
962
|
0
|
|
|
|
|
|
return; |
963
|
|
|
|
|
|
|
} |
964
|
0
|
|
|
|
|
|
for my $code (@{ $Hook{$hook} }) { |
|
0
|
|
|
|
|
|
|
965
|
0
|
|
|
|
|
|
eval_verbose "$hook hook", $code, @arg; |
966
|
|
|
|
|
|
|
} |
967
|
|
|
|
|
|
|
} |
968
|
|
|
|
|
|
|
|
969
|
|
|
|
|
|
|
=back |
970
|
|
|
|
|
|
|
|
971
|
|
|
|
|
|
|
=cut |
972
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
974
|
|
|
|
|
|
|
|
975
|
1
|
|
|
1
|
|
36
|
BEGIN { $^W = $Old_w } |
976
|
|
|
|
|
|
|
|
977
|
|
|
|
|
|
|
1; |
978
|
|
|
|
|
|
|
|
979
|
|
|
|
|
|
|
=head1 AVAILABILITY |
980
|
|
|
|
|
|
|
|
981
|
|
|
|
|
|
|
Check CPAN or http://www.argon.org/~roderick/ for the latest version. |
982
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
=head1 AUTHOR |
984
|
|
|
|
|
|
|
|
985
|
|
|
|
|
|
|
Roderick Schertler > |
986
|
|
|
|
|
|
|
|
987
|
|
|
|
|
|
|
=head1 SEE ALSO |
988
|
|
|
|
|
|
|
|
989
|
|
|
|
|
|
|
sirc(1), perl(1), Sirc::Chantrack(3pm). |
990
|
|
|
|
|
|
|
|
991
|
|
|
|
|
|
|
=cut |