📄 x6787.htm
字号:
>
methods which are available according to namespace. These 'set' methods
available for the <TT
CLASS="LITERAL"
>jabber:iq:register</TT
> namespace
are plentiful and include <TT
CLASS="LITERAL"
>SetName</TT
>, <TT
CLASS="LITERAL"
>SetEmail</TT
>,
<TT
CLASS="LITERAL"
>SetPhone</TT
> and so on. Each method will create a child
tag named after the method (e.g. <TT
CLASS="LITERAL"
>SetName</TT
> will create
a <TT
CLASS="LITERAL"
><name/></TT
> tag and <TT
CLASS="LITERAL"
>SetPhone</TT
>
will create a <TT
CLASS="LITERAL"
><phone/></TT
> tag) and insert the
value passed to the method into the tag.</P
><P
>For example, </P
><P
><PRE
CLASS="SCREEN"
>$query->SetName('DJ Adams');</PRE
></P
><P
>will insert (or amend) a tag in the <TT
CLASS="LITERAL"
><query/></TT
>
thus:</P
><P
><PRE
CLASS="SCREEN"
><iq type='set'>
<query xmlns='jabber:iq:register'>
<TT
CLASS="USERINPUT"
><B
><name>DJ Adams</name></B
></TT
>
</query>
</iq></PRE
></P
><P
>We use <TT
CLASS="LITERAL"
>eval</TT
> to allow us to make our
<TT
CLASS="LITERAL"
>SetXXXX</TT
>
method calls dynamically, according to each fieldname specified.
The <TT
CLASS="LITERAL"
>ucfirst()</TT
> function is used to change the first
character of the fieldname to upper case, to suit the <TT
CLASS="LITERAL"
>SetXXXX</TT
>
method naming conventions.</P
><P
>Once we've added all the fields, we send the complete packet
(<TT
CLASS="LITERAL"
>$iq</TT
>) to the server using the
<TT
CLASS="LITERAL"
>SendAndReceiveWithID()</TT
> method on the connection
(<TT
CLASS="LITERAL"
>$c</TT
>) object. This method is extremely powerful and
does many things for us. It keeps the process of writing small
scripts like this very simple. What is does is: adds a unique
<TT
CLASS="LITERAL"
>id</TT
> attribute to the <TT
CLASS="LITERAL"
><iq/></TT
>
packet, transmits the packet over the XML stream,
<I
CLASS="EMPHASIS"
>and waits for a response</I
>. </P
><P
>"Hey, what about the event-model that we read about?" you might ask. Of
course, Net::Jabber supports an event-model programming style, but for
now we can get away with keeping our code 'procedural' - and short - using
this high-level method which does everything we want. After all, in any
one execution of the script, we only wish to send one packet to the Jabber
server and receive one back. Nothing more complicated than that. </P
><P
>Later scripts will demonstrate the event-model.</P
><P
>The response is stored in <TT
CLASS="LITERAL"
>$result</TT
>, and is itself an
IQ packet, as we expect. So <TT
CLASS="LITERAL"
>$result</TT
> is a handle on
a Net::Jabber::IQ object that we can now manipulate.</P
><P
><PRE
CLASS="SCREEN"
> # Success
if ($result->GetType() eq 'result') {
print "Successful registration\n";
}
# Failure
else {
print "Error: ",
$result->GetErrorCode(),
" (",
$result->GetError(),
")\n";
}
}</PRE
></P
><P
>We check the type of the IQ returned from the server. If it's a 'result':</P
><P
><PRE
CLASS="SCREEN"
>RECV: <iq type='result' id='1'>
<query xmlns='jabber:iq:register'/>
</iq></PRE
></P
><P
>then great - the registration was successful. Otherwise, we can grab
the error code and description from the <TT
CLASS="LITERAL"
><error/></TT
>
element:</P
><P
><PRE
CLASS="SCREEN"
>RECV: <iq type='error'>
<query xmlns='jabber:iq:register'>
<username>dj</username>
<password>secret</password>
</query>
<TT
CLASS="USERINPUT"
><B
><error code='409'>Username Not Available</error></B
></TT
>
</iq></PRE
></P
><P
>using the <TT
CLASS="LITERAL"
>GetError()</TT
> and <TT
CLASS="LITERAL"
>GetErrorCode()</TT
>
methods on the IQ object. </P
><P
>We go through a similar process if there are no further parameters following
the host[:port] specification:</P
><P
><PRE
CLASS="SCREEN"
>else {
# Enquiry:
# Send <iq type='get'><query xmlns='jabber:iq:register'/></iq>
print "[Enquiry] ";
$iq = Net::Jabber::IQ->new();
$iq->SetType('get');
$query = $iq->NewQuery(NS_REGISTER);
$result = $c->SendAndReceiveWithID($iq); </PRE
></P
><P
>The only difference here is that we set the IQ type to 'get', not 'set',
and we don't insert any tags into the <TT
CLASS="LITERAL"
>$query</TT
> object,
before sending the packet off and waiting for a response.</P
><P
><PRE
CLASS="SCREEN"
> # Success
if ($result->GetType() eq 'result') {
$query = $result->GetQuery();
my %contents = $query->GetRegister();
delete $contents{'instructions'};
print "Fields: ", join(', ', keys %contents), "\n";
} </PRE
></P
><P
>If we receive a 'result' type, like this:</P
><P
><PRE
CLASS="SCREEN"
>RECV: <iq type='result'>
<query xmlns='jabber:iq:register'>
<instructions>
Choose a username and password to register with this server.
</instructions>
<name/>
<email/>
<username/>
<password/>
</query>
</iq></PRE
></P
><P
>then we need to extract the fields listed in the
<TT
CLASS="LITERAL"
><query/></TT
> tag and return them to the
user. While the <TT
CLASS="LITERAL"
>NewQuery()</TT
> method creates a new
<TT
CLASS="LITERAL"
><query/></TT
> tag inside an IQ object, the
<TT
CLASS="LITERAL"
>GetQuery()</TT
> method retrieves an existing one, in the
form of a Net::Jabber::Query object whose handle we store in
<TT
CLASS="LITERAL"
>$query</TT
>. We can call the <TT
CLASS="LITERAL"
>GetRegister()</TT
>
method on this query object, which returns a hash of the contents:</P
><P
><PRE
CLASS="SCREEN"
>(
'instructions' => 'Choose a username and password ...',
'name' => undef,
'email' => undef,
'username' => undef,
'password' => undef
)</PRE
></P
><P
>And, after removing the 'instructions', we can display them as the result.</P
><P
>In the case where an error is returned in response to the IQ get (perhaps
no registrations are allowed), we display the error in the same was as
before:</P
><P
><PRE
CLASS="SCREEN"
> # Failure
else {
$query = $result->GetQuery();
print "Error: ",
$result->GetErrorCode(),
" (",
$result->GetError(),
")\n";
}
}</PRE
></P
><P
>When we've finished, we close the connection and exit. Here we also have
the <TT
CLASS="LITERAL"
>usage()</TT
> subroutine defined.</P
><P
><PRE
CLASS="SCREEN"
>$c->Disconnect;
exit;
sub usage {
<<EOF
Usage:
Enquiry: reguser host[:port]
Attempt: reguser host[:port] field1=value1 [fieldN = valueN] ...
EOF
}</PRE
></P
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="JABTDG-CH-6-SECT-5.4.1"
>Using the Script</A
></H2
><P
>The script is very basic, but it gets the job done. It is suitable for
calling from another script, for mass user generation, although you may
wish to modify it so that a connection is not created and destroyed for
every username that needs to be registered. </P
><P
>It also illustrates how simple a Jabber client can be. In this case, the
Net::Jabber libraries mask the bulk of the effort (socket connection,
XML stream negotiation, XML fragment traffic management, and so on).
We'll be making use of this script to create users for our recipes later
on in the book.</P
></DIV
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x6569.htm"
>Prev</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.htm"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="c6941.htm"
>Next</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>User Authentication</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="c6313.htm"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Messages, Presence, and Presence Subscription</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -