line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package App::Pocosi; |
2
|
|
|
|
|
|
|
BEGIN { |
3
|
1
|
|
|
1
|
|
1029
|
$App::Pocosi::AUTHORITY = 'cpan:HINRIK'; |
4
|
|
|
|
|
|
|
} |
5
|
|
|
|
|
|
|
BEGIN { |
6
|
1
|
|
|
1
|
|
13
|
$App::Pocosi::VERSION = '0.03'; |
7
|
|
|
|
|
|
|
} |
8
|
|
|
|
|
|
|
|
9
|
1
|
|
|
1
|
|
5
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
25
|
|
10
|
1
|
|
|
1
|
|
5
|
use warnings FATAL => 'all'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
68
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
# we want instant child process reaping |
13
|
4
|
|
|
4
|
1
|
124620
|
sub POE::Kernel::USE_SIGCHLD () { return 1 } |
14
|
|
|
|
|
|
|
|
15
|
1
|
|
|
1
|
|
5
|
use App::Pocosi::Status; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
24
|
|
16
|
1
|
|
|
1
|
|
869
|
use Class::Load qw(try_load_class); |
|
1
|
|
|
|
|
29187
|
|
|
1
|
|
|
|
|
55
|
|
17
|
1
|
|
|
1
|
|
7
|
use Fcntl qw(O_CREAT O_EXCL O_WRONLY); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
49
|
|
18
|
1
|
|
|
1
|
|
5
|
use File::Glob ':glob'; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
219
|
|
19
|
1
|
|
|
1
|
|
5
|
use File::Spec::Functions 'rel2abs'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
37
|
|
20
|
1
|
|
|
1
|
|
5
|
use IO::Handle; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
37
|
|
21
|
1
|
|
|
1
|
|
5
|
use IRC::Utils qw(decode_irc); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
31
|
|
22
|
1
|
|
|
1
|
|
953
|
use Net::Netmask; |
|
1
|
|
|
|
|
5465
|
|
|
1
|
|
|
|
|
87
|
|
23
|
1
|
|
|
1
|
|
760
|
use POE; |
|
1
|
|
|
|
|
32709
|
|
|
1
|
|
|
|
|
7
|
|
24
|
1
|
|
|
1
|
|
8392
|
use POSIX 'strftime'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
10
|
|
25
|
1
|
|
|
1
|
|
64
|
use Scalar::Util 'looks_like_number'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
4365
|
|
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
sub new { |
28
|
0
|
|
|
0
|
0
|
|
my ($package, %args) = @_; |
29
|
0
|
|
|
|
|
|
return bless \%args, $package; |
30
|
|
|
|
|
|
|
} |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
sub run { |
33
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
# we print IRC output, which will be UTF-8 |
36
|
0
|
|
|
|
|
|
binmode $_, ':utf8' for (*STDOUT, *STDERR); |
37
|
|
|
|
|
|
|
|
38
|
0
|
0
|
|
|
|
|
if ($self->{list_plugins}) { |
39
|
0
|
|
|
|
|
|
require Module::Pluggable; |
40
|
0
|
|
|
|
|
|
Module::Pluggable->import( |
41
|
|
|
|
|
|
|
sub_name => '_available_plugins', |
42
|
|
|
|
|
|
|
search_path => 'POE::Component::Server::IRC::Plugin', |
43
|
|
|
|
|
|
|
); |
44
|
0
|
|
|
|
|
|
for my $plugin (sort $self->_available_plugins()) { |
45
|
0
|
|
|
|
|
|
$plugin =~ s/^POE::Component::Server::IRC::Plugin:://; |
46
|
0
|
|
|
|
|
|
print $plugin, "\n"; |
47
|
|
|
|
|
|
|
} |
48
|
0
|
|
|
|
|
|
return; |
49
|
|
|
|
|
|
|
} |
50
|
|
|
|
|
|
|
|
51
|
0
|
|
|
|
|
|
$self->_setup(); |
52
|
|
|
|
|
|
|
|
53
|
0
|
0
|
|
|
|
|
if ($self->{check_cfg}) { |
54
|
0
|
|
|
|
|
|
print "The configuration is valid and all modules could be compiled.\n"; |
55
|
0
|
|
|
|
|
|
return; |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
0
|
0
|
|
|
|
|
if ($self->{daemonize}) { |
59
|
0
|
|
|
|
|
|
require Proc::Daemon; |
60
|
0
|
|
|
|
|
|
eval { |
61
|
0
|
|
|
|
|
|
Proc::Daemon::Init->(); |
62
|
0
|
0
|
|
|
|
|
if (defined $self->{log_file}) { |
63
|
0
|
0
|
|
|
|
|
open STDOUT, '>>:encoding(utf8)', $self->{log_file} |
64
|
|
|
|
|
|
|
or die "Can't open $self->{log_file}: $!\n"; |
65
|
0
|
0
|
|
|
|
|
open STDERR, '>>&STDOUT' or die "Can't redirect STDERR: $!\n"; |
66
|
0
|
|
|
|
|
|
STDOUT->autoflush(1); |
67
|
|
|
|
|
|
|
} |
68
|
0
|
|
|
|
|
|
$poe_kernel->has_forked(); |
69
|
|
|
|
|
|
|
}; |
70
|
0
|
|
|
|
|
|
chomp $@; |
71
|
0
|
0
|
|
|
|
|
die "Can't daemonize: $@\n" if $@; |
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
|
74
|
0
|
0
|
|
|
|
|
if (defined $self->{pid_file}) { |
75
|
0
|
0
|
|
|
|
|
sysopen my $fh, $self->{pid_file}, O_CREAT|O_EXCL|O_WRONLY |
76
|
|
|
|
|
|
|
or die "Can't create pid file or it already exists. Pocosi already running?\n"; |
77
|
0
|
|
|
|
|
|
print $fh "$$\n"; |
78
|
0
|
|
|
|
|
|
close $fh; |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
POE::Session->create( |
82
|
0
|
|
|
|
|
|
object_states => [ |
83
|
|
|
|
|
|
|
$self => [qw( |
84
|
|
|
|
|
|
|
_start |
85
|
|
|
|
|
|
|
sig_die |
86
|
|
|
|
|
|
|
sig_int |
87
|
|
|
|
|
|
|
sig_term |
88
|
|
|
|
|
|
|
ircd_plugin_add |
89
|
|
|
|
|
|
|
ircd_plugin_del |
90
|
|
|
|
|
|
|
ircd_plugin_error |
91
|
|
|
|
|
|
|
ircd_plugin_status |
92
|
|
|
|
|
|
|
ircd_shutdown |
93
|
|
|
|
|
|
|
)], |
94
|
|
|
|
|
|
|
], |
95
|
|
|
|
|
|
|
); |
96
|
|
|
|
|
|
|
|
97
|
0
|
|
|
|
|
|
$poe_kernel->run(); |
98
|
0
|
0
|
|
|
|
|
unlink $self->{pid_file} if defined $self->{pid_file}; |
99
|
0
|
|
|
|
|
|
return; |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
sub _setup { |
103
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
104
|
|
|
|
|
|
|
|
105
|
0
|
0
|
|
|
|
|
if (defined $self->{cfg}{pid_file}) { |
106
|
0
|
|
|
|
|
|
$self->{pid_file} = rel2abs(bsd_glob(delete $self->{cfg}{pid_file})); |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
0
|
0
|
|
|
|
|
if (defined $self->{cfg}{log_file}) { |
110
|
0
|
|
|
|
|
|
my $log = rel2abs(bsd_glob(delete $self->{cfg}{log_file})); |
111
|
0
|
0
|
|
|
|
|
open my $fh, '>>', $log or die "Can't open $log: $!\n"; |
112
|
0
|
|
|
|
|
|
close $fh; |
113
|
0
|
|
|
|
|
|
$self->{log_file} = $log; |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
0
|
0
|
|
|
|
|
if (!$self->{no_color}) { |
117
|
0
|
|
|
|
|
|
require Term::ANSIColor; |
118
|
0
|
|
|
|
|
|
Term::ANSIColor->import(); |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
|
121
|
0
|
0
|
|
|
|
|
if (defined $self->{cfg}{lib}) { |
122
|
0
|
0
|
0
|
|
|
|
if (ref $self->{cfg}{lib} eq 'ARRAY' && @{ $self->{cfg}{lib} }) { |
|
0
|
|
|
|
|
|
|
123
|
0
|
|
|
|
|
|
unshift @INC, map { rel2abs(bsd_glob($_)) } @{ delete $self->{cfg}{lib} }; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
else { |
126
|
0
|
|
|
|
|
|
unshift @INC, rel2abs(bsd_glob(delete $self->{cfg}{lib})); |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
|
130
|
0
|
|
|
|
|
|
$self->_load_classes(); |
131
|
0
|
|
|
|
|
|
return; |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
sub _load_classes { |
135
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
136
|
0
|
|
|
|
|
|
my $cfg = $self->{cfg}; |
137
|
|
|
|
|
|
|
|
138
|
0
|
0
|
|
|
|
|
for my $plug_spec (@{ $cfg->{plugins} || [] }) { |
|
0
|
|
|
|
|
|
|
139
|
0
|
|
|
|
|
|
$self->_load_plugin($plug_spec); |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
0
|
0
|
|
|
|
|
if (!defined $cfg->{config}) { |
143
|
0
|
|
|
|
|
|
die "No 'config' parameter found in config file\n"; |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
|
146
|
0
|
0
|
|
|
|
|
if (defined $cfg->{class}) { |
147
|
0
|
|
|
|
|
|
$cfg->{class} = _load_either_class( |
148
|
|
|
|
|
|
|
"POE::Component::Server::IRC::$cfg->{class}", |
149
|
|
|
|
|
|
|
$cfg->{class}, |
150
|
|
|
|
|
|
|
); |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
else { |
153
|
0
|
|
|
|
|
|
$cfg->{class} = 'POE::Component::Server::IRC'; |
154
|
0
|
|
|
|
|
|
my ($success, $error) = try_load_class($cfg->{class}); |
155
|
0
|
0
|
|
|
|
|
chomp $error if defined $error; |
156
|
0
|
0
|
|
|
|
|
die "Can't load class $cfg->{class}: $error\n" if !$success; |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
|
159
|
0
|
|
|
|
|
|
return; |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
# find out the canonical class name for the plugin and load it |
163
|
|
|
|
|
|
|
sub _load_plugin { |
164
|
0
|
|
|
0
|
|
|
my ($self, $plug_spec) = @_; |
165
|
|
|
|
|
|
|
|
166
|
0
|
0
|
|
|
|
|
return if defined $plug_spec->[2]; |
167
|
0
|
|
|
|
|
|
my ($class, $args) = @$plug_spec; |
168
|
0
|
0
|
|
|
|
|
$args = {} if !defined $args; |
169
|
|
|
|
|
|
|
|
170
|
0
|
|
|
|
|
|
my $canonclass = _load_either_class( |
171
|
|
|
|
|
|
|
"POE::Component::Server::IRC::Plugin::$class", |
172
|
|
|
|
|
|
|
$class, |
173
|
|
|
|
|
|
|
); |
174
|
|
|
|
|
|
|
|
175
|
0
|
|
|
|
|
|
$plug_spec->[1] = $args; |
176
|
0
|
|
|
|
|
|
$plug_spec->[2] = $canonclass; |
177
|
0
|
|
|
|
|
|
return; |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
# create plugins, spawn components, and connect to IRC |
181
|
|
|
|
|
|
|
sub _start { |
182
|
0
|
|
|
0
|
|
|
my ($kernel, $session, $self) = @_[KERNEL, SESSION, OBJECT]; |
183
|
|
|
|
|
|
|
|
184
|
0
|
|
|
|
|
|
$kernel->sig(DIE => 'sig_die'); |
185
|
0
|
|
|
|
|
|
$kernel->sig(INT => 'sig_int'); |
186
|
0
|
|
|
|
|
|
$kernel->sig(TERM => 'sig_term'); |
187
|
0
|
|
|
|
|
|
$self->_status('normal', "Started (pid $$)"); |
188
|
|
|
|
|
|
|
|
189
|
0
|
|
|
|
|
|
$self->_status('normal', "Constructing plugins"); |
190
|
0
|
|
|
|
|
|
my ($own_plugs, $plugins) = $self->_construct_plugins(); |
191
|
|
|
|
|
|
|
|
192
|
0
|
|
|
|
|
|
$self->_status('normal', "Spawning IRCd component ($self->{cfg}{class})"); |
193
|
0
|
|
|
|
|
|
my $ircd = $self->_spawn_ircd(); |
194
|
|
|
|
|
|
|
|
195
|
0
|
|
|
|
|
|
$self->_status('normal', 'Registering plugins'); |
196
|
0
|
|
|
|
|
|
$self->_register_plugins($ircd, $session->ID(), [@$own_plugs, @$plugins]); |
197
|
|
|
|
|
|
|
|
198
|
0
|
|
|
|
|
|
$self->{own_plugins} = $own_plugs; |
199
|
0
|
|
|
|
|
|
$self->{ircd} = $ircd; |
200
|
|
|
|
|
|
|
|
201
|
0
|
|
|
|
|
|
$self->_add_auths(); |
202
|
0
|
|
|
|
|
|
$self->_add_operators(); |
203
|
0
|
|
|
|
|
|
$self->_add_denials(); |
204
|
0
|
|
|
|
|
|
$self->_add_exemptions(); |
205
|
0
|
|
|
|
|
|
$self->_add_peers(); |
206
|
0
|
|
|
|
|
|
$self->_add_listeners(); |
207
|
|
|
|
|
|
|
|
208
|
0
|
|
|
|
|
|
return; |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
sub _construct_plugins { |
212
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
213
|
|
|
|
|
|
|
|
214
|
0
|
|
|
|
|
|
my $plug_specs = $self->{cfg}{plugins}; |
215
|
0
|
|
|
|
|
|
my @plugins; |
216
|
0
|
|
|
|
|
|
for my $plug_spec (@$plug_specs) { |
217
|
0
|
|
|
|
|
|
my ($class, $args, $canonclass) = @$plug_spec; |
218
|
0
|
|
|
|
|
|
my $obj = $canonclass->new(%$args); |
219
|
0
|
|
|
|
|
|
my $isa = eval { $obj->isa($canonclass) }; |
|
0
|
|
|
|
|
|
|
220
|
0
|
0
|
|
|
|
|
die "isa() test failed for plugin of class $canonclass\n" if !$isa; |
221
|
0
|
|
|
|
|
|
push @plugins, [$class, $obj]; |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
|
224
|
0
|
|
|
|
|
|
my @own_plugs = ( |
225
|
|
|
|
|
|
|
[ |
226
|
|
|
|
|
|
|
'PocosiStatus', |
227
|
|
|
|
|
|
|
App::Pocosi::Status->new( |
228
|
|
|
|
|
|
|
Pocosi => $self, |
229
|
|
|
|
|
|
|
Trace => $self->{trace}, |
230
|
|
|
|
|
|
|
Verbose => $self->{verbose}, |
231
|
|
|
|
|
|
|
), |
232
|
|
|
|
|
|
|
], |
233
|
|
|
|
|
|
|
); |
234
|
|
|
|
|
|
|
|
235
|
0
|
0
|
|
|
|
|
if ($self->{interactive}) { |
236
|
0
|
|
|
|
|
|
require App::Pocosi::ReadLine; |
237
|
0
|
|
|
|
|
|
push @own_plugs, [ |
238
|
|
|
|
|
|
|
'PocosiReadLine', |
239
|
|
|
|
|
|
|
App::Pocosi::ReadLine->new( |
240
|
|
|
|
|
|
|
Pocosi => $self, |
241
|
|
|
|
|
|
|
), |
242
|
|
|
|
|
|
|
]; |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
|
245
|
0
|
|
|
|
|
|
return \@own_plugs, \@plugins; |
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
sub _spawn_ircd { |
249
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
250
|
|
|
|
|
|
|
|
251
|
0
|
|
|
|
|
|
my $class = $self->{cfg}{class}; |
252
|
0
|
0
|
|
|
|
|
my $ircd = $class->spawn( |
|
|
0
|
|
|
|
|
|
253
|
|
|
|
|
|
|
plugin_debug => 1, |
254
|
|
|
|
|
|
|
config => $self->{cfg}{config}, |
255
|
|
|
|
|
|
|
($self->{cfg}{flood} ? (antiflood => 0) : ()), |
256
|
|
|
|
|
|
|
(defined $self->{cfg}{auth} ? (auth => $self->{cfg}{auth}) : ()), |
257
|
|
|
|
|
|
|
); |
258
|
0
|
|
|
|
|
|
my $isa = eval { $ircd->isa($class) }; |
|
0
|
|
|
|
|
|
|
259
|
0
|
0
|
|
|
|
|
die "isa() test failed for component of class $class\n" if !$isa; |
260
|
|
|
|
|
|
|
|
261
|
0
|
|
|
|
|
|
return $ircd; |
262
|
|
|
|
|
|
|
} |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
sub _load_either_class { |
265
|
0
|
|
|
0
|
|
|
my ($primary, $secondary) = @_; |
266
|
|
|
|
|
|
|
|
267
|
0
|
|
|
|
|
|
my ($success, $error, $errors); |
268
|
0
|
|
|
|
|
|
($success, $error) = try_load_class($primary); |
269
|
0
|
0
|
|
|
|
|
return $primary if $success; |
270
|
|
|
|
|
|
|
|
271
|
0
|
|
|
|
|
|
$errors .= $error; |
272
|
0
|
|
|
|
|
|
($success, $error) = try_load_class($secondary); |
273
|
0
|
0
|
|
|
|
|
return $secondary if $success; |
274
|
|
|
|
|
|
|
|
275
|
0
|
0
|
|
|
|
|
chomp $error if defined $error; |
276
|
0
|
|
|
|
|
|
$errors .= $error; |
277
|
0
|
|
|
|
|
|
die "Failed to load class $primary or $secondary: $errors\n"; |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
sub _register_plugins { |
281
|
0
|
|
|
0
|
|
|
my ($self, $ircd, $session_id, $plugins) = @_; |
282
|
|
|
|
|
|
|
|
283
|
0
|
|
|
|
|
|
for my $plugin (@$plugins) { |
284
|
0
|
|
|
|
|
|
my ($name, $object) = @$plugin; |
285
|
0
|
|
|
|
|
|
$ircd->plugin_add("${name}_$session_id", $object); |
286
|
|
|
|
|
|
|
} |
287
|
|
|
|
|
|
|
|
288
|
0
|
|
|
|
|
|
return; |
289
|
|
|
|
|
|
|
} |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
sub _add_denials { |
292
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
293
|
0
|
|
|
|
|
|
my $ircd = $self->{ircd}; |
294
|
0
|
|
|
|
|
|
my $denials = $self->{cfg}{denials}; |
295
|
0
|
0
|
|
|
|
|
return if !defined $denials; |
296
|
|
|
|
|
|
|
|
297
|
0
|
|
|
|
|
|
for my $denial (@$denials) { |
298
|
0
|
|
|
|
|
|
my ($mask, $reason) = @$denial; |
299
|
0
|
|
|
|
|
|
my $netmask = Net::Netmask->new2($mask); |
300
|
0
|
0
|
|
|
|
|
if (!defined $netmask) { |
301
|
0
|
|
|
|
|
|
die "Invalid denial: $mask\n"; |
302
|
|
|
|
|
|
|
} |
303
|
0
|
|
|
|
|
|
$ircd->add_denial($netmask, $reason); |
304
|
|
|
|
|
|
|
} |
305
|
0
|
|
|
|
|
|
return; |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
sub _add_exemptions { |
309
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
310
|
0
|
|
|
|
|
|
my $ircd = $self->{ircd}; |
311
|
0
|
|
|
|
|
|
my $exemptions = $self->{cfg}{exemptions}; |
312
|
0
|
0
|
|
|
|
|
return if !defined $exemptions; |
313
|
|
|
|
|
|
|
|
314
|
0
|
|
|
|
|
|
for my $mask (@$exemptions) { |
315
|
0
|
|
|
|
|
|
my $netmask = Net::Netmask->new2($mask); |
316
|
0
|
0
|
|
|
|
|
if (!defined $netmask) { |
317
|
0
|
|
|
|
|
|
die "Invalid exemption: $mask\n"; |
318
|
|
|
|
|
|
|
} |
319
|
0
|
|
|
|
|
|
$ircd->add_exemption($netmask); |
320
|
|
|
|
|
|
|
} |
321
|
0
|
|
|
|
|
|
return; |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
sub _add_operators { |
325
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
326
|
0
|
|
|
|
|
|
my $ircd = $self->{ircd}; |
327
|
0
|
|
|
|
|
|
my $opers = $self->{cfg}{operators}; |
328
|
0
|
0
|
|
|
|
|
return if !defined $opers; |
329
|
|
|
|
|
|
|
|
330
|
0
|
|
|
|
|
|
for my $oper (@$opers) { |
331
|
0
|
0
|
|
|
|
|
die "No username supplier for operator\n" if !defined $oper->{username}; |
332
|
0
|
0
|
|
|
|
|
if (ref $oper->{ipmask} eq 'ARRAY') { |
333
|
0
|
|
|
|
|
|
my @netmasks; |
334
|
0
|
|
|
|
|
|
for my $mask (@{ $oper->{ipmask} }) { |
|
0
|
|
|
|
|
|
|
335
|
0
|
|
|
|
|
|
my $netmask = Net::Netmask->new2($mask); |
336
|
0
|
0
|
|
|
|
|
if (!defined $netmask) { |
337
|
0
|
|
|
|
|
|
die "Invalid netmask for oper $oper->{username}: $mask\n"; |
338
|
|
|
|
|
|
|
} |
339
|
0
|
|
|
|
|
|
push @netmasks, $netmask; |
340
|
|
|
|
|
|
|
} |
341
|
0
|
|
|
|
|
|
$oper->{ipmask} = \@netmasks; |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
|
344
|
0
|
|
|
|
|
|
$ircd->add_operator(%$oper); |
345
|
|
|
|
|
|
|
} |
346
|
0
|
|
|
|
|
|
return; |
347
|
|
|
|
|
|
|
} |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
sub _add_peers { |
350
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
351
|
0
|
|
|
|
|
|
my $ircd = $self->{ircd}; |
352
|
0
|
|
|
|
|
|
my $peers = $self->{cfg}{peers}; |
353
|
0
|
0
|
|
|
|
|
return if !defined $peers; |
354
|
0
|
|
|
|
|
|
$ircd->add_peer(%$_) for @$peers; |
355
|
0
|
|
|
|
|
|
return; |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
sub _add_auths { |
359
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
360
|
0
|
|
|
|
|
|
my $ircd = $self->{ircd}; |
361
|
0
|
|
|
|
|
|
my $auths = $self->{cfg}{auths}; |
362
|
0
|
0
|
|
|
|
|
return if !defined $auths; |
363
|
0
|
|
|
|
|
|
$ircd->add_auth(%$_) for @$auths; |
364
|
0
|
|
|
|
|
|
return; |
365
|
|
|
|
|
|
|
} |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
sub _add_listeners { |
368
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
369
|
0
|
|
|
|
|
|
my $ircd = $self->{ircd}; |
370
|
0
|
|
|
|
|
|
my $listeners = $self->{cfg}{listeners}; |
371
|
0
|
0
|
|
|
|
|
return if !defined $listeners; |
372
|
0
|
|
|
|
|
|
$ircd->yield('add_listener', %$_) for @$listeners; |
373
|
0
|
|
|
|
|
|
return; |
374
|
|
|
|
|
|
|
} |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
sub _dump { |
377
|
0
|
|
|
0
|
|
|
my ($arg) = @_; |
378
|
|
|
|
|
|
|
|
379
|
0
|
0
|
|
|
|
|
if (ref $arg eq 'ARRAY') { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
380
|
0
|
|
|
|
|
|
my @elems; |
381
|
0
|
|
|
|
|
|
for my $elem (@$arg) { |
382
|
0
|
|
|
|
|
|
push @elems, _dump($elem); |
383
|
|
|
|
|
|
|
} |
384
|
0
|
|
|
|
|
|
return '['. join(', ', @elems) .']'; |
385
|
|
|
|
|
|
|
} |
386
|
|
|
|
|
|
|
elsif (ref $arg eq 'HASH') { |
387
|
0
|
|
|
|
|
|
my @pairs; |
388
|
0
|
|
|
|
|
|
for my $key (keys %$arg) { |
389
|
0
|
|
|
|
|
|
push @pairs, [$key, _dump($arg->{$key})]; |
390
|
|
|
|
|
|
|
} |
391
|
0
|
|
|
|
|
|
return '{'. join(', ', map { "$_->[0] => $_->[1]" } @pairs) .'}'; |
|
0
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
} |
393
|
|
|
|
|
|
|
elsif (ref $arg) { |
394
|
0
|
|
|
|
|
|
require overload; |
395
|
0
|
|
|
|
|
|
return overload::StrVal($arg); |
396
|
|
|
|
|
|
|
} |
397
|
|
|
|
|
|
|
elsif (defined $arg) { |
398
|
0
|
0
|
|
|
|
|
return $arg if looks_like_number($arg); |
399
|
0
|
|
|
|
|
|
return "'".decode_irc($arg)."'"; |
400
|
|
|
|
|
|
|
} |
401
|
|
|
|
|
|
|
else { |
402
|
0
|
|
|
|
|
|
return 'undef'; |
403
|
|
|
|
|
|
|
} |
404
|
|
|
|
|
|
|
} |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
sub _event_debug { |
407
|
0
|
|
|
0
|
|
|
my ($self, $args, $event) = @_; |
408
|
|
|
|
|
|
|
|
409
|
0
|
0
|
|
|
|
|
if (!defined $event) { |
410
|
0
|
|
|
|
|
|
$event = (caller(1))[3]; |
411
|
0
|
|
|
|
|
|
$event =~ s/.*:://; |
412
|
|
|
|
|
|
|
} |
413
|
|
|
|
|
|
|
|
414
|
0
|
|
|
|
|
|
my @output; |
415
|
0
|
|
|
|
|
|
for my $i (0..$#{ $args }) { |
|
0
|
|
|
|
|
|
|
416
|
0
|
|
|
|
|
|
push @output, "ARG$i: " . _dump($args->[$i]); |
417
|
|
|
|
|
|
|
} |
418
|
0
|
|
|
|
|
|
$self->_status('debug', "$event: ".join(', ', @output)); |
419
|
0
|
|
|
|
|
|
return; |
420
|
|
|
|
|
|
|
} |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
# we handle plugin status messages here because the status plugin won't |
423
|
|
|
|
|
|
|
# see these for previously added plugins or plugin_del for itself, etc |
424
|
|
|
|
|
|
|
sub ircd_plugin_add { |
425
|
0
|
|
|
0
|
0
|
|
my ($self, $alias) = @_[OBJECT, ARG0]; |
426
|
0
|
0
|
|
|
|
|
$self->_event_debug([@_[ARG0..$#_]], 'IRCD_plugin_add') if $self->{trace}; |
427
|
0
|
|
|
|
|
|
$self->_status('normal', "Added plugin $alias"); |
428
|
0
|
|
|
|
|
|
return; |
429
|
|
|
|
|
|
|
} |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
sub ircd_plugin_del { |
432
|
0
|
|
|
0
|
0
|
|
my ($self, $alias) = @_[OBJECT, ARG0]; |
433
|
0
|
0
|
|
|
|
|
$self->_event_debug([@_[ARG0..$#_]], 'IRCD_plugin_del') if $self->{trace}; |
434
|
0
|
|
|
|
|
|
$self->_status('normal', "Deleted plugin $alias"); |
435
|
0
|
|
|
|
|
|
return; |
436
|
|
|
|
|
|
|
} |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
sub ircd_plugin_error { |
439
|
0
|
|
|
0
|
0
|
|
my ($self, $error) = @_[OBJECT, ARG0]; |
440
|
0
|
0
|
|
|
|
|
$self->_event_debug([@_[ARG0..$#_]], 'IRCD_plugin_error') if $self->{trace}; |
441
|
0
|
|
|
|
|
|
$self->_status('error', $error); |
442
|
0
|
|
|
|
|
|
return; |
443
|
|
|
|
|
|
|
} |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
sub ircd_plugin_status { |
446
|
0
|
|
|
0
|
0
|
|
my ($self, $plugin, $type, $status) = @_[OBJECT, ARG0..ARG2]; |
447
|
0
|
|
|
|
|
|
my $ircd = $_[SENDER]->get_heap(); |
448
|
0
|
|
|
|
|
|
my $plugins = $ircd->plugin_list(); |
449
|
0
|
|
|
|
|
|
my %plug2alias = map { $plugins->{$_} => $_ } keys %$plugins; |
|
0
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
|
451
|
0
|
0
|
|
|
|
|
if (ref $plugin ne 'App::Pocosi::Status') { |
452
|
0
|
|
|
|
|
|
$status = "[$plug2alias{$plugin}] $status"; |
453
|
|
|
|
|
|
|
} |
454
|
0
|
|
|
|
|
|
$self->_status($type, $status); |
455
|
0
|
|
|
|
|
|
return; |
456
|
|
|
|
|
|
|
} |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
sub ircd_shutdown { |
459
|
0
|
|
|
0
|
0
|
|
my ($self) = $_[OBJECT]; |
460
|
0
|
0
|
|
|
|
|
$self->_event_debug([@_[ARG0..$#_]], 'IRCD_shutdown') if $self->{trace}; |
461
|
0
|
|
|
|
|
|
$self->_status('normal', 'IRCd component shut down'); |
462
|
0
|
|
|
|
|
|
return; |
463
|
|
|
|
|
|
|
} |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
sub verbose { |
466
|
0
|
|
|
0
|
0
|
|
my ($self, $value) = @_; |
467
|
0
|
0
|
|
|
|
|
if (defined $value) { |
468
|
0
|
|
|
|
|
|
$self->{verbose} = $value; |
469
|
0
|
|
|
|
|
|
for my $plugin (@{ $self->{own_plugins} }) { |
|
0
|
|
|
|
|
|
|
470
|
0
|
0
|
|
|
|
|
$plugin->[1]->verbose($value) if $plugin->[1]->can('verbose'); |
471
|
|
|
|
|
|
|
} |
472
|
|
|
|
|
|
|
} |
473
|
0
|
|
|
|
|
|
return $self->{verbose}; |
474
|
|
|
|
|
|
|
} |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
sub trace { |
477
|
0
|
|
|
0
|
0
|
|
my ($self, $value) = @_; |
478
|
0
|
0
|
|
|
|
|
if (defined $value) { |
479
|
0
|
|
|
|
|
|
$self->{trace} = $value; |
480
|
0
|
|
|
|
|
|
for my $plugin (@{ $self->{own_plugins} }) { |
|
0
|
|
|
|
|
|
|
481
|
0
|
0
|
|
|
|
|
$plugin->[1]->trace($value) if $plugin->[1]->can('trace'); |
482
|
|
|
|
|
|
|
} |
483
|
|
|
|
|
|
|
} |
484
|
0
|
|
|
|
|
|
return $self->{trace}; |
485
|
|
|
|
|
|
|
} |
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
sub _status { |
488
|
0
|
|
|
0
|
|
|
my ($self, $type, $message) = @_; |
489
|
|
|
|
|
|
|
|
490
|
0
|
|
|
|
|
|
my $stamp = strftime('%Y-%m-%d %H:%M:%S', localtime); |
491
|
0
|
0
|
0
|
|
|
|
if (defined $type && $type eq 'error') { |
492
|
0
|
|
|
|
|
|
$message = "!!! $message"; |
493
|
|
|
|
|
|
|
} |
494
|
|
|
|
|
|
|
|
495
|
0
|
|
|
|
|
|
my $log_line = "$stamp $message"; |
496
|
0
|
|
|
|
|
|
my $term_line = $log_line; |
497
|
|
|
|
|
|
|
|
498
|
0
|
0
|
|
|
|
|
if (!$self->{no_color}) { |
499
|
0
|
0
|
0
|
|
|
|
if (defined $type && $type eq 'error') { |
|
|
0
|
0
|
|
|
|
|
500
|
0
|
|
|
|
|
|
$term_line = colored($term_line, 'red'); |
501
|
|
|
|
|
|
|
} |
502
|
|
|
|
|
|
|
elsif (defined $type && $type eq 'debug') { |
503
|
0
|
|
|
|
|
|
$term_line = colored($term_line, 'yellow'); |
504
|
|
|
|
|
|
|
} |
505
|
|
|
|
|
|
|
else { |
506
|
0
|
|
|
|
|
|
$term_line = colored($term_line, 'green'); |
507
|
|
|
|
|
|
|
} |
508
|
|
|
|
|
|
|
} |
509
|
|
|
|
|
|
|
|
510
|
0
|
0
|
|
|
|
|
print $term_line, "\n" if !$self->{daemonize}; |
511
|
0
|
0
|
|
|
|
|
if (defined $self->{log_file}) { |
512
|
0
|
0
|
|
|
|
|
if (open my $fh, '>>:encoding(utf8)', $self->{log_file}) { |
|
|
0
|
|
|
|
|
|
513
|
0
|
|
|
|
|
|
$fh->autoflush(1); |
514
|
0
|
|
|
|
|
|
print $fh $log_line, "\n"; |
515
|
0
|
|
|
|
|
|
close $fh; |
516
|
|
|
|
|
|
|
} |
517
|
|
|
|
|
|
|
elsif (!$self->{daemonize}) { |
518
|
0
|
|
|
|
|
|
warn "Can't open $self->{log_file}: $!\n"; |
519
|
|
|
|
|
|
|
} |
520
|
|
|
|
|
|
|
} |
521
|
0
|
|
|
|
|
|
return; |
522
|
|
|
|
|
|
|
} |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
sub sig_die { |
525
|
0
|
|
|
0
|
0
|
|
my ($kernel, $self, $ex) = @_[KERNEL, OBJECT, ARG1]; |
526
|
0
|
|
|
|
|
|
$kernel->sig_handled(); |
527
|
|
|
|
|
|
|
|
528
|
0
|
|
|
|
|
|
chomp $ex->{error_str}; |
529
|
0
|
|
|
|
|
|
my $error = "Event $ex->{event} in session ".$ex->{dest_session}->ID |
530
|
|
|
|
|
|
|
." raised exception:\n $ex->{error_str}"; |
531
|
|
|
|
|
|
|
|
532
|
0
|
|
|
|
|
|
$self->_status('error', $error); |
533
|
0
|
0
|
|
|
|
|
$self->shutdown('Exiting due to an exception') if !$self->{shutdown}; |
534
|
0
|
|
|
|
|
|
return; |
535
|
|
|
|
|
|
|
} |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
sub sig_int { |
538
|
0
|
|
|
0
|
0
|
|
my ($kernel, $self) = @_[KERNEL, OBJECT]; |
539
|
0
|
0
|
|
|
|
|
$self->shutdown('Exiting due to SIGINT') if !$self->{shutdown}; |
540
|
0
|
|
|
|
|
|
$kernel->sig_handled(); |
541
|
0
|
|
|
|
|
|
return; |
542
|
|
|
|
|
|
|
} |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
sub sig_term { |
545
|
0
|
|
|
0
|
0
|
|
my ($kernel, $self) = @_[KERNEL, OBJECT]; |
546
|
0
|
0
|
|
|
|
|
$self->shutdown('Exiting due to SIGTERM') if !$self->{shutdown}; |
547
|
0
|
|
|
|
|
|
$kernel->sig_handled(); |
548
|
0
|
|
|
|
|
|
return; |
549
|
|
|
|
|
|
|
} |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
sub shutdown { |
552
|
0
|
|
|
0
|
0
|
|
my ($self, $reason) = @_; |
553
|
0
|
0
|
|
|
|
|
return if $self->{shutdown}; |
554
|
0
|
|
|
|
|
|
$self->_status('normal', $reason); |
555
|
0
|
0
|
|
|
|
|
$self->{ircd}->shutdown() if $self->{ircd}; |
556
|
0
|
|
|
|
|
|
$self->{shutdown} = 1; |
557
|
0
|
|
|
|
|
|
return; |
558
|
|
|
|
|
|
|
} |
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
1; |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
=encoding utf8 |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
=head1 NAME |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
App::Pocosi - A command line tool for launching a POE::Component::Server::IRC instance |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
=head1 DESCRIPTION |
569
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
This distribution provides a generic way to launch a |
571
|
|
|
|
|
|
|
L instance. |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
=over 4 |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
=item * Prints useful status information (to your terminal and/or a log file) |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
=item * Will daemonize if you so wish |
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
=item * Supports a configuration file |
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
=item * Offers a user friendly way to pass arguments to POE::Component::Server::IRC |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
=item * Has an interactive mode where you can issue issue commands and |
584
|
|
|
|
|
|
|
call methods on the IRCd component. |
585
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
=back |
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
=head1 CONFIGURATION |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
class: POE::Component::Server::IRC |
591
|
|
|
|
|
|
|
log_file: /my/log.file |
592
|
|
|
|
|
|
|
pid_file: /my/pid.file |
593
|
|
|
|
|
|
|
lib: /my/modules |
594
|
|
|
|
|
|
|
flood: false |
595
|
|
|
|
|
|
|
auth: true |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
config: |
598
|
|
|
|
|
|
|
servername: myserver.com |
599
|
|
|
|
|
|
|
motd: |
600
|
|
|
|
|
|
|
- "Welcome to this great server" |
601
|
|
|
|
|
|
|
- "" |
602
|
|
|
|
|
|
|
- "Enjoy your stay" |
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
plugins: |
605
|
|
|
|
|
|
|
- [OperServ] |
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
listeners: |
608
|
|
|
|
|
|
|
- bindaddr: "127.0.0.1" |
609
|
|
|
|
|
|
|
port: 10023 |
610
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
denials: |
612
|
|
|
|
|
|
|
- ["12.34.56.0/24", "I don't like this IP block"] |
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
exemptions: |
615
|
|
|
|
|
|
|
- "12.34.56.78" |
616
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
operators: |
618
|
|
|
|
|
|
|
- username: jack |
619
|
|
|
|
|
|
|
password: foo |
620
|
|
|
|
|
|
|
ipmask: ["127.0.0.1", "1.2.3.4", "192.168.1.0/24"] |
621
|
|
|
|
|
|
|
- username: locke |
622
|
|
|
|
|
|
|
password: bar |
623
|
|
|
|
|
|
|
ipmask: "10.0.0.*" |
624
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
auths: |
626
|
|
|
|
|
|
|
- mask: "*@example.com" |
627
|
|
|
|
|
|
|
password: hlagh |
628
|
|
|
|
|
|
|
spoof: jacob |
629
|
|
|
|
|
|
|
no_tilde: true |
630
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
peers: |
632
|
|
|
|
|
|
|
- name: otherserver.com |
633
|
|
|
|
|
|
|
rpass: hlaghpass |
634
|
|
|
|
|
|
|
pass: hlaghpass |
635
|
|
|
|
|
|
|
type: r |
636
|
|
|
|
|
|
|
raddress: "127.0.0.1" |
637
|
|
|
|
|
|
|
rport: 12345 |
638
|
|
|
|
|
|
|
auto: true |
639
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
The configuration file is in L or L format. It consists |
641
|
|
|
|
|
|
|
of a hash containing the options described in the above code example. Only |
642
|
|
|
|
|
|
|
C is required. |
643
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
=head2 C |
645
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
Either the name of a directory containing Perl modules (e.g. plugins), or an |
647
|
|
|
|
|
|
|
array of such names. Kind of like Perl's I<-I>. |
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
=head2 C |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
Path to a pid file, as used by most daemons. If is specified, App::Pocosi |
652
|
|
|
|
|
|
|
will refuse to run if the file already exists. |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
=head2 C |
655
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
Path to a log file to which status messages will be written. |
657
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
=head2 C |
659
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
The IRC server component class. Defaults to |
661
|
|
|
|
|
|
|
L. |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
=head2 C |
664
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
This is a hash of various configuration variables for the IRCd. See |
666
|
|
|
|
|
|
|
PoCo-Server-IRC's L|POE::Component::Server::IRC/configure> |
667
|
|
|
|
|
|
|
for a list of parameters. |
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
=head2 C |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
An array of arrays containing a short plugin class name (e.g. 'OperServ') |
672
|
|
|
|
|
|
|
and optionally a hash of arguments to that plugin. When figuring out the |
673
|
|
|
|
|
|
|
correct package name, App::Pocosi will first try to load |
674
|
|
|
|
|
|
|
POE::Component::Server::IRC::Plugin::I before trying to load |
675
|
|
|
|
|
|
|
I. |
676
|
|
|
|
|
|
|
|
677
|
|
|
|
|
|
|
=head2 C |
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
An array of hashes. The keys should be any of the options listed in the docs |
680
|
|
|
|
|
|
|
for PoCo-Server-IRC-Backend's |
681
|
|
|
|
|
|
|
L|POE::Component::Server::IRC::Backend/add_listener> method. |
682
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
=head2 C |
684
|
|
|
|
|
|
|
|
685
|
|
|
|
|
|
|
An array of hashes. The keys are described in the docs for PoCo-Server-IRC's |
686
|
|
|
|
|
|
|
L|POE::Component::Server::IRC/add_auth> method. |
687
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
=head2 C |
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
An array of hashes. The keys are described in the docs for PoCo-Server-IRC's |
691
|
|
|
|
|
|
|
L|POE::Component::Server::IRC/add_operator> method. You |
692
|
|
|
|
|
|
|
you can supply an array of netmasks (the kind accepted by |
693
|
|
|
|
|
|
|
L's constructor) for the B<'ipmask'> key. |
694
|
|
|
|
|
|
|
|
695
|
|
|
|
|
|
|
=head2 C |
696
|
|
|
|
|
|
|
|
697
|
|
|
|
|
|
|
An array of hashes. The keys should be any of the options listed in the docs |
698
|
|
|
|
|
|
|
for PoCo-Server-IRC's |
699
|
|
|
|
|
|
|
L|POE::Component::Server::IRC/add_listener> method. |
700
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
=head2 C |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
An array of arrays. The first element of the inner array should be a netmask |
704
|
|
|
|
|
|
|
accepted by L's constructor. The second |
705
|
|
|
|
|
|
|
(optional) element should be a reason for the denial. |
706
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
=head2 C |
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
An array of netmasks (the kind which L's |
710
|
|
|
|
|
|
|
constructor accepts). |
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
=head1 OUTPUT |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
Here is some example output from the program: |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
$ pocosi -f example/config.yml |
717
|
|
|
|
|
|
|
2011-05-22 15:30:02 Started (pid 13191) |
718
|
|
|
|
|
|
|
2011-05-22 15:30:02 Constructing plugins |
719
|
|
|
|
|
|
|
2011-05-22 15:30:02 Spawning IRCd component (POE::Component::Server::IRC) |
720
|
|
|
|
|
|
|
2011-05-22 15:30:02 Registering plugins |
721
|
|
|
|
|
|
|
2011-05-22 15:30:02 Added plugin PocosiStatus_1 |
722
|
|
|
|
|
|
|
2011-05-22 15:30:02 Added plugin OperServ_1 |
723
|
|
|
|
|
|
|
2011-05-22 15:30:02 Started listening on 127.0.0.1:10023 |
724
|
|
|
|
|
|
|
2011-05-22 15:30:02 Connected to peer otherserver.com on 127.0.0.1:12345 |
725
|
|
|
|
|
|
|
2011-05-22 15:30:02 Server otherserver.com (hops: 1) introduced to the network by myserver.com |
726
|
|
|
|
|
|
|
^C2011-05-22 15:30:18 Exiting due to SIGINT |
727
|
|
|
|
|
|
|
2011-05-22 15:30:18 Deleted plugin OperServ_1 |
728
|
|
|
|
|
|
|
2011-05-22 15:30:18 Deleted plugin PocosiStatus_1 |
729
|
|
|
|
|
|
|
2011-05-22 15:30:18 IRCd component shut down |
730
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
=head1 AUTHOR |
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
Hinrik Ern SigurEsson, hinrik.sig@gmail.com |
734
|
|
|
|
|
|
|
|
735
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT |
736
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
Copyright 2011 Hinrik Ern SigurEsson |
738
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
This program is free software, you can redistribute it and/or modify |
740
|
|
|
|
|
|
|
it under the same terms as Perl itself. |
741
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
=cut |