File Coverage

blib/lib/Net/AIM/TOC.pm
Criterion Covered Total %
statement 24 169 14.2
branch 0 24 0.0
condition 0 16 0.0
subroutine 8 29 27.5
pod 7 7 100.0
total 39 245 15.9


line stmt bran cond sub pod time code
1             package Net::AIM::TOC;
2              
3             $VERSION = '0.97';
4              
5 1     1   6368 use strict;
  1         2  
  1         34  
6              
7 1     1   505 use Net::AIM::TOC::Config;
  1         1  
  1         363  
8              
9             sub new {
10 0     0 1   my $class = shift;
11              
12 0           my $self = {
13             _conn => undef,
14             };
15 0           bless $self, $class;
16              
17 0           return( $self );
18             };
19              
20             sub connect {
21 0     0 1   my $self = shift;
22 0           my $args = shift;
23              
24 0           my $conn = Net::AIM::TOC::Connection->new( $args );
25              
26 0           $self->{_conn} = $conn;
27              
28 0           return( 1 );
29             };
30              
31             sub sign_on {
32 0     0 1   my $self = shift;
33 0           my $screenname = shift;
34 0           my $password = shift;
35              
36 0 0 0       if( !defined($screenname) || !defined($password) ) {
37 0           throw Net::AIM::TOC::Error( -text => 'Username/password not defined' );
38             };
39              
40 0           my $ret = $self->{_conn}->send_signon( $screenname, $password );
41              
42 0           return( $ret );
43             };
44              
45              
46             sub send_im_to_aol {
47 0     0 1   my $self = shift;
48 0           my $user = shift;
49 0           my $msg = shift;
50              
51 0           my $ret = $self->{_conn}->sendIMToAOL( $user, $msg );
52              
53 0           return( $ret );
54             };
55              
56              
57             sub send_to_aol {
58 0     0 1   my $self = shift;
59 0           my $msg = shift;
60              
61 0           my $ret = $self->{_conn}->sendToAOL( $msg );
62              
63 0           return( $ret );
64             };
65              
66              
67             sub recv_from_aol {
68 0     0 1   my $self = shift;
69              
70 0           my( $msgObj ) = $self->{_conn}->recvFromAOL;
71              
72 0           return( $msgObj );
73             };
74              
75              
76             sub disconnect {
77 0     0 1   my $self = shift;
78              
79 0           $self->{_conn}->disconnect;
80              
81 0           return( 1 );
82             };
83              
84              
85             =pod
86              
87             =head1 NAME
88              
89             Net::AIM::TOC - Perl implementation of the AIM TOC protocol
90            
91             =head1 DESCRIPTION
92              
93             The C module implements in AIM TOC protocol in such a way which make it simple for using when writing bots or AIM clients in Perl.
94              
95             All of the code regarding the connection is abstracted in order to simplify the AIM connection down to merely sending and receiving instant messages and toc commands.
96              
97             =head1 SYNOPSIS
98              
99             use Error qw( :try );
100             use Net::AIM::TOC;
101              
102             try {
103             my $aim = Net::AIM::TOC->new;
104             $aim->connect;
105             $aim->sign_on( $screenname, $password );
106              
107             my $msgObj = $aim->recv_from_aol;
108             print $msgObj->getMsg, "\n";
109             $aim->send_im_to_aol( $buddy, $msg );
110              
111             $aim->disconnect;
112             exit( 0 );
113              
114             }
115             catch Net::AIM::TOC::Error with {
116             my $err = shift;
117             print $err->stringify, "\n";
118              
119             };
120              
121              
122             =head1 CLASS INTERFACE
123              
124             =head2 CONSTRUCTORS
125              
126             A C object is created by calling the new constructor without arguments. A reference to the newly created object is returned, however, no connection to AIM has yet been made. One first is required to called C and C before attempting to send/receive instant messages.
127              
128             =over 4
129              
130             =item new ()
131              
132             Returns C object but does not create a connection or sign on to the AIM service.
133              
134             =back
135              
136             =head2 OBJECT METHODS
137              
138             =over 4
139              
140             =item connect ( ARGS )
141              
142             The connect method can be called without arguments to connect to the AIM service using the default AIM servers.
143              
144             Alternatively, a hash containing any of the following keys can be passed in to connect to another service using the TOC protocol:
145              
146             -tocServer
147             -tocPort
148             -authServer
149             -authPort
150              
151             =item sign_on ( ARGS )
152              
153             C is called to sign on to the AIM service. The arguments to be passed in are the screen name and password to be used to sign on to the service.
154              
155             =item send_im_to_aol ( ARGS )
156              
157             Sends an instant message. The first argument should be the name of the receipient buddy and the second argument is the message which you are sending.
158              
159             =item send_to_aol ( ARGS )
160              
161             Sends whatever string is passed in on to the AIM service. Useful for sending toc commands.
162              
163             =item recv_from_aol ()
164              
165             Receives any data sent from the AIM service. This includes all TOC protocol messages (including instant messages), however, PAUSE And SIGN_ON messages are handled internally.
166              
167             This method returns a C object. See the documentation for this object is to be used.
168              
169             =item disconnect ()
170              
171             Disconnects from the AIM service.
172              
173             =back
174              
175             =head1 KNOWN BUGS
176              
177             None, but that does not mean there are not any.
178              
179             =head1 SEE ALSO
180              
181             C
182              
183             =head1 AUTHOR
184              
185             Alistair Francis, http://search.cpan.org/~friffin/
186              
187             =cut
188              
189              
190             # Net::AIM::TOC::Connection package.
191             # Nothing to see here, please move along
192              
193             package Net::AIM::TOC::Connection;
194              
195 1     1   5 use strict;
  1         1  
  1         27  
196              
197 1     1   6775 use Net::AIM::TOC::Message;
  1         2  
  1         25  
198              
199 1     1   841 use IO::Socket::INET;
  1         26122  
  1         8  
200              
201             sub new {
202 0     0     my $class = shift;
203 0           my $args = shift;
204              
205 0   0       my $self = {
      0        
      0        
      0        
206             _sock => undef,
207             _screenName => undef,
208             _tocServer => $args->{tocServer} || Net::AIM::TOC::Config::TOC_SERVER,
209             _tocPort => $args->{tocPort} || Net::AIM::TOC::Config::TOC_PORT,
210             _authServer => $args->{authServer} || Net::AIM::TOC::Config::AUTH_SERVER,
211             _authPort => $args->{authPort} || Net::AIM::TOC::Config::AUTH_PORT,
212             _outseq => int(rand(100000)),
213             };
214              
215 0           my $sock = IO::Socket::INET->new(
216             PeerAddr => $self->{_tocServer},
217             PeerPort => $self->{_tocPort},
218             Type => SOCK_STREAM,
219             Proto => 'tcp'
220             );
221              
222 0 0         if( !defined($sock) ) {
223 0           my $err_msg = 'Unable to connect to '. $self->{_tocServer} .' on port '. $self->{_tocPort};
224 0           throw Net::AIM::TOC::Error( -text => $err_msg );
225             };
226              
227 0           $self->{_sock} = $sock;
228 0           bless $self, $class;
229              
230 0           return( $self );
231             };
232              
233              
234             sub send_signon {
235 0     0     my $self = shift;
236 0           my $screen_name = shift;
237 0           my $password = shift;
238              
239 0           $self->{_screenName} = $screen_name;
240              
241 0           Net::AIM::TOC::Utils::printDebug( "send_signon: $screen_name" );
242              
243 0           my $data_out = "FLAPON\r\n\r\n";
244 0           $self->{_sock}->send( $data_out );
245              
246 0           my( $msgObj ) = $self->recvFromAOL;
247 0           Net::AIM::TOC::Utils::printDebug( $msgObj->getRawData );
248              
249 0           my $signon_data = pack "Nnna".length($screen_name), 1, 1, length($screen_name) , $screen_name;
250              
251 0           my $msg = pack "aCnn", '*', 1, $self->{_outseq}, length($signon_data);
252 0           $msg .= $signon_data;
253              
254 0           my $ret = $self->{_sock}->send( $msg, 0 );
255              
256 0 0         if( !defined($ret) ) {
257 0           throw Net::AIM::TOC::Error( -text => "syswrite: $!" );
258             };
259              
260 0           my $login_string = $self->_getLoginString( $screen_name, $password );
261              
262 0           $ret = $self->sendToAOL( $login_string );
263              
264             # receive SIGNON data from AOL
265 0           $msgObj = $self->recvFromAOL;
266 0           Net::AIM::TOC::Utils::printDebug( $msgObj->getRawData );
267              
268             # Sending of sign on data is performed by 'recvFromAOL' to ensure
269             # correct handling of PAUSE messages
270              
271 0           return( 1 );
272             };
273              
274              
275             sub _sendSignOnData {
276 0     0     my $self = shift;
277              
278             # These lines are required in order to sign on
279 0           my $ret = $self->sendToAOL( "toc_add_buddy $self->{_screenName}" );
280 0           $ret = $self->sendToAOL( 'toc_set_config {m 1}' );
281              
282             # We're done with the signon process
283 0           $ret = $self->sendToAOL( 'toc_init_done' );
284              
285             # remove the buddy we were required to add earlier
286 0           $ret = $self->sendToAOL( "toc_remove_buddy $self->{_screenName}" );
287              
288 0           return;
289             };
290              
291             sub _getLoginString {
292 0     0     my $self = shift;
293 0           my $screen_name = shift;
294 0           my $password = shift;
295              
296 0           my $login_string = 'toc_signon '. $self->{_authServer} .' '. $self->{_authPort} .' '. $screen_name .' '. Net::AIM::TOC::Utils::encodePass( $password ) .' english '. Net::AIM::TOC::Utils::encode( Net::AIM::TOC::Config::AGENT );
297              
298 0           return( $login_string );
299             };
300              
301              
302             sub recvFromAOL {
303 0     0     my $self = shift;
304              
305 0           my $buffer;
306              
307 0 0         if( !defined($self->{_sock}) ) {
308 0           throw Net::AIM::TOC::Error( -text => 'We are not connected' );
309             };
310              
311 0           my $ret = $self->{_sock}->recv( $buffer, 6 );
312 0 0         if( !defined($ret) ) {
313 0           throw Net::AIM::TOC::Error( -text => "sysread: $!" );
314             };
315 0           Net::AIM::TOC::Utils::printDebug( "RAW IN (header): '$buffer'" );
316              
317 0           my ($marker, $type, $in_seq, $len) = unpack "aCnn", $buffer;
318 0           Net::AIM::TOC::Utils::printDebug( "IN (header): '$marker', '$type', '$in_seq', '$len'" );
319              
320 0           $ret = $self->{_sock}->recv( $buffer, $len );
321 0 0         if( !defined($ret) ) {
322 0           throw Net::AIM::TOC::Error( -text => "sysread: $!" );
323             };
324 0           Net::AIM::TOC::Utils::printDebug( "RAW IN (data): '$buffer'" );
325              
326 0           my $data = unpack( 'a*', $buffer );
327 0           Net::AIM::TOC::Utils::printDebug( "IN (data): '$data'" );
328              
329 0           my $msgObj = Net::AIM::TOC::Message->new( $type, $data );
330              
331 0 0         if( $msgObj->getType eq 'SIGN_ON' ) {
332 0           $self->_sendSignOnData;
333             };
334              
335 0           return( $msgObj );
336             };
337              
338              
339             sub sendToAOL {
340 0     0     my $self = shift;
341 0           my $msg = shift;
342              
343 0 0         if( !defined($self->{_sock}) ) {
344 0           throw Net::AIM::TOC::Error( -text => 'We are not connected' );
345             };
346              
347 0           $msg .= "\0";
348              
349 0           Net::AIM::TOC::Utils::printDebug( "RAW OUT: $msg" );
350 0           my $data = pack "aCnna*", '*', 2, ++$self->{_outseq}, length($msg), $msg;
351 0           Net::AIM::TOC::Utils::printDebug( "OUT: $data" );
352              
353 0           my $ret = $self->{_sock}->send( $data, 0 );
354              
355 0 0         if( !defined($ret) ) {
356 0           throw Net::AIM::TOC::Error( -text => "syswrite: $!" );
357             };
358              
359 0           return( $ret );
360             };
361              
362              
363             sub sendIMToAOL {
364 0     0     my $self = shift;
365 0           my $user = shift;
366 0           my $msg = shift;
367              
368 0 0 0       if( !defined($user) || !defined($msg) ) {
369 0           Net::AIM::TOC::Utils::printDebug( "User or msg not defined\n" );
370 0           return;
371             };
372              
373 0           $user = Net::AIM::TOC::Utils::normalize( $user );
374 0           $msg = Net::AIM::TOC::Utils::encode( $msg );
375              
376 0           $msg = 'toc_send_im '. $user .' '. $msg;
377              
378 0           my $ret = $self->sendToAOL( $msg );
379              
380 0           return( $ret );
381             };
382              
383              
384             sub disconnect {
385 0     0     my $self = shift;
386              
387 0           $self->{_sock}->close;
388              
389 0           return;
390             };
391              
392              
393             # Net::AIM::TOC::Error* packages.
394             # Nothing to see here, please move along
395              
396             package Net::AIM::TOC::Error;
397              
398 1     1   2028 use strict;
  1         2  
  1         49  
399              
400             @Net::AIM::TOC::Error::ISA = qw( Error );
401              
402              
403             package Net::AIM::TOC::Error::Message;
404              
405 1     1   4 use strict;
  1         2  
  1         39  
406              
407             @Net::AIM::TOC::Error::Message::ISA = qw( Net::AIM::TOC::Error );
408              
409              
410              
411             # Net::AIM::TOC::Utils package.
412             # Nothing to see here, please move along
413              
414             package Net::AIM::TOC::Utils;
415              
416 1     1   4 use strict;
  1         2  
  1         394  
417              
418             sub printDebug {
419 0     0     my $msg = shift;
420              
421 0           if( Net::AIM::TOC::Config::DEBUG ) {
422             print STDERR $msg, "\n";
423             };
424              
425 0           return;
426             };
427              
428             sub encodePass {
429 0     0     my $password = shift;
430              
431 0           my @table = unpack "c*" , 'Tic/Toc';
432 0           my @pass = unpack "c*", $password;
433              
434 0           my $encpass = '0x';
435 0           foreach my $c (0 .. $#pass) {
436 0           $encpass.= sprintf "%02x", $pass[$c] ^ $table[ ( $c % 7) ];
437             };
438              
439 0           return( $encpass );
440             };
441              
442             sub encode {
443 0     0     my $str = shift;
444              
445 0           $str =~ s/([\\\}\{\(\)\[\]\$\"])/\\$1/g;
446 0           return( "\"$str\"" );
447             };
448              
449             sub normalize {
450 0     0     my $data = shift;
451            
452 0           $data =~ s/[^A-Za-z0-9]//g;
453 0           $data =~ tr/A-Z/a-z/;
454              
455 0           return( $data );
456             };
457              
458              
459             sub removeHtmlTags {
460 0     0     my $string = shift;
461 0   0       my $replacement = shift || '';
462              
463 0           $string =~ s/<.*?>/$replacement/g;
464              
465 0           return( $string );
466             };
467              
468              
469             sub getCurrentTime {
470 0     0     my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
471              
472 0 0         if( $sec < 10 ) { $sec = '0'.$sec };
  0            
473 0 0         if( $min < 10 ) { $min = '0'.$min };
  0            
474              
475 0           return( "$hour:$min:$sec" );
476             };
477              
478             1;
479