Skip to content

Commit fb057a4

Browse files
authored
Merge pull request #55 from toddr-bot/koan.toddr.bot/fix-disconnect-method-safety
fix: guard public API methods against calls while disconnected
2 parents cb8ef32 + b4603c4 commit fb057a4

File tree

2 files changed

+102
-0
lines changed

2 files changed

+102
-0
lines changed

lib/Net/Jabber/Bot.pm

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,11 @@ sub JoinForum {
472472
my $self = shift;
473473
my $forum_name = shift;
474474

475+
if ( !$self->IsConnected ) {
476+
WARN("Cannot join forum '$forum_name': not connected");
477+
return;
478+
}
479+
475480
DEBUG( "Joining $forum_name on " . $self->conference_server . " as " . $self->alias );
476481

477482
$self->jabber_client->MUCJoin(
@@ -498,6 +503,8 @@ sub Process { # Call connection process.
498503
my $self = shift;
499504
my $timeout_seconds = shift;
500505

506+
return if !$self->IsConnected;
507+
501508
#If not passed explicitly
502509
$timeout_seconds = $self->process_timeout if ( !defined $timeout_seconds );
503510

@@ -1140,6 +1147,11 @@ sub ChangeStatus {
11401147
my $presence_mode = shift;
11411148
my $status_string = shift; # (optional)
11421149

1150+
if ( !$self->IsConnected ) {
1151+
WARN("Cannot change status: not connected");
1152+
return 0;
1153+
}
1154+
11431155
$self->jabber_client->PresenceSend( show => $presence_mode, status => $status_string );
11441156

11451157
return 1;
@@ -1157,6 +1169,11 @@ In which case we need another sub for this.
11571169
sub GetRoster {
11581170
my $self = shift;
11591171

1172+
if ( !$self->IsConnected ) {
1173+
WARN("Cannot get roster: not connected");
1174+
return ();
1175+
}
1176+
11601177
my @rosterlist;
11611178
foreach my $jid ( $self->jabber_client->RosterDBJIDs() ) {
11621179
my $username = $jid->GetJID();
@@ -1176,6 +1193,8 @@ sub GetStatus {
11761193
my $self = shift;
11771194
my ($jid) = shift;
11781195

1196+
return "unavailable" if !$self->IsConnected;
1197+
11791198
my $Pres = $self->jabber_client->PresenceDBQuery($jid);
11801199

11811200
if ( !( defined($Pres) ) ) {
@@ -1203,6 +1222,11 @@ sub AddUser {
12031222
my $self = shift;
12041223
my $user = shift;
12051224

1225+
if ( !$self->IsConnected ) {
1226+
WARN("Cannot add user '$user': not connected");
1227+
return;
1228+
}
1229+
12061230
$self->jabber_client->Subscription( type => "subscribe", to => $user );
12071231
$self->jabber_client->Subscription( type => "subscribed", to => $user );
12081232
}
@@ -1217,6 +1241,11 @@ sub RmUser {
12171241
my $self = shift;
12181242
my $user = shift;
12191243

1244+
if ( !$self->IsConnected ) {
1245+
WARN("Cannot remove user '$user': not connected");
1246+
return;
1247+
}
1248+
12201249
$self->jabber_client->Subscription( type => "unsubscribe", to => $user );
12211250
$self->jabber_client->Subscription( type => "unsubscribed", to => $user );
12221251
}

t/07-test_disconnect_public_api.t

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#!perl
2+
3+
use strict;
4+
use warnings;
5+
6+
BEGIN { *CORE::GLOBAL::sleep = sub { }; }
7+
8+
use Test::More tests => 9;
9+
use Net::Jabber::Bot;
10+
11+
use FindBin;
12+
use lib "$FindBin::Bin/lib";
13+
use MockJabberClient;
14+
15+
my $bot_alias = 'make_test_bot';
16+
my $server = 'talk.google.com';
17+
18+
my %forums_and_responses;
19+
$forums_and_responses{'test_forum1'} = [ "jbot:", "" ];
20+
21+
my $bot = Net::Jabber::Bot->new(
22+
server => $server,
23+
conference_server => "conference.$server",
24+
port => 5222,
25+
username => 'test_username',
26+
password => 'test_pass',
27+
alias => $bot_alias,
28+
message_function => sub { },
29+
background_function => sub { },
30+
loop_sleep_time => 5,
31+
process_timeout => 5,
32+
forums_and_responses => \%forums_and_responses,
33+
ignore_server_messages => 1,
34+
ignore_self_messages => 1,
35+
out_messages_per_second => 5,
36+
max_message_size => 1000,
37+
max_messages_per_hour => 100,
38+
forum_join_grace => 0,
39+
);
40+
41+
isa_ok( $bot, "Net::Jabber::Bot" );
42+
ok( $bot->IsConnected(), "Bot starts connected" );
43+
44+
# Disconnect the bot
45+
$bot->Disconnect();
46+
ok( !$bot->IsConnected(), "Bot is disconnected" );
47+
48+
# Test that public API methods don't crash when disconnected.
49+
# Before this fix, each of these would die with:
50+
# "Can't call method ... on an undefined value"
51+
# because jabber_client is undef after Disconnect().
52+
53+
# ChangeStatus should return 0 (failure), not crash
54+
my $status_result = eval { $bot->ChangeStatus("available", "test status") };
55+
ok( !$@, "ChangeStatus does not crash when disconnected" )
56+
or diag("ChangeStatus died: $@");
57+
58+
# GetRoster should return empty list, not crash
59+
my @roster = eval { $bot->GetRoster() };
60+
ok( !$@, "GetRoster does not crash when disconnected" )
61+
or diag("GetRoster died: $@");
62+
is( scalar @roster, 0, "GetRoster returns empty list when disconnected" );
63+
64+
# GetStatus should return 'unavailable', not crash
65+
my $get_status = eval { $bot->GetStatus("someone\@$server") };
66+
ok( !$@, "GetStatus does not crash when disconnected" )
67+
or diag("GetStatus died: $@");
68+
is( $get_status, "unavailable", "GetStatus returns 'unavailable' when disconnected" );
69+
70+
# Process should return undef, not crash
71+
my $process_result = eval { $bot->Process(1) };
72+
ok( !$@, "Process does not crash when disconnected" )
73+
or diag("Process died: $@");

0 commit comments

Comments
 (0)