ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/Net-XMPP2/lib/Net/XMPP2/Client.pm
Revision: 1.7
Committed: Mon Jun 25 07:56:52 2007 UTC (19 years, 3 months ago) by elmex
Branch: MAIN
Changes since 1.6: +39 -3 lines
Log Message:
sime fixes and changes

File Contents

# Content
1 package Net::XMPP2::Client;
2 use strict;
3 use AnyEvent;
4 use Net::XMPP2::IM::Connection;
5 use Net::XMPP2::Util qw/stringprep_jid prep_bare_jid/;
6 use Net::XMPP2::Namespaces qw/xmpp_ns/;
7 use Net::XMPP2::Event;
8 use Net::XMPP2::IM::Account;
9
10 use XML::Twig;
11
12 sub _dumpxml {
13 my $data = shift;
14 my $t = XML::Twig->new;
15 if ($t->safe_parse ("<deb>$data</deb>")) {
16 $t->set_pretty_print ('indented');
17 $t->print;
18 print "\n";
19 } else {
20 print "[$data]\n";
21 }
22 }
23
24 our @ISA = qw/Net::XMPP2::Event/;
25
26 =head1 NAME
27
28 Net::XMPP2::Client - A XMPP Client abstraction
29
30 =head1 SYNOPSIS
31
32 use Net::XMPP2::Client;
33 use AnyEvent;
34
35 my $j = AnyEvent->condvar;
36
37 my $cl = Net::XMPP2::Client->new;
38 $cl->start;
39
40 $j->wait;
41
42 =head1 DESCRIPTION
43
44 This module tries to implement a straight forward and easy to
45 use API to communicate with XMPP entities. L<Net::XMPP2::Client>
46 handles connections and timeouts and all such stuff for you.
47
48 For more flexibility please have a look at L<Net::XMPP2::Connection>
49 and L<Net::XMPP2::IM::Connection>, they allow you to control what
50 and how something is being sent more precisely.
51
52 =head1 METHODS
53
54 =head2 new (%args)
55
56 Following arguments can be passed in C<%args>:
57
58 =over 4
59
60 =back
61
62 =cut
63
64 sub new {
65 my $this = shift;
66 my $class = ref($this) || $this;
67 my $self = { @_ };
68 bless $self, $class;
69 return $self;
70 }
71
72 =head2 add_account ($jid, $password, $host, $port)
73
74 This method adds a jabber account for connection with the JID C<$jid>
75 and the password C<$password>.
76
77 C<$host> and C<$port> are optional and can be undef. C<$host> overrides the
78 host to connect to.
79
80 Returns 1 on success and undef when the account already exists.
81
82 =cut
83
84 sub add_account {
85 my ($self, $jid, $password, $host, $port) = @_;
86
87 $jid = stringprep_jid $jid;
88 my $bj = prep_bare_jid $jid;
89
90 return if exists $self->{accounts}->{$bj};
91
92 my $acc =
93 $self->{accounts}->{$bj} =
94 Net::XMPP2::IM::Account->new (
95 jid => $jid,
96 password => $password,
97 host => $host,
98 port => $port,
99 );
100
101 $self->update_connections
102 if $self->{started};
103
104 $acc
105 }
106
107 =head2 start ()
108
109 This method initiates the connections to the XMPP servers.
110
111 =cut
112
113 sub start {
114 my ($self) = @_;
115 $self->{started} = 1;
116 $self->update_connections;
117 }
118
119 sub update_connections {
120 my ($self) = @_;
121
122 for my $acc (values %{$self->{accounts}}) {
123 unless ($acc->is_connected) {
124 my $con = $acc->spawn_connection;
125
126 $con->add_forward ($self, sub {
127 my ($con, $self, $ev, @arg) = @_;
128 $self->event ($ev, $acc, @arg);
129 });
130
131 $con->reg_cb (
132 session_ready => sub {
133 my ($con) = @_;
134 $self->event (connected => $acc);
135 0 # do once
136 },
137 debug_recv => sub { print "RRRRRRRRECVVVVVV:\n"; _dumpxml ($_[1]); 1 },
138 debug_send => sub { print "SSSSSSSSENDDDDDD:\n"; _dumpxml ($_[1]); 1 },
139 disconnect => sub {
140 delete $self->{accounts}->{$acc};
141 0
142 }
143 );
144
145 unless ($con->connect) {
146 $self->event (connect_error => "Couldn't connect to ".($acc->jid).": $!");
147 next
148 }
149 $con->init
150 }
151 }
152 }
153
154 =item disconnect ($msg)
155
156 Disconnect all accounts.
157
158 =cut
159
160 sub disconnect {
161 my ($self, $msg) = @_;
162 for my $acc (values %{$self->{accounts}}) {
163 if ($acc->is_connected) { $acc->connection ()->disconnect ($msg) }
164 }
165 }
166
167 =item remove_accounts ($msg)
168
169 Removes all accounts and disconnects.
170
171 =cut
172
173 sub remove_accounts {
174 my ($self, $msg) = @_;
175 for my $acc (keys %{$self->{accounts}}) {
176 my $acca = $self->{accounts}->{$acc};
177 if ($acca->is_connected) { $acca->connection ()->disconnect ($msg) }
178 delete $self->{accounts}->{$acc};
179 }
180 }
181
182 =item remove_account ($acc)
183
184 Removes and disconnects account C<$acc>.
185
186 =cut
187
188 sub remove_account {
189 my ($self, $acc, $reason) = @_;
190 if ($acc->is_connected) {
191 $acc->connection ()->disconnect ($reason);
192 }
193 delete $self->{accounts}->{$acc};
194 }
195
196 =item send_message ($msg, $dest_jid, $src)
197
198 Sends a message to the destination C<$dest_jid>.
199 C<$msg> can either be a string or a L<Net::XMPP2::IM::Message> object.
200 If C<$msg> is such an object C<$dest_jid> is optional, and will, when
201 passed, override the destination of the message.
202
203 C<$src> is optional. It specifies which account to use
204 to send the message. If it is not passed L<Net::XMPP2::Client> will try
205 to find an account itself. First it will look through all rosters
206 to find C<$dest_jid> and if none found it will pick any of the accounts that
207 are connected.
208
209 C<$src> can either be a JID or a L<Net::XMPP2::IM::Account> object as returned
210 by C<add_account> and C<get_account>.
211
212 =cut
213
214 sub send_message {
215 my ($self, $msg, $dest_jid, $src) = @_;
216
217 unless (ref $msg) {
218 $msg = Net::XMPP2::IM::Message->new (body => $msg);
219 }
220
221 if (defined $dest_jid) {
222 my $jid = stringprep_jid $dest_jid
223 or die "send_message: \$dest_jid is not a proper JID";
224 $msg->to ($jid);
225 }
226
227 my $srcacc;
228 if (ref $src) {
229 $srcacc = $src;
230 } elsif (defined $src) {
231 $srcacc = $self->get_account ($src)
232 } else {
233 $srcacc = $self->find_account_for_dest_jid ($dest_jid);
234 }
235
236 unless ($srcacc && $srcacc->is_connected) {
237 die "send_message: Couldn't get connected account for sending"
238 }
239
240 $msg->send ($srcacc->connection)
241 }
242
243 =item get_account ($jid)
244
245 Returns the L<Net::XMPP2::IM::Account> account object for the JID C<$jid>
246 if there is any such account added. (returns undef otherwise).
247
248 =cut
249
250 sub get_account {
251 my ($self, $jid) = @_;
252 $self->{accounts}->{prep_bare_jid $jid}
253 }
254
255 sub get_connected_accounts {
256 my ($self, $jid) = @_;
257 my (@a) = grep $_->is_connected, values %{$self->{accounts}};
258 @a
259 }
260
261 sub find_account_for_dest_jid {
262 my ($self, $jid) = @_;
263
264 my $any_acc;
265 for my $acc (values %{$self->{accounts}}) {
266 next unless $acc->is_connected;
267
268 # take "first" active account
269 $any_acc = $acc unless defined $any_acc;
270
271 my $roster = $acc->connection ()->get_roster;
272 if (my $c = $roster->get_contact ($jid)) {
273 return $acc;
274 }
275 }
276
277 $any_acc
278 }
279
280 sub get_contacts_for_jid {
281 my ($self, $jid) = @_;
282 my @cons;
283 for ($self->get_connected_accounts) {
284 my $roster = $_->connection ()->get_roster ();
285 my $con = $roster->get_contact ($jid);
286 push @cons, $con if $con;
287 }
288 return @cons;
289 }
290
291 =head1 EVENTS
292
293 In the following event descriptions the argument C<$account>
294 is always a L<Net::XMMP2::IM::Account> object.
295
296 All events from L<Net::XMPP2::IM::Connection> are forwarded to the client,
297 only that the first argument for every event is a C<$account> object.
298
299 Aside fom those, these events can be registered on with C<reg_cb>:
300
301 =over 4
302
303 =item connected => $account
304
305 This event is sent when the C<$account> was successfully connected.
306
307 =item connect_error => $account
308
309 This event is emitted when an error occured in the connection process for the
310 account C<$account>.
311
312 =item error => $account
313
314 This event is emitted when any error occured while communicating
315 over the connection to the C<$account> - after a connection was established.
316
317 =back
318
319 =head1 AUTHOR
320
321 Robin Redeker, C<< <elmex at ta-sa.org> >>
322
323 =head1 COPYRIGHT & LICENSE
324
325 Copyright 2007 Robin Redeker, all rights reserved.
326
327 This program is free software; you can redistribute it and/or modify it
328 under the same terms as Perl itself.
329
330 =cut
331
332 1; # End of Net::XMPP2::Client