File Coverage

blib/lib/Net/Ewtoo/Bot.pm
Criterion Covered Total %
statement 12 114 10.5
branch 0 22 0.0
condition 0 8 0.0
subroutine 4 24 16.6
pod 0 18 0.0
total 16 186 8.6


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2             # $Id: Bot.pm,v 1.14 2002/04/27 19:25:32 jodrell Exp $
3             # Copyright (c) 2002 Gavin Brown. All rights reserved. This program is
4             # free software; you can redistribute it and/or modify it under the same
5             # terms as Perl itself.
6              
7 1     1   1994 use IO::Socket;
  1         28216  
  1         4  
8 1     1   496 use IO::Handle;
  1         3  
  1         38  
9 1     1   5 use strict;
  1         15  
  1         46  
10              
11             package Net::Ewtoo::Bot;
12 1     1   4 use vars qw($VERSION);
  1         2  
  1         1251  
13             $VERSION = '0.16';
14              
15             =pod
16              
17             =head1 NAME
18              
19             Net::Ewtoo::Bot - a Ewtoo-compatible talker robot client module
20              
21             =head1 SYNOPSIS
22              
23             use Net::Ewtoo::Bot;
24              
25             my $NAME = 'jodbot';
26              
27             my $bot = new Net::Ewtoo::Bot;
28              
29             $bot->add_trigger("(.+?) says '$NAME, (.+?)'", \&handle_say);
30             $bot->set_delay('range', 0, 5);
31              
32             $bot->login($host, $port, $user, $pass);
33             $bot->say("Hi! I'm the $NAME robot!");
34              
35             $bot->listen();
36              
37             $bot->logout();
38              
39             exit;
40              
41             sub handle_say {
42             my ($sayer, $said) = @_;
43             if ($said eq 'hello') {
44             $bot->say("Why hello $sayer!");
45             } elsif ($said eq 'please go away') {
46             $bot->say("OK, bye!");
47             $bot->logout();
48             }
49             return;
50             }
51              
52             =head1 DESCRIPTION
53              
54             Net::Ewtoo::Bot provides an object-oriented interface to Ewtoo (I) type talker systems. The module provides support for the most common Ewtoo talker commands, as well as input pattern matching and callback triggers and timers.
55              
56             =head1 INSTALLATION
57              
58             To install this package, just change to the directory which you created by untarring the package, and type the following:
59              
60             perl Makefile.PL
61             make test
62             make
63             make install
64              
65             This will copy Bot.pm to your perl library directory for use by all perl scripts. You probably must be root to do this, unless you have installed a personal copy of perl.
66              
67             =head1 METHODS
68              
69             $bot->login($host, $port, $user, $pass);
70              
71             This logs the bot into the $host:$port talker using $user and $pass. The bot will send extra carriage returns to bypass MOTDs and saved messages.
72              
73             Any defined login subroutines are executed at this point.
74              
75             $bot->logout($message);
76              
77             Sends the "QUIT" command (in capitals for compatability with MBA4), and closes the socket. Any defined logout subroutines are executed beforehand. If $message is defined, the bot calls the "mquit" command with $message as its argument.
78              
79             $bot->set_delay($type, $lower, $upper);
80              
81             This method sets the delay between between the calling of a method and its execution. This is useful for adding a realistic delay during communications with another user. $type can be either 'fixed', in which case the delay is always $lower (in seconds) and $upper is ignored, or 'range', in which case the delay will be a random number of seconds between $lower and $upper.
82              
83             $bot->add_trigger($pattern, $callback);
84              
85             This method adds a trigger used by the listen() method. When a line of input is received that matches $pattern, $callback is executed. The arguments to $callback are any captured substrings you define in your pattern, which is a regular perl regexp (without the trailing and leading slashes).
86              
87             $bot->delete_trigger($pattern);
88              
89             Removes the trigger associated with $pattern from the trigger list.
90              
91             $bot->def_login($callback);
92              
93             Specifies a subroutine with $callback that will be executed after the bot logs in.
94              
95             $bot->def_logout($callback);
96              
97             Specifies a subroutine with $callback that will be executed before the bot logs out.
98              
99             $bot->listen($verbose);
100              
101             listen() reads input from the talker and executes triggers as necessary. If $verbose is set to 1, then any input received is printed to STDOUT.
102              
103             $bot->break();
104              
105             $break() sets a flag that tells the listen() method to finish and return.
106              
107             $bot->say($str);
108              
109             A convenience function that makes the bot say $str.
110              
111             $bot->think($str);
112              
113             A convenience function that makes the bot think $str.
114              
115             $bot->shout($str);
116              
117             A convenience function that makes the bot shout $str.
118              
119             $bot->tell($user, $str);
120              
121             A convenience function that makes the bot tell $str to $user.
122              
123             $bot->command($cmd);
124              
125             Allows the calling of an arbitrary talker command.
126              
127             $bot->getline();
128              
129             Reads a single line of input from the talker.
130              
131             =head1 COPYRIGHT
132              
133             This module is (c) 2001,2002 Gavin Brown (I), with additional input and advice from Richard Lawrence (I).
134              
135             This module is licensed under the same terms as Perl itself.
136              
137             =head1 TO DO
138              
139             Implement a timing mechanism for scheduled stuff.
140              
141             =head1 SEE ALSO
142              
143             The Ewtoo website at I, and the PlayGround Plus website at I.
144              
145             =cut
146              
147             my $socket = new IO::Handle;
148             $socket->autoflush(1);
149              
150             sub new {
151 0     0 0   my $class = shift;
152 0           my $self = {};
153 0           bless($self, $class);
154 0           return $self;
155             }
156              
157             sub login {
158 0     0 0   my ($self, $host, $port, $user, $pass) = @_;
159 0 0 0       $socket = IO::Socket::INET->new( PeerAddr => $host,
160             PeerPort => $port,
161             Proto => 'tcp',
162             Timeout => 10 ) or warn("$host:$port: $@") and return undef;
163 0           print $socket "$user\n$pass\n\n";
164 0 0 0       if (defined($self->{_login_subs}) && scalar(@{$self->{_login_subs}}) > 0) {
  0            
165 0           foreach my $sub(@{$self->{_login_subs}}) {
  0            
166 0           &{$sub}();
  0            
167             }
168             }
169 0           return;
170             }
171              
172             sub logout {
173 0     0 0   my ($self, $message) = @_;
174 0 0 0       if (defined($self->{_logout_subs}) && scalar(@{$self->{_logout_subs}}) > 0) {
  0            
175 0           foreach my $sub(@{$self->{_logout_subs}}) {
  0            
176 0           &{$sub}();
  0            
177             }
178             }
179 0 0         if ($message ne '') {
180 0           print $socket "mquit $message\n";
181             } else {
182 0           print $socket "QUIT\n";
183             }
184 0           close($socket);
185 0           return;
186             }
187              
188             sub set_delay {
189 0     0 0   my ($self, $mode, $lower, $upper) = @_;
190 0 0         if ($mode =~ /^(fixed|range)$/i) {
191 0           $self->{_mode} = lc($mode);
192 0           $self->{_range} = [$lower, $upper];
193             } else {
194 0           die("Invalid delay mode");
195             }
196 0           return;
197             }
198              
199             sub add_trigger {
200 0     0 0   my ($self, $pattern, $sub) = @_;
201 0           $self->{_patterns}{$pattern} = $sub;
202 0           return;
203             }
204              
205             sub delete_trigger {
206 0     0 0   my ($self, $pattern) = @_;
207 0           delete $self->{_patterns}{$pattern};
208 0           return;
209             }
210              
211             ### these two methods are kept in but don't work - i haven't come up with a neat
212             ### way to add a timing system that doesn't interrupt the program's flow and
213             ### doesn't use threads.
214              
215             sub add_timer {
216 0     0 0   my ($self, $interval, $sub) = @_;
217 0           push(@{$self->{_timers}}, { interval => $interval, sub => $sub, init => time() });
  0            
218 0           return scalar(@{$self->{_timers}}) - 1;
  0            
219             }
220              
221             sub delete_timer {
222 0     0 0   my ($self, $timer_no) = @_;
223 0 0         if (${$self->{_timers}}[$timer_no]) {
  0            
224 0           undef ${$self->{_timers}}[$timer_no];
  0            
225             } else {
226 0           die("Invalid timer ID '$timer_no'");
227             }
228 0           return;
229             }
230              
231             sub def_login {
232 0     0 0   my ($self, $sub) = shift;
233 0           push(@{$self->{_login_subs}}, $sub);
  0            
234 0           return;
235             }
236              
237             sub def_logout {
238 0     0 0   my ($self, $sub) = shift;
239 0           push(@{$self->{_logout_subs}}, $sub);
  0            
240 0           return;
241             }
242              
243             sub listen {
244 0     0 0   my ($self, $print) = @_;
245 0           $self->{_listen} = 1;
246 0           while (<$socket>) {
247 0           $_ = $self->_clean_input($_);
248 0 0         print if ($print == 1);
249 0 0         return if $self->{_listen} != 1;
250 0           foreach my $pattern(sort keys %{$self->{_patterns}}) {
  0            
251 0 0         if (my @matches = (/$pattern/i)) {
252 0           &{$self->{_patterns}{$pattern}}(@matches);
  0            
253             }
254             }
255             }
256 0           return;
257             }
258              
259             sub break {
260 0     0 0   my $self = shift;
261 0           $self->{_listen} = 0;
262 0           return;
263             }
264              
265             sub say {
266 0     0 0   my ($self, $str) = @_;
267 0           $self->command("say $str");
268 0           return;
269             }
270              
271             sub think {
272 0     0 0   my ($self, $str) = @_;
273 0           $self->command("think $str");
274 0           return;
275             }
276              
277             sub shout {
278 0     0 0   my ($self, $str) = @_;
279 0           $self->command("shout $str");
280 0           return;
281             }
282              
283             sub tell {
284 0     0 0   my ($self, $target, $str) = @_;
285 0           $self->command("tell $target $str");
286 0           return;
287             }
288              
289             sub command {
290 0     0 0   my ($self, $str) = @_;
291 0           $self->_delay();
292 0           print $socket "$str\n";
293 0           return;
294             }
295              
296             sub getline {
297 0     0 0   my $self = shift;
298 0           return $self->_clean_input(<$socket>);
299             }
300              
301             sub _delay {
302 0     0     my $self = shift;
303 0 0         if ($self->{_mode} eq 'fixed') {
    0          
304 0           sleep(${$self->{_range}}[0]);
  0            
305             } elsif ($self->{_mode} eq 'range') {
306 0           sleep(${$self->{_range}}[0] + int(rand(${$self->{_range}}[1])));
  0            
  0            
307             }
308 0           return;
309             }
310              
311             # this kills any ANSI escape characters and colour codes in the supplied string:
312             sub _clean_input {
313 0     0     my ($self, $str) = @_;
314 0           $str =~ s/\[(.+?)m//ig;
315 0           return $str;
316             }
317              
318             1;