ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Net-XMPP2/lib/Net/XMPP2/Ext/RegisterForm.pm
Revision: 1.8
Committed: Thu Jul 26 19:45:13 2007 UTC (19 years, 2 months ago) by elmex
Branch: MAIN
Changes since 1.7: +114 -29 lines
Log Message:
Finally implemented the last parts of in band registration.
Let me call it 'in band frustration'!

File Contents

# User Rev Content
1 elmex 1.5 package Net::XMPP2::Ext::RegisterForm;
2 elmex 1.1 use strict;
3     use Net::XMPP2::Util;
4     use Net::XMPP2::Namespaces qw/xmpp_ns/;
5 elmex 1.5 use Net::XMPP2::Ext::DataForm;
6 elmex 1.6 use Net::XMPP2::Ext::OOB;
7 elmex 1.1
8     =head1 NAME
9    
10 elmex 1.5 Net::XMPP2::Ext::RegisterForm - Handle for in band registration
11 elmex 1.1
12     =head1 SYNOPSIS
13    
14     my $con = Net::XMPP2::Connection->new (...);
15     ...
16     $con->do_in_band_register (sub {
17     my ($form, $error) = @_;
18     if ($error) { print "ERROR: ".$error->string."\n" }
19     else {
20     if ($form->type eq 'simple') {
21     if ($form->has_field ('username') && $form->has_field ('password')) {
22     $form->set_field (
23     username => 'test',
24     password => 'qwerty',
25     );
26     $form->submit (sub {
27     my ($form, $error) = @_;
28     if ($error) { print "SUBMIT ERROR: ".$error->string."\n" }
29     else {
30     print "Successfully registered as ".$form->field ('username')."\n"
31     }
32     });
33     } else {
34     print "Couldn't fill out the form: " . $form->field ('instructions') ."\n";
35     }
36     } elsif ($form->type eq 'data_form' {
37     my $dform = $form->data_form;
38     ... fill out the form $dform (of type Net::XMPP2::DataForm) ...
39     $form->submit_data_form ($dform, sub {
40     my ($form, $error) = @_;
41     if ($error) { print "DATA FORM SUBMIT ERROR: ".$error->string."\n" }
42     else {
43     print "Successfully registered as ".$form->field ('username')."\n"
44     }
45     })
46     }
47     }
48     });
49    
50     =head1 DESCRIPTION
51    
52     This module represents an in band registration form
53     which can be filled out and submitted.
54    
55     You can get an instance of this class only by requesting it
56     from a L<Net::XMPP2::Connection> by calling the C<request_inband_register_form>
57     method.
58    
59 elmex 1.8 =over 4
60    
61     =item B<new (%args)>
62    
63     Usually the constructor takes no arguments except when you want to construct
64     an answer form, then you call the constructor like this:
65    
66     If you have legacy form fields as a hash ref in C<$filled_legacy_form>:
67    
68     Net::XMPP2::Ext::RegisterForm (
69     legacy_form => $filled_legacy_form,
70     answered => 1
71     );
72    
73     If you have a data form in C<$answer_data_form>:
74    
75     Net::XMPP2::Ext::RegisterForm (
76     legacy_form => $answer_data_form,
77     answered => 1
78     );
79    
80 elmex 1.1 =cut
81    
82     sub new {
83     my $this = shift;
84     my $class = ref($this) || $this;
85     my $self = bless { @_ }, $class;
86     $self
87     }
88    
89 elmex 1.8 =item B<try_fillout_registration ($username, $password)>
90    
91     This method tries to fill out a form which was received from the
92     other end. It enters the username and password and returns a
93     new L<Net::XMPP2::Ext::RegisterForm> object which is the answer
94     form.
95    
96     B<NOTE:> This function is just a heuristic to fill out a form for automatic
97     registration, but it might fail if the forms are more complex and have
98     required fields that we don't know.
99    
100     Registration without user interaction is theoretically not possible because
101     forms can be different from server to server and require different information.
102     Please also have a look at XEP-0077.
103 elmex 1.4
104 elmex 1.8 Note that if the form is more complicated this method will not work
105     and it's not guranteed that the registration will be successful.
106 elmex 1.4
107 elmex 1.8 Calling this method on a answer form (where C<is_answer_form> returns true)
108     will have an undefined result.
109 elmex 1.4
110 elmex 1.8 =cut
111 elmex 1.4
112     sub try_fillout_registration {
113     my ($self, $username, $password) = @_;
114    
115     my $form;
116     my $nform;
117 elmex 1.6
118 elmex 1.4 if (my $df = $self->get_data_form) {
119     my $af = Net::XMPP2::Ext::DataForm->new;
120     $af->make_answer_form ($df);
121     $af->set_field_value (username => $username);
122     $af->set_field_value (password => $password);
123     $nform = $af;
124    
125     } else {
126     my $frm = $self->get_standard_form_fields;
127     $form = {
128     username => $username,
129     password => $password
130     };
131     }
132    
133     return
134     Net::XMPP2::Ext::RegisterForm->new (
135 elmex 1.6 data_form => $nform,
136     legacy_form => $form,
137     answered => 1
138 elmex 1.4 );
139     }
140    
141 elmex 1.8 =item B<is_answer_form>
142    
143     This method will return a true value if this form was returned by eg.
144     C<try_fillout_registration> or generally represents an answer form.
145    
146     =cut
147    
148 elmex 1.4 sub is_answer_form {
149     my ($self) = @_;
150     $self->{answered}
151     }
152    
153 elmex 1.8 =item B<is_already_registered>
154    
155     This method returns true if the received form
156     were just the current registration data. Basically this method returns
157     true when you are already registered to the server.
158    
159     =cut
160    
161 elmex 1.4 sub is_already_registered {
162 elmex 1.1 my ($self) = @_;
163 elmex 1.7 exists $self->{legacy_form}
164     && exists $self->{legacy_form}->{registered}
165 elmex 1.4 }
166    
167 elmex 1.8 =item B<get_legacy_form_fields>
168 elmex 1.4
169 elmex 1.8 This method returns a hash with the keys being the fields
170     of the legacy form as described in the XML scheme of XEP-0077.
171 elmex 1.6
172 elmex 1.8 If the form contained just nodes the keys will have undef as value.
173 elmex 1.6
174 elmex 1.8 If the form contained also register information, in case C<is_already_registered>
175     returns a true value, the values will contain the strings for the fields.
176 elmex 1.6
177     =cut
178    
179     sub get_legacy_form_fields {
180 elmex 1.4 my ($self) = @_;
181 elmex 1.6 $self->{legacy_form}
182 elmex 1.4 }
183    
184 elmex 1.6 =item B<get_data_form>
185    
186     This method returns the L<Net::XMPP2::Ext::DataForm> that came
187     with the registration response. If no data form was provided by the
188     server this method returns undef.
189    
190     =cut
191    
192 elmex 1.4 sub get_data_form {
193     my ($self) = @_;
194 elmex 1.6 $self->{data_form}
195     }
196    
197    
198     =item B<get_oob>
199    
200     This method returns a hash like the one returned from
201     the function C<url_from_node> in L<Net::XMPP2::Ext::OOB>.
202     It contains the out of band data for this registration form.
203    
204     =cut
205    
206     sub get_oob {
207     my ($self) = @_;
208     $self->{oob}
209 elmex 1.4 }
210    
211 elmex 1.8 sub init_new_form {
212     my ($self, $formnode) = @_;
213    
214     my $df = Net::XMPP2::Ext::DataForm->new;
215     $df->from_node ($formnode);
216     $self->{data_form} = $df;
217     }
218    
219     sub _get_legacy_form {
220     my ($self, $node) = @_;
221    
222     my $form = {};
223    
224     for ($node->nodes) {
225     if ($_->eq_ns ('register')) {
226     $form->{$_->name} = $_->text;
227     }
228     }
229    
230     $form
231     }
232    
233 elmex 1.4 sub init_from_node {
234     my ($self, $node) = @_;
235 elmex 1.1
236 elmex 1.8 if (my (@form) = $node->find_all ([qw/register query/], [qw/data_form x/])) {
237     $self->init_new_form (@form);
238 elmex 1.4 }
239 elmex 1.6 if (my ($xoob) = $node->find_all ([qw/register query/], [qw/oob x/])) {
240     $self->{oob} = Net::XMPP2::Ext::OOB->url_from_node ($xoob);
241     }
242    
243     my $form = $self->_get_legacy_form ($node);
244     $self->{legacy_form} = $form;
245 elmex 1.1 }
246    
247 elmex 1.8 =item B<answer_form_to_simxml>
248    
249     This method returns a list of C<simxml> nodes.
250    
251     =cut
252    
253     sub answer_form_to_simxml {
254     my ($self) = @_;
255    
256     if ($self->{data_form}) {
257     return $self->{data_form}->to_simxml;
258    
259     } else {
260     my @childs;
261    
262     my $lf = $self->get_legacy_form_fields;
263    
264     for (keys %$lf) {
265     push @childs, {
266     ns => 'register',
267     name => $_,
268     childs => [ $lf->{$_} ]
269     }
270     }
271    
272     return @childs;
273     }
274     }
275    
276 elmex 1.1 =head1 AUTHOR
277    
278 elmex 1.2 Robin Redeker, C<< <elmex at ta-sa.org> >>, JID: C<< <elmex at jabber.org> >>
279 elmex 1.1
280     =head1 COPYRIGHT & LICENSE
281    
282     Copyright 2007 Robin Redeker, all rights reserved.
283    
284     This program is free software; you can redistribute it and/or modify it
285     under the same terms as Perl itself.
286    
287     =cut
288    
289     1; # End of Net::XMPP2::RegisterForm