DJabberd
view release on metacpan or search on metacpan
demo/demo.conf view on Meta::CPAN
### server admin port
AdminPort 5200
### the name of your vhost. Clients must connect with the string:
### username@demo.localhost
<VHost demo.localhost>
### Note that the order of defining plugins matters; Their respective
### ->register() methods are called in the order the classes are
### read, which means if any callbacks are registered, they are executed
### also in that order.
### This is double important if a callback stops the chain; all callbacks
### registered after that one will not be executed!
### A base plugin to set up the demo application.
### It sets the below bot to be your buddy at
### start up, and intercept any messages sent
### to the bot so it can answer them
<Plugin DJabberd::Plugin::Demo />
### PLAIN and LOGIN send user's password in clear,
### you should really use that only if you also enable StartTLS
demo/lib/DJabberd/Plugin/Demo.pm view on Meta::CPAN
# use Djabberd::Callback;
# use DJabberd::Bot::Demo;
# use DJabberd::Subscription;
# use DJabberd::RosterStorage;
### initialize a logger
our $logger = DJabberd::Log->get_logger();
### register our plugin. we don't need to do any actions now, but we're
### registering two hooks to be called on certain events. Hooks are implemented
### using callbacks. To see which hooks are available, read 'DJabberd::HookDocs'.
### To see how callbacks work, see 'DJabberd::Callback'.
sub register {
my($self, $vhost) = @_;
### when the client asks for the roster, call this hook first. This allows
### us to manipulate the roster before the client sees it.
$vhost->register_hook("RosterGet", \&hook_on_roster_get);
### when we get any incoming messages, call this hook first. This allows us
### to dispatch any messages for our bot to the bot object
$vhost->register_hook("switch_incoming_client", \&hook_switch_incoming_client);
demo/lib/DJabberd/Plugin/Demo.pm view on Meta::CPAN
### pretty print message showing us that the linking worked
$logger->debug( "Automatically linked ". $ritem->jid .' to '.
$jid->as_bare_string );
},
});
### Update the roster to add the bot (as described in $ritem) to the
### client (as described in $jid). Will call callback $rs_cb when done.
$rs->addupdate_roster_item( $rs_cb, $jid, $ritem );
### callbacks have the possiblity to stop the callback chain from
### continuing, by either throwing an error or telling the callback
### mechanism it is done. In our case, we want the chain to continue.
### See DJabberd::HookDocs for details on this.
$cb->decline;
}
### hook to call when an event comes in
sub hook_switch_incoming_client {
### our arguments are:
### $vhost: The vhost object the client connected to. See DJabberd::VHost
-- allow a fast path when bulk sending tons of messages (like hundreds of unavailable stanzas
on disconnect): allow a means to, given a set of full/bare (at least bare) JIDs, filter out
the ones to be known not available. (for instance, local/cluster
ones, where we're the authority on their presence).
-- can we reuse s2s connections in both directions? Our code doesn't, but worse,
I don't think it'd even allow other people to try and do it to us. What does spec say?
-- s2s and client timeouts
-- cleanup/unifiy callbacks.... error vs. fail, on_data vs set vs loaded, etc...
give them types?
-- debian install guide.
-- debian packaging
-- $stanza->process and $stanza->deliver take a $conn, but
now that stanzas always know their connection, that
parameter is kinda useless. remove them all?
-- actually, we should also store a non-weak vhost ref
-- need to write some tests for components
-- need a better API for components so they aren't so ugly. maybe just a nice subclass?
-- make Component subclass that implements JEP-0114
-- privsep for security and scalability
-- network read eval should do something different on xml versus perl errors
maybe another eval around callbacks that cleans up the callback and then propagates
separate logfile for our errors versus client errors
-- timer that runs every x seconds cleaning up an array of weakrefs to callbacks that are still active
and then put the callback start time in the object, so we can force clean up of callbacks
-- SASL doesn't support ANONYMOUS or EXTERNAL
lib/DJabberd/Agent.pm view on Meta::CPAN
</Plugin>
It is also possible to use an instance directly as an object, to delegate stanza handling
from another delivery plugin:
my $agent = MyAgent->new(
message => "Kumquats are groovy!",
);
$agent->handle_stanza($vhost, $stanza);
In this case, the caller will need to handle the delivery hook callbacks itself
in an appropriate manner, but it can be assumed that a call to C<handle_stanza>
will always "deliver" the stanza in some sense.
=head1 DESCRIPTION
This module is the basis for several other higher-level DJabberd classes which provide
an API for creating software agents that communicate over XMPP. This includes components
which serve an entire domain (see L<DJabberd::Component>) and bot-like nodes which
respond only to a specific node name in a domain (see L<DJabberd::Agent::Node>).
lib/DJabberd/HookDocs.pm view on Meta::CPAN
$hook{'filter_incoming_client'} = {};
$hook{'switch_incoming_client'} = {};
$hook{'filter_incoming_server'} = {};
$hook{'switch_incoming_server'} = {};
$hook{'GetPassword'} = {
des => "Lookup a user's plaintext password",
args => [ "username" => '$username', "conn" => 'Connection', ],
callbacks => {
set => ['password'],
},
};
$hook{'CheckCleartext'} = {
des => "Check a user's plaintext password",
args => [ "username" => '$username', "conn" => 'Connection', 'password' => '$password', ],
callbacks => {
accept => [],
reject => [],
},
};
$hook{'CheckDigest'} = {
des => "Check the non-SASL-auth digest field to see if it matches digest of password+streamid",
args => [ "username" => '$username', "conn" => 'Connection', 'digest' => '$digest', ],
callbacks => {
accept => [],
reject => [],
},
};
$hook{'CheckJID'} = {
des => "Check if this knows about this JID",
args => [ "username" => '$username', "conn" => 'Connection', ],
callbacks => {
accept => [],
reject => [],
},
};
$hook{'pre_stanza_write'} = {
des => "Called before a stanza is written to a user. Default action if all declined is to just deliver it.",
};
$hook{'c2s-iq'} = {};
$hook{'deliver'} = {
args => ['Stanza'],
};
$hook{'RosterGet'} = {
args => ['JID'],
callbacks => {
set_roster => [ 'Roster' ],
},
des => "Retrieve user JID's roster.",
};
$hook{'RosterRemoveItem'} = {
args => ['RosterItem'],
des => "Remove an provided RosterItem from connection's roster.",
};
lib/DJabberd/HookDocs.pm view on Meta::CPAN
$hook{'ConnectionClosing'} = {
args => ['Connection'],
callback => {
done => {},
},
des => "Gets called when a connection is in closing state, you can't do anything but let it fall through",
};
# HandleStanza hook is designed to allow plugins to support and respond to additional stanza types.
# Recipients of the HandleStanza hook must execute thier callbacks synchonously (blocking),
# or else we will fall though to the unsupported-stanza-type stream error.
# This make makes sense, because handling the hook should be a very simple operation:
# simply provide a class name that implements the processing of the stanza.
# The actual processing will happen via call to 'process' (should be overriden in class provided).
$hook{'HandleStanza'} = {
args => ['Node', 'Stanza'],
callback => {
handle => [ 'class' ]
},
des => "When recieving an unknown stanza, one handler must run 'handle' callback with the class to bless stanza to or result is stream error.",
};
# SendFeatures hook is designed to allow plugins to send additional items in the stream:features stanza to clients.
# Recipients of the SendFeatures hook must execute thier callbacks synchonously (blocking),
# or else we will fall though to sending only the default features.
$hook{'SendFeatures'} = {
args => ['Connection'],
callback => {
stanza => [ 'xml_string' ]
},
des => "When features stanza is sent to the client right after stream start, adds extra xml to the contents of features.",
};
$hook{'GetSASLManager'} = {
des => "return a SASL Manager object for handling SASL negotiation",
args => [ "conn" => 'Connection' ],
callbacks => {
get => [],
},
};
1;
lib/DJabberd/VHost.pm view on Meta::CPAN
$self->{roster_cache}{$barestr} = $roster;
# upon connect there are three immediate requests of a user's
# roster, then pretty much never again, so we keep it cached 5 seconds,
# then discard it.
Danga::Socket->AddTimer(5.0, sub {
delete $self->{roster_cache}{$barestr};
});
# call all the on-success items, but deleting the current list
# first, lest any of the callbacks load more roster items
delete $self->{roster_wanters}{$barestr};
my $done = 0;
foreach my $li (@$list) {
$li->[0]->($roster);
$done = 1 if $roster->inc_cache_gets >= 3;
}
# if they've used it three times, they're done with
# the initial roster, probes, and broadcast, so drop
# it early, not waiting for 5 seconds.
if ($done) {
delete $self->{roster_cache}{$barestr};
}
},
},
fallback => sub {
# call all the on-fail items, but deleting the current list
# first, lest any of the callbacks load more roster items
delete $self->{roster_wanters}{$barestr};
foreach my $li (@$list) {
$li->[1]->() if $li->[1];
}
});
}
# $jidarg can be a $jid for now. future: arrayref of jid objs
# $cb is $cb->($map) where $map is hashref of fulljidstr -> $presence_stanza_obj
sub check_presence {
t/hookchain.t view on Meta::CPAN
baz => sub {
$outside = "baz!\n";
},
},
fallback => sub {
print "fallback.\n";
});
}
is($track_obj, undef, "ref in args destroyed");
# testing an object in the callbacks being destroyed
{
my $obj = {};
$track_obj = \$obj;
weaken($track_obj);
$vhost->run_hook_chain(phase => "Foo",
args => [ "arg1", "arg2" ],
methods => {
bar => sub {
$outside = "bar $obj!\n";
},
baz => sub {
$outside = "baz $obj!\n";
},
},
fallback => sub {
print "fallback.\n";
});
}
is($track_obj, undef, "ref in callbacks destroyed");
# testing an object in the fallback being destroyed
{
my $obj = {};
$track_obj = \$obj;
weaken($track_obj);
$vhost->run_hook_chain(phase => "Foo",
args => [ "arg1", "arg2" ],
methods => {
( run in 0.331 second using v1.01-cache-2.11-cpan-9b1e4054eb1 )