line
stmt
bran
cond
sub
pod
time
code
1
package Net::AOLIM;
2
3
1
1
7608
use IO::Socket;
1
38742
1
7
4
1
1
2652
use IO::Select;
1
2558
1
89
5
require 5.001;
6
7
1
1
9
use vars qw($VERSION $AUTOLOAD);
1
8
1
8316
8
9
=pod
10
11
=head1 NAME
12
13
Net::AOLIM - Object-Oriented interface to the AOL Instant Messenger TOC client protocol
14
15
=head1 SYNOPSIS
16
17
The really short form:
18
19
use Net::AOLIM;
20
$aim = Net::AOLIM->new('username' => $user,
21
'password' => $pass,
22
'callback' => \&handler);
23
24
$aim->signon;
25
26
$aim->toc_send_im($destuser, $message);
27
28
=cut
29
30
###################################################################
31
# Copyright 2000-02 Riad Wahby All rights reserved #
32
# This program is free software. You may redistribute it and/or #
33
# modify it under the same terms as Perl itself. #
34
###################################################################
35
36
# subroutine declarations
37
sub new;
38
sub signon;
39
sub read_sflap_packet;
40
sub send_sflap_packet;
41
sub srv_socket;
42
sub pw_roast;
43
sub norm_uname;
44
sub toc_format_msg;
45
sub toc_format_login_msg;
46
sub toc_send_im;
47
sub add_buddies;
48
sub remove_buddies;
49
sub add_online_buddies;
50
sub remove_online_buddies;
51
sub set_srv_buddies;
52
sub current_buddies;
53
sub current_permits;
54
sub current_denies;
55
sub im_permit;
56
sub im_deny;
57
sub add_im_permit;
58
sub add_im_deny;
59
sub im_deny_all;
60
sub add_im_deny_all;
61
sub im_permit_all;
62
sub add_im_permit_all;
63
sub toc_set_config;
64
sub toc_evil;
65
sub toc_chat_join;
66
sub toc_chat_send;
67
sub toc_chat_whisper;
68
sub toc_chat_evil;
69
sub toc_chat_invite;
70
sub toc_chat_leave;
71
sub toc_chat_accept;
72
sub toc_get_info;
73
sub toc_set_info;
74
sub toc_set_away;
75
sub toc_get_dir;
76
sub toc_set_dir;
77
sub toc_dir_search;
78
sub toc_set_idle;
79
sub ui_add_fh;
80
sub ui_del_fh;
81
sub ui_all_fh;
82
sub ui_exists_fh;
83
sub ui_set_callback;
84
sub ui_get_callback;
85
sub ui_dataget;
86
87
#
88
# some constants to use, including error codes.
89
# :-) the curse of ex-C-programmers--no #defines
90
#
91
92
# max packet length
93
$MAX_PACKLENGTH = 65535;
94
95
# SFLAP types
96
$SFLAP_TYPE_SIGNON = 1;
97
$SFLAP_TYPE_DATA = 2;
98
$SFLAP_TYPE_ERROR = 3;
99
$SFLAP_TYPE_SIGNOFF = 4;
100
$SFLAP_TYPE_KEEPALIVE = 5;
101
$SFLAP_MAX_LENGTH = 1024;
102
103
# return codes
104
$SFLAP_SUCCESS = 0;
105
$SFLAP_ERR_UNKNOWN = 1;
106
$SFLAP_ERR_ARGS = 2;
107
$SFLAP_ERR_LENGTH = 3;
108
$SFLAP_ERR_READ = 4;
109
$SFLAP_ERR_SEND = 5;
110
111
# misc SFLAP constants
112
$SFLAP_FLAP_VERSION = 1;
113
$SFLAP_TLV_TAG = 1;
114
$SFLAP_HEADER_LEN = 6;
115
116
# Net::AOLIM version
117
$VERSION = "1.61";
118
119
# number of arguments that server messages have:
120
%SERVER_MSG_ARGS = ( 'SIGN_ON' => 1,
121
'CONFIG' => 1,
122
'NICK' => 1,
123
'IM_IN' => 3,
124
'UPDATE_BUDDY' => 6,
125
'ERROR' => 2,
126
'EVILED' => 2,
127
'CHAT_JOIN' => 2,
128
'CHAT_IN' => 4,
129
'CHAT_UPDATE_BUDDY' => 0,
130
'CHAT_INVITE' => 4,
131
'CHAT_LEFT' => 1,
132
'GOTO_URL' => 2,
133
'DIR_STATUS' => 2,
134
'PAUSE' => 0 );
135
136
=pod
137
138
=head1 NOTES
139
140
Error conditions will be stored in $main::IM_ERR, with any arguments
141
to the error condition stored in $main::IM_ERR_ARGS.
142
143
The hash %Net::AOLIM::ERROR_MSGS contains english translations of all of
144
the error messages that are either internal to the module or
145
particular to the TOC protocol.
146
147
Errors may take arguments indicating a more specific failure
148
condition. In this case, they will either be stored in
149
$main::IM_ERR_ARGS or they will come from the server ERROR message.
150
To insert the arguments in the proper place, use a construct similar
151
to:
152
153
$ERROR = $Net::AOLIM::ERROR_MSGS{$IM_ERR};
154
$ERROR =~ s/\$ERR_ARG/$IM_ERR_ARGS/g;
155
156
This assumes that the error code is stored in $IM_ERR and the error
157
argument is stored in $IM_ERR_ARGS.
158
159
All methods will return undef on error, and will set $main::IM_ERR and
160
$main::IM_ERR_ARGS as appropriate.
161
162
It seems that TOC servers won't acknowledge a login unless at least
163
one buddy is added before toc_init_done is sent. Thus, as of version
164
1.6, Net::AOLIM will add the current user to group "Me" if you don't
165
create your buddy list before calling signon(). Don't bother removing
166
this if you have added your buddies; it'll automagically disappear.
167
168
=cut
169
170
%ERROR_MSGS = ( 0 => 'Success',
171
1 => 'Net::AOLIM Error: Unknown',
172
2 => 'Net::AOLIM Error: Incorrect Arguments',
173
3 => 'Net::AOLIM Error: Exceeded Max Packet Length (1024)',
174
4 => 'Net::AOLIM Error: Reading from server',
175
5 => 'Net::AOLIM Error: Sending to server',
176
6 => 'Net::AOLIM Error: Login timeout',
177
901 => 'General Error: $ERR_ARG not currently available',
178
902 => 'General Error: Warning of $ERR_ARG not currently available',
179
903 => 'General Error: A message has been dropped, you are exceeding the server speed limit',
180
950 => 'Chat Error: Chat in $ERR_ARG is unavailable',
181
960 => 'IM and Info Error: You are sending messages too fast to $ERR_ARG',
182
961 => 'IM and Info Error: You missed an IM from $ERR_ARG because it was too big',
183
962 => 'IM and Info Error: You missed an IM from $ERR_ARG because it was sent too fast',
184
970 => 'Dir Error: Failure',
185
971 => 'Dir Error: Too many matches',
186
972 => 'Dir Error: Need more qualifiers',
187
973 => 'Dir Error: Dir service temporarily unavailble',
188
974 => 'Dir Error: Email lookup restricted',
189
975 => 'Dir Error: Keyword ignored',
190
976 => 'Dir Error: No keywords',
191
977 => 'Dir Error: Language not supported',
192
978 => 'Dir Error: Country not supported',
193
979 => 'Dir Error: Failure unknown $ERR_ARG',
194
980 => 'Auth Error: Incorrect nickname or password',
195
981 => 'Auth Error: The service is temporarily unavailable',
196
982 => 'Auth Error: Your warning level is too high to sign on',
197
983 => 'Auth Error: You have been connecting and disconnecting too frequently. Wait 10 minutes and try again. If you continue to try, you will need to wait even longer.',
198
989 => 'Auth Error: An unknown signon error has occurred $ERR_ARG' );
199
200
=pod
201
202
=head1 DESCRIPTION
203
204
This section documents every member function of the Net::AOLIM class.
205
206
=head2 $Net::AOLIM->new()
207
208
This is the Net::AOLIM Constructor.
209
210
It should be called with following arguments (items with default
211
values are optional):
212
213
'username' => login
214
'password' => password
215
'callback' => \&callbackfunction
216
'server' => servername (default toc.oscar.aol.com)
217
'port' => port number (default 1234)
218
'allow_srv_settings' => <1 | 0> (default 1)
219
'login_server' => login server (default login.oscar.aol.com)
220
'login_port' => login port (default 5198)
221
'login_timeout' => timeout in seconds to wait for a response to the
222
toc_signon packet. Default is 0 (infinite)
223
'aim_agent' => agentname (max 200 char)
224
Default is AOLIM:$Version VERSION$
225
There have been some reports that changing this
226
may cause TOC servers to stop responding to signon
227
requests
228
229
callback is the callback function that handles incoming data from the
230
server (already digested into command plus args). This is the meat of
231
the client program.
232
233
allow_srv_settings is a boolean that dictates whether the object
234
should modify the user configuration on the server. If
235
allow_srv_settings is false, the server settings will be ignored and
236
will not be modified. Otherwise, the server settings will be read in
237
and parsed, and will be modified by calls that modify the buddy list.
238
239
aim_agent is the name of the client program as reported to the TOC
240
server
241
242
Returns a blessed instantiation of Net::AOLIM.
243
244
=cut
245
246
sub new
247
{
248
0
0
1
my $whatami = shift @_;
249
250
0
while ($key = shift @_)
251
{
252
0
0
if ($var = shift @_)
253
{
254
0
$args{$key} = $var;
255
}
256
}
257
258
0
0
0
unless ((defined $args{'username'}) && (defined $args{'password'}) && (defined $args{'callback'}))
0
259
{
260
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
261
0
return undef;
262
}
263
264
0
0
($args{'allow_srv_settings'} = 1) unless (defined $args{'allow_srv_settings'});
265
0
0
$args{'server'} ||= 'toc.oscar.aol.com';
266
0
0
$args{'port'} ||= 1234;
267
0
0
$args{'login_server'} ||= 'login.oscar.aol.com';
268
0
0
$args{'login_port'} ||= 5198;
269
0
0
$args{'aim_agent'} ||= 'AOLIM:$Version ' . $VERSION . "\$";
270
0
0
$args{'login_timeout'} ||= undef();
271
272
# Make a new instance of instmsg and bless it.
273
274
0
my $new_instmsg = { 'username' => $args{'username'},
275
'password' => $args{'password'},
276
'server' => $args{'server'},
277
'port' => $args{'port'},
278
'allow_srv_settings' => $args{'allow_srv_settings'},
279
'roastedp' => pw_roast('', $args{'password'}),
280
'unamenorm' => norm_uname('', $args{'username'}),
281
'im_socket' => '',
282
'client_seq_number' => time % 65536,
283
'login_server' => $args{'login_server'},
284
'login_port' => $args{'login_port'},
285
'buddies' => {},
286
'permit' => [],
287
'deny' => [],
288
'callback' => $args{'callback'},
289
'callbacks' => {},
290
'permit_mode' => '1',
291
'sel' => IO::Select->new(),
292
'pause' => '0',
293
'aim_agent' => $args{'aim_agent'},
294
'login_timeout' => $args{'login_timeout'},
295
};
296
297
0
bless $new_instmsg, $whatami;
298
0
$main::IM_ERR = 0;
299
0
return $new_instmsg;
300
}
301
302
######################################################
303
# SOCKET LEVEL FUNCTIONS
304
# the functions here operate at the socket level
305
#
306
# signon is included here because it is the function
307
# that actually creates the socket
308
######################################################
309
310
=pod
311
312
=head2 $aim->signon()
313
314
Call this after calling C and after setting initial buddy
315
listings with C, C, C,
316
C, and C as necessary.
317
318
Returns undef on failure, setting $main::IM_ERR and $main::IM_ERR_ARGS
319
as appropriate. Returns 0 on success.
320
321
This function is also called every time we receive a SIGN_ON packet
322
from the server. This is because we are required to react in a
323
specific way to the SIGN_ON packet, and this method contains all
324
necessary functionality. We should only receive SIGN_ON while
325
connected if we have first received a PAUSE (see the B
326
documentation included with this package for details of how PAUSE
327
works).
328
329
=cut
330
331
sub signon
332
{
333
#
334
# call this after new() to sign on to the IM service
335
#
336
# takes no arguments
337
#
338
# returns 0 on success, undef on failure. If failure,
339
# check $main::IM_ERR for reason.
340
#
341
0
0
1
my $imsg = $_[0];
342
0
my $im_socket = \$imsg->{'im_socket'};
343
344
0
0
unless ($imsg->{'pause'})
345
{
346
# unless we're coming off a pause, make our socket
347
0
0
$$im_socket = IO::Socket::INET->new(PeerAddr => $imsg->{'server'},
348
PeerPort => $imsg->{'port'},
349
Proto => 'tcp',
350
Type => SOCK_STREAM)
351
or die "Couldn't connect to server: $!";
352
353
0
$$im_socket->autoflush(1);
354
355
# add this filehandle to the select loop that we will later use
356
0
$imsg->{'sel'}->add($$im_socket);
357
358
0
my $so_srv_sflap_signon;
359
my $so_srv_version;
360
0
my $so_sflap_signon;
361
0
my $so_toc_ascii;
362
0
my $so_toc_srv_so;
363
0
my $so_toc_srv_config;
364
0
my $so_toc_srv_config_msg;
365
0
my $so_toc_srv_config_rest;
366
0
my $so_init_done;
367
368
# send a FLAPON to initiate the connection; this is the only time
369
# that stuff should be printed directly to the server without
370
# using send_sflap_packet
371
0
syswrite $$im_socket,"FLAPON\r\n\r\n";
372
373
0
0
return undef unless (defined ($so_srv_sflap_signon = $imsg->read_sflap_packet()));
374
375
0
$ulen = length $imsg->{'unamenorm'};
376
377
0
$so_sflap_signon = pack "Nnna".$ulen, 1, 1, $ulen, $imsg->{'unamenorm'};
378
379
380
0
0
return undef unless (defined ($imsg->send_sflap_packet($SFLAP_TYPE_SIGNON, $so_sflap_signon, 1, 1)));
381
382
0
$so_toc_ascii = $imsg->toc_format_login_msg('toc_signon',$imsg->{'login_server'},$imsg->{'login_port'},$imsg->{'unamenorm'},$imsg->{'roastedp'},'english',$imsg->{'aim_agent'});
383
384
0
0
return undef unless (defined ($imsg->send_sflap_packet($SFLAP_TYPE_DATA, $so_toc_ascii, 0, 0)));
385
386
0
my @ready = $imsg->{'sel'}->can_read($imsg->{'login_timeout'});
387
388
0
0
if (scalar(@ready) > 0)
389
{
390
0
0
return undef unless (defined ($so_toc_srv_so = $imsg->read_sflap_packet()));
391
}
392
else
393
{
394
0
$main::IM_ERR = 6;
395
0
return undef;
396
}
397
398
0
0
unless ($so_toc_srv_so =~ /SIGN_ON/)
399
{
400
# we didn't sign on successfully
401
0
0
if ($so_toc_srv_so =~ /ERROR:(.*)/)
402
{
403
# if we get an error code from the server, send it
404
# back in $main::IM_ERR
405
0
($main::IM_ERR, $main::IM_ERR_ARG) = split (/:/, $1, 2);
406
}
407
else
408
{
409
0
$main::IM_ERR = $SFLAP_ERR_UNKNOWN;
410
}
411
0
return undef;
412
}
413
}
414
415
# we can't possibly be paused at this point; make sure $imsg->{'pause'} = 0
416
0
$imsg->{'pause'} = 0;
417
418
# have to call toc_set_config before we finish init
419
0
0
return undef unless (defined $imsg->toc_set_config());
420
421
# now we finish the signon with an init_done
422
0
$so_init_done = $imsg->toc_format_msg('toc_init_done');
423
424
425
0
0
return undef unless (defined $imsg->send_sflap_packet($SFLAP_TYPE_DATA, $so_init_done, 0, 0));
426
427
0
return $SFLAP_SUCCESS;
428
}
429
430
=pod
431
432
=head2 $aim->read_sflap_packet()
433
434
This method returns data from a single waiting SFLAP packet on the
435
server socket. The returned value is the payload section of the SFLAP
436
packet which is completely unparsed.
437
438
Most users will never need to call this method.
439
440
For more information, see B below and the B
441
manpage.
442
443
=cut
444
445
sub read_sflap_packet
446
{
447
#
448
# read an sflap packet, including a safe
449
# method of making sure that we get all
450
# the info in the sflap packet
451
#
452
# takes no arguments
453
#
454
# returns the read data upon success, or undef if an error
455
# occurs (and the errno appears in $main::IM_ERR)
456
#
457
0
0
1
my $imsg = shift @_;
458
0
my ($rsp_header, $rsp_recv_packet);
459
0
my ($rsp_ast, $rsp_type, $rsp_seq_new, $rsp_dlen);
460
0
my ($rsp_decoded);
461
0
my $im_socket = \$imsg->{'im_socket'};
462
463
# unless we get a valid read, we return an unknown error
464
465
0
0
0
unless (defined(sysread $$im_socket, $rsp_header, $SFLAP_HEADER_LEN, 0) && (length($rsp_header) == $SFLAP_HEADER_LEN))
466
{
467
0
$main::IM_ERR = $SFLAP_ERR_READ;
468
0
return undef;
469
}
470
471
# Now we read the info off the packet, including the data length and the
472
# sequence number
473
0
($rsp_ast,$rsp_type,$rsp_seq_new,$rsp_dlen) = unpack "aCnn", $rsp_header;
474
475
# now we pull down more bytes equal to the length field in
476
# the previous read
477
478
0
0
0
unless (defined(sysread $$im_socket, $rsp_recv_packet, $rsp_dlen, 0) && (length($rsp_recv_packet) == $rsp_dlen))
479
{
480
0
$main::IM_ERR = $SFLAP_ERR_READ;
481
0
return undef;
482
}
483
484
# if it's a signon packet, we read the version number
485
0
0
0
if (($rsp_type == $SFLAP_TYPE_SIGNON) && ($rsp_dlen == 4))
486
{
487
0
($rsp_decoded) = unpack "N", $rsp_recv_packet;
488
0
$main::IM_ERR = $SFLAP_SUCCESS;
489
0
return $rsp_decoded;
490
}
491
# otherwise, we just read it as ASCII
492
else
493
{
494
0
($rsp_decoded) = unpack "a*", $rsp_recv_packet;
495
0
$main::IM_ERR = $SFLAP_SUCCESS;
496
0
return $rsp_decoded;
497
}
498
499
# if we fall through to here, something's wrong; return an
500
# unknown error
501
0
$main::IM_ERR = $SFLAP_ERR_UNKNOWN;
502
0
return undef;
503
}
504
505
=pod
506
507
=head2 $aim->send_sflap_packet($type, $data, $formatted, $noterm)
508
509
This method sends an SFLAP packet to the server.
510
511
C<$type> is one of the SFLAP types (see B).
512
513
C<$data> is the payload to send.
514
515
If C<$formatted> evaluates to true, the data is assumed to be the
516
completely formed payload of the SFLAP packet; otherwise, the payload
517
will be packed as necessary. This defaults to 0. In either case, the
518
header is prepended to the payload.
519
520
If C<$noterm> evaluates to true, the payload will not be terminated
521
with a '\0'. Otherwise, it will be terminated. If C<$formatted> is
522
true, this option is ignored and no null is appended. This defaults
523
to 0.
524
525
Most users will never need to use this method.
526
527
For more information, see B and B below.
528
529
=cut
530
531
sub send_sflap_packet
532
{
533
#
534
# take data, manufacture an SFLAP header,
535
# and send off the info.
536
#
537
# takes four arguments:
538
#
539
# sflap_type: gives the type to include in the header
540
# sflap_data: either ASCII or a preformatted string to
541
# send as the payload
542
# already_formatted: set to 1 to prevent the formatting
543
# of sflap_data as ASCII (if it has already
544
# been formatted). Defaults to 0
545
# no_null_terminate: set to 1 to prevent the addition of
546
# a null terminator to the data. Default 0.
547
# No null termination is added if already_formatted
548
# is set.
549
#
550
# returns undef if unsuccessful, and puts the error in $main::IM_ERR
551
# otherwise returns 0
552
#
553
554
0
0
1
my $imsg = shift @_;
555
0
my $im_socket = \$imsg->{'im_socket'};
556
557
# arguments
558
0
my $sflap_type = $_[0];
559
0
my $sflap_data = $_[1];
560
0
my $already_formatted = $_[2];
561
0
my $no_null_terminate = $_[3];
562
563
0
0
0
unless ((defined $sflap_type) && (defined $sflap_data) && (defined $already_formatted) && (defined $no_null_terminate))
0
0
564
{
565
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
566
0
return undef;
567
}
568
569
# internal variables
570
0
my ($ssp_header, $ssp_data, $ssp_packet, $ssp_datalen);
571
572
0
0
if ($already_formatted)
573
{
574
# we don't have to modify the data
575
0
$ssp_data = $sflap_data;
576
0
$ssp_datalen = length $sflap_data;
577
0
$ssp_header = pack "aCnn", "*", $sflap_type, $imsg->{'client_seq_number'}, $ssp_datalen;
578
0
$ssp_packet = $ssp_header . $ssp_data;
579
}
580
else
581
{
582
0
0
unless ($no_null_terminate)
583
{
584
# we need to be sure that there's only one \0 at the end of
585
# the string
586
0
$sflap_data =~ s/\0*$//;
587
0
$sflap_data .= "\0";
588
}
589
590
# now we calculate the length and make the packet
591
0
$ssp_datalen = length $sflap_data;
592
0
$ssp_data = pack "a".$ssp_datalen, $sflap_data;
593
0
$ssp_header = pack "aCnn", "*", $sflap_type, $imsg->{'client_seq_number'}, $ssp_datalen;
594
0
$ssp_packet = $ssp_header . $ssp_data;
595
}
596
597
# if the packet is too long, return an error
598
# our connection will be dropped otherwise
599
0
0
if ((length $ssp_packet) >= $SFLAP_MAX_LENGTH)
600
{
601
0
$main::IM_ERR = $SFLAP_ERR_LENGTH;
602
0
return undef;
603
}
604
605
# if we are successful we return 0
606
0
0
if (syswrite $$im_socket,$ssp_packet)
607
{
608
0
$$im_socket->flush();
609
0
$imsg->{'client_seq_number'}++;
610
0
return $SFLAP_SUCCESS;
611
}
612
613
# if we fall through to here, we have a problem
614
0
$main::IM_ERR = $SFLAP_ERR_SEND;
615
0
return undef;
616
}
617
618
=cut
619
620
=head2 $aim->srv_socket()
621
622
This method returns a reference to the socket to which the server is
623
connected. It must be dereferenced before it can be used. Thus:
624
625
C<$foo = $aim-Esrv_socket();>
626
C
627
628
Most users will never need to directly access the server socket.
629
630
For more information, see the B manpage and B
631
OWN> below.
632
633
=cut
634
635
sub srv_socket
636
{
637
#
638
# takes no arguments
639
#
640
# returns a reference to the socket on which we communicate
641
# with the server
642
#
643
0
0
1
my $imsg = shift @_;
644
645
0
return \$imsg->{'im_socket'};
646
}
647
648
########################################################
649
# MISCELLANEOUS FUNCTIONS
650
# these serve important functions, but
651
# are not directly accessed by the user
652
# of the Net::AOLIM package
653
########################################################
654
655
=pod
656
657
=head2 $aim->pw_roast($password)
658
659
This method returns the 'roasted' version of a password. A roasted
660
password is the original password XORed with the roast string
661
'Tic/Toc' (which is repeated until the length is the same as the
662
password length).
663
664
This method is called automatically in $aim->signon. Most users will
665
never need this method.
666
667
For more information, see the B manpage and B
668
OWN> below.
669
670
=cut
671
672
sub pw_roast
673
{
674
#
675
# this takes one argument, the
676
# password, and returns the roasted
677
# string
678
#
679
0
0
1
my $imsg = shift @_;
680
0
my $pr_password = $_[0];
681
0
my $pr_len = (length $pr_password) * 8;
682
0
my $pr_roasted;
683
my $pr_roasted_bits;
684
0
my $pr_roast_string = '01010100011010010110001100101111010101000110111101100011';
685
0
my $pr_password_bits = unpack("B*", pack("a".$pr_len, $pr_password));
686
687
0
0
unless (defined $pr_password)
688
{
689
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
690
0
return undef;
691
}
692
693
0
for ($i = 0; $i < $pr_len; $i++)
694
{
695
0
my $bit1 = substr $pr_password_bits, $i, 1;
696
0
my $bit2 = substr $pr_roast_string, ($i % 56), 1;
697
0
my $newbit = $bit1 ^ $bit2;
698
0
$pr_roasted_bits .= $newbit;
699
}
700
701
0
$pr_roasted = "0x" . (unpack "H*", (pack "B*", $pr_roasted_bits));
702
703
0
return $pr_roasted;
704
}
705
706
=pod
707
708
=head2 $aim->norm_uname($username)
709
710
This method returns the 'normalized' version of a username. A
711
normalized username has all spaces removed and is all lowercase. All
712
usernames sent to the server should be normalized first if they are an
713
argument to a TOC command.
714
715
All methods in this class automatically normalize username arguments
716
to the server; thus, most users will never use this method.
717
718
For more information, see the B manpage and B
719
OWN> below.
720
721
=cut
722
723
sub norm_uname
724
{
725
#
726
# this takes one argument, the
727
# username to normalize
728
#
729
# returns the normalized username
730
#
731
0
0
1
my $imsg = shift @_;
732
0
my $nu_username = $_[0];
733
734
0
0
unless (defined $nu_username)
735
{
736
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
737
0
return undef;
738
}
739
740
0
$nu_username =~ s/ //g;
741
0
$nu_username = "\L$nu_username\E";
742
}
743
744
=pod
745
746
=head2 $aim->toc_format_msg($command[, $arg1[, arg2[, ...]]])
747
748
This method formats a message properly for sending to the TOC server.
749
That is, it is escaped and quoted, and the fields are appended with
750
spaces as specified by the protocol.
751
752
Note that all methods in this class automatically format messages
753
appropriately; most users will never need to call this method.
754
755
See B and B below.
756
757
=cut
758
759
sub toc_format_msg
760
{
761
#
762
# this takes at least one argument.
763
# the first argument will be returned unaltered
764
# at the beginning of the string which is a
765
# join (with spaces) of the remaining arguments
766
# after they have been properly escaped and quoted.
767
#
768
0
0
1
my $imsg = shift @_;
769
0
my $toc_command = shift @_;
770
0
my $escaped;
771
my $finalmsg;
772
773
0
0
unless (defined $toc_command)
774
{
775
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
776
0
return undef;
777
}
778
779
0
0
if (@_)
780
{
781
0
foreach $arg (@_)
782
{
783
0
$escaped = $arg;
784
0
$escaped =~ s/([\$\{\}\[\]\(\)\"\\\'])/\\$1/g;
785
0
$finalmsg .= ' "' . $escaped. '"';
786
}
787
}
788
else
789
{
790
0
$finalmsg = "";
791
}
792
793
0
$finalmsg = $toc_command . $finalmsg;
794
795
0
return $finalmsg;
796
}
797
798
=pod
799
800
=head2 $aim->toc_format_login_msg($command[, $arg1[, arg2[, ...]]])
801
802
This method formats a login message properly for sending to the TOC
803
server. That is, all fields are escaped, but only the user_agent
804
field is quoted. Fields are separated with spaces as specified in the
805
TOC protocol.
806
807
Note that the login procedure calls this function automatically; the
808
user will probably never need to use it.
809
810
See B and B below.
811
812
=cut
813
814
sub toc_format_login_msg
815
{
816
#
817
# this takes at least one argument.
818
# the first argument will be returned unaltered
819
# at the beginning of the string which is a
820
# join (with spaces) of the remaining arguments
821
# after they have been properly escaped and quoted.
822
#
823
0
0
1
my $imsg = shift @_;
824
0
my $toc_command = shift @_;
825
0
my $useragentstr = pop @_;
826
0
my $escaped;
827
my $finalmsg;
828
829
0
0
unless (defined $toc_command)
830
{
831
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
832
0
return undef;
833
}
834
835
0
0
if (@_)
836
{
837
0
foreach $arg (@_)
838
{
839
0
$escaped = $arg;
840
0
$escaped =~ s/([\$\{\}\[\]\(\)\"\\\'])/\\$1/g;
841
0
$finalmsg .= ' ' . $escaped. '';
842
}
843
}
844
else
845
{
846
0
$finalmsg = "";
847
}
848
849
0
$useragentstr =~ s/([\$\{\}\[\]\(\)\"\\\'])/\\$1/g;
850
851
0
$finalmsg = $toc_command . $finalmsg . ' "' . $useragentstr . '"';
852
853
0
return $finalmsg;
854
}
855
856
############################################################
857
# TOC Interface functions
858
#
859
# These are the functions that the Net::AOLIM package user
860
# will most often interface with; these are basically
861
# directly mapped to TOC functions of the same name
862
############################################################
863
864
=pod
865
866
=head2 $aim->toc_send_im($uname, $msg, $auto)
867
868
This method sends an IM message C<$msg> to the user specified by
869
C<$uname>. The third argument indicates whether or not this IM should
870
be sent as an autoreply, which may produce different behavior from the
871
remote client (but has no direct effect on the content of the IM).
872
873
=cut
874
875
sub toc_send_im
876
{
877
#
878
# takes three arguments:
879
#
880
# tsi_uname: the username to send the packet to
881
# tsi_msg: the message to send
882
# tsi_auto: if this should be an autoreply packet, set
883
# this to true
884
#
885
# returns $TOC_SUCCESS on success, or undef on
886
# error (and $main::IM_ERR is set with an error code)
887
#
888
0
0
1
my $imsg = shift @_;
889
0
my $tsi_uname = $_[0];
890
0
my $tsi_msg = $_[1];
891
892
0
0
0
unless ((defined $imsg) && (defined $tsi_uname) && (defined $tsi_msg))
0
893
{
894
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
895
0
return undef;
896
}
897
898
0
my $tsi_full_msg = $imsg->toc_format_msg("toc_send_im",$imsg->norm_uname($tsi_uname),$tsi_msg);
899
900
0
0
if ($tsi_auto)
901
{
902
0
$tsi_full_msg .= " auto";
903
}
904
905
906
0
0
return undef unless (defined ($imsg->send_sflap_packet($SFLAP_TYPE_DATA, $tsi_full_msg, 0, 0)));
907
908
0
return $TOC_SUCCESS;
909
}
910
911
#*****************************************************
912
# Buddy functions
913
#
914
# all of these have to do with buddy functions, such
915
# as adding and removing buddies from your buddy list
916
#*****************************************************
917
918
=pod
919
920
=head2 $aim->add_buddies($group, $buddy1[, $buddy2[, ...]])
921
922
This method, which should only be called B, adds
923
buddies to the initial local buddy list in group C<$group>. Once
924
C is called, use add_online_buddies instead.
925
926
=cut
927
928
sub add_buddies
929
{
930
#
931
# takes at least two arguments.
932
#
933
# the first argument is the name of
934
# the group that the names after it will
935
# be added to.
936
#
937
# each arg is taken to be a buddy
938
# in the user's buddy list which is
939
# sent during signon.
940
#
941
0
0
1
my $imsg = shift @_;
942
0
my $ib_group = shift @_;
943
944
0
0
0
unless ((defined $ib_group) && (defined $_[0]))
945
{
946
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
947
0
return undef;
948
}
949
950
0
0
($ { $imsg->{'buddies'} }{$ib_group} = []) unless (scalar @{$ { $imsg->{'buddies'} }{$ib_group}});
0
0
0
951
952
0
my @norm_buddies;
953
954
0
foreach $buddy (@_)
955
{
956
0
my $norm_buddy = $imsg->norm_uname($buddy);
957
0
unshift @norm_buddies, $norm_buddy;
958
}
959
960
0
my %union;
961
962
0
foreach $e (@norm_buddies, @ { $ { $imsg->{'buddies'}}{$ib_group}})
0
0
963
{
964
0
$union{$e}++;
965
}
966
967
0
@ { $ { $imsg->{'buddies'}}{$ib_group}} = keys %union;
0
0
968
}
969
970
sub remove_buddies
971
{
972
#
973
# takes at least one argument
974
#
975
# each argument is taken to be
976
# a buddy which will be removed
977
# from the buddy list
978
#
979
0
0
0
my $imsg = shift @_;
980
981
0
0
unless (defined $_[0])
982
{
983
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
984
0
return undef;
985
}
986
987
0
my @norm_buddies;
988
989
0
foreach $buddy (@_)
990
{
991
0
my $norm_buddy = $imsg->norm_uname($buddy);
992
0
unshift @norm_buddies, $norm_buddy;
993
}
994
995
0
foreach $group (keys %{$imsg->{'buddies'}})
0
996
{
997
0
my %temp;
998
999
0
map {$temp{$_} = 1;} @ { $ { $imsg->{'buddies'} } {$group} };
0
0
0
1000
0
map {delete $temp{$_};} @norm_buddies;
0
1001
1002
0
@ { $ { $imsg->{'buddies'} } {$group} } = keys %temp;
0
0
1003
1004
0
0
unless (scalar @ { $ { $imsg->{'buddies'} } {$group} })
0
0
1005
{
1006
0
delete $ { $imsg->{'buddies'} }{$group};
0
1007
}
1008
}
1009
}
1010
1011
=pod
1012
1013
=head2 $aim->add_online_buddies($group, $buddy1[, $buddy2[, ...]])
1014
1015
This method takes the same arguments as C, but is
1016
intended for use after C has been called.
1017
1018
If allow_srv_settings is true (see C), it will also set the
1019
settings on the server to the new settings.
1020
1021
=cut
1022
1023
sub add_online_buddies
1024
{
1025
#
1026
# takes at least two arguments
1027
#
1028
# this should be called only after signon
1029
# adds all arguments after the firist as buddies
1030
# to the buddy list. the first argument is
1031
# the name of the group in which to add them
1032
#
1033
# if you want to add people to your initial buddy
1034
# list, us im_buddies()
1035
#
1036
# returns undef on error
1037
#
1038
0
0
1
my $imsg = shift @_;
1039
1040
0
0
return undef unless (defined $imsg->add_buddies(@_));
1041
1042
0
$imsg->toc_set_config();
1043
}
1044
1045
=pod
1046
1047
=head2 $aim->remove_online_buddies($buddy1[, $buddy2[, ...]])
1048
1049
Removes all arguments from the buddy list (removes from all groups).
1050
1051
If allow_srv_settings is true (see C), it will also set the
1052
settings on the server to the new settings.
1053
1054
=cut
1055
1056
sub remove_online_buddies
1057
{
1058
#
1059
# takes at least one argument
1060
#
1061
# this should be called only after signon
1062
# removes all arguments from the buddy list.
1063
#
1064
# returns undef on error
1065
#
1066
0
0
1
my $imsg = shift @_;
1067
1068
0
0
return undef unless (defined $imsg->remove_buddies(@_));
1069
1070
0
my $rob_message = $imsg->toc_format_msg('toc_remove_buddy', @_);
1071
1072
1073
0
0
return undef unless (defined ($imsg->send_sflap_packet($SFLAP_TYPE_DATA, $rob_message, 0, 0)));
1074
1075
0
0
if ($imsg->{'allow_srv_settings'})
1076
{
1077
0
$imsg->toc_set_config();
1078
}
1079
}
1080
1081
sub set_srv_buddies
1082
{
1083
#
1084
# adds buddies in our list from the server
1085
#
1086
# takes one argument, the CONFIG string from the
1087
# server
1088
#
1089
0
0
0
my $imsg = shift @_;
1090
0
my $srv_buddy_list = $_[0];
1091
1092
0
0
return unless ($imsg->{'allow_srv_settings'});
1093
1094
0
$srv_buddy_list =~ s/^CONFIG://;
1095
1096
0
0
return unless (@srv_buddies = split "\n", $srv_buddy_list);
1097
1098
0
for ($i=0; $i < scalar (@srv_buddies); $i++)
1099
{
1100
0
0
if ($srv_buddies[$i] =~ /^g\s*(.*)/)
1101
{
1102
0
my $group = $1;
1103
0
my $continue = 1;
1104
0
$i++;
1105
1106
0
my @buddylist;
1107
1108
0
while ($continue)
1109
{
1110
0
0
if ($srv_buddies[$i] =~ /^b\s*(.*)/)
1111
{
1112
0
unshift @buddylist, $1;
1113
0
$i++;
1114
}
1115
else
1116
{
1117
0
$i--;
1118
0
$continue = 0;
1119
}
1120
}
1121
1122
0
my %union;
1123
1124
0
foreach $e (@buddylist, @ { $ { $imsg->{'buddies'}}{$group}})
0
0
1125
{
1126
0
$union{$e}++;
1127
}
1128
1129
0
@{ $ { $imsg->{'buddies'}}{$group}} = keys %union;
0
0
1130
}
1131
}
1132
}
1133
1134
=pod
1135
1136
=head2 $aim->current_buddies(\%buddyhash)
1137
1138
This method fills the hash referenced by C<\%buddyhash> with the
1139
currently stored buddy information. Each key in the returned hash is
1140
the name of a buddy group, and the corresponding value is a list of
1141
the members of that group.
1142
1143
=cut
1144
1145
sub current_buddies
1146
{
1147
#
1148
# takes one argument, a pointer to a hash that should
1149
# be filled with the current users such that each hash
1150
# key is a buddy group and the corresponding value is a
1151
# list of buddies in that group. Thus,
1152
#
1153
# @{$hash{"foo"}}
1154
#
1155
# is the list of users in the group called foo
1156
#
1157
0
0
1
my $imsg = shift @_;
1158
0
my $buddyhash = $_[0];
1159
1160
0
0
unless (defined $buddyhash)
1161
{
1162
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
1163
0
return undef;
1164
}
1165
1166
0
%$buddyhash = % { $imsg->{'buddies'}};
0
1167
}
1168
1169
=pod
1170
1171
=head2 $aim->current_permits()
1172
1173
This method takes no arguments. It returns the current 'permit' list.
1174
1175
=cut
1176
1177
sub current_permits
1178
{
1179
#
1180
# takes no arguments
1181
#
1182
# returns a list of the people currently on the "permit" list
1183
#
1184
0
0
1
my $imsg = shift @_;
1185
1186
0
return @ {$imsg->{'permit'}};
0
1187
}
1188
1189
=pod
1190
1191
=head2 $aim->current_denies()
1192
1193
This method takes no arguments. It returns the current 'deny' list.
1194
1195
=cut
1196
1197
sub current_denies
1198
{
1199
#
1200
# takes no arguments
1201
#
1202
# returns a list of the people currently on the "deny" list
1203
#
1204
0
0
1
my $imsg = shift @_;
1205
1206
0
return @ {$imsg->{'deny'}};
0
1207
}
1208
1209
#*********************************************************
1210
# ACCESS PERMISSION OPTIONS
1211
#
1212
# these functions affect the users that are permitted to
1213
# see you; interfaces are provided for both online and
1214
# offline specification of permissions
1215
1216
=pod
1217
1218
=head2 $aim->im_permit($user1[, $user2[, ...]])
1219
1220
This method should only be called B. It adds all
1221
arguments to the current permit list and deletes the current deny
1222
list. It also sets the permit mode to 'permit some'.
1223
1224
If you would like to do this while online, use the C
1225
method instead.
1226
1227
=cut
1228
1229
sub im_permit
1230
{
1231
#
1232
# takes at least one argument
1233
#
1234
# each arg is one person to be added
1235
# to the user's permit list. If a permit
1236
# list is used, only people on the permit
1237
# list will be allowed
1238
#
1239
0
0
1
my $imsg = shift @_;
1240
0
$imsg->{'permit_mode'} = 3;
1241
# if we permit, we can't deny
1242
0
$imsg->{'deny'} = [];
1243
1244
0
0
unless (defined $_[0])
1245
{
1246
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
1247
0
return undef;
1248
}
1249
1250
0
my @norm_permits;
1251
1252
0
foreach $permit (@_)
1253
{
1254
0
my $norm_permit = $imsg->norm_uname($permit);
1255
0
unshift @norm_permits, $norm_permit;
1256
}
1257
1258
0
my %union;
1259
1260
0
foreach $e (@norm_permits, @{ $imsg->{'permit'}})
0
1261
{
1262
0
$union{$e}++;
1263
}
1264
1265
0
@{ $imsg->{'permit'}} = keys %union;
0
1266
}
1267
1268
=pod
1269
1270
=head2 $aim->im_deny($user1[, $user2[, ...]])
1271
1272
This method should only be called B. It adds all
1273
arguments to the current deny list and deletes the current permit
1274
list. It also sets the permit mode to 'deny some'.
1275
1276
If you would like to do this while online, use the C
1277
method instead.
1278
1279
=cut
1280
1281
sub im_deny
1282
{
1283
#
1284
# takes at least one argument
1285
#
1286
# each arg is one person to be added
1287
# to the user's deny list. If a deny
1288
# list is used, only people on the deny
1289
# list will be denied
1290
#
1291
0
0
1
my $imsg = shift @_;
1292
0
$imsg->{'permit_mode'} = 4;
1293
# if we deny, we can't permit
1294
0
$imsg->{'permit'} = [];
1295
1296
0
0
unless (defined $_[0])
1297
{
1298
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
1299
0
return undef;
1300
}
1301
1302
0
my @norm_denies;
1303
1304
0
foreach $deny (@_)
1305
{
1306
0
my $norm_deny = $imsg->norm_uname($deny);
1307
0
unshift @norm_denies, $norm_deny;
1308
}
1309
1310
0
my %union;
1311
1312
0
foreach $e (@norm_denies, @ { $imsg->{'deny'}})
0
1313
{
1314
0
$union{$e}++;
1315
}
1316
1317
0
@ { $imsg->{'deny'}} = keys %union;
0
1318
}
1319
1320
=pod
1321
1322
=head2 $aim->add_im_permit($user1[, $user2[, ...]])
1323
1324
This is the method that should be called if you are online and wish to
1325
add users to the permit list. It will, as a consequence, delete the
1326
current deny list and set the current mode to 'permit some'.
1327
1328
=cut
1329
1330
sub add_im_permit
1331
{
1332
#
1333
# takes at least one argument
1334
#
1335
# each argument is added to the permit
1336
# list. If a permit list is used, only
1337
# the people on the permit list will
1338
# be allowed.
1339
#
1340
# this should only be called after signon is completed
1341
# if you want to do permit before then, use im_permit
1342
#
1343
0
0
1
my $imsg = shift @_;
1344
1345
0
0
return undef unless (defined $imsg->im_permit(@_));
1346
1347
0
$imsg->toc_set_config();
1348
}
1349
1350
=pod
1351
1352
=head2 $aim->add_im_deny($user1[, $user2[, ...]])
1353
1354
This is the method that should be used if you are online and wish to
1355
add users to the deny list. It will, as a consequence, delete the
1356
current permit list and set the current mode to 'deny some'.
1357
1358
=cut
1359
1360
sub add_im_deny
1361
{
1362
#
1363
# takes at least one argument
1364
#
1365
# each argument is added to the deny
1366
# list. If a deny list is used, only
1367
# the people in the deny list will be
1368
# banned
1369
#
1370
# this should be called after signon is completed
1371
# if you want to do deny before then, use im_deny
1372
#
1373
0
0
1
my $imsg = shift @_;
1374
1375
0
0
return undef unless (defined $imsg->im_deny(@_));
1376
1377
0
$imsg->toc_set_config();
1378
}
1379
1380
=pod
1381
1382
=head2 $aim->im_deny_all()
1383
1384
This method should be called only B. It will delete
1385
both the permit and deny list and set the mode to 'deny all'.
1386
1387
=cut
1388
1389
sub im_deny_all
1390
{
1391
#
1392
# takes no arguments
1393
#
1394
# sets mode to deny all
1395
#
1396
0
0
1
my $imsg = shift @_;
1397
0
$imsg->{'permit_mode'} = 2;
1398
1399
# clear the permit and deny lists
1400
0
$imsg->{'permit'} = [];
1401
0
$imsg->{'deny'} = [];
1402
}
1403
1404
=pod
1405
1406
=head2 $aim->im_permit_all()
1407
1408
This method should be called only B. It will delete
1409
both the permit and deny list and set the mode to 'permit all'.
1410
1411
=cut
1412
1413
sub im_permit_all
1414
{
1415
#
1416
# takes no arguments
1417
#
1418
# sets mode to allow all
1419
#
1420
0
0
1
my $imsg = shift @_;
1421
0
$imsg->{'permit_mode'} = 1;
1422
1423
0
$imsg->{'permit'} = [];
1424
0
$imsg->{'deny'} = [];
1425
}
1426
1427
=pod
1428
1429
=head2 $aim->add_im_deny_all()
1430
1431
This is the method that should be used if you are online and wish to
1432
go into 'deny all' mode. It will also delete both the permit and deny
1433
lists.
1434
1435
=cut
1436
1437
sub add_im_deny_all
1438
{
1439
#
1440
# takes no arguments
1441
#
1442
# sets mode to deny all
1443
#
1444
# use this only when connected; otherwise,
1445
# if you want to set before connecting, use
1446
# im_deny_all
1447
#
1448
0
0
1
my $imsg = shift @_;
1449
1450
0
$imsg->im_deny_all;
1451
1452
0
my $aida_message = $imsg->toc_format_msg('toc_add_permit');
1453
1454
1455
0
0
return undef unless (defined ($imsg->send_sflap_packet($SFLAP_TYPE_DATA, $aida_message, 0, 0)));
1456
1457
0
0
if ($imsg->{'allow_srv_settings'})
1458
{
1459
0
$imsg->toc_set_config;
1460
}
1461
}
1462
1463
=pod
1464
1465
=head2 $aim->add_im_permit_all()
1466
1467
This is the method that should be used if you are online and wish to
1468
go into 'permit all' mode. It will also delete both the permit and
1469
deny lists.
1470
1471
=cut
1472
1473
sub add_im_permit_all
1474
{
1475
#
1476
# takes no arguments
1477
#
1478
# sets mode to allow all
1479
#
1480
# use this only when connected; otherwise,
1481
# if you want to set before connecting, use
1482
# im_permit_all
1483
#
1484
0
0
1
my $imsg = shift @_;
1485
1486
0
$imsg->im_permit_all;
1487
1488
0
my $aipa_message = $imsg->toc_format_msg('toc_add_deny');
1489
1490
1491
0
0
return undef unless (defined ($imsg->send_sflap_packet($SFLAP_TYPE_DATA, $aipa_message, 0, 0)));
1492
1493
0
0
if ($imsg->{'allow_srv_settings'})
1494
{
1495
0
$imsg->toc_set_config;
1496
}
1497
}
1498
1499
sub toc_set_config
1500
{
1501
#
1502
# takes no arguments
1503
#
1504
# sets the config on the server
1505
# so that it is carried from session
1506
# to session by the server
1507
#
1508
# this is called at signon and
1509
# after each call to add_im_buddies
1510
# or remove_im_buddies
1511
#
1512
# In V1.6, this function was modified so that
1513
# if there are no currently defined buddies,
1514
# the current user is set as a buddy in group
1515
# "Me". This is necessary because an empty
1516
# buddy list will cause signon to fail.
1517
#
1518
# returns undef on error
1519
#
1520
0
0
0
my $imsg = shift @_;
1521
1522
0
my $tsc_config_info;
1523
my $tsc_packet;
1524
0
my $tsc_permit_mode = $imsg->{'permit_mode'};
1525
1526
0
0
if (scalar(keys %{$imsg->{'buddies'}}))
0
1527
{
1528
0
foreach $group (keys %{$imsg->{'buddies'}})
0
1529
{
1530
0
my $aob_message = $imsg->toc_format_msg('toc_add_buddy', $group, @ { $ { $imsg->{'buddies'} } {$group} });
0
0
1531
1532
0
0
return undef unless (defined ($imsg->send_sflap_packet($SFLAP_TYPE_DATA, $aob_message, 0, 0)));
1533
1534
0
0
if ($imsg->{'allow_srv_settings'})
1535
{
1536
0
$tsc_config_info .= "g $group\n";
1537
1538
0
foreach $buddy (@ { $ { $imsg->{'buddies'} } {$group} })
0
0
1539
{
1540
0
$tsc_config_info .= "b $buddy\n";
1541
}
1542
}
1543
}
1544
}
1545
else
1546
{
1547
0
my $aob_message = $imsg->toc_format_msg('toc_add_buddy', 'Me', $imsg->{'username'});
1548
0
0
return undef unless (defined ($imsg->send_sflap_packet($SFLAP_TYPE_DATA, $aob_message, 0, 0)));
1549
}
1550
1551
0
0
if (scalar @ { $imsg->{'permit'} })
0
1552
{
1553
0
my $aip_message = $imsg->toc_format_msg('toc_add_permit', @ { $imsg->{'permit'} });
0
1554
1555
0
0
return undef unless (defined ($imsg->send_sflap_packet($SFLAP_TYPE_DATA, $aip_message, 0, 0)));
1556
1557
0
0
if ($imsg->{'allow_srv_settings'})
1558
{
1559
0
foreach $permit (@ { $imsg->{'permit'} })
0
1560
{
1561
0
$tsc_config_info .= "p $permit\n";
1562
}
1563
}
1564
}
1565
1566
0
0
if (scalar @ { $imsg->{'deny'} })
0
1567
{
1568
0
my $aid_message = $imsg->toc_format_msg('toc_add_deny', @_);
1569
1570
1571
0
0
return undef unless (defined ($imsg->send_sflap_packet($SFLAP_TYPE_DATA, $aid_message, 0, 0,)));
1572
1573
0
0
if ($imsg->{'allow_srv_settings'})
1574
{
1575
0
foreach $deny (@ { $imsg->{'deny'} })
0
1576
{
1577
0
$tsc_config_info .= "d $deny\n";
1578
}
1579
}
1580
}
1581
1582
0
0
if ($imsg->{'allow_srv_settings'})
1583
{
1584
0
$tsc_config_info .= "m $tsc_permit_mode\n";
1585
0
$tsc_config_info = "{" . $tsc_config_info . "}";
1586
1587
0
$tsc_packet = 'toc_set_config ' . $tsc_config_info . "\0";
1588
1589
0
0
return undef unless (defined $imsg->send_sflap_packet($SFLAP_TYPE_DATA, $tsc_packet, 1, 1));
1590
}
1591
}
1592
1593
=pod
1594
1595
=head2 $aim->toc_evil($user, $anon)
1596
1597
This method will apply 'evil' to the specified user C<$user>. If
1598
C<$anon> evaluates to true, the evil will be done anonymously.
1599
1600
=cut
1601
1602
sub toc_evil
1603
{
1604
#
1605
# takes two arguments
1606
#
1607
# the first argument is the
1608
# username to evil
1609
# the second argument should be
1610
# 1 if the evil should be sent
1611
# anonymously
1612
#
1613
# returns undef if an error occurs
1614
#
1615
0
0
1
my $imsg = shift @_;
1616
0
my $te_user = $_[0];
1617
0
0
my $te_anon = ($_[1] ? 'anon' : 'norm');
1618
1619
0
0
0
unless ((defined $te_user) && (defined $te_anon))
1620
{
1621
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
1622
0
return undef;
1623
}
1624
1625
0
my $te_evil_msg = $imsg->toc_format_msg('toc_evil', $imsg->norm_uname($te_user), $te_anon);
1626
1627
1628
0
0
return undef unless (defined $imsg->send_sflap_packet($SFLAP_TYPE_DATA, $te_evil_msg, 0, 0));
1629
}
1630
1631
=pod
1632
1633
=head2 $aim->toc_chat_join($exchange, $room_name)
1634
1635
This method will join the chat room specified by C<$exchange> and
1636
C<$room_name>. Currently, the only valid value for C<$exchange> is 4.
1637
1638
See the B manpage included with this package for more
1639
information on chatting.
1640
1641
=cut
1642
1643
sub toc_chat_join
1644
{
1645
#
1646
# takes two arguments
1647
#
1648
# exchange : the chat room exchange number to use
1649
# room_name : the name of the room to join
1650
#
1651
# returns undef on error
1652
#
1653
# this function does not get the chat room ID;
1654
# that is handled when the server sends back the
1655
# CHAT_JOIN packet, and we have a handler for that
1656
# in the incoming handler
1657
#
1658
0
0
1
my $imsg = shift @_;
1659
0
my $tcj_exchange = $_[0];
1660
0
my $tcj_room_name = $_[1];
1661
1662
0
$tcj_room_name =~ s/\s+/ /g;
1663
1664
1665
0
0
0
unless ((defined $tcj_exchange) && (defined $tcj_room_name))
1666
{
1667
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
1668
0
return undef;
1669
}
1670
1671
0
my $tcj_message = $imsg->toc_format_msg('toc_chat_join', $tcj_exchange, $tcj_room_name);
1672
1673
1674
1675
0
0
return undef unless (defined ($imsg->send_sflap_packet($SFLAP_TYPE_DATA, $tcj_message, 0, 0)));
1676
}
1677
1678
=pod
1679
1680
=head2 $aim->toc_chat_send($roomid, $message)
1681
1682
This method will send the message C<$message> to the room C<$roomid>
1683
(which should be the room ID provided by the server in response to a
1684
toc_chat_join or toc_accept_invite).
1685
1686
You will receive this message back from the server as well, so your UI
1687
does not have to handle this message in a special way.
1688
1689
=cut
1690
1691
sub toc_chat_send
1692
{
1693
#
1694
# takes two arguments
1695
#
1696
# roomid : the chat room ID as returned by the CHAT_JOIN server message
1697
# message: the message to send to the chat room
1698
#
1699
# no mirroring is necessary; the message will come to you by way of the
1700
# server, so you'll see your own message automatically
1701
#
1702
# returns undef on error
1703
#
1704
0
0
1
my $imsg = shift @_;
1705
0
my $tcs_roomid = $_[0];
1706
0
my $tcs_msgtext = $_[1];
1707
1708
0
0
0
unless ((defined $tcs_roomid) && (defined $tcs_msgtext))
1709
{
1710
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
1711
0
return undef;
1712
}
1713
1714
0
my $tcs_message = $imsg->toc_format_msg('toc_chat_send', $tcs_roomid, $tcs_msgtext);
1715
1716
1717
0
0
return undef unless (defined ($imsg->send_sflap_packet($SFLAP_TYPE_DATA, $tcs_message, 0, 0)));
1718
}
1719
1720
=pod
1721
1722
=head2 $aim->toc_chat_whisper($roomid, $dstuser, $message)
1723
1724
This method sends the message C<$message> to C<$dstuser> in the room
1725
C<$roomid>.
1726
1727
The server will B send you a copy of this message, so your user
1728
interface should have a special case for displaying outgoing whispers.
1729
1730
=cut
1731
1732
sub toc_chat_whisper
1733
{
1734
#
1735
# takes three arguments:
1736
#
1737
# roomid : the chat room ID as returned by the CHAT_JOIN server message
1738
# dstuser: the user to whom the whisper should be directed
1739
# message: the message to send to the user as a whisper
1740
#
1741
# you should mirror this to your UI if you want to see it go there as well,
1742
# because the server will not send you a copy of this message as it does with
1743
# regular chat messages.
1744
#
1745
0
0
1
my $imsg = shift @_;
1746
0
my $tcw_roomid = $_[0];
1747
0
my $tcw_dstuser = $_[1];
1748
0
my $tcw_msgtext = $_[2];
1749
1750
0
0
0
unless ((defined $tcw_roomid) && (defined $tcw_dstuser) && (defined $tcw_msgtext))
0
1751
{
1752
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
1753
0
return undef;
1754
}
1755
1756
0
my $tcw_message = $imsg->toc_format_msg('toc_chat_whisper', $tcw_roomid, $imsg->norm_uname($tcw_dstuser), $tcw_msgtext);
1757
1758
1759
0
0
return undef unless (defined ($imsg->send_sflap_packet($SFLAP_TYPE_DATA, $tcs_message, 0, 0)));
1760
}
1761
1762
=pod
1763
1764
=head2 $aim->toc_chat_evil($roomid, $dstuser, $anon)
1765
1766
This will apply evil to the user C<$dstuser> in room C<$room>. If
1767
C<$anon> evaluates to true, it will be applied anonymously.
1768
1769
Please note that this functionality is currently disabled by the TOC
1770
servers.
1771
1772
=cut
1773
1774
sub toc_chat_evil
1775
{
1776
#
1777
# takes three arguments:
1778
#
1779
# roomid : the chat room ID as returned by the CHAT_JOIN server message
1780
# dstuser: the user that should be eviled
1781
# isanon : should be 1 if the evil should be registered anonymously
1782
#
1783
# returns undef on error
1784
#
1785
# the chat evil functionality is currently disabled at the server end
1786
#
1787
0
0
1
my $imsg = shift @_;
1788
0
my $tce_roomid = $_[0];
1789
0
my $tce_dstuser = $_[1];
1790
0
0
my $tce_anon = ($_[2] ? 'anon' : 'norm');
1791
1792
0
0
0
unless ((defined $tce_roomid) && (defined $tce_dstuser) && (defined $tce_anon))
0
1793
{
1794
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
1795
0
return undef;
1796
}
1797
1798
0
my $tce_message = $imsg->toc_format_msg('toc_chat_evil', $tce_roomid, $imsg->norm_uname($tce_dstuser), $tce_anon);
1799
1800
1801
0
0
return undef unless (defined ($imsg->send_sflap_packet($SFLAP_TYPE_DATA, $tce_message, 0, 0)));
1802
}
1803
1804
=pod
1805
1806
=head2 $aim->toc_chat_invite($roomid, $msgtext, $buddy1[, $buddy2[, ...]])
1807
1808
This method will invite all users C<$buddy1..$buddyN> to room
1809
C<$roomid> with invitation text C<$msgtext>.
1810
1811
=cut
1812
1813
sub toc_chat_invite
1814
{
1815
#
1816
# takes at least three arguments:
1817
#
1818
# roomid : the chat room ID as returned by the CHAT_JOIN server message
1819
# msgtext: the text of the invitation message
1820
# buddy1...buddyn : the buddies to invite to the room. You can have as many
1821
# as you'd like, up to the max message length (1024)
1822
#
1823
# returns undef on error
1824
#
1825
0
0
1
my $imsg = shift @_;
1826
0
my $tci_roomid = shift @_;
1827
0
my $tci_msgtext = shift @_;
1828
0
my @tci_buddies = @_;
1829
1830
0
0
0
unless ((defined $tci_roomid) && (defined $tci_msgtext) && (@tci_buddies))
0
1831
{
1832
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
1833
0
return undef;
1834
}
1835
1836
0
while (my $tci_tmp_buddy = shift @_)
1837
{
1838
0
push @tci_buddies, $imsg->norm_uname($tci_tmp_buddy);
1839
}
1840
1841
0
my $tci_message = $imsg->toc_format_msg('toc_chat_invite', $tci_roomid, $tci_msgtext, @tci_buddies);
1842
1843
1844
0
0
return undef unless (defined ($imsg->send_sflap_packet($SFLAP_TYPE_DATA, $tci_message, 0, 0)));
1845
}
1846
1847
=pod
1848
1849
=head2 $aim->toc_chat_leave($roomid)
1850
1851
This method will notify the server that you have left room C<$roomid>.
1852
1853
=cut
1854
1855
sub toc_chat_leave
1856
{
1857
#
1858
# takes one argument:
1859
#
1860
# roomid : the room ID as returned by the CHAT_JOIN server message
1861
#
1862
# returns undef on error
1863
#
1864
0
0
1
my $imsg = shift @_;
1865
0
my $tcl_roomid = $_[0];
1866
1867
0
0
unless (defined $tcl_roomid)
1868
{
1869
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
1870
}
1871
1872
0
my $tcl_message = $imsg->toc_format_msg('toc_chat_leave', $tcl_roomid);
1873
1874
1875
0
0
return undef unless (defined ($imsg->send_sflap_packet($SFLAP_TYPE_DATA, $tcl_message, 0, 0)));
1876
}
1877
1878
=pod
1879
1880
=head2 $aim->toc_chat_accept($roomid)
1881
1882
This method accepts a chat invitation to room C<$roomid>. You do not
1883
have to send a C message if you have been invited and
1884
accept with this method.
1885
1886
=cut
1887
1888
sub toc_chat_accept
1889
{
1890
#
1891
# takes one argument:
1892
#
1893
# roomid : the room ID as given by the CHAT_INVITE server message
1894
#
1895
# returns undef on error
1896
#
1897
0
0
1
my $imsg = shift @_;
1898
0
my $tca_roomid = $_[0];
1899
1900
0
0
unless (defined $tca_roomid)
1901
{
1902
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
1903
0
return undef;
1904
}
1905
1906
0
my $tcl_message = $imsg->toc_format_msg('toc_chat_accept', $tca_roomid);
1907
1908
0
0
return undef unless (defined ($imsg->send_sflap_packet($SFLAP_TYPE_DATA, $tcl_message, 0, 0)));
1909
}
1910
1911
=pod
1912
1913
=head2 $aim->toc_get_info($username)
1914
1915
This method requests info on user C<$username>. See B for more
1916
information on what the server returns.
1917
1918
=cut
1919
1920
sub toc_get_info
1921
{
1922
#
1923
# takes one argument:
1924
#
1925
# username: the username of the person on whom to get info
1926
#
1927
# returns undef on error
1928
#
1929
0
0
1
my $imsg = shift @_;
1930
0
my $tgi_username = $_[0];
1931
1932
0
0
unless (defined $tgi_username)
1933
{
1934
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
1935
0
return undef;
1936
}
1937
1938
0
my $tgi_message = $imsg->toc_format_msg('toc_get_info', $tgi_username);
1939
1940
0
0
return undef unless (defined ($imsg->send_sflap_packet($SFLAP_TYPE_DATA, $tgi_message, 0, 0)));
1941
}
1942
1943
=pod
1944
1945
=head2 $aim->toc_set_info($info)
1946
1947
This method sets the information for the current user to the ASCII
1948
text (HTML formatted) contained in C<$info>.
1949
1950
=cut
1951
1952
sub toc_set_info
1953
{
1954
#
1955
# takes one argument:
1956
#
1957
# information : the information of the user as HTML
1958
#
1959
# returns undef on error
1960
#
1961
0
0
1
my $imsg = shift @_;
1962
0
my $tsi_info = $_[0];
1963
1964
0
0
unless (defined $tsi_info)
1965
{
1966
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
1967
0
return undef;
1968
}
1969
1970
0
my $tsi_message = $imsg->toc_format_msg('toc_set_info', $tsi_info);
1971
1972
0
0
return undef unless (defined ($imsg->send_sflap_packet($SFLAP_TYPE_DATA, $tsi_message, 0, 0)));
1973
}
1974
1975
=pod
1976
1977
=head2 $aim->toc_set_away($msg)
1978
1979
This method sets or unsets the away message. If C<$msg> is undefined,
1980
away is unset. Otherwise, away is set with the message in C<$msg>.
1981
1982
=cut
1983
1984
sub toc_set_away
1985
{
1986
#
1987
# takes zero or one arguments:
1988
#
1989
# awaymsg: the away message. If not specified, the away status is unset
1990
#
1991
0
0
1
my $imsg = shift @_;
1992
0
my $tsa_awaymsg = $_[0];
1993
1994
0
my $tsa_message = $imsg->toc_format_msg('toc_set_away', $tsa_awaymsg);
1995
1996
0
0
return undef unless (defined ($imsg->send_sflap_packet($SFLAP_TYPE_DATA, $tsa_message, 0, 0)));
1997
}
1998
1999
=pod
2000
2001
=head2 $aim->toc_get_dir($username)
2002
2003
This method sends a request to the server for directory information on
2004
C<$username>. See B for information on what the server will return.
2005
2006
=cut
2007
2008
sub toc_get_dir
2009
{
2010
#
2011
# takes one argument
2012
#
2013
# username : the username of the person whose dir info to retrieve
2014
#
2015
0
0
1
my $imsg = shift @_;
2016
0
my $tgd_username = $_[0];
2017
2018
0
0
unless (defined $tgd_username)
2019
{
2020
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
2021
0
return undef;
2022
}
2023
2024
0
my $tgd_message = $imsg->toc_format_msg('toc_get_dir', $imsg->norm_uname($tgd_username));
2025
2026
0
0
return undef unless (defined ($imsg->send_sflap_packet($SFLAP_TYPE_DATA, $tgd_message, 0, 0)));
2027
}
2028
2029
=pod
2030
2031
=head2 $aim->toc_set_dir($userinfo)
2032
2033
This method sets the information on the current user to the string
2034
provided as C<$userinfo>. See B for more information on the
2035
format of the C<$userinfo> string.
2036
2037
=cut
2038
2039
sub toc_set_dir
2040
{
2041
#
2042
# takes one argument
2043
#
2044
# userinfo : the user information for the TOC directory. This should be specified as
2045
# "first name":"middle name":"last name":"maiden name":"city":"state":"country":"email":"allow web searches"
2046
#
2047
0
0
1
my $imsg = shift @_;
2048
0
my $tsd_userinfo = $_[0];
2049
2050
0
0
unless (defined $tsd_userinfo)
2051
{
2052
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
2053
0
return undef;
2054
}
2055
2056
0
my $tsd_message = $imsg->toc_format_msg('toc_set_dir', $tsd_userinfo);
2057
2058
0
0
return undef unless (defined ($imsg->send_sflap_packet($SFLAP_TYPE_DATA, $tsd_message, 0, 0)));
2059
}
2060
2061
=pod
2062
2063
=head2 $aim->toc_dir_search($searchstr)
2064
2065
This method will search the directory using C<$searchstr>. See
2066
B for more information on how this string should look.
2067
2068
=cut
2069
2070
sub toc_dir_search
2071
{
2072
#
2073
# takes one argument
2074
#
2075
# searchstr : the string of information to search for. This should be specified as
2076
# "first name":"middle name":"last name":"maiden name":"city":"state":"country":"email"
2077
#
2078
0
0
1
my $imsg = shift @_;
2079
0
my $tds_searchstr = $_[0];
2080
2081
0
0
unless (defined $tds_searchstr)
2082
{
2083
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
2084
0
return undef;
2085
}
2086
2087
0
my $tds_message = $imsg->toc_format_msg('toc_dir_search', $tds_searchstr);
2088
2089
0
0
return undef unless (defined ($imsg->send_sflap_packet($SFLAP_TYPE_DATA, $tds_message, 0, 0)));
2090
}
2091
2092
=pod
2093
2094
=head2 $aim->toc_set_idle($seconds)
2095
2096
This method sets the number of seconds that the client has been idle.
2097
If it is 0, the idle is cleared. Otherwise, the idle is set and the
2098
server will continue to count up the idle time (thus, you need only
2099
call C once in order to become idle).
2100
2101
=cut
2102
2103
sub toc_set_idle
2104
{
2105
#
2106
# takes one argument:
2107
#
2108
# seconds : the number of seconds the user has been idle. use 0 to clear the
2109
# idle counter and stop idle counting. Setting it to any other
2110
# value will make the server set that idle time and continue to increment
2111
# the idle time, so only one is necessary to start idle timing
2112
#
2113
# returns undef on error
2114
#
2115
0
0
1
my $imsg = shift @_;
2116
0
my $tsi_seconds = $_[0];
2117
2118
0
0
unless (defined $tsi_seconds)
2119
{
2120
0
$tsi_seconds = 0;
2121
}
2122
2123
0
my $tsi_message = $imsg->toc_format_msg('toc_set_idle', $tsi_seconds);
2124
2125
0
0
return undef unless (defined ($imsg->send_sflap_packet($SFLAP_TYPE_DATA, $tsi_message, 0, 0)));
2126
}
2127
2128
#*****************************************************
2129
# Module interface/data movement functions
2130
#
2131
# these functions have to do with checking whether input
2132
# is ready and allowing the user to request that we block
2133
# on the filehandles that we have in our select loop
2134
# (including user-added filehandles) until something happens
2135
#*****************************************************
2136
2137
=pod
2138
2139
=head2 $aim->ui_add_fh($filehandle, \&callback)
2140
2141
This method will add a filehandle to the C loop that will be
2142
called with C. If information is found to be on that
2143
filehandle, the callback will be executed. It is the responsibility
2144
of the callback to read the data off the socket.
2145
2146
B
2147
is unreliable at best. Avoid the use of read(), EFHE, and print();
2148
instead, use sysread() and syswrite()>
2149
2150
=cut
2151
2152
sub ui_add_fh
2153
{
2154
#
2155
# takes two arguments:
2156
#
2157
# filehandle : a filehandle to add to the select loop
2158
# this should be a reference to the filehandle (or
2159
# a scalar containing the reference, such as the one
2160
# returned by IO::Socket)
2161
# callback : the callback function to call when data comes
2162
# over the selected filehandle. This function will
2163
# be called with the data that came over the filehandle
2164
# as the argument. This should be passed as a reference
2165
# to the function
2166
#
2167
0
0
1
my $imsg = shift @_;
2168
0
my $fh = $_[0];
2169
0
my $cb = $_[1];
2170
2171
0
0
0
unless ((defined $fh) && (defined $cb))
2172
{
2173
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
2174
0
return undef;
2175
}
2176
2177
0
$imsg->{'sel'}->add($fh);
2178
0
$ { $imsg->{'callbacks'} }{$fh} = $cb;
0
2179
}
2180
2181
=pod
2182
2183
=head2 $aim->ui_del_fh($filehandle)
2184
2185
The filehandle C<$filehandle> will be removed from the C
2186
loop and it will no longer be checked for input nor its callback
2187
activated.
2188
2189
=cut
2190
2191
sub ui_del_fh
2192
{
2193
#
2194
# takes one argument:
2195
#
2196
# filehandle : the filehandle to delete from the select loop
2197
# this should be the same reference or scalar that
2198
# was passed to ui_add_fh
2199
#
2200
0
0
1
my $imsg = shift @_;
2201
0
my $fh = $_[0];
2202
2203
0
0
unless (defined $fh)
2204
{
2205
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
2206
0
return undef;
2207
}
2208
2209
0
$imsg->{'sel'}->remove($fh);
2210
0
delete $ { $imsg->{'callbacks'} }{$fh};
0
2211
}
2212
2213
=pod
2214
2215
=head2 $aim->ui_all_fh()
2216
2217
This method returns a list of all filehandles currently in the
2218
C loop.
2219
2220
=cut
2221
2222
sub ui_all_fh
2223
{
2224
#
2225
# takes no arguments
2226
#
2227
# returns a list of all the current filehandles
2228
# in the select loop
2229
#
2230
0
0
1
my $imsg = shift @_;
2231
2232
0
return $imsg->{'sel'}->handles();
2233
}
2234
2235
=pod
2236
2237
=head2 $aim->ui_exists_fh($filehandle)
2238
2239
This method will return true if C<$filehandle> is in the select loop.
2240
Otherwise, it will return undefined.
2241
2242
=cut
2243
2244
sub ui_exists_fh
2245
{
2246
#
2247
# takes one argument
2248
#
2249
# filehandle : the filehandle to check for existence in
2250
# the select loop
2251
#
2252
# returns a true value if filehandle is in the loop, and
2253
# undefined otherwise
2254
#
2255
0
0
1
my $imsg = shift @_;
2256
0
my $fh = $_[0];
2257
2258
0
return $imsg->{'sel'}->exists($fh);
2259
}
2260
2261
=pod
2262
2263
=head2 $aim->ui_set_callback(\&callback)
2264
2265
This method will change the callback function for the server socket to
2266
the method referenced by \&callback. This allows you to change the
2267
callback from the one specified when the object was created. (Imagine
2268
the possibilities--dynamically created callback functions using
2269
C... mmmm...)
2270
2271
=cut
2272
2273
sub ui_set_callback
2274
{
2275
#
2276
# takes one argument:
2277
#
2278
# callback : a reference to the callback function
2279
# for incoming remote data
2280
#
2281
# to set the callback for a user-defined filehandle,
2282
# use the ui_add_fh function
2283
#
2284
0
0
1
my $imsg = shift @_;
2285
0
my $callback = $_[0];
2286
0
my $im_socket = \$imsg->{'im_socket'};
2287
2288
0
0
unless (defined $callback)
2289
{
2290
0
$main::IM_ERR = $SFLAP_ERR_ARGS;
2291
0
return undef;
2292
}
2293
2294
0
$imsg->{'callback'} = $callback;
2295
}
2296
2297
=pod
2298
2299
=head2 $aim->ui_get_callback($filehandle)
2300
2301
This method returns a reference to the callback associated with
2302
$filehandle, or the callback associated with the server socket if
2303
$filehandle is undefined.
2304
2305
=cut
2306
2307
sub ui_get_callback
2308
{
2309
#
2310
# takes zero or one arguments:
2311
#
2312
# filehandle : the filehandle whose callback should be returned
2313
#
2314
# if filehandle is not specified, the a reference to the callback
2315
# for the server socket is returned
2316
#
2317
0
0
1
my $imsg = shift @_;
2318
0
my $fh = $_[0];
2319
2320
0
0
if (defined $fh)
2321
{
2322
0
return $ { $imsg->{'callbacks'}}{$fh};
0
2323
}
2324
else
2325
{
2326
0
return $imsg->{'callback'};
2327
}
2328
}
2329
2330
=pod
2331
2332
=head2 $aim->ui_dataget($timeout)
2333
2334
This is the workhorse method in this object. When this method is
2335
called, it will go through a single C loop to find if any
2336
filehandles are ready for reading. If $timeout is defined, the
2337
C timeout will be that number of seconds (fractions are OK).
2338
Otherwise, C will block.
2339
2340
For each filehandle that is ready for reading, this function will call
2341
the appropriate callback function. It is the responsibility of the
2342
callback to read the data off the filehandle and handle it
2343
appropriately. The exception to this rule is the server socket, whose
2344
data will be read and passed to the server socket callback function.
2345
All pasrsing of data from the server into edible chunks will be done
2346
for you before the server socket callback function is called. From
2347
there, it is up to to the client program to parse the server responses
2348
appropriately. They will be passed such that each field in the server
2349
response is one argument to the callback (the number of arguments will
2350
be correct). For more information on the information coming from the
2351
server, see B.
2352
2353
This method returns undef on an error (including errors from
2354
callbacks, which should be signified by returning undef) and returns
2355
the number of filehandles that were read otherwise.
2356
2357
=cut
2358
2359
sub ui_dataget
2360
{
2361
#
2362
# takes zero or one arguments:
2363
#
2364
# time : the time in seconds to wait for the selects to return
2365
#
2366
# if time is undef(), then the call will block
2367
#
2368
# for each filehandle that returns something, the matching
2369
# callback function will be called to read the data and handle
2370
# it.
2371
#
2372
# returns undef on error
2373
#
2374
0
0
1
my $imsg = shift @_;
2375
0
my $timeout = $_[0];
2376
0
my $recv_buffer = "";
2377
0
my @ready = ();
2378
0
my $im_socket = \$imsg->{'im_socket'};
2379
2380
0
@ready = $imsg->{'sel'}->can_read($timeout);
2381
2382
0
foreach $rfh (@ready)
2383
{
2384
0
0
if ($rfh == $$im_socket)
2385
{
2386
0
0
return undef unless defined($recv_buffer = $imsg->read_sflap_packet());
2387
0
($tp_type, $tp_tmp) = split(/:/, $recv_buffer, 2);
2388
2389
# pause if we've been told to by the server
2390
0
0
if ($tp_type eq 'PAUSE')
0
0
2391
{
2392
0
$imsg->{'pause'} = 1;
2393
}
2394
# re-run signon if we're getting a new SIGN_ON packet
2395
elsif ($tp_type eq 'SIGN_ON')
2396
{
2397
0
$imsg->signon;
2398
}
2399
# handle CONFIG packets from the server, respecting
2400
# the allow_srv_settings flag from the user
2401
elsif ($tp_type eq 'CONFIG')
2402
{
2403
0
$imsg->set_srv_buddies($tp_tmp);
2404
}
2405
2406
0
&{$imsg->{'callback'}}($tp_type, split(/:/,$tp_tmp,$SERVER_MSG_ARGS{$tp_type}));
0
2407
}
2408
else
2409
{
2410
0
0
return undef unless (&{$ { $imsg->{'callbacks'}}{$rfh}});
0
0
2411
}
2412
}
2413
0
return scalar(@ready);
2414
}
2415
2416
=pod
2417
2418
=head1 ROLLING YOUR OWN
2419
2420
This section deals with usage that deals directly with the server
2421
connection and bypasses the ui_* interface and/or the toc_* interface.
2422
If you are happy calling ui_dataget et al., do not bother reading this
2423
section. If, however, you plan not to use the provided interfaces, or
2424
if you want to know more of what is going on, continue on.
2425
2426
First of all, if you do not plan to use the provided interface to the
2427
server socket, you will need to be able to access the server socket
2428
directly. In order to do this, use $aim-Esrv_socket:
2429
2430
$srv_sock = $aim->srv_socket;
2431
2432
This will return a B to the socket. You will need to
2433
dereference it in order to use it.
2434
2435
In general, however, even if you are rolling your own, you will
2436
probably not need to use C or the like.
2437
C will handle unwrapping the data coming from the
2438
server and will return the payload of the packet as a single scalar.
2439
Using this will give you the data coming from the server in a form
2440
that you can C to get the message and its arguments. In
2441
order to facilitate such splitting, C<%Net::AOLIM::SERVER_MSG_ARGS> is
2442
supplied. For each valid server message,
2443
C<$Net::AOLIM::SERVER_MSG_ARGS{$msg}> will return one less than the
2444
proper number of splits to perform on the data coming from the server.
2445
The intended use is such:
2446
2447
($msg, $rest) = split(/:/, $aim->read_sflap_packet(), 2);
2448
@msg_args = split(/:/, $rest, $Net::AOLIM::SERVER_MSG_ARGS{$msg});
2449
2450
Now you have the server message in C<$msg> and the arguments in
2451
C<@msg_args>.
2452
2453
To send packets to the server without having to worry about making
2454
SFLAP packets, use C. If you have a string to
2455
send to the server (which is not formatted), you would use:
2456
2457
$aim->send_sflap_packet($SFLAP_TYPE_DATA, $message, 0, 0);
2458
2459
The SFLAP types (listed in B are:
2460
2461
$SFLAP_TYPE_SIGNON
2462
$SFLAP_TYPE_DATA
2463
$SFLAP_TYPE_ERROR
2464
$SFLAP_TYPE_SIGNOFF
2465
$SFLAP_TYPE_KEEPALIVE
2466
2467
Most of the time you will use $SFLAP_TYPE_DATA.
2468
2469
If you want to roll your own messages, read the code for
2470
C and you should be able to figure it out. Note
2471
that the header is always supplied by C.
2472
Specifying C will only make C assume
2473
that C<$message> is a preformatted payload. Specifying C<$noterm>
2474
will prevent C from adding a trailing '\0' to the
2475
payload. If it is already formatted, C will ignore
2476
C<$noterm>.
2477
2478
Messages sent to the server should be escaped and formatted properly
2479
as defined in B. C<$aim-Etoc_format_msg> will do just this;
2480
supply it with the TOC command and the arguments to the TOC command
2481
(each as separate strings) and it will return a single string that is
2482
formatted appropriately.
2483
2484
All usernames sent as TOC command arguments must be normalized (see
2485
B). C<$aim-Enorm_uname()> will do just this. Make sure to
2486
normalize usernames before passing them as arguments to
2487
C<$aim-Etoc_format_msg()>.
2488
2489
C performs roasting as defined in B. It is not very
2490
exciting. I do not see why it is that you would ever need to do this,
2491
as C<$aim-Esignon()> handles this for you (and the roasted password is
2492
stored in C<$aim-E{'roastedp'}>). However, if you want to play with
2493
it, there it is.
2494
2495
=head1 EXAMPLES
2496
2497
See the file F for an example of how to interact with
2498
this class.
2499
2500
=head1 FILES
2501
2502
F
2503
2504
A sample client that demonstrates how this object could be used.
2505
2506
=head1 SEE ALSO
2507
2508
See also B.
2509
2510
=head1 AUTHOR
2511
2512
Copyright 2000-02 Riad Wahby EBE All rights reserved
2513
This program is free software. You may redistribute it and/or
2514
modify it under the same terms as Perl itself.
2515
2516
=head1 HISTORY
2517
2518
B<0.01>
2519
2520
Initial Beta Release. (7/7/00)
2521
2522
B<0.1>
2523
2524
First public (CPAN) release. (7/14/00)
2525
2526
B<0.11>
2527
2528
Re-release under a different name with minor changes to the
2529
documentation. (7/16/00)
2530
2531
B<0.12>
2532
2533
Minor modification to fix a condition in which the server's
2534
connection closing could cause an infinite loop.
2535
2536
B<1.0>
2537
2538
Changed the client agent string to TOC1.0 to fix a problem where
2539
connections were sometimes ignored. Also changed the default signon
2540
port to 5198 and the login port to 1234.
2541
2542
B<1.1>
2543
2544
Changed the client agent string again, this time to what seems
2545
like the "correct" format, which is
2546
PROGRAM:$Version info$
2547
Also added the ability to set a login timeout in case the SIGN_ON
2548
packet never comes.
2549
2550
B<1.2>
2551
2552
Fixed a bug in toc_chat_invite that made it ignore some of its
2553
arguments. This should fix various problems with using this
2554
subroutine. Thanks to Mike Golvach for pointing this out.
2555
2556
B<1.3>
2557
2558
Changed (defined @tci_buddies) to (@tci_buddies) in toc_chat_invite.
2559
Fixed a potential infinite loop in set_srv_buddies involving an
2560
off-by-one error in a for() test. Thanks to Bruce Winter for
2561
pointing this out.
2562
2563
B<1.4>
2564
2565
Changed the way that Net::AOLIM sends the login command string
2566
because AOL apparently changed their server software, breaking the
2567
previous implementation. The new method requires that only the
2568
user agent string be in double quotes; all other fields should not
2569
be quoted. Note that this does not affect the user interface at
2570
all---it's all handled internally. Thanks to Bruce Winter, Fred
2571
Frey, Aryeh Goldsmith, and tik for help in tracking down and
2572
fixing this error.
2573
2574
Also added additional checks to read_sflap_packet so that if the
2575
other end of the connection dies we don't go into an infinite
2576
loop. Thanks to Chris Nelson for pointing this out.
2577
2578
B<1.5>
2579
2580
Added a very simple t/use.t test script that just makes sure
2581
the module loads properly.
2582
2583
B<1.6>
2584
2585
Patched around yet another undocumented "feature" of the TOC
2586
protocol---namely, in order to successfully sign on, you must have
2587
at least one buddy in your buddy list. At sign-on, in the absence
2588
of a real buddy list, Net::AOLIM inserts the current user as a
2589
buddy in group "Me." Don't bother removing this buddy, as it
2590
doesn't really exist---as soon as you add any real buddies, this
2591
one will go away. Thanks to Galen Johnson and Jay Luker for
2592
emailing with the symptoms.
2593
2594
B<1.61>
2595
2596
Made a small change to the example.pl script to keep it from
2597
dumping deref warnings. Thanks to an anonymous person who sent
2598
this suggestion through the CPAN bug tracking system.
2599
2600
=cut