<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/css" href="http://commons.oreilly.com/wiki/skins/common/feed.css?97"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
	<channel>
		<title>JabChapter 10 - Revision history</title>
		<link>http://commons.oreilly.com/wiki/index.php?title=JabChapter_10&amp;action=history</link>
		<description>Revision history for this page on the wiki</description>
		<language>en</language>
		<generator>MediaWiki 1.11.0</generator>
		<lastBuildDate>Sat, 25 May 2013 18:23:22 GMT</lastBuildDate>
		<item>
			<title>Newacct: /* The Demo::JBook Script */</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=JabChapter_10&amp;diff=26204&amp;oldid=prev</link>
			<description>&lt;p&gt;&lt;span class=&quot;autocomment&quot;&gt;The Demo::JBook Script&lt;/span&gt;&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 01:33, 26 July 2010&lt;/td&gt;
			&lt;/tr&gt;
		&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 389:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 389:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; &lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;   # No arguments: Instructions&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;   # No arguments: Instructions&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;   if (&lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;scalar &lt;/del&gt;@a &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;== 0&lt;/del&gt;) {&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;   if (&lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;!&lt;/ins&gt;@a) {&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; &lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;     # Construct IQ-get in iq:search namespace&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;     # Construct IQ-get in iq:search namespace&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 514:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 514:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; &lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;   $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;/body&amp;amp;gt;&amp;amp;lt;/html&amp;amp;gt;&amp;quot;); $c-&amp;amp;gt;disconnect;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;   $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;/body&amp;amp;gt;&amp;amp;lt;/html&amp;amp;gt;&amp;quot;); $c-&amp;amp;gt;disconnect;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;#160;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt; &lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;   return;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;   return;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; &lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 523:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 523:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;br&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;br&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot;&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;=== Taking Demo::JBook Step by Step === &lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;=== Taking Demo::JBook Step by Step === &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;br&amp;gt;Now that we've got a hold on the&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;br&amp;gt;Now that we've got a hold on the&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;!-- diff cache key wikicontent:diff:version:1.11a:oldid:26203:newid:26204 --&gt;
&lt;/table&gt;</description>
			<pubDate>Mon, 26 Jul 2010 01:33:13 GMT</pubDate>			<dc:creator>Newacct</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:JabChapter_10</comments>		</item>
		<item>
			<title>Newacct at 01:30, 26 July 2010</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=JabChapter_10&amp;diff=26203&amp;oldid=prev</link>
			<description>&lt;p&gt;&lt;/p&gt;
&lt;a href=&quot;http://commons.oreilly.com/wiki/index.php?title=JabChapter_10&amp;amp;diff=26203&amp;amp;oldid=25880&quot;&gt;(Difference between revisions)&lt;/a&gt;</description>
			<pubDate>Mon, 26 Jul 2010 01:30:53 GMT</pubDate>			<dc:creator>Newacct</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:JabChapter_10</comments>		</item>
		<item>
			<title>Newacct at 08:01, 10 December 2009</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=JabChapter_10&amp;diff=25880&amp;oldid=prev</link>
			<description>&lt;p&gt;&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 08:01, 10 December 2009&lt;/td&gt;
			&lt;/tr&gt;
		&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,890:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,890:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;''The JabberRPCRequester script, written in Python''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;''The JabberRPCRequester script, written in Python''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;code&amp;gt;import jabber import xmlrpclib &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;import string &lt;/del&gt;import sys&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;code&amp;gt;import jabber import xmlrpclib import sys&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;Server   = 'qmacro.dyndns.org' Username = 'client' Password = 'pass'&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;Server   = 'qmacro.dyndns.org' Username = 'client' Password = 'pass'&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,896:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,896:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;Method   = 'examples.getCountyName';&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;Method   = 'examples.getCountyName';&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;county   = &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;string.atoi&lt;/del&gt;(sys.argv[1])&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;county   = &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;int&lt;/ins&gt;(sys.argv[1])&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;con = jabber.Client(host=Server) try: con.connect() except IOError, e:&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;con = jabber.Client(host=Server) try: con.connect() except IOError, e:&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,923:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,923:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;code&amp;gt;import jabber import xmlrpclib &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;import string &lt;/del&gt;import sys&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;code&amp;gt;import jabber import xmlrpclib import sys&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/code&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/code&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;we specify a number of parameters:&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;we specify a number of parameters:&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,947:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,947:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;code&amp;gt;county = &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;string.atoi&lt;/del&gt;(sys.argv[1])&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;code&amp;gt;county = &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;int&lt;/ins&gt;(sys.argv[1])&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/code&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/code&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;The method expects an integer, so we convert it directly. This has a&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;The method expects an integer, so we convert it directly. This has a&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;favorable secondary effect when we come to XML-RPC encode the request;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;favorable secondary effect when we come to XML-RPC encode the request;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;if we hadn't called the &amp;lt;tt&amp;gt;&lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;string.atoi&lt;/del&gt;()&amp;lt;/tt&amp;gt; function and left&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;if we hadn't called the &amp;lt;tt&amp;gt;&lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;int&lt;/ins&gt;()&amp;lt;/tt&amp;gt; function and left&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;tt&amp;gt;county&amp;lt;/tt&amp;gt; as a string, this is what the XML-RPC-encoded parcel&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;tt&amp;gt;county&amp;lt;/tt&amp;gt; as a string, this is what the XML-RPC-encoded parcel&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;would have looked like:&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;would have looked like:&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;!-- diff cache key wikicontent:diff:version:1.11a:oldid:25624:newid:25880 --&gt;
&lt;/table&gt;</description>
			<pubDate>Thu, 10 Dec 2009 08:01:54 GMT</pubDate>			<dc:creator>Newacct</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:JabChapter_10</comments>		</item>
		<item>
			<title>Uncopy: content navi added</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=JabChapter_10&amp;diff=25624&amp;oldid=prev</link>
			<description>&lt;p&gt;content navi added&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 14:23, 18 September 2009&lt;/td&gt;
			&lt;/tr&gt;
		&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot;&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;{{Content Programming Jabber}}&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;=Pointers for Further Development=&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;=Pointers for Further Development=&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;br&amp;gt;The previous two chapters have demonstrated&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;br&amp;gt;The previous two chapters have demonstrated&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;!-- diff cache key wikicontent:diff:version:1.11a:oldid:1777:newid:25624 --&gt;
&lt;/table&gt;</description>
			<pubDate>Fri, 18 Sep 2009 14:23:29 GMT</pubDate>			<dc:creator>Uncopy</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:JabChapter_10</comments>		</item>
		<item>
			<title>Mikeh: /* What Demo::JBook Will Do */</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=JabChapter_10&amp;diff=1777&amp;oldid=prev</link>
			<description>&lt;p&gt;&lt;span class=&quot;autocomment&quot;&gt;What Demo::JBook Will Do&lt;/span&gt;&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 22:28, 16 September 2006&lt;/td&gt;
			&lt;/tr&gt;
		&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 108:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 108:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[image:jab_1001.png|Searching the JUD: the search form|&lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;conter&lt;/del&gt;|350 px]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[image:jab_1001.png|Searching the JUD: the search form|&lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;center&lt;/ins&gt;|350 px]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;br&amp;gt;&amp;lt;/code&amp;gt; The search fields are not fixed;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;br&amp;gt;&amp;lt;/code&amp;gt; The search fields are not fixed;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;instead, they're dynamically generated, according to the result of an&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;instead, they're dynamically generated, according to the result of an&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 297:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 297:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;br&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;br&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot;&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;=== Using Demo::JBook as an Apache Handler === &lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;=== Using Demo::JBook as an Apache Handler === &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;br&amp;gt;The ''Demo::JBook''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;br&amp;gt;The ''Demo::JBook''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;!-- diff cache key wikicontent:diff:version:1.11a:oldid:1750:newid:1777 --&gt;
&lt;/table&gt;</description>
			<pubDate>Sat, 16 Sep 2006 22:28:30 GMT</pubDate>			<dc:creator>Mikeh</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:JabChapter_10</comments>		</item>
		<item>
			<title>Mikeh at 22:18, 16 September 2006</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=JabChapter_10&amp;diff=1750&amp;oldid=prev</link>
			<description>&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;=Pointers for Further Development=&lt;br /&gt;
&amp;lt;br&amp;gt;The previous two chapters have demonstrated&lt;br /&gt;
how Jabber can be used to build applications and solutions in many&lt;br /&gt;
functional areas. They expanded upon and indeed went beyond the theme of&lt;br /&gt;
instant messaging (IM) to employ the fundamental features of contextual&lt;br /&gt;
messaging, presence, and request/response sequences, in a wide range of&lt;br /&gt;
scenarios.&lt;br /&gt;
&lt;br /&gt;
While these scenarios have in some ways been inward looking, they are&lt;br /&gt;
natural progressions that originated inside the IM world and matured&lt;br /&gt;
into applications and solutions that retain much of the messaging&lt;br /&gt;
flavor. Let's consider what else Jabber has to offer as a messaging and&lt;br /&gt;
routing mechanism.&lt;br /&gt;
&lt;br /&gt;
This chapter explores some &amp;quot;outward looking&amp;quot; scenarios, to give you&lt;br /&gt;
pointers and ideas for the future.  With ''Demo::JBook'', we consider&lt;br /&gt;
the possibility of &amp;quot;Jabber without Jabber&amp;quot;—in other words, using Jabber&lt;br /&gt;
as an ''infrastructure'', in this case as a data store, without focus on&lt;br /&gt;
any particular Jabber client or IM functionality. We also explore how&lt;br /&gt;
Jabber is the perfect transport partner for procedure calls formalized&lt;br /&gt;
in XML: ''JabberRPCRequester'' and ''JabberRPCResponder'' are scripts&lt;br /&gt;
that exchange method calls and responses encoded in XML-RPC.&lt;br /&gt;
&lt;br /&gt;
Using Jabber as a conduit to foreign systems is also a theme of this&lt;br /&gt;
chapter. With ''ldapr'', we build a script that reflects the hierarchy&lt;br /&gt;
and contents of an LDAP data store, allowing that store to be navigated&lt;br /&gt;
from a Jabber client. Finally, we look to the business world, employing&lt;br /&gt;
Jabber in a tiny but crucial role as a conduit between SAP systems and&lt;br /&gt;
their users.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== A Simple Jabber-Based Address Book == &lt;br /&gt;
&amp;lt;br&amp;gt;With the availability of many&lt;br /&gt;
different off-the-shelf Jabber clients and the use of these clients as&lt;br /&gt;
generic tools to interact with diverse Jabber-based services, it's easy&lt;br /&gt;
to lose sight of the fact that Jabber can also be used to contribute to&lt;br /&gt;
''infrastructure'' solutions. That is, applications and utilities can be&lt;br /&gt;
built using the Jabber protocols, in conjunction with Jabber&lt;br /&gt;
server-based services, without the need for a Jabber client.&lt;br /&gt;
&lt;br /&gt;
By way of illustration, let's build a simple two-level address book&lt;br /&gt;
using Jabber services. We'll call it ''Demo::JBook''. We'll use this&lt;br /&gt;
address book to look up details of our friends and colleagues while&lt;br /&gt;
we're on the move. The ideal platform for this is going to be a web&lt;br /&gt;
browser, in that it's accessible from personal workstations, airport web&lt;br /&gt;
consoles, cybercafés, and personal digital assistants (PDAs) that offer&lt;br /&gt;
access to the Internet.&lt;br /&gt;
&lt;br /&gt;
The point of this illustration is not to show that there's a single&lt;br /&gt;
solution to the problem of disconnected, incompatible, and&lt;br /&gt;
unsynchronized directory information (because, despite any answers that&lt;br /&gt;
you may get to the contrary—no such solution exists). Instead, the goal&lt;br /&gt;
is to show that it's possible to make use of Jabber services and get to&lt;br /&gt;
information stored and managed by those services without having to use a&lt;br /&gt;
Jabber client.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using the JUD and vCards === &lt;br /&gt;
&amp;lt;br&amp;gt;The two levels in our address book are&lt;br /&gt;
going to reflect two distinct (but related) mechanisms in Jabber. We're&lt;br /&gt;
going to base our address book on the Jabber User Directory (JUD)&lt;br /&gt;
component and supply further information, in a &amp;quot;drill-down&amp;quot; action,&lt;br /&gt;
using vCards.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; The JUD&lt;br /&gt;
: Our address book will act as a query frontend for a user directory in&lt;br /&gt;
: the form of a JUD. It doesn't matter ''which'' JUD we use; obviously,&lt;br /&gt;
: that depends on how the application is to be deployed. On one hand, it&lt;br /&gt;
: might be appropriate to point it at your company's internal JUD, if&lt;br /&gt;
: you have one. On the other hand, it might also be just as appropriate&lt;br /&gt;
: to point it at one of the larger public JUDs, such as the one&lt;br /&gt;
: connected to the Jabber server running on ''jabber.org'' (which is&lt;br /&gt;
: ''users.jabber.org''). &lt;br /&gt;
; vCards&lt;br /&gt;
: Every Jabber entity—users, components, and servers—has the potential&lt;br /&gt;
: to have a vCard. We saw in Chapter 4 that the Jabber server itself,&lt;br /&gt;
: and many of the components connected to it, had a vCard definition.&lt;br /&gt;
: While the vCard standard is still fluid, the implementation within&lt;br /&gt;
: Jabber, as described in Section 6.5.1 in Chapter 6, is enough to be&lt;br /&gt;
: useful. The key to the application is that both the Jabber mechanisms&lt;br /&gt;
: that it relies upon—the JUD and vCards—can be accessed independently&lt;br /&gt;
: of the availability of the users that the information stored in those&lt;br /&gt;
: mechanisms represents. The JUD runs as an independent component and&lt;br /&gt;
: manages the directory information using its own data store. With the&lt;br /&gt;
: default JUD and XML Database (XDB) component configurations, this data&lt;br /&gt;
: store will be in the Jabber server's spool directory in a file called&lt;br /&gt;
: jud/global.xdb. &lt;br /&gt;
&lt;br /&gt;
Users interact with the JUD to manage their information, using IQ&lt;br /&gt;
elements qualified by the &amp;lt;tt&amp;gt;jabber:iq:register&amp;lt;/tt&amp;gt; namespace. User&lt;br /&gt;
vCard information is also stored at the server side, and users manage&lt;br /&gt;
the vCard contents using IQ elements qualified by the&lt;br /&gt;
&amp;lt;tt&amp;gt;vcard-temp&amp;lt;/tt&amp;gt; namespace. Again, with the default configuration,&lt;br /&gt;
the vCard information, stored along with the rest of the user data&lt;br /&gt;
relevant to the Jabber server in user-specific spool files, will be held&lt;br /&gt;
in the Jabber server's spool directory in files called&lt;br /&gt;
[hostname]/[user].xml.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What Demo::JBook Will Do === &lt;br /&gt;
&amp;lt;br&amp;gt;The JUD can be queried using a normal&lt;br /&gt;
Jabber client. In Figure 10-1, we can see the search form of Jabber&lt;br /&gt;
Instant Messenger (JIM).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:jab_1001.png|Searching the JUD: the search form|conter|350 px]]&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;/code&amp;gt; The search fields are not fixed;&lt;br /&gt;
instead, they're dynamically generated, according to the result of an&lt;br /&gt;
initial IQ-get in the &amp;lt;tt&amp;gt;jabber:iq:search&amp;lt;/tt&amp;gt; namespace. Just as an&lt;br /&gt;
IQ-get in the &amp;lt;tt&amp;gt;jabber:iq:register&amp;lt;/tt&amp;gt; namespace (as illustrated in&lt;br /&gt;
Section 8.3) is used for registering users, the&lt;br /&gt;
&amp;lt;tt&amp;gt;jabber:iq:search&amp;lt;/tt&amp;gt; namespace is is used for search requests. This&lt;br /&gt;
is illustrated in Example 10-1, where an IQ-get is sent to the JUD at&lt;br /&gt;
&amp;lt;tt&amp;gt;jud.gnu.mine.nu&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''An IQ-get to a JUD in the jabber:iq:search namespace''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SEND: &amp;amp;lt;iq type=&amp;quot;get&amp;quot; id=&amp;quot;9138&amp;quot; to=&amp;quot;jud.gnu.mine.nu&amp;quot;&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;query xmlns=&amp;quot;jabber:iq:search&amp;quot;/&amp;amp;gt; &amp;amp;lt;/iq&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
RECV: &amp;amp;lt;iq from='jud.gnu.mine.nu' id='9138'&lt;br /&gt;
to='qmacro@jabber.org/study' type='result'&amp;amp;gt; &amp;amp;lt;query&lt;br /&gt;
xmlns='jabber:iq:search'&amp;amp;gt; &amp;amp;lt;first/&amp;amp;gt; &amp;amp;lt;last/&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;instructions&amp;amp;gt; Fill in a field to search for any matching Jabber&lt;br /&gt;
users. &amp;amp;lt;/instructions&amp;amp;gt; &amp;amp;lt;/query&amp;amp;gt; &amp;amp;lt;/iq&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
In response to the IQ-get request, the JUD sends back a list of fields&lt;br /&gt;
with which the directory can be searched, along with some simple&lt;br /&gt;
instructions.&lt;br /&gt;
&lt;br /&gt;
The actual search follows the same registration pattern (using the&lt;br /&gt;
&amp;lt;tt&amp;gt;jabber:iq:register&amp;lt;/tt&amp;gt; namespace) that we saw in Section 8.3. After&lt;br /&gt;
receiving a list of possible search fields, a search request is made&lt;br /&gt;
with an IQ-set, as shown in Example 10-2. The results, returned in an&lt;br /&gt;
IQ-result from the JUD, are listed with each entry contained in an&lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;amp;lt;item/&amp;amp;gt;&amp;lt;/tt&amp;gt; tag. The search results are shown in Figure 10-2.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:title=Searching the JUD: the search&lt;br /&gt;
results|image=0596002025-jab_1002.png&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''The JUD search request and response''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SEND: &amp;amp;lt;iq type=&amp;quot;set&amp;quot; id=&amp;quot;2627&amp;quot; to=&amp;quot;users.jabber.org&amp;quot;&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;query xmlns=&amp;quot;jabber:iq:search&amp;quot;&amp;amp;gt; &amp;amp;lt;last&amp;amp;gt;adams&amp;amp;lt;/last&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/query&amp;amp;gt; &amp;amp;lt;/iq&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
RECV: &amp;amp;lt;iq from='users.jabber.org' id='2627'&lt;br /&gt;
to='qmacro@jabber.org/study' type='result'&amp;amp;gt; &amp;amp;lt;query&lt;br /&gt;
xmlns='jabber:iq:search'&amp;amp;gt; &amp;amp;lt;item jid='qmacro@jabber.org'&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;nick&amp;amp;gt;qmacro&amp;amp;lt;/nick&amp;amp;gt; &amp;amp;lt;first&amp;amp;gt;DJ&amp;amp;lt;/first&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;email&amp;amp;gt;dj.adams@gmx.net&amp;amp;lt;/email&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;last&amp;amp;gt;Adams&amp;amp;lt;/last&amp;amp;gt; &amp;amp;lt;/item&amp;amp;gt; &amp;amp;lt;item&lt;br /&gt;
jid='qmacro@jabber.com'&amp;amp;gt; &amp;amp;lt;nick&amp;amp;gt;dj&amp;amp;lt;/nick&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;first&amp;amp;gt;DJ&amp;amp;lt;/first&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;email&amp;amp;gt;dj.adams@gmx.net&amp;amp;lt;/email&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;last&amp;amp;gt;Adams&amp;amp;lt;/last&amp;amp;gt; &amp;amp;lt;/item&amp;amp;gt; &amp;amp;lt;item&lt;br /&gt;
jid='joseph@gnu.mine.nu'&amp;amp;gt; &amp;amp;lt;nick&amp;amp;gt;joseph&amp;amp;lt;/nick&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;first&amp;amp;gt;Joseph&amp;amp;lt;/first&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;email&amp;amp;gt;joseph@pipetree.com&amp;amp;lt;/email&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;last&amp;amp;gt;Adams&amp;amp;lt;/last&amp;amp;gt; &amp;amp;lt;/item&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
          ... (more items) ...&lt;br /&gt;
&lt;br /&gt;
        &amp;amp;lt;/query&amp;amp;gt; &amp;amp;lt;/iq&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== Searching a JUD ==== &lt;br /&gt;
&amp;lt;br&amp;gt;The first level that we'll build into&lt;br /&gt;
''Demo::JBook'' is the ability to query a JUD. The address book is to be&lt;br /&gt;
browser-based, so we'll generate HTML on the fly according to the search&lt;br /&gt;
fields we receive in response to our IQ-get. It should look something&lt;br /&gt;
like that shown in Figure 10-3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:jab_1003.png|JUD search form in HTML|center|350 px]]&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
The items returned in the search results don't really provide much&lt;br /&gt;
information:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;item jid='joseph@gnu.mine.nu'&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;nick&amp;amp;gt;joseph&amp;amp;lt;/nick&amp;amp;gt; &amp;amp;lt;first&amp;amp;gt;Joseph&amp;amp;lt;/first&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;email&amp;amp;gt;joseph@pipetree.com&amp;amp;lt;/email&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;last&amp;amp;gt;Adams&amp;amp;lt;/last&amp;amp;gt; &amp;amp;lt;/item&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Here, we have the user's first and last names, his nickname, and his&lt;br /&gt;
email address. One of the functions of the JUD is to determine which&lt;br /&gt;
fields are storable.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Sidebar|JUD FieldsThe fields in a JUD that are used to store the&lt;br /&gt;
directory data are determined either by a hardcoded list in the JUD&lt;br /&gt;
source itself or a configurable list that's stored and maintained&lt;br /&gt;
separate from the JUD code. The list fields allowed for searching a JUD&lt;br /&gt;
may or may not be used for storing the information; it may be a subset&lt;br /&gt;
(it makes no sense, of course, for it to be a superset). For example, if&lt;br /&gt;
the fields used to store information in a JUD are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;name/&amp;amp;gt; &amp;amp;lt;email/&amp;amp;gt; &amp;amp;lt;first/&amp;amp;gt; &amp;amp;lt;last/&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;nick/&amp;amp;gt; &amp;amp;lt;text/&amp;amp;gt;&amp;lt;/code&amp;gt; it may be that the fields available for&lt;br /&gt;
searching may be just:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;first/&amp;amp;gt; &amp;amp;lt;last/&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
as shown in Example 10-1.&lt;br /&gt;
&lt;br /&gt;
In case you're wondering how to discover the fields that can be used to&lt;br /&gt;
populate the information in the JUD, an IQ-get can be used in the&lt;br /&gt;
&amp;lt;tt&amp;gt;jabber:iq:register&amp;lt;/tt&amp;gt; namespace to qualify a ''registration''&lt;br /&gt;
conversation with the JUD, which is where the information is&lt;br /&gt;
&amp;quot;registered,&amp;quot; or stored. This is shown in Example 10-3.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''An IQ-get to a JUD in the jabber:iq:register namespace''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SEND: &amp;amp;lt;iq type='get' to='jud.gnu.mine.nu'&amp;amp;gt; &amp;amp;lt;query&lt;br /&gt;
xmlns='jabber:iq:register'/&amp;amp;gt; &amp;amp;lt;/iq&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
RECV: &amp;amp;lt;iq from='jud.gnu.mine.nu' to='qmacro@jabber.com/study'&lt;br /&gt;
type='result'&amp;amp;gt; &amp;amp;lt;query xmlns='jabber:iq:register'&amp;amp;gt; &amp;amp;lt;nick/&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;first/&amp;amp;gt; &amp;amp;lt;email/&amp;amp;gt; &amp;amp;lt;last/&amp;amp;gt; &amp;amp;lt;text/&amp;amp;gt; &amp;amp;lt;name/&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;instructions&amp;amp;gt; Fill in all of the fields to add yourself to the&lt;br /&gt;
JUD. &amp;amp;lt;/instructions&amp;amp;gt; &amp;amp;lt;/query&amp;amp;gt; &amp;amp;lt;/iq&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We can see in Figure 10-4 how the results will typically be rendered.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:jab_1004.png|JUD search results as rendered in Demo::JBook|center|350 px&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== Retrieving vCard information ==== &lt;br /&gt;
&amp;lt;br&amp;gt;As well as registering with a&lt;br /&gt;
JUD, it's possible that a user has maintained more information about&lt;br /&gt;
himself—in his vCard. Depending on the Jabber client used, various user&lt;br /&gt;
information can be stored in a personal vCard, which is stored on the&lt;br /&gt;
server side. In Figure 10-5, we see the JIM client's vCard maintenance&lt;br /&gt;
window, titled User Profile.&lt;br /&gt;
&lt;br /&gt;
The result of entering information and clicking the OK button in Figure&lt;br /&gt;
10-5 can be seen in Example 10-4, where an IQ-set in the&lt;br /&gt;
&amp;lt;tt&amp;gt;vcard-temp&amp;lt;/tt&amp;gt; namespace is made to store the information (some of&lt;br /&gt;
the vCard tags have been omitted to keep the example short). Notice how&lt;br /&gt;
no &amp;lt;tt&amp;gt;to&amp;lt;/tt&amp;gt; attribute is specified in the IQ-set and how the result&lt;br /&gt;
appears to come from the sender (&amp;lt;tt&amp;gt;qmacro@jabber.com/study&amp;lt;/tt&amp;gt;). The&lt;br /&gt;
storage of personal—user-specific—vCard information is a function of the&lt;br /&gt;
Jabber Session Manager (JSM), which is where the &amp;lt;tt&amp;gt;&amp;amp;lt;iq/&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
element will be routed automatically, as it is coming in over a client&lt;br /&gt;
connection (defined by the &amp;lt;tt&amp;gt;jabber:client&amp;lt;/tt&amp;gt; stream-level&lt;br /&gt;
namespace). This is further discussed in Section 5.4.3.1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:jab_1005.png|Updating personal vCard information with JIM|center|350 px&amp;lt;br&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Setting vCard information in the vcard-temp namespace''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SEND: &amp;amp;lt;iq type=&amp;quot;set&amp;quot;&amp;amp;gt; &amp;amp;lt;VCARD version=&amp;quot;3.0&amp;quot;&lt;br /&gt;
xmlns=&amp;quot;vcard-temp&amp;quot;&amp;amp;gt; &amp;amp;lt;N&amp;amp;gt; &amp;amp;lt;GIVEN&amp;amp;gt;DJ&amp;amp;lt;/GIVEN&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;FAMILY&amp;amp;gt;Adams&amp;amp;lt;/FAMILY&amp;amp;gt; &amp;amp;lt;MIDDLE/&amp;amp;gt; &amp;amp;lt;/N&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;NICKNAME&amp;amp;gt;qmacro&amp;amp;lt;/NICKNAME&amp;amp;gt; &amp;amp;lt;EMAIL&amp;amp;gt; &amp;amp;lt;INTERNET/&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;PREF/&amp;amp;gt; dj.adams@gmx.net &amp;amp;lt;/EMAIL&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
          ...&lt;br /&gt;
&lt;br /&gt;
        &amp;amp;lt;/VCARD&amp;amp;gt; &amp;amp;lt;/iq&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
RECV: &amp;amp;lt;iq type='result' from='qmacro@jabber.com/study'&lt;br /&gt;
to='qmacro@jabber.com/study'/&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
As well as being storable, the information in a personal vCard is also&lt;br /&gt;
retrievable by anyone, anytime. The idea of a personal vCard is that the&lt;br /&gt;
information it contains is permanently available. Because the vCard data&lt;br /&gt;
is stored server side, it can be retrieved anytime the user is online.&lt;br /&gt;
&lt;br /&gt;
The key (literally and metaphorically) of each of the search result&lt;br /&gt;
items returned is a JID. We can see this in Example 10-2, where each&lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;amp;lt;item/&amp;amp;gt;&amp;lt;/tt&amp;gt; tag has a &amp;lt;tt&amp;gt;jid&amp;lt;/tt&amp;gt; attribute. You won't be&lt;br /&gt;
surprised to know that the key to accessing someone's vCard is his JID&lt;br /&gt;
too. So we have a great way for ''Demo::JBook'' to jump from level 1,&lt;br /&gt;
which displays JUD search results, to level 2 by retrieving and&lt;br /&gt;
displaying a vCard via the JID. The results of jumping from a JUD result&lt;br /&gt;
entry to a vCard display for the selected user, via the JUD, can be seen&lt;br /&gt;
in Figure 10-6.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:jab_1006.png|A vCard as displayed in Demo::JBook|center|350 px-&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Using Demo::JBook as an Apache Handler === &lt;br /&gt;
&amp;lt;br&amp;gt;The ''Demo::JBook''&lt;br /&gt;
application is going to exist as an Apache ''mod_perl'' handler, that&lt;br /&gt;
is, we'll use the power of Perl's integration into the Apache web server&lt;br /&gt;
to write an Apache module in Perl. You can find out more about&lt;br /&gt;
''mod_perl'' at http://perl.apache.org.&lt;br /&gt;
&lt;br /&gt;
Being a ''mod_perl'' module, ''Demo::JBook'' exists in the form of a&lt;br /&gt;
Perl module and is configured in Apache to service calls to&lt;br /&gt;
&amp;lt;tt&amp;gt;http://[&amp;lt;/tt&amp;gt;''hostname''&amp;lt;tt&amp;gt;]/jbook&amp;lt;/tt&amp;gt;. The configuration can be&lt;br /&gt;
comfortably placed in the main Apache configuration file, httpd.conf,&lt;br /&gt;
or, as is common in ''mod_perl'' installations, in an extra file usually&lt;br /&gt;
called perl.conf, which is linked to httpd.conf as follows:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;IfModule mod_perl.c&amp;amp;gt; Include conf/perl.conf&lt;br /&gt;
&amp;amp;lt;/IfModule&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The configuration for ''Demo::JBook'' is placed in the perl.conf file,&lt;br /&gt;
as shown in Example 10-5.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''Configuring the module as a handler in Apache''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;require conf/startup.pl&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
&amp;amp;lt;Location /jbook&amp;amp;gt; SetHandler perl-script PerlHandler Demo::JBook&lt;br /&gt;
&amp;amp;lt;/Location&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;PerlHandler&amp;lt;/tt&amp;gt; directive refers to the ''Demo::JBook'' module,&lt;br /&gt;
which is the JBook.pm file that exists in the Demo/ directory. The&lt;br /&gt;
module will be invoked to handle calls to the relative URL ''/jbook''.&lt;br /&gt;
You can add the location of the ''Demo::JBook'' module to ''mod_perl'''s&lt;br /&gt;
list of directories in the &amp;lt;tt&amp;gt;BEGIN&amp;lt;/tt&amp;gt; section of the startup.pl&lt;br /&gt;
script, in the conf/ directory, like this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;BEGIN { use Apache (); use lib '[the directory location of&lt;br /&gt;
Demo::JBook]';&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== The Demo::JBook Script === &lt;br /&gt;
&amp;lt;br&amp;gt;Before taking the ''Demo::JBook'' script&lt;br /&gt;
apart, let's have a look at the script in its entirety, shown in &lt;br /&gt;
Example 10-6. Written in Perl, ''Demo::JBook'' uses the&lt;br /&gt;
&amp;lt;tt&amp;gt;Jabber::Connection&amp;lt;/tt&amp;gt; library.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''The Demo::JBook script, written in Perl''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;package Demo::JBook;&lt;br /&gt;
&lt;br /&gt;
use strict;&lt;br /&gt;
&lt;br /&gt;
use Jabber::Connection; use Jabber::NodeFactory; use Jabber::NS qw(:iq&lt;br /&gt;
:misc);&lt;br /&gt;
&lt;br /&gt;
use constant SERVER   =&amp;amp;gt; 'gnu.mine.nu'; use constant USER     =&amp;amp;gt;&lt;br /&gt;
'jbook'; use constant PASS     =&amp;amp;gt; 'pass'; use constant RESOURCE =&amp;amp;gt;&lt;br /&gt;
'jbook'; use constant JUD      =&amp;amp;gt; 'jud.gnu.mine.nu';&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub handler {&lt;br /&gt;
&lt;br /&gt;
  my $r = shift; my @a = $r-&amp;amp;gt;args;&lt;br /&gt;
&lt;br /&gt;
  my $nf = Jabber::NodeFactory-&amp;amp;gt;new;&lt;br /&gt;
&lt;br /&gt;
  $r-&amp;amp;gt;content_type('text/html'); $r-&amp;amp;gt;send_http_header;&lt;br /&gt;
&lt;br /&gt;
  $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;html&amp;amp;gt;&amp;amp;lt;head&amp;amp;gt;&amp;amp;lt;title&amp;amp;gt;JBook&amp;amp;lt;/title&amp;amp;gt;&lt;br /&gt;
  &amp;amp;lt;/head&amp;amp;gt;&amp;amp;lt;body&amp;amp;gt;&amp;quot;); $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;h1&amp;amp;gt;&amp;amp;lt;a&lt;br /&gt;
  href=&amp;quot;/jbook&amp;quot;&amp;amp;gt;JBook&amp;amp;lt;/a&amp;amp;gt;&amp;amp;lt;/h1&amp;amp;gt;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  # Connect to the Jabber server&lt;br /&gt;
  my $c = Jabber::Connection-&amp;amp;gt;new(server =&amp;amp;gt; SERVER); unless&lt;br /&gt;
  ($c-&amp;amp;gt;connect) { $r-&amp;amp;gt;print(&amp;quot;Sorry, no connection to Jabber&lt;br /&gt;
  available at &amp;quot;.SERVER); $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;/body&amp;amp;gt;&amp;amp;lt;/html&amp;amp;gt;&amp;quot;);&lt;br /&gt;
  return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  $c-&amp;amp;gt;auth(USER, PASS, RESOURCE);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  # No arguments: Instructions&lt;br /&gt;
  if (scalar @a == 0) {&lt;br /&gt;
&lt;br /&gt;
    # Construct IQ-get in iq:search namespace&lt;br /&gt;
    my $iq = $nf-&amp;amp;gt;newNode('iq'); $iq-&amp;amp;gt;attr('to', JUD);&lt;br /&gt;
    $iq-&amp;amp;gt;attr('type', IQ_GET); $iq-&amp;amp;gt;insertTag('query', NS_SEARCH);&lt;br /&gt;
&lt;br /&gt;
    # Send the IQ-get&lt;br /&gt;
    my $result = $c-&amp;amp;gt;ask($iq);&lt;br /&gt;
&lt;br /&gt;
    if ($result-&amp;amp;gt;attr('type') eq IQ_ERROR) { $r-&amp;amp;gt;print(&amp;quot;sorry, no&lt;br /&gt;
    connection to JUD available at &amp;quot;.JUD);&lt;br /&gt;
    $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;/body&amp;amp;gt;&amp;amp;lt;/html&amp;amp;gt;&amp;quot;); $c-&amp;amp;gt;disconnect;&lt;br /&gt;
    return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    my $info = $result-&amp;amp;gt;getTag('', NS_SEARCH);&lt;br /&gt;
&lt;br /&gt;
    # Display the results in HTML&lt;br /&gt;
    $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;p&amp;amp;gt;&amp;amp;lt;strong&amp;amp;gt;&amp;quot;.JUD.&amp;quot;&amp;amp;lt;/strong&amp;amp;gt;&amp;amp;lt;/p&amp;amp;gt&lt;br /&gt;
    ;\n&amp;quot;);&lt;br /&gt;
    $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;p&amp;amp;gt;&amp;quot;.$info-&amp;amp;gt;getTag('instructions')-&amp;amp;gt;data.&amp;quot;&lt;br /&gt;
    &amp;amp;lt;/p&amp;amp;gt;\n&amp;quot;); $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;form&amp;amp;gt;&amp;amp;lt;table&amp;amp;gt;\n&amp;quot;); foreach&lt;br /&gt;
    my $field ($info-&amp;amp;gt;getChildren) { next if $field-&amp;amp;gt;name eq&lt;br /&gt;
    'instructions'; $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;tr&amp;amp;gt;&amp;quot;);&lt;br /&gt;
    $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;td&amp;amp;gt;&amp;quot;.ucfirst($field-&amp;amp;gt;name).&amp;quot;&amp;amp;lt;/td&amp;amp;gt;&amp;quot;);&lt;br /&gt;
    $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;td&amp;amp;gt;&amp;amp;lt;input type=&amp;quot;text'&lt;br /&gt;
    name=&amp;quot;&amp;quot;.$field-&amp;amp;gt;name.&amp;quot;&amp;quot;&amp;amp;gt;&amp;amp;lt;/td&amp;amp;gt;&amp;quot;);&lt;br /&gt;
    $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;/tr&amp;amp;gt;\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;tr&amp;amp;gt;&amp;amp;lt;td&amp;amp;gt;&amp;amp;lt;/td&amp;amp;gt;&amp;amp;lt;td&amp;amp;gt;&amp;amp;lt;input&lt;br /&gt;
    type=&amp;quot;submit&amp;quot;&amp;amp;gt;&amp;amp;lt;/td&amp;amp;gt;&amp;amp;lt;/tr&amp;amp;gt;\n&amp;quot;);&lt;br /&gt;
    $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;/table&amp;amp;gt;&amp;amp;lt;/form&amp;amp;gt;\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  # Multiple arguments: JUD lookup&lt;br /&gt;
  elsif (scalar @a &amp;amp;gt; 1) {&lt;br /&gt;
&lt;br /&gt;
    # Treat the arguments as a hash&lt;br /&gt;
    my %a = @a;&lt;br /&gt;
&lt;br /&gt;
    # Construct an IQ-set&lt;br /&gt;
    my $iq = $nf-&amp;amp;gt;newNode('iq'); $iq-&amp;amp;gt;attr('to', JUD);&lt;br /&gt;
    $iq-&amp;amp;gt;attr('type', IQ_SET); my $query = $iq-&amp;amp;gt;insertTag('query',&lt;br /&gt;
    NS_SEARCH);&lt;br /&gt;
&lt;br /&gt;
    while (my($name, $val) = each(%a)) {&lt;br /&gt;
    $query-&amp;amp;gt;insertTag($name)-&amp;amp;gt;data($val) if $val;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    # Make call&lt;br /&gt;
    my $result = $c-&amp;amp;gt;ask($iq);&lt;br /&gt;
&lt;br /&gt;
    if ($result-&amp;amp;gt;attr('type') eq IQ_ERROR) { $r-&amp;amp;gt;print(&amp;quot;sorry,&lt;br /&gt;
    cannot query JUD&amp;quot;); $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;/body&amp;amp;gt;&amp;amp;lt;/html&amp;amp;gt;&amp;quot;);&lt;br /&gt;
    $c-&amp;amp;gt;disconnect; return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    my $info = $c-&amp;amp;gt;ask($iq)-&amp;amp;gt;getTag('', NS_SEARCH);&lt;br /&gt;
&lt;br /&gt;
    my $items = 0;&lt;br /&gt;
&lt;br /&gt;
    $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;p&amp;amp;gt;&amp;amp;lt;strong&amp;amp;gt;&amp;quot;.JUD.&amp;quot;&amp;amp;lt;/strong&amp;amp;gt;&amp;amp;lt;/p&amp;amp;gt&lt;br /&gt;
    ;\n&amp;quot;); $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;table border=&amp;quot;1&amp;quot;&amp;amp;gt;\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    foreach my $item ($info-&amp;amp;gt;getChildren) {&lt;br /&gt;
&lt;br /&gt;
      # Heading&lt;br /&gt;
      unless ($items) { $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;tr&amp;amp;gt;&amp;quot;); foreach my $tag&lt;br /&gt;
      ($item-&amp;amp;gt;getChildren) {&lt;br /&gt;
      $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;th&amp;amp;gt;&amp;quot;.ucfirst($tag-&amp;amp;gt;name).&amp;quot;&amp;amp;lt;/th&amp;amp;gt;&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;/tr&amp;amp;gt;\n&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;tr&amp;amp;gt;&amp;quot;); my $flag = 0; foreach my $tag&lt;br /&gt;
      ($item-&amp;amp;gt;getChildren) { unless (length($tag-&amp;amp;gt;data) == 0 or&lt;br /&gt;
      $flag++) { $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;td&amp;amp;gt;&amp;amp;lt;a&lt;br /&gt;
      href=&amp;quot;/jbook?&amp;quot;.$item-&amp;amp;gt;attr('jid').&amp;quot;&amp;quot;&amp;amp;gt;&amp;quot;);&lt;br /&gt;
      $r-&amp;amp;gt;print($tag-&amp;amp;gt;data.&amp;quot;&amp;amp;lt;/a&amp;amp;gt;&amp;amp;lt;/td&amp;amp;gt;&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        else { $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;td&amp;amp;gt;&amp;quot;.$tag-&amp;amp;gt;data.&amp;quot;&amp;amp;lt;/td&amp;amp;gt;&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
      $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;/tr&amp;amp;gt;\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      $items++;&lt;br /&gt;
    }&lt;br /&gt;
    $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;/table&amp;amp;gt;\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;p&amp;amp;gt;$items results found&amp;amp;lt;/p&amp;amp;gt;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  # Single argument: vCard lookup&lt;br /&gt;
  else {&lt;br /&gt;
&lt;br /&gt;
    # Construct query&lt;br /&gt;
    my $iq = $nf-&amp;amp;gt;newNode('iq'); $iq-&amp;amp;gt;attr('to', $a[0]);&lt;br /&gt;
    $iq-&amp;amp;gt;attr('type', IQ_GET); $iq-&amp;amp;gt;insertTag('vcard', NS_VCARD);&lt;br /&gt;
&lt;br /&gt;
    # Make call and retrieve results&lt;br /&gt;
    my $result = $c-&amp;amp;gt;ask($iq);&lt;br /&gt;
&lt;br /&gt;
    if ($result-&amp;amp;gt;attr('type') eq IQ_ERROR)  { $r-&amp;amp;gt;print(&amp;quot;sorry,&lt;br /&gt;
    cannot retrieve vCard for $a[0]&amp;quot;);&lt;br /&gt;
    $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;/body&amp;amp;gt;&amp;amp;lt;/html&amp;amp;gt;&amp;quot;); $c-&amp;amp;gt;disconnect;&lt;br /&gt;
    return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    my $vcard = $result-&amp;amp;gt;getTag('', NS_VCARD);&lt;br /&gt;
&lt;br /&gt;
    print (&amp;quot;&amp;amp;lt;strong&amp;amp;gt;$a[0]&amp;amp;lt;/strong&amp;amp;gt;\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    # Display each of the top-level tags if they contain data&lt;br /&gt;
    foreach my $tag ($vcard-&amp;amp;gt;getChildren) { print&lt;br /&gt;
    &amp;quot;&amp;amp;lt;br/&amp;amp;gt;&amp;quot;.$tag-&amp;amp;gt;name.&amp;quot; : &amp;quot;.$tag-&amp;amp;gt;data.&amp;quot;\n&amp;quot; if&lt;br /&gt;
    $tag-&amp;amp;gt;data;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;/body&amp;amp;gt;&amp;amp;lt;/html&amp;amp;gt;&amp;quot;); $c-&amp;amp;gt;disconnect;&lt;br /&gt;
&lt;br /&gt;
  return;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
1;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Taking Demo::JBook Step by Step === &lt;br /&gt;
&amp;lt;br&amp;gt;Now that we've got a hold on the&lt;br /&gt;
scope and scale of ''Demo::JBook'', let's take the script apart—step by&lt;br /&gt;
step—to see how it works.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Declarations ==== &lt;br /&gt;
&amp;lt;br&amp;gt;Because ''Demo::JBook'' is an Apache handler, it&lt;br /&gt;
exists as a  Perl module—hence the &amp;lt;tt&amp;gt;package&amp;lt;/tt&amp;gt; declaration at the&lt;br /&gt;
top of the file:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;package Demo::JBook;&lt;br /&gt;
&lt;br /&gt;
use strict;&lt;br /&gt;
&lt;br /&gt;
use Jabber::Connection; use Jabber::NodeFactory; use Jabber::NS qw(:iq&lt;br /&gt;
:misc);&lt;br /&gt;
&lt;br /&gt;
use constant SERVER   =&amp;amp;gt; 'gnu.mine.nu'; use constant USER     =&amp;amp;gt;&lt;br /&gt;
'jbook'; use constant PASS     =&amp;amp;gt; 'pass'; use constant RESOURCE =&amp;amp;gt;&lt;br /&gt;
'jbook'; use constant JUD      =&amp;amp;gt; 'users.jabber.org';&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This code exists within the ''Demo::JBook'' package that was declared as&lt;br /&gt;
the handler for the &amp;lt;tt&amp;gt;http://[&amp;lt;/tt&amp;gt;''hostname''&amp;lt;tt&amp;gt;]/jbook&amp;lt;/tt&amp;gt;&lt;br /&gt;
location, shown in Example 10-5. We're going to make full use of the&lt;br /&gt;
&amp;lt;tt&amp;gt;Jabber::Connection&amp;lt;/tt&amp;gt; library and bring in all three of its&lt;br /&gt;
modules for managing the Jabber server connection, for dispatching&lt;br /&gt;
elements that arrive (&amp;lt;tt&amp;gt;Jabber::Connection&amp;lt;/tt&amp;gt;), for building and&lt;br /&gt;
manipulating elements (&amp;lt;tt&amp;gt;Jabber::NodeFactory&amp;lt;/tt&amp;gt;), and using common&lt;br /&gt;
Jabber programming constants (&amp;lt;tt&amp;gt;Jabber::NS&amp;lt;/tt&amp;gt;). In the case of&lt;br /&gt;
&amp;lt;tt&amp;gt;Jabber::NS&amp;lt;/tt&amp;gt;, we need only a few namespaces to manage our JUD and&lt;br /&gt;
vCard queries, so the &amp;lt;tt&amp;gt;:iq&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;:misc&amp;lt;/tt&amp;gt; tags will be used&lt;br /&gt;
to refer a collection of constants in &amp;lt;tt&amp;gt;Jabber::NS&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The constants &amp;lt;tt&amp;gt;SERVER&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;USER&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;PASS&amp;lt;/tt&amp;gt;, and&lt;br /&gt;
&amp;lt;tt&amp;gt;RESOURCE&amp;lt;/tt&amp;gt; define the connection to the Jabber server. This&lt;br /&gt;
connection doesn't have to be made to the JUD that will be queried by&lt;br /&gt;
''Demo::JBook''. By way of illustration, we have ''jabber.org'''s JUD&lt;br /&gt;
(&amp;lt;tt&amp;gt;users.jabber.org&amp;lt;/tt&amp;gt;) specified as the value for the &amp;lt;tt&amp;gt;JUD&amp;lt;/tt&amp;gt;&lt;br /&gt;
constant. For the purpose of this example, this will be the JUD that&lt;br /&gt;
''Demo::JBook'' will query.&lt;br /&gt;
&lt;br /&gt;
You can use the ''reguser'' script, described in Section 7.4, to create&lt;br /&gt;
the ''Demo::JBook'' user. See Section 8.2.1.1 for an example of how this&lt;br /&gt;
can be done.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== General handler preparation ==== &lt;br /&gt;
&amp;lt;br&amp;gt;Following the script's&lt;br /&gt;
declarations, it's time to define the handler function that Apache will&lt;br /&gt;
call to handle incoming requests to the&lt;br /&gt;
&amp;lt;tt&amp;gt;http://[&amp;lt;/tt&amp;gt;''hostname''&amp;lt;tt&amp;gt;]/jbook&amp;lt;/tt&amp;gt; location. The name of the&lt;br /&gt;
handler must be &amp;lt;tt&amp;gt;handler()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sub handler {&lt;br /&gt;
&lt;br /&gt;
  my $r = shift; my @a = $r-&amp;amp;gt;args;&lt;br /&gt;
&lt;br /&gt;
  my $nf = Jabber::NodeFactory-&amp;amp;gt;new;&lt;br /&gt;
&lt;br /&gt;
  $r-&amp;amp;gt;content_type('text/html'); $r-&amp;amp;gt;send_http_header;&lt;br /&gt;
&lt;br /&gt;
  $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;html&amp;amp;gt;&amp;amp;lt;head&amp;amp;gt;&amp;amp;lt;title&amp;amp;gt;JBook&amp;amp;lt;/title&amp;amp;gt;&lt;br /&gt;
  &amp;amp;lt;/head&amp;amp;gt;&amp;amp;lt;body&amp;amp;gt;&amp;quot;); $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;h1&amp;amp;gt;&amp;amp;lt;a&lt;br /&gt;
  href=&amp;quot;/jbook&amp;quot;&amp;amp;gt;JBook&amp;amp;lt;/a&amp;amp;gt;&amp;amp;lt;/h1&amp;amp;gt;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  # Connect to home Jabber server&lt;br /&gt;
  my $c = Jabber::Connection-&amp;amp;gt;new(server =&amp;amp;gt; SERVER); unless&lt;br /&gt;
  ($c-&amp;amp;gt;connect) { $r-&amp;amp;gt;print(&amp;quot;Sorry, no connection to Jabber&lt;br /&gt;
  available at &amp;quot;.SERVER); $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;/body&amp;amp;gt;&amp;amp;lt;/html&amp;amp;gt;&amp;quot;);&lt;br /&gt;
  return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  $c-&amp;amp;gt;auth(USER, PASS, RESOURCE);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The ''mod_perl'' mechanism hands the &amp;lt;tt&amp;gt;handler()&amp;lt;/tt&amp;gt; function an&lt;br /&gt;
argument that is stored in a variable called &amp;lt;tt&amp;gt;$r&amp;lt;/tt&amp;gt;. This is the&lt;br /&gt;
HyperText Transfer Protocol (HTTP) ''request'' that has been made, which&lt;br /&gt;
is handled by the function.&lt;br /&gt;
&lt;br /&gt;
Calling the &amp;lt;tt&amp;gt;args()&amp;lt;/tt&amp;gt; method on our request object gives us a list&lt;br /&gt;
of arguments. These arguments follow the question mark in a typical HTTP&lt;br /&gt;
GET request. In Figure 10-3, the URL in the Location bar is&lt;br /&gt;
http://www.pipetree.com/jbook.  In this URL, there is neither a question&lt;br /&gt;
mark nor any arguments. The assignment to &amp;lt;tt&amp;gt;@a&amp;lt;/tt&amp;gt; here:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;  my @a = $r-&amp;amp;gt;args;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
would leave &amp;lt;tt&amp;gt;@a&amp;lt;/tt&amp;gt; empty.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Note|The first part of the URL containing the hostname is truncated by&lt;br /&gt;
the size of the browser window.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
However, if the URL in the Location bar (shown in Figure 10-4) contained&lt;br /&gt;
question marks and/or arguments, such as:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;http://www.pipetree.com/jbook?name=&amp;amp;amp;first=&amp;amp;amp;last=adams&amp;amp;amp&lt;br /&gt;
;nick=&amp;amp;amp;email=&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
the arguments that &amp;lt;tt&amp;gt;@a&amp;lt;/tt&amp;gt; would receive follow the question mark&lt;br /&gt;
and are separated in pairs with ampersands and further separated with&lt;br /&gt;
equals signs. So here, &amp;lt;tt&amp;gt;@a&amp;lt;/tt&amp;gt; would receive the arguments:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; name, (blank), first, (blank), last, adams, nick, (blank),&lt;br /&gt;
email, (blank)&amp;lt;/code&amp;gt; In the final URL example, shown in Figure 10-6:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; http://www.pipetree.com/jbook?dj@gnu.mine.nu&amp;lt;/code&amp;gt; the array&lt;br /&gt;
received by &amp;lt;tt&amp;gt;@a&amp;lt;/tt&amp;gt; is just a single element:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; dj@gnu.mine.nu&amp;lt;/code&amp;gt; The content of &amp;lt;tt&amp;gt;@a&amp;lt;/tt&amp;gt; defines which stage&lt;br /&gt;
of the script  takes the appropriate action. Queries will be generated&lt;br /&gt;
in the form of  IQ-gets and IQ-sets to retrieve information from the JUD&lt;br /&gt;
as well as to retrieve personal vCards. To do this, we need to create an&lt;br /&gt;
instance of a node factory, so we can build elements:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;  my $nf = Jabber::NodeFactory-&amp;amp;gt;new;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
After retrieving the request arguments and creating a node factory&lt;br /&gt;
instance, it's time to generate some HTML that will be common to all of&lt;br /&gt;
''Demo::JBook'''s features. The &amp;lt;tt&amp;gt;print()&amp;lt;/tt&amp;gt; method will be used on&lt;br /&gt;
the request object &amp;lt;tt&amp;gt;$r&amp;lt;/tt&amp;gt; to send a response back to the requesting&lt;br /&gt;
web browser:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &lt;br /&gt;
$r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;html&amp;amp;gt;&amp;amp;lt;head&amp;amp;gt;&amp;amp;lt;title&amp;amp;gt;JBook&amp;amp;lt;/title&amp;amp;gt;&amp;amp;&lt;br /&gt;
lt;/head&amp;amp;gt;&amp;amp;lt;body&amp;amp;gt;&amp;quot;); $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;h1&amp;amp;gt;&amp;amp;lt;a&lt;br /&gt;
href=&amp;quot;/jbook&amp;quot;&amp;amp;gt;JBook&amp;amp;lt;/a&amp;amp;gt;&amp;amp;lt;/h1&amp;amp;gt;&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Next, we need to create a connection to the Jabber server for each&lt;br /&gt;
request:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;  # Connect to home Jabber server my $c =&lt;br /&gt;
Jabber::Connection-&amp;amp;gt;new(server =&amp;amp;gt; SERVER); unless ($c-&amp;amp;gt;connect)&lt;br /&gt;
{ $r-&amp;amp;gt;print(&amp;quot;Sorry, no connection to Jabber available at &amp;quot;.SERVER);&lt;br /&gt;
$r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;/body&amp;amp;gt;&amp;amp;lt;/html&amp;amp;gt;&amp;quot;); return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  $c-&amp;amp;gt;auth(USER, PASS, RESOURCE);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
It will be much more efficient to create a persistent connection that&lt;br /&gt;
could be used to serve further requests. One way to do this is to fork a&lt;br /&gt;
daemon that connects to the Jabber server, acting as a proxy for this&lt;br /&gt;
script. Rather than make direct requests to the Jabber server,&lt;br /&gt;
''Demo::JBook'' is used to send the IQ elements to the daemon, which in&lt;br /&gt;
turn uses its persistent Jabber connection to make queries on&lt;br /&gt;
''Demo::JBook'''s behalf. A setup like this is shown in Figure 10-7.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:jab_1007.png|Using a persistent connection to Jabber|center|350 px]]&amp;lt;br&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== State 1: Build the JUD query form ==== &lt;br /&gt;
&amp;lt;br&amp;gt;Based upon how many&lt;br /&gt;
arguments we have in the &amp;lt;tt&amp;gt;@a&amp;lt;/tt&amp;gt; array, as described earlier, we can&lt;br /&gt;
build the response, which will represent one of three states:&lt;br /&gt;
&lt;br /&gt;
* JUD query form &lt;br /&gt;
* JUD query results &lt;br /&gt;
* vCard display If ''Demo::JBook'' is called without arguments (i.e., &lt;br /&gt;
&amp;lt;tt&amp;gt;http://[&amp;lt;/tt&amp;gt;''hostname''&amp;lt;tt&amp;gt;]/jbook&amp;lt;/tt&amp;gt;), which we test for like&lt;br /&gt;
this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if (scalar @a == 0) {&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
then we want to build and present the JUD search form. This form—the&lt;br /&gt;
fields that the form consists of—will be specific to the particular JUD&lt;br /&gt;
that will be searched.&lt;br /&gt;
&lt;br /&gt;
We construct an IQ-get to send to the JUD to ask for a list of search&lt;br /&gt;
fields and instructions. What we're looking for is something like the&lt;br /&gt;
IQ-get shown in Example 10-1, like this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SEND: &amp;amp;lt;iq type=&amp;quot;get&amp;quot; to=&amp;quot;users.jabber.org&amp;quot;&amp;amp;gt; &amp;amp;lt;query&lt;br /&gt;
xmlns=&amp;quot;jabber:iq:search&amp;quot;/&amp;amp;gt; &amp;amp;lt;/iq&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
To construct this, we start with a new node (''element'') created by&lt;br /&gt;
using the node factory:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;    my $iq = $nf-&amp;amp;gt;newNode('iq'); $iq-&amp;amp;gt;attr('to', JUD);&lt;br /&gt;
$iq-&amp;amp;gt;attr('type', IQ_GET); $iq-&amp;amp;gt;insertTag('query', NS_SEARCH);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
In previous recipes, we've called methods in the Jabber libraries&lt;br /&gt;
(&amp;lt;tt&amp;gt;Jabberpy&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;JabberBeans&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Net::Jabber&amp;lt;/tt&amp;gt;, and&lt;br /&gt;
&amp;lt;tt&amp;gt;Jabber::Connection&amp;lt;/tt&amp;gt;) to send an element to the Jabber server.&lt;br /&gt;
Typically, such a method is called a &amp;lt;tt&amp;gt;send()&amp;lt;/tt&amp;gt; method. Here, we&lt;br /&gt;
don't use a &amp;lt;tt&amp;gt;send()&amp;lt;/tt&amp;gt; method. Instead, we use&lt;br /&gt;
&amp;lt;tt&amp;gt;Jabber::Connection&amp;lt;/tt&amp;gt;'s &amp;lt;tt&amp;gt;ask()&amp;lt;/tt&amp;gt;. Like&lt;br /&gt;
&amp;lt;tt&amp;gt;Net::Jabber&amp;lt;/tt&amp;gt;'s &amp;lt;tt&amp;gt;SendAndReceiveWithID()&amp;lt;/tt&amp;gt; method, and&lt;br /&gt;
&amp;lt;tt&amp;gt;Jabberpy&amp;lt;/tt&amp;gt;'s method of the same name, &amp;lt;tt&amp;gt;ask()&amp;lt;/tt&amp;gt; not only&lt;br /&gt;
''sends'' the element to the Jabber server, it waits for a reply.&lt;br /&gt;
&lt;br /&gt;
A ''reply''—in Jabber terms—is a ''response'' in the form of an element&lt;br /&gt;
that comes back along the stream, ''with a&lt;br /&gt;
matching''&amp;lt;tt&amp;gt;id&amp;lt;/tt&amp;gt;''attribute''. In this case, we're making an IQ-get&lt;br /&gt;
and are expecting a response back from the recipient of that IQ-get. One&lt;br /&gt;
way of expecting and handling the response would be to use a predefined&lt;br /&gt;
callback specified for &amp;lt;tt&amp;gt;&amp;amp;lt;iq/&amp;amp;gt;&amp;lt;/tt&amp;gt; elements and send our IQ-get&lt;br /&gt;
with the &amp;lt;tt&amp;gt;send()&amp;lt;/tt&amp;gt; method. However, this means that the script&lt;br /&gt;
receives the response in an element callback that's somewhat independent&lt;br /&gt;
of our call to &amp;lt;tt&amp;gt;send()&amp;lt;/tt&amp;gt;. As well as catching the response in the&lt;br /&gt;
callback, we also need some way of matching it up with the original&lt;br /&gt;
request. Not to mention getting back on track with the flow of execution&lt;br /&gt;
that represented the logical sequence of events that we were in the&lt;br /&gt;
middle of following when we called &amp;lt;tt&amp;gt;send()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
There's an easier way, if we want to make a request and wait for the&lt;br /&gt;
response to that request before continuing on in the script. This way&lt;br /&gt;
makes use of the &amp;lt;tt&amp;gt;ask()&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
What the &amp;lt;tt&amp;gt;ask()&amp;lt;/tt&amp;gt; method does is avoid the need to catch responses&lt;br /&gt;
in callbacks and match them up with their originating requests. It&lt;br /&gt;
&amp;lt;tt&amp;gt;send()&amp;lt;/tt&amp;gt;s the element to the Jabber server and blocks until an&lt;br /&gt;
element with a matching &amp;lt;tt&amp;gt;id&amp;lt;/tt&amp;gt; attribute value is received. Other&lt;br /&gt;
elements that might be received while waiting for the response are duly&lt;br /&gt;
dispatched as normal. It's not as if elements get queued up if the&lt;br /&gt;
response takes a moment or two to arrive. When the matching element&lt;br /&gt;
arrives on the stream, it is passed directly back to the caller of the&lt;br /&gt;
&amp;lt;tt&amp;gt;ask()&amp;lt;/tt&amp;gt; method, in the same form as if it had been handed to a&lt;br /&gt;
callback—in object form, as an instance of a&lt;br /&gt;
&amp;lt;tt&amp;gt;Jabber::NodeFactory::Node&amp;lt;/tt&amp;gt; object, in this case.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;my $result = $c-&amp;amp;gt;ask($iq);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
So here, &amp;lt;tt&amp;gt;$result&amp;lt;/tt&amp;gt; receives the response to the&lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;amp;lt;iq/&amp;amp;gt;&amp;lt;/tt&amp;gt; element just sent. This response will look&lt;br /&gt;
something like this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;RECV: &amp;amp;lt;iq from='users.jabber.org' id='43'&lt;br /&gt;
to='jbook@gnu.mine.nu/jbook' type='result'&amp;amp;gt; &amp;amp;lt;query&lt;br /&gt;
xmlns='jabber:iq:search'&amp;amp;gt; &amp;amp;lt;nick/&amp;amp;gt; &amp;amp;lt;first/&amp;amp;gt; &amp;amp;lt;email/&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;last/&amp;amp;gt; &amp;amp;lt;instructions&amp;amp;gt; Fill in a field to search for any&lt;br /&gt;
matching Jabber users. &amp;amp;lt;/instructions&amp;amp;gt; &amp;amp;lt;/query&amp;amp;gt; &amp;amp;lt;/iq&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
It's addressed to the JID that the script is using,&lt;br /&gt;
&amp;lt;tt&amp;gt;jbook@gnu.mine.nu/jbook&amp;lt;/tt&amp;gt;. But hold on—there's something that&lt;br /&gt;
doesn't look quite right here, that is, when compared to the example of&lt;br /&gt;
the IQ-get we just sent. Indeed—there's an &amp;lt;tt&amp;gt;id&amp;lt;/tt&amp;gt; attribute in the&lt;br /&gt;
response. We didn't specify one in the Perl code that built the&lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;amp;lt;iq/&amp;amp;gt;&amp;lt;/tt&amp;gt; element. The &amp;lt;tt&amp;gt;ask()&amp;lt;/tt&amp;gt; method did it for us.&lt;br /&gt;
Knowing that it's going to have to check the &amp;lt;tt&amp;gt;id&amp;lt;/tt&amp;gt; attribute on&lt;br /&gt;
every incoming element to find a match for the element it's just sent&lt;br /&gt;
off for us, the &amp;lt;tt&amp;gt;ask()&amp;lt;/tt&amp;gt; method makes sure that the outgoing&lt;br /&gt;
element actually ''has'' an &amp;lt;tt&amp;gt;id&amp;lt;/tt&amp;gt; attribute. If it doesn't, it&lt;br /&gt;
adds one, giving it a unique value. That way, it stands a fighting&lt;br /&gt;
chance of returning to the caller something this side of the end of&lt;br /&gt;
time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Note|Talking of time, if you're uneasy about calling blocking&lt;br /&gt;
functions in general, you can always set an &amp;lt;tt&amp;gt;alarm()&amp;lt;/tt&amp;gt; to&lt;br /&gt;
interrupt the call after a certain length of time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
For more information on matching requests and responses, see Section 2.5&lt;br /&gt;
in Chapter 2.&lt;br /&gt;
&lt;br /&gt;
Now let's move on to the response to IQ-get, which we now have in&lt;br /&gt;
&amp;lt;tt&amp;gt;$result&amp;lt;/tt&amp;gt;. While we're expecting an IQ-result in response to&lt;br /&gt;
IQ-get, the request might not have been succesful, and we simply bail&lt;br /&gt;
out gracefully if it isn't, ending our connection with the Jabber&lt;br /&gt;
server:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;    if ($result-&amp;amp;gt;attr('type') eq IQ_ERROR) {&lt;br /&gt;
$r-&amp;amp;gt;print(&amp;quot;Sorry, no connection to the JUD available at &amp;quot;.JUD);&lt;br /&gt;
$r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;/body&amp;amp;gt;&amp;amp;lt;/html&amp;amp;gt;&amp;quot;); $c-&amp;amp;gt;disconnect; return;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Otherwise, we're expecting a result, containing the search fields and&lt;br /&gt;
some instructions. These will be contained within the query tag&lt;br /&gt;
qualified by the &amp;lt;tt&amp;gt;jabber:iq:search&amp;lt;/tt&amp;gt; namespace (the tag is usually&lt;br /&gt;
called &amp;lt;tt&amp;gt;query&amp;lt;/tt&amp;gt;, but here, as elsewhere in the script, we're not&lt;br /&gt;
taking any chances and are looking for &amp;quot;the first (hopefully the only!)&lt;br /&gt;
occurrence of a child tag qualified by the &amp;lt;tt&amp;gt;jabber:iq:search&amp;lt;/tt&amp;gt;&lt;br /&gt;
namespace.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;    my $info = $result-&amp;amp;gt;getTag('', NS_SEARCH);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
An HTML form is built from the instructions and the search fields; the&lt;br /&gt;
instructions are retrieved with:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;$info-&amp;amp;gt;getTag('instructions')-&amp;amp;gt;data&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
which retrieves the &amp;lt;tt&amp;gt;&amp;amp;lt;instructions/&amp;amp;gt;&amp;lt;/tt&amp;gt; tag and extracts its&lt;br /&gt;
contents.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;getChildren()&amp;lt;/tt&amp;gt; method is called upon our&lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;amp;lt;query/&amp;amp;gt;&amp;lt;/tt&amp;gt; tag to discover what fields are available. For&lt;br /&gt;
all those fields, barring the &amp;quot;instructions&amp;quot; one, we create an input&lt;br /&gt;
text field:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;    # Display the results in HTML&lt;br /&gt;
$r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;p&amp;amp;gt;&amp;amp;lt;strong&amp;amp;gt;&amp;quot;.JUD.&amp;quot;&amp;amp;lt;/strong&amp;amp;gt;&amp;amp;lt;/p&amp;amp;gt;\n&amp;quot;&lt;br /&gt;
);&lt;br /&gt;
$r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;p&amp;amp;gt;&amp;quot;.$info-&amp;amp;gt;getTag('instructions')-&amp;amp;gt;data.&amp;quot;&amp;amp;lt;&lt;br /&gt;
/p&amp;amp;gt;\n&amp;quot;); $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;form&amp;amp;gt;&amp;amp;lt;table&amp;amp;gt;\n&amp;quot;); foreach my&lt;br /&gt;
$field ($info-&amp;amp;gt;getChildren) { next if $field-&amp;amp;gt;name eq&lt;br /&gt;
'instructions'; $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;tr&amp;amp;gt;&amp;quot;);&lt;br /&gt;
$r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;td&amp;amp;gt;&amp;quot;.ucfirst($field-&amp;amp;gt;name).&amp;quot;&amp;amp;lt;/td&amp;amp;gt;&amp;quot;);&lt;br /&gt;
$r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;td&amp;amp;gt;&amp;amp;lt;input type=&amp;quot;text'&lt;br /&gt;
name=&amp;quot;&amp;quot;.$field-&amp;amp;gt;name.&amp;quot;&amp;quot;&amp;amp;gt;&amp;amp;lt;/td&amp;amp;gt;&amp;quot;);&lt;br /&gt;
$r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;/tr&amp;amp;gt;\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;tr&amp;amp;gt;&amp;amp;lt;td&amp;amp;gt;&amp;amp;lt;/td&amp;amp;gt;&amp;amp;lt;td&amp;amp;gt;&amp;amp;lt;input&lt;br /&gt;
    type=&amp;quot;submit&amp;quot;&amp;amp;gt;&amp;amp;lt;/td&amp;amp;gt;&amp;amp;lt;/tr&amp;amp;gt;\n&amp;quot;);&lt;br /&gt;
    $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;/table&amp;amp;gt;&amp;amp;lt;/form&amp;amp;gt;\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Once the form has been built, the work for this stage is complete—the&lt;br /&gt;
form is relayed to the user, who will submit a completed form, thereby&lt;br /&gt;
invoking the next state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== State 2: Query the JUD ==== &lt;br /&gt;
&amp;lt;br&amp;gt;The submission of the HTML form will&lt;br /&gt;
cause a number of name/value pairs to be passed as part of the HTTP GET&lt;br /&gt;
request. These names and values are captured into the &amp;lt;tt&amp;gt;@a&amp;lt;/tt&amp;gt; array&lt;br /&gt;
as described earlier. If we have more than one entry in &amp;lt;tt&amp;gt;@a&amp;lt;/tt&amp;gt;, we&lt;br /&gt;
know it's a form submission and must respond to that by querying the JUD&lt;br /&gt;
and returning the results. In this case, as we know that the contents of&lt;br /&gt;
&amp;lt;tt&amp;gt;@a&amp;lt;/tt&amp;gt; are name/value pairs, we can view those contents as a hash,&lt;br /&gt;
using a new variable &amp;lt;tt&amp;gt;%a&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;  elsif (scalar @a &amp;amp;gt; 1) { my %a = @a;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Now, &amp;lt;tt&amp;gt;%a&amp;lt;/tt&amp;gt; will contain entries where the keys are the names of&lt;br /&gt;
the search fields and the values are the values entered in the form.&lt;br /&gt;
&lt;br /&gt;
In the same way that we constructed an IQ-get to query the JUD for the&lt;br /&gt;
search fields and instructions, we construct an IQ-set to perform the&lt;br /&gt;
actual query:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;    my $iq = $nf-&amp;amp;gt;newNode('iq'); $iq-&amp;amp;gt;attr('to', JUD);&lt;br /&gt;
$iq-&amp;amp;gt;attr('type', IQ_SET); my $query = $iq-&amp;amp;gt;insertTag('query',&lt;br /&gt;
NS_SEARCH);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Using the information in &amp;lt;tt&amp;gt;%a&amp;lt;/tt&amp;gt;, we insert tags for each of the&lt;br /&gt;
search fields for which a value was specified in the form. For example,&lt;br /&gt;
if only the value &amp;lt;tt&amp;gt;adams&amp;lt;/tt&amp;gt; was specified, in the field&lt;br /&gt;
representing the &amp;lt;tt&amp;gt;&amp;amp;lt;last/&amp;amp;gt;&amp;lt;/tt&amp;gt; search field, as shown in Figure&lt;br /&gt;
10-3, we would only want to insert:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;last&amp;amp;gt;adams&amp;amp;lt;/last&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
as a child of the IQ-set's &amp;lt;tt&amp;gt;&amp;amp;lt;query/&amp;amp;gt;&amp;lt;/tt&amp;gt; tag:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;    while (my($name, $val) = each(%a)) {&lt;br /&gt;
$query-&amp;amp;gt;insertTag($name)-&amp;amp;gt;data($val) if $val;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Also in a similar way to handling state 1, we make the call by using the&lt;br /&gt;
&amp;lt;tt&amp;gt;ask()&amp;lt;/tt&amp;gt; method; the response will be received into the&lt;br /&gt;
&amp;lt;tt&amp;gt;$result&amp;lt;/tt&amp;gt; variable as an object representation of the IQ-result&lt;br /&gt;
(or IQ-error) element:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;    my $result = $c-&amp;amp;gt;ask($iq);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We deal simply with any error situation:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;    if ($result-&amp;amp;gt;attr('type') eq IQ_ERROR) {&lt;br /&gt;
$r-&amp;amp;gt;print(&amp;quot;Sorry, cannot query the JUD&amp;quot;);&lt;br /&gt;
$r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;/body&amp;amp;gt;&amp;amp;lt;/html&amp;amp;gt;&amp;quot;); $c-&amp;amp;gt;disconnect; return;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
otherwise proceeding to extract the &amp;lt;tt&amp;gt;&amp;amp;lt;query/&amp;amp;gt;&amp;lt;/tt&amp;gt; tag from the&lt;br /&gt;
search result. This tag will contain the &amp;lt;tt&amp;gt;&amp;amp;lt;item/&amp;amp;gt;&amp;lt;/tt&amp;gt;s&lt;br /&gt;
representing the JUD entries found to match the search criteria&lt;br /&gt;
submitted (see the response in Example 10-2):&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;    my $info = $c-&amp;amp;gt;ask($iq)-&amp;amp;gt;getTag('', NS_SEARCH);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We want to display a simple table of results, with each table row&lt;br /&gt;
representing an &amp;lt;tt&amp;gt;&amp;amp;lt;item/&amp;amp;gt;&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;    my $items = 0;&lt;br /&gt;
&lt;br /&gt;
    $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;p&amp;amp;gt;&amp;amp;lt;strong&amp;amp;gt;&amp;quot;.JUD.&amp;quot;&amp;amp;lt;/strong&amp;amp;gt;&amp;amp;lt;/p&amp;amp;gt&lt;br /&gt;
    ;\n&amp;quot;); $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;table border=&amp;quot;1&amp;quot;&amp;amp;gt;\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    foreach my $item ($info-&amp;amp;gt;getChildren) {&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
During the first iteration of the &amp;lt;tt&amp;gt;foreach&amp;lt;/tt&amp;gt; loop, that is, on our&lt;br /&gt;
first child tag of &amp;lt;tt&amp;gt;&amp;amp;lt;query/&amp;amp;gt;&amp;lt;/tt&amp;gt;, we take the opportunity to&lt;br /&gt;
write out a heading row, using the HTML &amp;lt;tt&amp;gt;&amp;amp;lt;th/&amp;amp;gt;&amp;lt;/tt&amp;gt; (table&lt;br /&gt;
heading) tags:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;      unless ($items) { $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;tr&amp;amp;gt;&amp;quot;); foreach my&lt;br /&gt;
$tag ($item-&amp;amp;gt;getChildren) {&lt;br /&gt;
$r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;th&amp;amp;gt;&amp;quot;.ucfirst($tag-&amp;amp;gt;name).&amp;quot;&amp;amp;lt;/th&amp;amp;gt;&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;/tr&amp;amp;gt;\n&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The main part of our loop translates the information found in each&lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;amp;lt;item/&amp;amp;gt;&amp;lt;/tt&amp;gt; tag:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;item jid='joseph@gnu.mine.nu'&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;nick&amp;amp;gt;joseph&amp;amp;lt;/nick&amp;amp;gt; &amp;amp;lt;first&amp;amp;gt;Joseph&amp;amp;lt;/first&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;email&amp;amp;gt;joseph@pipetree.com&amp;amp;lt;/email&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;last&amp;amp;gt;Adams&amp;amp;lt;/last&amp;amp;gt; &amp;amp;lt;/item&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
into HTML table rows, with one table cell (&amp;lt;tt&amp;gt;&amp;amp;lt;td/&amp;amp;gt;&amp;lt;/tt&amp;gt;) for&lt;br /&gt;
each item field:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;      $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;tr&amp;amp;gt;&amp;quot;); my $flag = 0; foreach my $tag&lt;br /&gt;
($item-&amp;amp;gt;getChildren) { unless (length($tag-&amp;amp;gt;data) == 0 or $flag++)&lt;br /&gt;
{ $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;td&amp;amp;gt;&amp;amp;lt;a&lt;br /&gt;
href=&amp;quot;/jbook?&amp;quot;.$item-&amp;amp;gt;attr('jid').&amp;quot;&amp;quot;&amp;amp;gt;&amp;quot;);&lt;br /&gt;
$r-&amp;amp;gt;print($tag-&amp;amp;gt;data.&amp;quot;&amp;amp;lt;/a&amp;amp;gt;&amp;amp;lt;/td&amp;amp;gt;&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        else { $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;td&amp;amp;gt;&amp;quot;.$tag-&amp;amp;gt;data.&amp;quot;&amp;amp;lt;/td&amp;amp;gt;&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
      $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;/tr&amp;amp;gt;\n&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
In this section of the code, we also make the link between the first and&lt;br /&gt;
second level of the address book. The JID, specified in each&lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;amp;lt;item/&amp;amp;gt;&amp;lt;/tt&amp;gt; tag's &amp;lt;tt&amp;gt;jid&amp;lt;/tt&amp;gt; attribute, is the key to the&lt;br /&gt;
JUD entry that the item represents and also the key to the vCard of the&lt;br /&gt;
user that has that JID. For each of the item lines in the table, we need&lt;br /&gt;
to build a selectable link to lead the user to the second level, which&lt;br /&gt;
allows him to view the vCard. This is what we want each link to look&lt;br /&gt;
like:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; http://www.pipetree.com/jbook?dj@gnu.mine.nu&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
That is, a single argument, representing the JID, specified after the&lt;br /&gt;
question mark. The condition:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;unless (length($tag-&amp;amp;gt;data) == 0 or $flag++)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
serves to ensure that the link is made on a single, nonempty field in&lt;br /&gt;
the JUD item. When registering with a standard JUD, none of the fields&lt;br /&gt;
are compulsory, so it's quite possible for there to be missing values&lt;br /&gt;
returned in the search results. So we want to make sure that the&lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;amp;lt;a href=&amp;quot;...&amp;quot;&amp;amp;gt;...&amp;amp;lt;/a&amp;amp;gt;&amp;lt;/tt&amp;gt; link that we build actually&lt;br /&gt;
surrounds some value; otherwise, it wouldn't be clickable. The&lt;br /&gt;
&amp;lt;tt&amp;gt;$flag&amp;lt;/tt&amp;gt; variable just ensures we  build only one link and not a&lt;br /&gt;
link for every nonempty field.&lt;br /&gt;
&lt;br /&gt;
Finally, the number of items found is displayed with:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;      $items++;&lt;br /&gt;
    }&lt;br /&gt;
    $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;/table&amp;amp;gt;\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;p&amp;amp;gt;$items results found&amp;amp;lt;/p&amp;amp;gt;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== State 3: Retrieve a vCard ==== &lt;br /&gt;
&amp;lt;br&amp;gt;If we receive a single argument in&lt;br /&gt;
the request, we'll take it to be a JID, passed from the link in the&lt;br /&gt;
table build in the previous state, and immediately build an IQ-get to&lt;br /&gt;
retrieve the vCard. The JID is to be found in the first element in the&lt;br /&gt;
&amp;lt;tt&amp;gt;@a&amp;lt;/tt&amp;gt; array—&amp;lt;tt&amp;gt;$a[0]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;  else {&lt;br /&gt;
&lt;br /&gt;
    my $iq = $nf-&amp;amp;gt;newNode('iq'); $iq-&amp;amp;gt;attr('to', $a[0]);&lt;br /&gt;
    $iq-&amp;amp;gt;attr('type', IQ_GET); $iq-&amp;amp;gt;insertTag('vcard', NS_VCARD);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Notice how the name of the query tag in this query is not&lt;br /&gt;
&amp;lt;tt&amp;gt;query&amp;lt;/tt&amp;gt;, but &amp;lt;tt&amp;gt;vcard&amp;lt;/tt&amp;gt;. See Section 6.5.1 in Chapter 6 for&lt;br /&gt;
details.&lt;br /&gt;
&lt;br /&gt;
The retrieval query is in the form of an IQ-get, rather than an IQ-set.&lt;br /&gt;
As we needed to send information in our JUD query (the search criteria),&lt;br /&gt;
an IQ-set was appropriate. Here, an IQ-get is appropriate as we're not&lt;br /&gt;
including any information to qualify our request; all we need to send is&lt;br /&gt;
this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;iq type='get' to='dj@gnu.mine.nu'&amp;amp;gt; &amp;amp;lt;vcard&lt;br /&gt;
xmlns='vcard-temp'/&amp;amp;gt; &amp;amp;lt;/iq&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
After sending the &amp;lt;tt&amp;gt;&amp;amp;lt;iq/&amp;amp;gt;&amp;lt;/tt&amp;gt; element, waiting for the&lt;br /&gt;
response, and checking for any errors, we extract the vCard detail and&lt;br /&gt;
display it:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;    my $result = $c-&amp;amp;gt;ask($iq);&lt;br /&gt;
&lt;br /&gt;
    if ($result-&amp;amp;gt;attr('type') eq IQ_ERROR)  { $r-&amp;amp;gt;print(&amp;quot;Sorry,&lt;br /&gt;
    cannot retrieve the vCard for $a[0]&amp;quot;);&lt;br /&gt;
    $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;/body&amp;amp;gt;&amp;amp;lt;/html&amp;amp;gt;&amp;quot;); $c-&amp;amp;gt;disconnect;&lt;br /&gt;
    return;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The structure of the vCard namespace is rather complicated and&lt;br /&gt;
long-winded, and it's common for many of the fields to remain unfilled.&lt;br /&gt;
So to keep the script simple, we're going to display all the top-level&lt;br /&gt;
fields that aren't empty:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;    my $vcard = $result-&amp;amp;gt;getTag('', NS_VCARD);&lt;br /&gt;
&lt;br /&gt;
    print (&amp;quot;&amp;amp;lt;strong&amp;amp;gt;$a[0]&amp;amp;lt;/strong&amp;amp;gt;\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    foreach my $tag ($vcard-&amp;amp;gt;getChildren) { print&lt;br /&gt;
    &amp;quot;&amp;amp;lt;br/&amp;amp;gt;&amp;quot;.$tag-&amp;amp;gt;name.&amp;quot; : &amp;quot;.$tag-&amp;amp;gt;data.&amp;quot;\n&amp;quot; if&lt;br /&gt;
    $tag-&amp;amp;gt;data;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== General handler close ==== &lt;br /&gt;
&amp;lt;br&amp;gt;Once we've dealt with the possible&lt;br /&gt;
states, we send the closing HTML statements common to all three of them,&lt;br /&gt;
and disconnect from the Jabber server:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;  $r-&amp;amp;gt;print(&amp;quot;&amp;amp;lt;/body&amp;amp;gt;&amp;amp;lt;/html&amp;amp;gt;&amp;quot;); $c-&amp;amp;gt;disconnect;&lt;br /&gt;
&lt;br /&gt;
  return;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
At this stage, there's nothing more for the module to do. Having&lt;br /&gt;
discerned the state from the arguments in the URL (and thereby the&lt;br /&gt;
appropriate action) and having carried out that action, the module ends,&lt;br /&gt;
handing control back to its ''mod_perl'' host. Remembering that&lt;br /&gt;
''Demo::JBook'' is an Apache handler in the form of a Perl module, we&lt;br /&gt;
need to ensure that the module itself returns a true value (as with any&lt;br /&gt;
Perl module):&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;}&lt;br /&gt;
&lt;br /&gt;
1;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Notes for Improvement === &lt;br /&gt;
&amp;lt;br&amp;gt;The ''Demo::JBook'' script is merely an&lt;br /&gt;
example. On top of tightening up the error and exception handling, there&lt;br /&gt;
are a few other things that you might want to consider doing to improve&lt;br /&gt;
upon it:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; Jabber connectivity&lt;br /&gt;
: As mentioned already, you'll probably want to improve the connection&lt;br /&gt;
: efficiency to the Jabber server by holding a socket open and sharing&lt;br /&gt;
: this connection across multiple calls to the handler. &lt;br /&gt;
; Choice of JUD&lt;br /&gt;
: The JUD to be queried is fixed; you may prefer to allow the user to&lt;br /&gt;
: select which JUD will be searched. What's more, selection of more than&lt;br /&gt;
: one JUD would allow a powerful search across public Jabber user&lt;br /&gt;
: directories. &lt;br /&gt;
; Key handling&lt;br /&gt;
: We've seen how a JUD is queried in Example 10-2. Some JUDs use the&lt;br /&gt;
: simple key-based security and pass an additional &amp;lt;tt&amp;gt;&amp;amp;lt;key/&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: tag containing random data—a sort of session key, as described in&lt;br /&gt;
: Section 6.2.11 and Section 6.2.13. Any &amp;lt;tt&amp;gt;&amp;amp;lt;key/&amp;amp;gt;&amp;lt;/tt&amp;gt; tag&lt;br /&gt;
: received from the JUD in response to an IQ-get must be sent back&lt;br /&gt;
: verbatim to the JUD in the subsequent IQ-set. Otherwise the search&lt;br /&gt;
: will fail, and you'll get a response similar to that shown in Example&lt;br /&gt;
: 10-7. &lt;br /&gt;
; Visual impact&lt;br /&gt;
: Last but not least, the visual impact of the end result as shown here&lt;br /&gt;
: (in Figure 10-3, Figure 10-4, and Figure 10-6) lacks a certain&lt;br /&gt;
: something. You might want to do something about that—give it a grander&lt;br /&gt;
: design, make it more pleasing, or at least interesting, to the eye.&lt;br /&gt;
: The HTML has been kept deliberately basic in this recipe, so as not to&lt;br /&gt;
: cloud the real theme of &amp;quot;Jabber without Jabber.&amp;quot; &lt;br /&gt;
''Failure to return a key could cause a search to fail''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;RECV: &amp;amp;lt;iq from='users.jabber.com' id='jud33'&lt;br /&gt;
to='jbook@gnu.mine.nu/jbook' type='error'&amp;amp;gt; &amp;amp;lt;query&lt;br /&gt;
xmlns='jabber:iq:search'&amp;amp;gt; &amp;amp;lt;error code='405'&amp;amp;gt;Keys do not&lt;br /&gt;
match.&amp;amp;lt;/error&amp;amp;gt; &amp;amp;lt;/query&amp;amp;gt; &amp;amp;lt;/iq&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== XML-RPC over Jabber == &lt;br /&gt;
&amp;lt;br&amp;gt;XML-RPC is an easy way to get software that's&lt;br /&gt;
running on different operating systems to be able to make and respond to&lt;br /&gt;
procedure calls (the &amp;quot;RPC&amp;quot; part of the name stands for &amp;quot;Remote Procedure&lt;br /&gt;
Call&amp;quot;) over the Internet.&lt;br /&gt;
&lt;br /&gt;
The basis of XML-RPC is straightforward and is described at XML-RPC's&lt;br /&gt;
home page (http://www.xml-rpc.com). The procedure calls, each consisting&lt;br /&gt;
of the name of the procedure (or ''method'') to call and a set of&lt;br /&gt;
arguments to go with that call and the corresponding responses, each&lt;br /&gt;
consisting of a set of results, are encoded in an XML-based format. The&lt;br /&gt;
requests and responses, so encoded, are exchanged over HTTP, carried as&lt;br /&gt;
the payloads of POST requests.&lt;br /&gt;
&lt;br /&gt;
Example 10-8 shows a typical request in XML-RPC encoding. It's calling a&lt;br /&gt;
procedure called &amp;lt;tt&amp;gt;examples.getStateName&amp;lt;/tt&amp;gt;, and passing a single&lt;br /&gt;
integer parameter with the value 41.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''An XML-RPC request''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;?xml version=&amp;quot;1.0&amp;quot;?&amp;amp;gt; &amp;amp;lt;methodCall&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;methodName&amp;amp;gt;examples.getStateName&amp;amp;lt;/methodName&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;params&amp;amp;gt; &amp;amp;lt;param&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;value&amp;amp;gt;&amp;amp;lt;i4&amp;amp;gt;41&amp;amp;lt;/i4&amp;amp;gt;&amp;amp;lt;/value&amp;amp;gt; &amp;amp;lt;/param&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/params&amp;amp;gt; &amp;amp;lt;/methodCall&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Example 10-9 shows a typical response to that request. The response&lt;br /&gt;
consists of a single string value &amp;quot;South Dakota.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''An XML-RPC response''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;?xml version=&amp;quot;1.0&amp;quot;?&amp;amp;gt; &amp;amp;lt;methodResponse&amp;amp;gt; &amp;amp;lt;params&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;param&amp;amp;gt; &amp;amp;lt;value&amp;amp;gt;&amp;amp;lt;string&amp;amp;gt;South&lt;br /&gt;
Dakota&amp;amp;lt;/string&amp;amp;gt;&amp;amp;lt;/value&amp;amp;gt; &amp;amp;lt;/param&amp;amp;gt; &amp;amp;lt;/params&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/methodResponse&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The choice of the word &amp;quot;payload&amp;quot; to describe the encoded requests and&lt;br /&gt;
responses is significant: each request, headed with an XML declaration&lt;br /&gt;
(&amp;lt;tt&amp;gt;&amp;amp;lt;?xml version=&amp;quot;1.0&amp;quot;?&amp;amp;gt;&amp;lt;/tt&amp;gt;) and encapsulated as a single tag&lt;br /&gt;
(&amp;lt;tt&amp;gt;&amp;amp;lt;methodCall/&amp;amp;gt;&amp;lt;/tt&amp;gt;), and each response, also headed with an&lt;br /&gt;
XML declaration and encapsulated as a single tag&lt;br /&gt;
(&amp;lt;tt&amp;gt;&amp;amp;lt;methodResponse/&amp;amp;gt;&amp;lt;/tt&amp;gt;), are succinct, fully formed, and&lt;br /&gt;
complete parcels that have meaning independent of their HTTP carrier.&lt;br /&gt;
&lt;br /&gt;
While the XML-RPC specification stipulates that these parcels be carried&lt;br /&gt;
over HTTP, we could take advantage of the power and simplicity of the&lt;br /&gt;
''encoding'' and carry procedure calls and responses over Jabber.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Jabber-RPC === &lt;br /&gt;
&amp;lt;br&amp;gt;Jabber-RPC is the name given to the marriage of&lt;br /&gt;
encoding from the XML-RPC specification and Jabber as the transport&lt;br /&gt;
mechanism. As well as building upon a stable specification, Jabber-RPC&lt;br /&gt;
brings advantages of its own to the world of procedure calls over the&lt;br /&gt;
Internet. Many of the potential XML-RPC responders are HTTP servers&lt;br /&gt;
behind corporate firewalls or one-way Network Address Translation (NAT)&lt;br /&gt;
mechanisms and are therefore unreachable from the Internet. Substituting&lt;br /&gt;
Jabber as a transport gives calls a better chance of reaching their&lt;br /&gt;
destination. If a Jabber-RPC responder—a program that connects to a&lt;br /&gt;
Jabber server, is addressable by a JID, and can receive (and respond to)&lt;br /&gt;
XML-RPC-encoded calls—is connected to a Jabber server visible to the&lt;br /&gt;
Internet, then request calls have to make it only to that Jabber server,&lt;br /&gt;
and internal packet routing within the server will allow the parcels to&lt;br /&gt;
reach their destinations behind the firewall, whether those destinations&lt;br /&gt;
are client-based or component-based responders.&lt;br /&gt;
&lt;br /&gt;
It should be clear by now that the idea of Jabber-RPC is to transport&lt;br /&gt;
the XML-RPC-encoded parcels in an extension, an attachment, to an IQ&lt;br /&gt;
element. Just as the details for a search attempt (for example of a&lt;br /&gt;
Jabber User Directory) are carried in an IQ-set extension qualified by&lt;br /&gt;
the &amp;lt;tt&amp;gt;jabber:iq:search&amp;lt;/tt&amp;gt; namespace (as shown in Example 10-2), so&lt;br /&gt;
the Jabber-RPC method calls are carried in an IQ-set extension qualified&lt;br /&gt;
by a namespace of its own. This namespace is a new one and is&lt;br /&gt;
&amp;lt;tt&amp;gt;jabber:iq:rpc&amp;lt;/tt&amp;gt;.&amp;lt;ref&amp;gt;This was decided during a session at the&lt;br /&gt;
JabberCon conference in August 2001 and has since been approved as a&lt;br /&gt;
draft protocol. More details are available at&lt;br /&gt;
http://www.pipetree.com/jabber/jrpc.html. &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Similarly, as the results of a JUD search are returned in an IQ-result,&lt;br /&gt;
so Jabber-RPC method responses are returned in an IQ-result. Example&lt;br /&gt;
10-10 shows a simple Jabber-RPC-based method call and response, using&lt;br /&gt;
the same XML-RPC-encoded parcels as shown in Example 10-8 and Example&lt;br /&gt;
10-9.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''A Jabber-RPC request/response conversation''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SEND: &amp;amp;lt;iq type='set' to='responder@company-a.com/jrpc-server'&lt;br /&gt;
id='1'&amp;amp;gt; &amp;amp;lt;query xmlns='jabber:iq:rpc'&amp;amp;gt; &amp;amp;lt;methodCall&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;methodName&amp;amp;gt;examples.getStateName&amp;amp;lt;/methodName&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;params&amp;amp;gt; &amp;amp;lt;param&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;value&amp;amp;gt;&amp;amp;lt;i4&amp;amp;gt;41&amp;amp;lt;/i4&amp;amp;gt;&amp;amp;lt;/value&amp;amp;gt; &amp;amp;lt;/param&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/params&amp;amp;gt; &amp;amp;lt;/methodCall&amp;amp;gt; &amp;amp;lt;/query&amp;amp;gt; &amp;amp;lt;/iq&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
RECV: &amp;amp;lt;iq type='result' to='requester@company-b.com/jrpc-client'&lt;br /&gt;
from='responder@company-a.com/jrpc-server' id='1'&amp;amp;gt; &amp;amp;lt;query&lt;br /&gt;
xmlns='jabber:iq:rpc'&amp;amp;gt; &amp;amp;lt;methodResponse&amp;amp;gt; &amp;amp;lt;params&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;param&amp;amp;gt; &amp;amp;lt;value&amp;amp;gt;&amp;amp;lt;string&amp;amp;gt;South&lt;br /&gt;
Dakota&amp;amp;lt;/string&amp;amp;gt;&amp;amp;lt;/value&amp;amp;gt; &amp;amp;lt;/param&amp;amp;gt; &amp;amp;lt;/params&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/methodResponse&amp;amp;gt; &amp;amp;lt;/query&amp;amp;gt; &amp;amp;lt;/iq&amp;amp;gt;&amp;lt;/code&amp;gt; It's clear that the&lt;br /&gt;
parcels of XML-RPC encoding lend themselves very well to being&lt;br /&gt;
transported in a meaningful way over Jabber and that Jabber's ultimate&lt;br /&gt;
flexibility makes this possible.&lt;br /&gt;
&lt;br /&gt;
The only major difference between the payloads as carried in an HTTP&lt;br /&gt;
POST and the payloads as carried in an &amp;lt;tt&amp;gt;&amp;amp;lt;iq/&amp;amp;gt;&amp;lt;/tt&amp;gt; element is&lt;br /&gt;
that there's no XML declaration. It's not possible of course, when you&lt;br /&gt;
consider the ''context'' of the IQ elements. They're document fragments&lt;br /&gt;
in the XML stream between the requester (or responder) and the Jabber&lt;br /&gt;
server. As explained in Section 5.3, these documents are fanfared with&lt;br /&gt;
their own XML declaration, and any further declaration within the&lt;br /&gt;
document is illegal from an XML point of view.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Sidebar|Jabber-RPC Requesters and RespondersA quick word about&lt;br /&gt;
Jabber-RPC requesters and reponders. Connection to a Jabber server is&lt;br /&gt;
possible in two main ways, as we've seen in the recipes so far: as a&lt;br /&gt;
client via the JSM or as a component connected directly to the jabberd&lt;br /&gt;
backbone. At the simplest level, all a Jabber-RPC requester or responder&lt;br /&gt;
is, is something that makes a Jabber connection, sends and receives IQ&lt;br /&gt;
elements, and uses a ''standard'' XML-RPC library to encode, decode, and&lt;br /&gt;
service the requests and responses.&lt;br /&gt;
&lt;br /&gt;
It doesn't matter whether the requesters and responders are built as&lt;br /&gt;
clients or components. One could argue that the Jabber client model fits&lt;br /&gt;
more naturally into the role of a requester, and the Jabber component&lt;br /&gt;
model fits more naturally into the role of a responder, but this isn't a&lt;br /&gt;
requirement. Indeed, if you're not the Jabber server administrator and&lt;br /&gt;
don't have access to the server configuration (to be able to insert a&lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;amp;lt;service/&amp;amp;gt;&amp;lt;/tt&amp;gt; stanza for a new component—see Section&lt;br /&gt;
9.3.1.1), building a Jabber-RPC responder as a Jabber client may be the&lt;br /&gt;
path of least resistance.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Building a Requester and a Responder === &lt;br /&gt;
&amp;lt;br&amp;gt;Let's have a look at the&lt;br /&gt;
power and flexibility of Jabber-RPC and how to build requesters and&lt;br /&gt;
responders. We're going to build a client-based requester, in Python,&lt;br /&gt;
and a client-based responder, in Java. There are two great XML-RPC&lt;br /&gt;
library implementations for Python and Java that we'll use to do the&lt;br /&gt;
legwork for us. Figure 10-8 shows what we want to build.&lt;br /&gt;
&lt;br /&gt;
To keep things fairly simple, we'll just implement and call something&lt;br /&gt;
similar to the &amp;lt;tt&amp;gt;getStateName()&amp;lt;/tt&amp;gt; function already shown in the&lt;br /&gt;
examples: &amp;lt;tt&amp;gt;getCountyName()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:jab_1008.png|The Jabber-RPC requester and responder|center|350 px&amp;lt;br&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The responder: JabberRPCResponder ==== &lt;br /&gt;
&amp;lt;br&amp;gt;We'll start up the Java&lt;br /&gt;
client-based Jabber-RPC responder (imaginatively called&lt;br /&gt;
''JabberRPCResponder'') specifying a handler class that is to service&lt;br /&gt;
the XML-RPC-encoded method calls, get it to connect to a Jabber server,&lt;br /&gt;
and listen for incoming Jabber-RPC requests. It will use the Helma&lt;br /&gt;
XML-RPC library (at http://xmlrpc.helma.org) to service incoming&lt;br /&gt;
requests using the handler class.&lt;br /&gt;
&lt;br /&gt;
Being a Java script, we'll use the JabberBeans library. We'll need to&lt;br /&gt;
extend the library's capabilities to handle extensions in the new&lt;br /&gt;
&amp;lt;tt&amp;gt;jabber:iq:rpc&amp;lt;/tt&amp;gt; namespace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The requester: JabberRPCRequester ==== &lt;br /&gt;
&amp;lt;br&amp;gt;The Python client-based&lt;br /&gt;
Jabber-RPC requester will also start up and connect to a Jabber server.&lt;br /&gt;
We'll use a different server than the one the responder is connected to;&lt;br /&gt;
after all, the whole point of XML-RPC and Jabber-RPC is to make the RPC&lt;br /&gt;
world a smaller and bigger place at the same time, through the power of&lt;br /&gt;
the Internet. We're going to use the Pythonware XML-RPC library&lt;br /&gt;
(http://www.pythonware.com/products/xmlrpc/index.htm) to encode a&lt;br /&gt;
&amp;lt;tt&amp;gt;getCountyName()&amp;lt;/tt&amp;gt; request and decode the response.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== JabberRPCResponder === &lt;br /&gt;
&amp;lt;br&amp;gt;Let's look at the Jabber-RPC responder first.&lt;br /&gt;
There is a single script, called ''JabberRPCResponder'', but there are&lt;br /&gt;
also a number of supporting classes that we need. Let's take things one&lt;br /&gt;
at a time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The RPCHandler class ==== &lt;br /&gt;
&amp;lt;br&amp;gt;The Helma XML-RPC library implementation&lt;br /&gt;
allows you to build XML-RPC responders independent of any particular&lt;br /&gt;
transport by using an instance of the &amp;lt;tt&amp;gt;XmlRpcServer&amp;lt;/tt&amp;gt; object,&lt;br /&gt;
which represents an abstraction of an XML-RPC server. You can then&lt;br /&gt;
construct a class—the ''handler class''—containing your methods to be&lt;br /&gt;
callable via XML-RPC. The calling of these methods is coordinated by the&lt;br /&gt;
&amp;lt;tt&amp;gt;XmlRpcServer&amp;lt;/tt&amp;gt; object, which you tell about your handler class&lt;br /&gt;
using the &amp;lt;tt&amp;gt;addHandler()&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
This is what the handler class, called &amp;lt;tt&amp;gt;RPCHandler&amp;lt;/tt&amp;gt;, looks like:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;// RPCHandler: A class of XML-RPC-callable methods&lt;br /&gt;
&lt;br /&gt;
public class RPCHandler {&lt;br /&gt;
&lt;br /&gt;
  // Note: This is a &amp;quot;traditional&amp;quot; list of counties!&lt;br /&gt;
&lt;br /&gt;
  private String county[] = {&amp;quot;Bedfordshire&amp;quot;, &amp;quot;Berkshire&amp;quot;,&lt;br /&gt;
  &amp;quot;Buckinghamshire&amp;quot;, &amp;quot;Cambridgeshire&amp;quot;, &amp;quot;Cheshire&amp;quot;, &amp;quot;Cornwall&amp;quot;,&lt;br /&gt;
  &amp;quot;Cumberland&amp;quot;, &amp;quot;Derbyshire&amp;quot;, &amp;quot;Devon&amp;quot;, &amp;quot;Dorset&amp;quot;, &amp;quot;Durham&amp;quot;, &amp;quot;Essex&amp;quot;,&lt;br /&gt;
  &amp;quot;Gloucestershire&amp;quot;, &amp;quot;Hampshire&amp;quot;, &amp;quot;Herefordshire&amp;quot;, &amp;quot;Hertfordshire&amp;quot;,&lt;br /&gt;
  &amp;quot;Humberside&amp;quot;, &amp;quot;Huntingdonshire&amp;quot;, &amp;quot;Kent&amp;quot;, &amp;quot;Lancashire&amp;quot;,&lt;br /&gt;
  &amp;quot;Leicestershire&amp;quot;, &amp;quot;Lincolnshire&amp;quot;, &amp;quot;London&amp;quot;, &amp;quot;Middlesex&amp;quot;, &amp;quot;Norfolk&amp;quot;,&lt;br /&gt;
  &amp;quot;Northamptonshire&amp;quot;, &amp;quot;Northumberland&amp;quot;, &amp;quot;Nottinghamshire&amp;quot;,&lt;br /&gt;
  &amp;quot;Oxfordshire&amp;quot;, &amp;quot;Rutland&amp;quot;, &amp;quot;Shropshire&amp;quot;, &amp;quot;Somerset&amp;quot;, &amp;quot;Staffordshire&amp;quot;,&lt;br /&gt;
  &amp;quot;Suffolk&amp;quot;, &amp;quot;Surrey&amp;quot;, &amp;quot;Sussex&amp;quot;, &amp;quot;Warwickshire&amp;quot;, &amp;quot;Westmorland&amp;quot;,&lt;br /&gt;
  &amp;quot;Wiltshire&amp;quot;, &amp;quot;Worcestershire&amp;quot;, &amp;quot;Yorkshire&amp;quot;};&lt;br /&gt;
&lt;br /&gt;
  public RPCHandler() {}&lt;br /&gt;
&lt;br /&gt;
  public String getCountyName(int c) { return county[c - 1];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The class has three elements:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; The list of counties&lt;br /&gt;
: The names of counties are stored in a simple array, &amp;lt;tt&amp;gt;county[]&amp;lt;/tt&amp;gt;. &lt;br /&gt;
; The constructor&lt;br /&gt;
: We don't need to do anything in the constructor,&lt;br /&gt;
: &amp;lt;tt&amp;gt;RPCHandler()&amp;lt;/tt&amp;gt;, as there's no requirement to manipulate objects&lt;br /&gt;
: directly, so the constructor remains empty. &lt;br /&gt;
; The single available method&lt;br /&gt;
: All public methods in the class are available through the&lt;br /&gt;
: &amp;lt;tt&amp;gt;XmlRpcServer&amp;lt;/tt&amp;gt; object. Here we have a single method for the&lt;br /&gt;
: purposes of this recipe: &amp;lt;tt&amp;gt;getCountyName()&amp;lt;/tt&amp;gt; returns the name of&lt;br /&gt;
: the county for the index given. When we examine the&lt;br /&gt;
: ''JabberRPCResponder'' script (in Section 10.2.3.3) we'll see how the&lt;br /&gt;
: &amp;lt;tt&amp;gt;XmlRpcServer&amp;lt;/tt&amp;gt; object is instantiated and how this&lt;br /&gt;
: &amp;lt;tt&amp;gt;RPCHandler&amp;lt;/tt&amp;gt; class is used. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The IQRPC classes ==== &lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;tt&amp;gt;JabberBeans&amp;lt;/tt&amp;gt; deals with Jabber&lt;br /&gt;
element extensions—&amp;lt;tt&amp;gt;&amp;amp;lt;query/&amp;amp;gt;&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;&amp;amp;lt;x/&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
tags—using individual helper classes. We've seen this in the&lt;br /&gt;
&amp;lt;tt&amp;gt;HostAlive&amp;lt;/tt&amp;gt; recipe in Section 8.2, where the&lt;br /&gt;
&amp;lt;tt&amp;gt;IQAuthBuilder&amp;lt;/tt&amp;gt; class is used to construct an authorization&lt;br /&gt;
extension:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;query xmlns='jabber:iq:auth'&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;username&amp;amp;gt;alive&amp;amp;lt;/username&amp;amp;gt; ... &amp;amp;lt;/query&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The helper classes are oriented around namespaces. Because we have a new&lt;br /&gt;
namespace to deal with (&amp;lt;tt&amp;gt;jabber:iq:rpc&amp;lt;/tt&amp;gt;), &amp;lt;tt&amp;gt;JabberBeans&amp;lt;/tt&amp;gt;&lt;br /&gt;
needs to have helper classes to handle extensions in that namespace.&lt;br /&gt;
&lt;br /&gt;
We need a minimum of two helper classes. We need a class that represents&lt;br /&gt;
an extension—a &amp;lt;tt&amp;gt;&amp;amp;lt;query/&amp;amp;gt;&amp;lt;/tt&amp;gt; tag—in the &amp;lt;tt&amp;gt;jabber:iq:rpc&amp;lt;/tt&amp;gt;&lt;br /&gt;
namespace. If we are going to construct IQ elements containing such&lt;br /&gt;
Jabber-RPC extensions, we also need a class to ''build'' those&lt;br /&gt;
extensions. The class that represents the &amp;lt;tt&amp;gt;jabber:iq:rpc&amp;lt;/tt&amp;gt;&lt;br /&gt;
extension is called &amp;lt;tt&amp;gt;IQRPC&amp;lt;/tt&amp;gt;, and the class that is the builder&lt;br /&gt;
for the extensions is called &amp;lt;tt&amp;gt;IQRPCBuilder&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For an example we're already familiar with, look at the steps leading up&lt;br /&gt;
to the authorization phase in the ''HostAlive'' script (and indeed our&lt;br /&gt;
''JabberRPCResponder'' script, which is shown in the next section); the&lt;br /&gt;
authorization IQ element is constructed as follows:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;InfoQueryBuilder iqb = new InfoQueryBuilder(); IQAuthBuilder&lt;br /&gt;
iqAuthb = new IQAuthBuilder();&lt;br /&gt;
&lt;br /&gt;
iqb.setType(&amp;quot;set&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
iqAuthb.setUsername(user); iqAuthb.setPassword(pass);&lt;br /&gt;
iqAuthb.setResource(resource);&lt;br /&gt;
&lt;br /&gt;
iqb.addExtension(iqAuthb.build());&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
If we bear in mind that this is what we want to end up with:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;iq type='set'&amp;amp;gt; &amp;amp;lt;query xmlns='jabber:iq:auth'&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;username&amp;amp;gt;...&amp;amp;lt;/username&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;password&amp;amp;gt;...&amp;amp;lt;/password&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;resource&amp;amp;gt;...&amp;amp;lt;/resource&amp;amp;gt; &amp;amp;lt;/query&amp;amp;gt; &amp;amp;lt;/iq&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
then we can understand what's going on:&lt;br /&gt;
&lt;br /&gt;
* The &amp;lt;tt&amp;gt;&amp;amp;lt;query/&amp;amp;gt;&amp;lt;/tt&amp;gt; tag in the &amp;lt;tt&amp;gt;jabber:iq:auth&amp;lt;/tt&amp;gt;&lt;br /&gt;
namespace is built with an ''authorization builder'', &amp;lt;tt&amp;gt;iqAuthb&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which is an instance of &amp;lt;tt&amp;gt;IQAuthBuilder&amp;lt;/tt&amp;gt;. &lt;br /&gt;
* Values for the tags within &amp;lt;tt&amp;gt;&amp;amp;lt;query/&amp;amp;gt;&amp;lt;/tt&amp;gt;, such as &amp;lt;tt&amp;gt;&amp;amp;lt;username/&amp;amp;gt;&amp;lt;/tt&amp;gt; and&lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;amp;lt;password/&amp;amp;gt;&amp;lt;/tt&amp;gt;, are set using methods belonging to that builder class. &lt;br /&gt;
* The actual extension is generated with a call to the&lt;br /&gt;
&amp;lt;tt&amp;gt;build()&amp;lt;/tt&amp;gt; method. Using &amp;lt;tt&amp;gt;addExtension()&amp;lt;/tt&amp;gt;, the newly&lt;br /&gt;
generated extension is added to the container representing the&lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;amp;lt;iq/&amp;amp;gt;&amp;lt;/tt&amp;gt; element being constructed by the ''IQ&lt;br /&gt;
builder''&amp;lt;tt&amp;gt;iqb&amp;lt;/tt&amp;gt;, an instance of &amp;lt;tt&amp;gt;InfoQueryBuilder&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Figure 8-3 shows the relationship between these builders and the things&lt;br /&gt;
they create. (For a review of what's required to authenticate with a&lt;br /&gt;
Jabber server, see Section 7.3.)&lt;br /&gt;
&lt;br /&gt;
Although necessary, the IQRPC classes aren't the focus of this recipe&lt;br /&gt;
and can be found in Appendix B. They are essentially modified copies of&lt;br /&gt;
the classes for the &amp;lt;tt&amp;gt;jabber:iq:time&amp;lt;/tt&amp;gt; namespace: &amp;lt;tt&amp;gt;IQTime&amp;lt;/tt&amp;gt;&lt;br /&gt;
and &amp;lt;tt&amp;gt;IQTimeBuilder&amp;lt;/tt&amp;gt;. They just need to be compiled and made&lt;br /&gt;
available in the &amp;lt;tt&amp;gt;$CLASSPATH.&amp;lt;/tt&amp;gt; Putting them in the same directory&lt;br /&gt;
as the ''JabberRPCResponder'' script will work fine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The JabberRPCResponder script ==== &lt;br /&gt;
&amp;lt;br&amp;gt;Example 10-11 shows the&lt;br /&gt;
''JabberRPCResponder'' script in its entirety. In the next section we'll&lt;br /&gt;
take it piece by piece.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''The JabberRPCResponder Script, written in Java''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;import org.jabber.jabberbeans.*; import&lt;br /&gt;
org.jabber.jabberbeans.Extension.*; import&lt;br /&gt;
org.jabber.jabberbeans.util.JID; import java.net.InetAddress; import&lt;br /&gt;
java.util.Enumeration; import java.io.*; import helma.xmlrpc.*;&lt;br /&gt;
&lt;br /&gt;
public class JabberRPCResponder implements PacketListener { private&lt;br /&gt;
String server   = &amp;quot;gnu.mine.nu&amp;quot;; private String user     = &amp;quot;server&amp;quot;;&lt;br /&gt;
private String pass     = &amp;quot;pass&amp;quot;; private String resource =&lt;br /&gt;
&amp;quot;jrpc-server&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  private XmlRpcServer responder;&lt;br /&gt;
&lt;br /&gt;
  private ConnectionBean cb;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  // Constructor&lt;br /&gt;
  public JabberRPCResponder() { responder = new XmlRpcServer();&lt;br /&gt;
  responder.addHandler(&amp;quot;examples&amp;quot;, new RPCHandler());&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Main program&lt;br /&gt;
  public static void main(String args[]) { JabberRPCResponder server =&lt;br /&gt;
  new JabberRPCResponder(); try { server.start();&lt;br /&gt;
    }&lt;br /&gt;
    catch (Exception e) { System.out.println(&amp;quot;Cannot start server: &amp;quot; +&lt;br /&gt;
    e.toString());&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void start() throws Exception { cb = new ConnectionBean();&lt;br /&gt;
  InetAddress addr;&lt;br /&gt;
&lt;br /&gt;
    cb.addPacketListener(this);&lt;br /&gt;
&lt;br /&gt;
    // Connect&lt;br /&gt;
    cb.connect(addr=InetAddress.getByName(server));&lt;br /&gt;
&lt;br /&gt;
    // Authenticate&lt;br /&gt;
    InfoQueryBuilder iqb = new InfoQueryBuilder(); IQAuthBuilder iqAuthb&lt;br /&gt;
    = new IQAuthBuilder();&lt;br /&gt;
&lt;br /&gt;
    iqb.setType(&amp;quot;set&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    iqAuthb.setUsername(user); iqAuthb.setPassword(pass);&lt;br /&gt;
    iqAuthb.setResource(resource);&lt;br /&gt;
&lt;br /&gt;
    iqb.addExtension(iqAuthb.build());&lt;br /&gt;
&lt;br /&gt;
	  InfoQuery iq = (InfoQuery)iqb.build();&lt;br /&gt;
&lt;br /&gt;
    cb.send(iq);&lt;br /&gt;
&lt;br /&gt;
    // Send presence&lt;br /&gt;
    PresenceBuilder pb = new PresenceBuilder(); cb.send(pb.build());&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  // Packet listener interface:&lt;br /&gt;
&lt;br /&gt;
  public void receivedPacket(PacketEvent pe) { Packet packet =&lt;br /&gt;
  pe.getPacket(); System.out.println(&amp;quot;RECV:&amp;quot; + packet.toString());&lt;br /&gt;
&lt;br /&gt;
    if (packet instanceof InfoQuery) { Enumeration e =&lt;br /&gt;
    ((InfoQuery)packet).Extensions(); if (e.hasMoreElements()) {&lt;br /&gt;
    Extension ext = (Extension)e.nextElement();&lt;br /&gt;
&lt;br /&gt;
        String request = ext.toString(); String id =&lt;br /&gt;
        ((InfoQuery)packet).getIdentifier(); JID from =&lt;br /&gt;
        ((InfoQuery)packet).getFromAddress();&lt;br /&gt;
&lt;br /&gt;
        ByteArrayInputStream bis = new&lt;br /&gt;
        ByteArrayInputStream(request.getBytes()); String result = new&lt;br /&gt;
        String(responder.execute(bis));&lt;br /&gt;
&lt;br /&gt;
        String response = result; int pos = result.lastIndexOf(&amp;quot;?&amp;amp;gt;&amp;quot;);&lt;br /&gt;
        if (pos &amp;amp;gt;= 0) { response = result.substring(pos + 2);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        IQRPCBuilder iqrpcb = new IQRPCBuilder();&lt;br /&gt;
        iqrpcb.setPayload(response);&lt;br /&gt;
&lt;br /&gt;
        InfoQueryBuilder iqb = new InfoQueryBuilder();&lt;br /&gt;
&lt;br /&gt;
        iqb.setType(&amp;quot;result&amp;quot;); iqb.setIdentifier(id);&lt;br /&gt;
        iqb.setToAddress(from); iqb.addExtension(iqrpcb.build());&lt;br /&gt;
&lt;br /&gt;
        InfoQuery iq; try { iq = (InfoQuery)iqb.build();&lt;br /&gt;
        }&lt;br /&gt;
        catch (InstantiationException ie) { System.out.println(&amp;quot;Build&lt;br /&gt;
        failed: &amp;quot; + ie.toString()); return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cb.send(iq);&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void sentPacket(PacketEvent pe) { Packet packet =&lt;br /&gt;
  pe.getPacket(); System.out.println(&amp;quot;SEND:&amp;quot; + packet.toString());&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void sendFailed(PacketEvent pe) { Packet packet =&lt;br /&gt;
  pe.getPacket(); System.out.println(&amp;quot;failed to send:&amp;quot; +&lt;br /&gt;
  packet.toString());&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Looking at JabberRPCResponder Step by Step === &lt;br /&gt;
&amp;lt;br&amp;gt;Now let's examine the&lt;br /&gt;
''JabberRPCResponder'' script step by step so we can see how it works:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;import org.jabber.jabberbeans.*; import&lt;br /&gt;
org.jabber.jabberbeans.Extension.*; import&lt;br /&gt;
org.jabber.jabberbeans.util.JID; import java.net.InetAddress; import&lt;br /&gt;
java.util.Enumeration; import java.io.*; import helma.xmlrpc.*;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We need to bring in the &amp;lt;tt&amp;gt;jabberbeans&amp;lt;/tt&amp;gt; classes as shown, as well&lt;br /&gt;
as some core Java features that we'll see used in the script a bit&lt;br /&gt;
later: an &amp;lt;tt&amp;gt;InetAddress&amp;lt;/tt&amp;gt; to represent the Jabber server's&lt;br /&gt;
hostname, an &amp;lt;tt&amp;gt;Enumeration&amp;lt;/tt&amp;gt; interface to access the extensions in&lt;br /&gt;
the incoming IQ elements, and &amp;lt;tt&amp;gt;java.io&amp;lt;/tt&amp;gt; features for feeding the&lt;br /&gt;
XML-RPC-encoded  requests to the &amp;lt;tt&amp;gt;XmlRpcServer&amp;lt;/tt&amp;gt; object. We also&lt;br /&gt;
bring in the classes from the Helma XML-RPC library.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;public class JabberRPCResponder implements PacketListener {&lt;br /&gt;
private String server   = &amp;quot;gnu.mine.nu&amp;quot;; private String user     =&lt;br /&gt;
&amp;quot;server&amp;quot;; private String pass     = &amp;quot;pass&amp;quot;; private String resource =&lt;br /&gt;
&amp;quot;jrpc-server&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  private XmlRpcServer responder;&lt;br /&gt;
&lt;br /&gt;
  private ConnectionBean cb;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The definition of our &amp;lt;tt&amp;gt;JabberRPCResponder&amp;lt;/tt&amp;gt; class looks similar to&lt;br /&gt;
that of the &amp;lt;tt&amp;gt;HostAlive&amp;lt;/tt&amp;gt; class in Section 8.2. However, rather&lt;br /&gt;
than merely connecting to a Jabber server and sending packets off down&lt;br /&gt;
the stream, we want to ''listen'' for incoming packets—in this case, IQ&lt;br /&gt;
elements carrying &amp;lt;tt&amp;gt;jabber:iq:rpc&amp;lt;/tt&amp;gt;-qualified payloads—and handle&lt;br /&gt;
them. Accordingly, we specify that our main class implements&lt;br /&gt;
&amp;lt;tt&amp;gt;PacketListener&amp;lt;/tt&amp;gt;, a JabberBeans interface that Jabber clients use&lt;br /&gt;
to receive notification of incoming packets. The interface describes&lt;br /&gt;
three methods: &amp;lt;tt&amp;gt;receivedPacket()&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;sentPacket()&amp;lt;/tt&amp;gt;, and&lt;br /&gt;
&amp;lt;tt&amp;gt;sendFailed()&amp;lt;/tt&amp;gt;. We'll define our &amp;lt;tt&amp;gt;receivedPacket()&amp;lt;/tt&amp;gt;&lt;br /&gt;
method, described later in this section, to catch and process the&lt;br /&gt;
incoming Jabber-RPC requests.&lt;br /&gt;
&lt;br /&gt;
We're going to use an &amp;lt;tt&amp;gt;XmlRpcServer&amp;lt;/tt&amp;gt; object, in&lt;br /&gt;
&amp;lt;tt&amp;gt;responder&amp;lt;/tt&amp;gt;, to provide the translation services between our&lt;br /&gt;
&amp;lt;tt&amp;gt;RPCHandler&amp;lt;/tt&amp;gt; class that contains the methods we want to &amp;quot;expose,&amp;quot;&lt;br /&gt;
and the XML-RPC-encoded requests and responses.&lt;br /&gt;
&lt;br /&gt;
Naturally, we also need a JabberBeans &amp;lt;tt&amp;gt;ConnectionBean&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
we'll hold in &amp;lt;tt&amp;gt;cb&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;  public JabberRPCResponder() { responder = new XmlRpcServer();&lt;br /&gt;
responder.addHandler(&amp;quot;examples&amp;quot;, new RPCHandler());&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;JabberRPCResponder&amp;lt;/tt&amp;gt; class constructor,&lt;br /&gt;
&amp;lt;tt&amp;gt;JabberRPCResponder()&amp;lt;/tt&amp;gt;, will be called in the &amp;lt;tt&amp;gt;main()&amp;lt;/tt&amp;gt;&lt;br /&gt;
method later in the script. It is used to create an instance of the&lt;br /&gt;
Helma &amp;lt;tt&amp;gt;XmlRpcServer&amp;lt;/tt&amp;gt; object, and associate our&lt;br /&gt;
&amp;lt;tt&amp;gt;RPCHandler&amp;lt;/tt&amp;gt; class with it, as a ''handler'' for method calls.&lt;br /&gt;
The &amp;lt;tt&amp;gt;addHandler()&amp;lt;/tt&amp;gt; method takes two arguments: the first is the&lt;br /&gt;
method prefix name, such as &amp;lt;tt&amp;gt;examples&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;methodName&amp;lt;/tt&amp;gt;&lt;br /&gt;
specification:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;methodName&amp;amp;gt;examples.getCountyName&amp;amp;lt;/methodName&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
and the second is the object—an instantiation of our handler class—which&lt;br /&gt;
contains the methods that the &amp;lt;tt&amp;gt;XmlRpcServer&amp;lt;/tt&amp;gt; will use to&lt;br /&gt;
&amp;quot;service&amp;quot; requests. In other words, the &amp;lt;tt&amp;gt;XmlRpcServer&amp;lt;/tt&amp;gt; object&lt;br /&gt;
will determine that a call to &amp;lt;tt&amp;gt;examples.getCountyName&amp;lt;/tt&amp;gt; should be&lt;br /&gt;
handled, as &amp;lt;tt&amp;gt;getCountyName&amp;lt;/tt&amp;gt;, by the &amp;lt;tt&amp;gt;RPCHandler&amp;lt;/tt&amp;gt; object.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;main()&amp;lt;/tt&amp;gt; method is quite short:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;  public static void main(String args[]) { JabberRPCResponder&lt;br /&gt;
server = new JabberRPCResponder(); try { server.start();&lt;br /&gt;
    }&lt;br /&gt;
    catch (Exception e) { System.out.println(&amp;quot;Cannot start server: &amp;quot; +&lt;br /&gt;
    e.toString());&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We instantiate our &amp;lt;tt&amp;gt;JabberRPCResponder&amp;lt;/tt&amp;gt; object into&lt;br /&gt;
&amp;lt;tt&amp;gt;server&amp;lt;/tt&amp;gt; and call the &amp;lt;tt&amp;gt;start()&amp;lt;/tt&amp;gt; method. Various functions&lt;br /&gt;
in &amp;lt;tt&amp;gt;start()&amp;lt;/tt&amp;gt; can raise exceptions; we take care of them all here&lt;br /&gt;
with a simple &amp;lt;tt&amp;gt;catch&amp;lt;/tt&amp;gt; clause and abort if necessary, rather than&lt;br /&gt;
include all of &amp;lt;tt&amp;gt;start()&amp;lt;/tt&amp;gt;'s functions here and have multiple&lt;br /&gt;
&amp;lt;tt&amp;gt;try&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catch&amp;lt;/tt&amp;gt; statements:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;  public void start() throws Exception { cb = new&lt;br /&gt;
ConnectionBean(); InetAddress addr;&lt;br /&gt;
&lt;br /&gt;
    cb.addPacketListener(this);&lt;br /&gt;
&lt;br /&gt;
    // Connect&lt;br /&gt;
    cb.connect(addr=InetAddress.getByName(server));&lt;br /&gt;
&lt;br /&gt;
    // Authenticate&lt;br /&gt;
    InfoQueryBuilder iqb = new InfoQueryBuilder(); IQAuthBuilder iqAuthb&lt;br /&gt;
    = new IQAuthBuilder();&lt;br /&gt;
&lt;br /&gt;
    iqb.setType(&amp;quot;set&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    iqAuthb.setUsername(user); iqAuthb.setPassword(pass);&lt;br /&gt;
    iqAuthb.setResource(resource);&lt;br /&gt;
&lt;br /&gt;
    iqb.addExtension(iqAuthb.build());&lt;br /&gt;
&lt;br /&gt;
	  InfoQuery iq = (InfoQuery)iqb.build();&lt;br /&gt;
&lt;br /&gt;
    cb.send(iq);&lt;br /&gt;
&lt;br /&gt;
    // Send presence&lt;br /&gt;
    PresenceBuilder pb = new PresenceBuilder(); cb.send(pb.build());&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Most of the content of this &amp;lt;tt&amp;gt;start()&amp;lt;/tt&amp;gt; function should be fairly&lt;br /&gt;
familiar. We instantiate a &amp;lt;tt&amp;gt;ConnectionBean&amp;lt;/tt&amp;gt; and will use that, in&lt;br /&gt;
&amp;lt;tt&amp;gt;cb&amp;lt;/tt&amp;gt;, throughout the script to send elements to the Jabber&lt;br /&gt;
server. Our &amp;lt;tt&amp;gt;PacketListener&amp;lt;/tt&amp;gt; is added as a listener to the&lt;br /&gt;
&amp;lt;tt&amp;gt;ConnectionBean&amp;lt;/tt&amp;gt;, causing a method of that interface&lt;br /&gt;
(&amp;lt;tt&amp;gt;packetReceived()&amp;lt;/tt&amp;gt;) to be invoked when an incoming element&lt;br /&gt;
appears on the stream managed by that &amp;lt;tt&amp;gt;ConnectionBean&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In the same way as described in Section 8.2.2 in Chapter 8, we build our&lt;br /&gt;
IQ element to authenticate, and send it to the server with the&lt;br /&gt;
&amp;lt;tt&amp;gt;ConnectionBean&amp;lt;/tt&amp;gt;'s &amp;lt;tt&amp;gt;send()&amp;lt;/tt&amp;gt; method. We also send an&lt;br /&gt;
initial availability, in the form of a simple &amp;lt;tt&amp;gt;&amp;amp;lt;presence/&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
element to the server.&lt;br /&gt;
&lt;br /&gt;
Having connected to and authenticated with the server and sent initial&lt;br /&gt;
availability, we can sit back and relax. All the subsequent activity&lt;br /&gt;
will be initiated by the arrival of IQ elements on the stream. As&lt;br /&gt;
described already, these will be made known (and available) in the form&lt;br /&gt;
of calls to the &amp;lt;tt&amp;gt;receivedPacket()&amp;lt;/tt&amp;gt; method of the&lt;br /&gt;
&amp;lt;tt&amp;gt;PacketListener&amp;lt;/tt&amp;gt; interface:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;  // Packet Listener interface:&lt;br /&gt;
&lt;br /&gt;
  public void receivedPacket(PacketEvent pe) { Packet packet =&lt;br /&gt;
  pe.getPacket(); System.out.println(&amp;quot;RECV:&amp;quot; + packet.toString());&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The method receives a &amp;lt;tt&amp;gt;PacketEvent&amp;lt;/tt&amp;gt; object, which represents both&lt;br /&gt;
the ''event'' of a packet (an element) arriving and the packet itself,&lt;br /&gt;
which we retrieve into &amp;lt;tt&amp;gt;packet&amp;lt;/tt&amp;gt; with the &amp;lt;tt&amp;gt;getPacket()&amp;lt;/tt&amp;gt;&lt;br /&gt;
method. For debugging purposes, we print out what we get.&lt;br /&gt;
&lt;br /&gt;
Now to determine what has actually arrived:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;    if (packet instanceof InfoQuery) { Enumeration e =&lt;br /&gt;
((InfoQuery)packet).Extensions(); if (e.hasMoreElements()) { Extension&lt;br /&gt;
ext = (Extension)e.nextElement();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We check to see if the element is an IQ element, and, if so, we retrieve&lt;br /&gt;
the extensions—the &amp;lt;tt&amp;gt;&amp;amp;lt;query/&amp;amp;gt;&amp;lt;/tt&amp;gt; tags—that the element&lt;br /&gt;
contains. Calling the &amp;lt;tt&amp;gt;Extensions()&amp;lt;/tt&amp;gt; method on the&lt;br /&gt;
&amp;lt;tt&amp;gt;packet&amp;lt;/tt&amp;gt; object returns an &amp;lt;tt&amp;gt;Enumeration&amp;lt;/tt&amp;gt; of those tags.&lt;br /&gt;
&lt;br /&gt;
We're expecting only one tag, and we pull that into &amp;lt;tt&amp;gt;ext&amp;lt;/tt&amp;gt; using&lt;br /&gt;
the &amp;lt;tt&amp;gt;nextElement()&amp;lt;/tt&amp;gt; method on our &amp;lt;tt&amp;gt;Enumeration&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Note|For the sake of simplicity, we're not checking here whether the&lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;amp;lt;query/&amp;amp;gt;&amp;lt;/tt&amp;gt; tag received is qualified by the&lt;br /&gt;
&amp;lt;tt&amp;gt;jabber:iq:rpc&amp;lt;/tt&amp;gt; namespace. You might wish to do that in your&lt;br /&gt;
version.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;        String request = ext.toString(); String id =&lt;br /&gt;
((InfoQuery)packet).getIdentifier(); JID from =&lt;br /&gt;
((InfoQuery)packet).getFromAddress();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We can pull the extension into string form, with the &amp;lt;tt&amp;gt;toString()&amp;lt;/tt&amp;gt;&lt;br /&gt;
method, ready for passing to our &amp;lt;tt&amp;gt;XmlRpcServer&amp;lt;/tt&amp;gt; object. At this&lt;br /&gt;
stage, &amp;lt;tt&amp;gt;ext&amp;lt;/tt&amp;gt; contains the complete XML-RPC-encoded parcel,&lt;br /&gt;
starting with the &amp;lt;tt&amp;gt;&amp;amp;lt;methodCall&amp;amp;gt;&amp;lt;/tt&amp;gt; opening tag:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;methodCall&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;methodName&amp;amp;gt;examples.getCountyName&amp;amp;lt;/methodName&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;params&amp;amp;gt; &amp;amp;lt;param&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;value&amp;amp;gt;&amp;amp;lt;i4&amp;amp;gt;14&amp;amp;lt;/i4&amp;amp;gt;&amp;amp;lt;/value&amp;amp;gt; &amp;amp;lt;/param&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/params&amp;amp;gt; &amp;amp;lt;/methodCall&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
So that we can send a response back to the requester, we need two other&lt;br /&gt;
things from the incoming element besides the actual request payload. In&lt;br /&gt;
general, when an &amp;lt;tt&amp;gt;&amp;amp;lt;iq/&amp;amp;gt;&amp;lt;/tt&amp;gt; element is sent, representing a&lt;br /&gt;
request, either as an IQ-get or an IQ-set, the sender is expecting the&lt;br /&gt;
response, either an IQ-result or an IQ-error, with the ''same value'' in&lt;br /&gt;
the &amp;lt;tt&amp;gt;id&amp;lt;/tt&amp;gt;  attribute. This is so the responses, once received, can&lt;br /&gt;
be matched up with the original requests. So we need to store the&lt;br /&gt;
&amp;lt;tt&amp;gt;id&amp;lt;/tt&amp;gt; value, available to us through the &amp;lt;tt&amp;gt;getIdentifier()&amp;lt;/tt&amp;gt;&lt;br /&gt;
method of the &amp;lt;tt&amp;gt;packet&amp;lt;/tt&amp;gt; object. We also need the JID of the&lt;br /&gt;
sender, retrieved with the &amp;lt;tt&amp;gt;getFromAddress()&amp;lt;/tt&amp;gt; method, so we can&lt;br /&gt;
specify it in the &amp;lt;tt&amp;gt;to&amp;lt;/tt&amp;gt; attribute of the IQ-result we'll be&lt;br /&gt;
sending back.&lt;br /&gt;
&lt;br /&gt;
Now it's time to service the request:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;        ByteArrayInputStream bis = new&lt;br /&gt;
ByteArrayInputStream(request.getBytes()); String result = new&lt;br /&gt;
String(responder.execute(bis));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
With the &amp;lt;tt&amp;gt;execute()&amp;lt;/tt&amp;gt; method of our &amp;lt;tt&amp;gt;XmlRpcServer&amp;lt;/tt&amp;gt; object&lt;br /&gt;
in &amp;lt;tt&amp;gt;responder&amp;lt;/tt&amp;gt;, we convert the &amp;lt;tt&amp;gt;&amp;amp;lt;methodCall/&amp;amp;gt;&amp;lt;/tt&amp;gt; into&lt;br /&gt;
a &amp;lt;tt&amp;gt;&amp;amp;lt;methodResponse/&amp;amp;gt;&amp;lt;/tt&amp;gt;, in effect. The decoding of the&lt;br /&gt;
XML-RPC-encoded request, the determination of which method in which&lt;br /&gt;
class to call (in our case it will be the &amp;lt;tt&amp;gt;getCountyName()&amp;lt;/tt&amp;gt;&lt;br /&gt;
method in our &amp;lt;tt&amp;gt;RPCHandler&amp;lt;/tt&amp;gt; class), the calling of that method,&lt;br /&gt;
and the encoding of the result into an XML-RPC-encoded response are all&lt;br /&gt;
done magically and transparently for us by &amp;lt;tt&amp;gt;XmlRpcServer&amp;lt;/tt&amp;gt; (thank&lt;br /&gt;
goodness, or this recipe would be unbearably long!).&lt;br /&gt;
&lt;br /&gt;
There's a bit of jiggling about required before we can make the&lt;br /&gt;
&amp;lt;tt&amp;gt;execute()&amp;lt;/tt&amp;gt; call, though. The method is expecting an&lt;br /&gt;
&amp;lt;tt&amp;gt;InputStream&amp;lt;/tt&amp;gt; object, and we've got a &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt;. Not to&lt;br /&gt;
worry, we just convert it with a &amp;lt;tt&amp;gt;ByteArrayInputStream&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
can take a byte array (from &amp;lt;tt&amp;gt;request.getBytes()&amp;lt;/tt&amp;gt;) and produce an&lt;br /&gt;
&amp;lt;tt&amp;gt;InputStream&amp;lt;/tt&amp;gt; object &amp;lt;tt&amp;gt;bis&amp;lt;/tt&amp;gt;. Similarly, &amp;lt;tt&amp;gt;execute()&amp;lt;/tt&amp;gt;&lt;br /&gt;
produces a byte array, so that is converted to a &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt; by&lt;br /&gt;
wrapping the call with &amp;lt;tt&amp;gt;String()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The incoming XML-RPC-encoded request, being carried in the IQ element,&lt;br /&gt;
will not include an XML declaration. Luckily, the &amp;lt;tt&amp;gt;XmlRpcServer&amp;lt;/tt&amp;gt;&lt;br /&gt;
does not mind that one is not present before decoding and dispatching&lt;br /&gt;
the request. It will, however, include one on the encoded response it&lt;br /&gt;
emits. So we must check for that and strip it off if there is one:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;        String response = result; int pos =&lt;br /&gt;
result.lastIndexOf(&amp;quot;?&amp;amp;gt;&amp;quot;); if (pos &amp;amp;gt;= 0) { response =&lt;br /&gt;
result.substring(pos + 2);&lt;br /&gt;
        &amp;lt;/code&amp;gt;}&lt;br /&gt;
Now we have everything we need to return the XML-RPC-encoded response to&lt;br /&gt;
the requester. It's time to call on the services of our &amp;lt;tt&amp;gt;IQRPC&amp;lt;/tt&amp;gt;&lt;br /&gt;
classes:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;        IQRPCBuilder iqrpcb = new IQRPCBuilder();&lt;br /&gt;
iqrpcb.setPayload(response);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We create an instance of the &amp;lt;tt&amp;gt;IQRPCBuilder&amp;lt;/tt&amp;gt; and call the single&lt;br /&gt;
method &amp;lt;tt&amp;gt;setPayload()&amp;lt;/tt&amp;gt; to load the XML-RPC-encoded response into&lt;br /&gt;
the &amp;lt;tt&amp;gt;&amp;amp;lt;query/&amp;amp;gt;&amp;lt;/tt&amp;gt; tag, which is qualified by the&lt;br /&gt;
&amp;lt;tt&amp;gt;jabber:iq:rpc&amp;lt;/tt&amp;gt; namespace. This is effectively the &amp;quot;extension&amp;quot; in&lt;br /&gt;
&amp;lt;tt&amp;gt;JabberBeans&amp;lt;/tt&amp;gt; parlance:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;        InfoQueryBuilder iqb = new InfoQueryBuilder();&lt;br /&gt;
&lt;br /&gt;
        iqb.setType(&amp;quot;result&amp;quot;); iqb.setIdentifier(id);&lt;br /&gt;
        iqb.setToAddress(from); iqb.addExtension(iqrpcb.build());&lt;br /&gt;
&lt;br /&gt;
        InfoQuery iq; try { iq = (InfoQuery)iqb.build();&lt;br /&gt;
        }&lt;br /&gt;
        catch (InstantiationException ie) { System.out.println(&amp;quot;Build&lt;br /&gt;
        failed: &amp;quot; + ie.toString()); return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        cb.send(iq);&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
After creating an IQ element container using an&lt;br /&gt;
&amp;lt;tt&amp;gt;InfoQueryBuilder&amp;lt;/tt&amp;gt; and setting the appropriate attributes, we&lt;br /&gt;
generate the &amp;lt;tt&amp;gt;&amp;amp;lt;query/&amp;amp;gt;&amp;lt;/tt&amp;gt; tag (&amp;lt;tt&amp;gt;iqrpcb.build()&amp;lt;/tt&amp;gt;) and&lt;br /&gt;
add it to the IQ element container with &amp;lt;tt&amp;gt;addExtension()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;amp;lt;iq/&amp;amp;gt;&amp;lt;/tt&amp;gt; is then generated—it now contains our&lt;br /&gt;
payload—and sent back to the server, where it will be routed to the&lt;br /&gt;
original requester.&lt;br /&gt;
&lt;br /&gt;
That's pretty much all there is to it. We have a couple of other methods&lt;br /&gt;
belonging to the &amp;lt;tt&amp;gt;PacketListener&amp;lt;/tt&amp;gt; interface:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;  public void sentPacket(PacketEvent pe) { Packet packet =&lt;br /&gt;
pe.getPacket(); System.out.println(&amp;quot;SEND:&amp;quot; + packet.toString());&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void sendFailed(PacketEvent pe) { Packet packet =&lt;br /&gt;
  pe.getPacket(); System.out.println(&amp;quot;Failed to send:&amp;quot; +&lt;br /&gt;
  packet.toString());&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We fill these methods with debugging-style output statements for our&lt;br /&gt;
convenience.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== JabberRPCRequester === &lt;br /&gt;
&amp;lt;br&amp;gt;Now that we've got our Jabber-RPC responder&lt;br /&gt;
all set up, it's time to turn our attention to our requester,&lt;br /&gt;
''JabberRPCRequester'', shown in Example 10-12. This is a Python script&lt;br /&gt;
that uses the &amp;lt;tt&amp;gt;Jabberpy&amp;lt;/tt&amp;gt; library and Pythonware's&lt;br /&gt;
&amp;lt;tt&amp;gt;xmlrpclib&amp;lt;/tt&amp;gt; library. It's a pretty simple affair.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''The JabberRPCRequester script, written in Python''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;import jabber import xmlrpclib import string import sys&lt;br /&gt;
&lt;br /&gt;
Server   = 'qmacro.dyndns.org' Username = 'client' Password = 'pass'&lt;br /&gt;
Resource = 'jrpc-client' Endpoint = 'server@gnu.mine.nu/jrpc-server';&lt;br /&gt;
Method   = 'examples.getCountyName';&lt;br /&gt;
&lt;br /&gt;
county   = string.atoi(sys.argv[1])&lt;br /&gt;
&lt;br /&gt;
con = jabber.Client(host=Server) try: con.connect() except IOError, e:&lt;br /&gt;
print &amp;quot;Couldn't connect: %s&amp;quot; % e sys.exit(0)&lt;br /&gt;
&lt;br /&gt;
con.auth(Username,Password,Resource)&lt;br /&gt;
&lt;br /&gt;
request = xmlrpclib.dumps(((county),), methodname=Method);&lt;br /&gt;
&lt;br /&gt;
iq = jabber.Iq(to=Endpoint, type=&amp;quot;set') iq.setQuery('jabber:iq:rpc')&lt;br /&gt;
iq.setQueryPayload(request)&lt;br /&gt;
&lt;br /&gt;
result = con.SendAndWaitForResponse(iq)&lt;br /&gt;
&lt;br /&gt;
if result.getType() == 'result': response =&lt;br /&gt;
str(result.getQueryPayload()) parms, func = xmlrpclib.loads(response)&lt;br /&gt;
print parms[0] else: print &amp;quot;Could not complete call&amp;quot;&lt;br /&gt;
&lt;br /&gt;
con.disconnect()&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Looking at JabberRPCRequester Step by Step === &lt;br /&gt;
&amp;lt;br&amp;gt;After importing the&lt;br /&gt;
libraries that we will need:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;import jabber import xmlrpclib import string import sys&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
we specify a number of parameters:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Server   = 'qmacro.dyndns.org' Username = 'client' Password =&lt;br /&gt;
'pass' Resource = 'jrpc-client'&lt;br /&gt;
&lt;br /&gt;
Endpoint = 'server@gnu.mine.nu/jrpc-server'; Method   =&lt;br /&gt;
'examples.getCountyName';&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The script connects to the Jabber server defined in &amp;lt;tt&amp;gt;Server&amp;lt;/tt&amp;gt;,&lt;br /&gt;
with the username defined in &amp;lt;tt&amp;gt;Username&amp;lt;/tt&amp;gt;. The resource that will&lt;br /&gt;
be passed in the authentication request is &amp;lt;tt&amp;gt;jrpc-client&amp;lt;/tt&amp;gt;. There&lt;br /&gt;
is as much significance in this name as there is in the name of the&lt;br /&gt;
resource used by ''JabberRPCResponder'' (&amp;lt;tt&amp;gt;jrpc-server&amp;lt;/tt&amp;gt;): none.&lt;br /&gt;
It's just a useful naming convention to adopt when writing requesters&lt;br /&gt;
and responders.&lt;br /&gt;
&lt;br /&gt;
A single parameter, which will be interpreted as the index of the county&lt;br /&gt;
to retrieve via the call to &amp;lt;tt&amp;gt;examples.getCountyName&amp;lt;/tt&amp;gt;, is&lt;br /&gt;
expected.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;county = string.atoi(sys.argv[1])&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The method expects an integer, so we convert it directly. This has a&lt;br /&gt;
favorable secondary effect when we come to XML-RPC encode the request;&lt;br /&gt;
if we hadn't called the &amp;lt;tt&amp;gt;string.atoi()&amp;lt;/tt&amp;gt; function and left&lt;br /&gt;
&amp;lt;tt&amp;gt;county&amp;lt;/tt&amp;gt; as a string, this is what the XML-RPC-encoded parcel&lt;br /&gt;
would have looked like:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;methodCall&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;methodName&amp;amp;gt;examples.getCountyName&amp;amp;lt;/methodName&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;params&amp;amp;gt; &amp;amp;lt;param&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;value&amp;amp;gt;&amp;amp;lt;string&amp;amp;gt;1&amp;amp;lt;/string&amp;amp;gt;&amp;amp;lt;/value&amp;amp;gt; &amp;amp;lt;/param&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/params&amp;amp;gt; &amp;amp;lt;/methodCall&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
However, this is what we really want:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;methodCall&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;methodName&amp;amp;gt;examples.getCountyName&amp;amp;lt;/methodName&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;params&amp;amp;gt; &amp;amp;lt;param&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;value&amp;amp;gt;&amp;amp;lt;int&amp;amp;gt;1&amp;amp;lt;/int&amp;amp;gt;&amp;amp;lt;/value&amp;amp;gt; &amp;amp;lt;/param&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/params&amp;amp;gt; &amp;amp;lt;/methodCall&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
In the same way as in the previous Python recipes, we connect to the&lt;br /&gt;
Jabber server and authenticate:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;con = jabber.Client(host=Server) try: con.connect() except&lt;br /&gt;
IOError, e: print &amp;quot;Couldn't connect: %s&amp;quot; % e sys.exit(0)&lt;br /&gt;
&lt;br /&gt;
con.auth(Username,Password,Resource)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Now all we have to do is compose our XML-RPC-encoded request and send it&lt;br /&gt;
on its way to the Jabber-RPC responder, which in our case, identified&lt;br /&gt;
here by the JID in the &amp;lt;tt&amp;gt;Endpoint&amp;lt;/tt&amp;gt; variable, is our&lt;br /&gt;
''JabberRPCResponder'' script.&lt;br /&gt;
&lt;br /&gt;
It's time to call on the services of the XML-RPC library. We use the&lt;br /&gt;
&amp;lt;tt&amp;gt;dumps()&amp;lt;/tt&amp;gt; function to build an XML-RPC encoding, passing the&lt;br /&gt;
single parameter (in a tuple, which is required by &amp;lt;tt&amp;gt;dumps()&amp;lt;/tt&amp;gt;)&lt;br /&gt;
representing the county index and the name of the method to call:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;request = xmlrpclib.dumps(((county),), methodname=Method);&amp;lt;/code&amp;gt; We&lt;br /&gt;
build the IQ-set containing a &amp;lt;tt&amp;gt;&amp;amp;lt;query/&amp;amp;gt;&amp;lt;/tt&amp;gt; element in the&lt;br /&gt;
&amp;lt;tt&amp;gt;jabber:iq:rpc&amp;lt;/tt&amp;gt; namespace, by creating an instance of an&lt;br /&gt;
&amp;lt;tt&amp;gt;Iq&amp;lt;/tt&amp;gt; object, and calling methods to specify that namespace&lt;br /&gt;
(&amp;lt;tt&amp;gt;setQuery()&amp;lt;/tt&amp;gt;) and insert the XML-RPC encoding as the payload&lt;br /&gt;
(&amp;lt;tt&amp;gt;setQueryPayload()&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;iq = jabber.Iq(to=Endpoint, type='set')&lt;br /&gt;
iq.setQuery('jabber:iq:rpc') iq.setQueryPayload(request)&amp;lt;/code&amp;gt; At this&lt;br /&gt;
stage, we need to send it off and wait for a response. You have probably&lt;br /&gt;
noticed that, unlike in previous Python recipes, this script hasn't&lt;br /&gt;
defined or registered a callback to handle incoming elements. This is&lt;br /&gt;
because we're approaching the task in a slightly different way in this&lt;br /&gt;
script. The method used to send the element to the Jabber&lt;br /&gt;
server—&amp;lt;tt&amp;gt;SendAndWaitForResponse()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result = con.SendAndWaitForResponse(iq)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
is the rather verbose cousin of the &amp;lt;tt&amp;gt;Jabber::Connection&amp;lt;/tt&amp;gt;&lt;br /&gt;
library's &amp;lt;tt&amp;gt;ask()&amp;lt;/tt&amp;gt; method, as described in Section 10.1.5.3. It&lt;br /&gt;
does &amp;quot;exactly what it says on the tin,&amp;quot; namely, send the element off to&lt;br /&gt;
the server and block until an element is received that is deemed, by a&lt;br /&gt;
matchup  of the &amp;lt;tt&amp;gt;id&amp;lt;/tt&amp;gt; attribute values on both elements, to be the&lt;br /&gt;
response. If no &amp;lt;tt&amp;gt;id&amp;lt;/tt&amp;gt; attribute exists on the outgoing element, it&lt;br /&gt;
is stamped with one (with a value unique within the current usage of the&lt;br /&gt;
&amp;lt;tt&amp;gt;jabber&amp;lt;/tt&amp;gt; class). Both are also relations of&lt;br /&gt;
&amp;lt;tt&amp;gt;Net::Jabber&amp;lt;/tt&amp;gt;'s &amp;lt;tt&amp;gt;SendAndReceiveWithID()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
So &amp;lt;tt&amp;gt;result&amp;lt;/tt&amp;gt; receives an element object. It's an IQ element, as&lt;br /&gt;
that is what a response to an IQ element will be. If the call&lt;br /&gt;
''transport'' (as opposed to the call itself) is successful, the&lt;br /&gt;
response will be an IQ-result. If not, for example, if the&lt;br /&gt;
&amp;lt;tt&amp;gt;Endpoint&amp;lt;/tt&amp;gt; that we specified doesn't exist, then the response&lt;br /&gt;
will be an IQ-error.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if result.getType() == 'result': response =&lt;br /&gt;
str(result.getQueryPayload()) parms, func = xmlrpclib.loads(response)&lt;br /&gt;
print parms[0] else: print &amp;quot;Could not complete call&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Conversely, while the call transport might have succeeded, the call&lt;br /&gt;
itself might have failed, for example, if we had specified a nonexistent&lt;br /&gt;
method name in &amp;lt;tt&amp;gt;Method&amp;lt;/tt&amp;gt;. However, for our purposes, we're going&lt;br /&gt;
to assume that the call was successful. So we grab the payload (i.e.,&lt;br /&gt;
the contents of the &amp;lt;tt&amp;gt;&amp;amp;lt;query/&amp;amp;gt;&amp;lt;/tt&amp;gt; tag) and string it with&lt;br /&gt;
&amp;lt;tt&amp;gt;str()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;loads()&amp;lt;/tt&amp;gt; function of &amp;lt;tt&amp;gt;xmlrpclib&amp;lt;/tt&amp;gt; is used to extract&lt;br /&gt;
the details from an XML-RPC-encoded parcel; it will produce two values,&lt;br /&gt;
which we capture in &amp;lt;tt&amp;gt;resp&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;func&amp;lt;/tt&amp;gt;. The first is the&lt;br /&gt;
set of parameters, common to either a request or a response, and the&lt;br /&gt;
second is the method name, if it exists in the encoding. We want to&lt;br /&gt;
decode a &amp;lt;tt&amp;gt;&amp;amp;lt;methodResponse/&amp;amp;gt;&amp;lt;/tt&amp;gt; here, so there's no method&lt;br /&gt;
name present, but there should be a set of parameters.&lt;br /&gt;
&lt;br /&gt;
We take the first (and only) element from the set of parameters in&lt;br /&gt;
&amp;lt;tt&amp;gt;resp&amp;lt;/tt&amp;gt; and print it out.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Jabber-RPC in Perl === &lt;br /&gt;
&amp;lt;br&amp;gt;Exciting as this recipe might be, it's not&lt;br /&gt;
very visual. There are no screenshots of note to show, just a couple of&lt;br /&gt;
STDOUTs from two scripts started at the command line. To fix this&lt;br /&gt;
&amp;quot;problem,&amp;quot; we're going to round this recipe off with a quick look at&lt;br /&gt;
Jabber-RPC in Perl. Based on the &amp;lt;tt&amp;gt;Jabber::Connection&amp;lt;/tt&amp;gt; library is&lt;br /&gt;
a fairly new Perl library called &amp;lt;tt&amp;gt;Jabber::RPC&amp;lt;/tt&amp;gt;, which sports two&lt;br /&gt;
modules: &amp;lt;tt&amp;gt;Jabber::RPC::Client.pm&amp;lt;/tt&amp;gt; and&lt;br /&gt;
&amp;lt;tt&amp;gt;Jabber::RPC::Server.pm&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you're slightly perplexed about what it takes to extend Jabber&lt;br /&gt;
support in Java, take a look at Example 10-13 and Example 10-14. The&lt;br /&gt;
first is an implementation, in Perl, of the ''JabberRPCResponder'' and&lt;br /&gt;
all its class periphery. The second is an implementation of our&lt;br /&gt;
''JabberRPCRequester''.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''A Jabber-RPC Responder in Perl''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;use strict; use Jabber::RPC::Server;&lt;br /&gt;
&lt;br /&gt;
my @county = (&amp;quot;Bedfordshire&amp;quot;, &amp;quot;Berkshire&amp;quot;, &amp;quot;Buckinghamshire&amp;quot;,&lt;br /&gt;
&amp;quot;Cambridgeshire&amp;quot;, &amp;quot;Cheshire&amp;quot;, &amp;quot;Cornwall&amp;quot;, &amp;quot;Cumberland&amp;quot;, &amp;quot;Derbyshire&amp;quot;,&lt;br /&gt;
&amp;quot;Devon&amp;quot;, &amp;quot;Dorset&amp;quot;, &amp;quot;Durham&amp;quot;, &amp;quot;Essex&amp;quot;, &amp;quot;Gloucestershire&amp;quot;, &amp;quot;Hampshire&amp;quot;,&lt;br /&gt;
&amp;quot;Herefordshire&amp;quot;, &amp;quot;Hertfordshire&amp;quot;, &amp;quot;Humberside&amp;quot;, &amp;quot;Huntingdonshire&amp;quot;,&lt;br /&gt;
&amp;quot;Kent&amp;quot;, &amp;quot;Lancashire&amp;quot;, &amp;quot;Leicestershire&amp;quot;, &amp;quot;Lincolnshire&amp;quot;, &amp;quot;London&amp;quot;,&lt;br /&gt;
&amp;quot;Middlesex&amp;quot;, &amp;quot;Norfolk&amp;quot;, &amp;quot;Northamptonshire&amp;quot;, &amp;quot;Northumberland&amp;quot;,&lt;br /&gt;
&amp;quot;Nottinghamshire&amp;quot;, &amp;quot;Oxfordshire&amp;quot;, &amp;quot;Rutland&amp;quot;, &amp;quot;Shropshire&amp;quot;, &amp;quot;Somerset&amp;quot;,&lt;br /&gt;
&amp;quot;Staffordshire&amp;quot;, &amp;quot;Suffolk&amp;quot;, &amp;quot;Surrey&amp;quot;, &amp;quot;Sussex&amp;quot;, &amp;quot;Warwickshire&amp;quot;,&lt;br /&gt;
&amp;quot;Westmorland&amp;quot;, &amp;quot;Wiltshire&amp;quot;, &amp;quot;Worcestershire&amp;quot;, &amp;quot;Yorkshire&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
sub getCountyName { my $county = shift; return $county[$county - 1];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
my $server = new Jabber::RPC::Server( server    =&amp;amp;gt; 'gnu.mine.nu',&lt;br /&gt;
identauth =&amp;amp;gt; 'server:pass', resource  =&amp;amp;gt; 'jrpc-server', methods  &lt;br /&gt;
=&amp;amp;gt; {'examples.getCountyName' =&amp;amp;gt; \&amp;amp;amp;getCountyName}, );&lt;br /&gt;
&lt;br /&gt;
$server-&amp;amp;gt;start;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''A Jabber-RPC Requester in Perl''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;use strict; use Jabber::RPC::Client;&lt;br /&gt;
&lt;br /&gt;
my $client = new Jabber::RPC::Client( server    =&amp;amp;gt;&lt;br /&gt;
'qmacro.dyndns.org', identauth =&amp;amp;gt; 'client:pass', resource  =&amp;amp;gt;&lt;br /&gt;
'jrpc-client', endpoint  =&amp;amp;gt; 'dj@localhost/jrpc-server', );&lt;br /&gt;
&lt;br /&gt;
print $client-&amp;amp;gt;call('examples.getCountyName', $ARGV[0])&lt;br /&gt;
      || $client-&amp;amp;gt;lastFault;&amp;lt;/code&amp;gt;&lt;br /&gt;
That's it. There's no more code than that. So don't lose heart. Just use&lt;br /&gt;
Perl; you know it makes sense.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Browsing LDAP == &lt;br /&gt;
&amp;lt;br&amp;gt;''Browsing'', a relatively new Jabber feature&lt;br /&gt;
(introduced in Section 2.9 and described through its associated&lt;br /&gt;
namespace in Section 6.2.5), is an extremely powerful and flexible&lt;br /&gt;
beast. Whereas many of the standard Jabber namespaces such as&lt;br /&gt;
&amp;lt;tt&amp;gt;jabber:iq:oob&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;jabber:iq:auth&amp;lt;/tt&amp;gt;, and&lt;br /&gt;
&amp;lt;tt&amp;gt;jabber:iq:register&amp;lt;/tt&amp;gt; busy themselves with providing context for&lt;br /&gt;
relatively narrow areas of information (out-of-band information&lt;br /&gt;
exchange, authentication, and registration, respectively),&lt;br /&gt;
&amp;lt;tt&amp;gt;jabber:iq:browse&amp;lt;/tt&amp;gt; is a namespace that qualifies, and therefore&lt;br /&gt;
defines, a flexible container that can be used to carry all sorts of&lt;br /&gt;
information—information  that is wrapped in meaning and context and that&lt;br /&gt;
can have virtually unlimited levels of hierarchy. What's more, it can&lt;br /&gt;
deliver information in a standard way that can be understood by Jabber&lt;br /&gt;
clients.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Note|As of this writing, the only Jabber client to implement browsing&lt;br /&gt;
is WinJab.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Put another way, it means that we can extend the scope of Jabber&lt;br /&gt;
deployment to areas outside what we traditionally see as the &amp;quot;Jabber&lt;br /&gt;
world.&amp;quot; The power and simplicity of the Jabber browsing namespace design&lt;br /&gt;
means that we can adapt its use to whatever purpose we have in mind. As&lt;br /&gt;
we push out the Jabber protocol and give entities within our networks&lt;br /&gt;
the gift of speech and presence (in other words, give them a JID and&lt;br /&gt;
graft on a Jabber connection stub), we will want to identify those&lt;br /&gt;
entities as something more than a collection of hazy objects that sit&lt;br /&gt;
behind Jabber addresses.&lt;br /&gt;
&lt;br /&gt;
* Want to find out about dictionaries that are reachable by Jabber?&lt;br /&gt;
Browse to a directory and pull out those JIDs—the dictionaries'&lt;br /&gt;
addresses—that are identified as ''keyword/dictionary'' JID-types. &lt;br /&gt;
* Want to allow your users to navigate an information hierarchy outside&lt;br /&gt;
the Jabber space but from within the comfort of their Jabber client?&lt;br /&gt;
Build a &amp;quot;reflector&amp;quot; that navigates the hierarchy on behalf of your&lt;br /&gt;
Jabber users and transforms it into a Jabber browsing context—by&lt;br /&gt;
formulating the information in &amp;lt;tt&amp;gt;jabber:iq:browse&amp;lt;/tt&amp;gt; terms. Jabber&lt;br /&gt;
browsing is one of those oddities that is so simple and so ultimately&lt;br /&gt;
flexible that it's sometimes better to demonstrate it than to talk about&lt;br /&gt;
it. Let's have a look at what browsing can do by building  ''ldapr'', a&lt;br /&gt;
&amp;quot;reflector&amp;quot; for information in a database accessed by the Lightweight&lt;br /&gt;
Directory Access Protocol (LDAP).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Building the Reflector === &lt;br /&gt;
&amp;lt;br&amp;gt;We're going to build the reflector as a&lt;br /&gt;
component that connects directly to the Jabber backbone. This makes&lt;br /&gt;
sense, as it's a service that we'll probably want to run continuously&lt;br /&gt;
(and perhaps start up and shut down in conjunction with the Jabber&lt;br /&gt;
server itself), rather than something more transient like a client-based&lt;br /&gt;
'bot, for example.&lt;br /&gt;
&lt;br /&gt;
Before we go any further, have a look at Figure 10-9.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:jab_1009.png|Basic browsing in WinJab|center|350 px]]&amp;lt;br&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
This figure shows WinJab's browser window, which, when first opened,&lt;br /&gt;
requests the top-level browse information from the Jabber server that&lt;br /&gt;
WinJab is connected to (&amp;lt;tt&amp;gt;cicero&amp;lt;/tt&amp;gt;, in this case). This is the&lt;br /&gt;
information in the &amp;lt;tt&amp;gt;&amp;amp;lt;browse/&amp;amp;gt;&amp;lt;/tt&amp;gt; section of the JSM component&lt;br /&gt;
custom configuration, as described in Section 4.4.3.8, which looks like:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;browse&amp;amp;gt; &amp;amp;lt;conference type='public' jid='conf.cicero'&lt;br /&gt;
name='Public Chat'/&amp;amp;gt; &amp;amp;lt;/browse&amp;amp;gt;&amp;lt;/code&amp;gt; We can see just one icon,&lt;br /&gt;
representing the Public Chat conference service.&lt;br /&gt;
&lt;br /&gt;
WinJab sensibly uses this location—the Jabber server (specifically the&lt;br /&gt;
JSM) itself— as a starting position for browsing navigation. From the&lt;br /&gt;
description of &amp;lt;tt&amp;gt;jabber:iq:browse&amp;lt;/tt&amp;gt; in Section 6.2.5, we know that&lt;br /&gt;
each element within a &amp;lt;tt&amp;gt;&amp;amp;lt;browse/&amp;amp;gt;&amp;lt;/tt&amp;gt; section is identified&lt;br /&gt;
with a JID, in the &amp;lt;tt&amp;gt;jid&amp;lt;/tt&amp;gt; attribute. Here, the Public Chat element&lt;br /&gt;
has a JID of &amp;lt;tt&amp;gt;conf.cicero&amp;lt;/tt&amp;gt;. If we click on the element's icon in&lt;br /&gt;
WinJab's browser window, it would make a further browse request—an&lt;br /&gt;
IQ-get with an empty extension qualified by the&lt;br /&gt;
&amp;lt;tt&amp;gt;jabber:iq:browse&amp;lt;/tt&amp;gt; namespace—''to that JID''. Thus is a browse&lt;br /&gt;
hierarchy descended. Example 10-15 shows what that browse request might&lt;br /&gt;
look like.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''Browsing to the Public Chat service''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;iq type='get' to='conf.cicero' id='82A'&amp;amp;gt; &amp;amp;lt;query&lt;br /&gt;
xmlns='jabber:iq:browse'/&amp;amp;gt; &amp;amp;lt;/iq&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== Identifying ldapr in the browsing hierarchy ==== &lt;br /&gt;
&amp;lt;br&amp;gt;This is exactly&lt;br /&gt;
where our reflector service, in the form of a script called ''ldapr'',&lt;br /&gt;
will fit in. In the same way as we described our RSS news agent&lt;br /&gt;
(''newsagent'') in the JSM configuration's &amp;lt;tt&amp;gt;&amp;amp;lt;browse/&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
section, we'll now describe ''ldapr''. We add it, like this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;browse&amp;amp;gt; &amp;amp;lt;conference type='public' jid='conf.cicero'&lt;br /&gt;
name='Public Chat'/&amp;amp;gt; &amp;amp;lt;service type='x-ldap' jid='ldap.cicero'&lt;br /&gt;
name='LDAP Reflector'/&amp;amp;gt; &amp;amp;lt;/browse&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
There are a couple of things to note in the definition:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; service/x-ldap&lt;br /&gt;
: The LDAP reflector is a service, so we use the &amp;lt;tt&amp;gt;service&amp;lt;/tt&amp;gt;&lt;br /&gt;
: category for the tag name used to describe it. While there are already&lt;br /&gt;
: many subtypes defined within the &amp;lt;tt&amp;gt;jabber:iq:browse&amp;lt;/tt&amp;gt; namespace&lt;br /&gt;
: (such as &amp;lt;tt&amp;gt;irc&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;aim&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;jud&amp;lt;/tt&amp;gt;), none of them&lt;br /&gt;
: matches what this service is going to offer, so in the same way as we&lt;br /&gt;
: invent Multipurpose Internet Mail Extensions (MIME) subtypes in the&lt;br /&gt;
: &amp;lt;tt&amp;gt;x-&amp;lt;/tt&amp;gt; space, we specify &amp;lt;tt&amp;gt;x-ldap&amp;lt;/tt&amp;gt; for the &amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt;&lt;br /&gt;
: attribute here. &lt;br /&gt;
; ldap.cicero&lt;br /&gt;
: Each component has a JID. In browsing, the JID is the key to&lt;br /&gt;
: navigation. When the icon representing this service is clicked, it's&lt;br /&gt;
: to this JID that the browse request is sent. To provide a smooth&lt;br /&gt;
: navigational path through the hierarchy, it's up to the component to&lt;br /&gt;
: return browse data items that are identified by JIDs appropriate for&lt;br /&gt;
: further navigation. We'll see what this means in the next section. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== Navigating into the LDAP hierarchy ==== &lt;br /&gt;
&amp;lt;br&amp;gt;Having our reflector&lt;br /&gt;
component defined in the JSM's &amp;lt;tt&amp;gt;&amp;amp;lt;browse/&amp;amp;gt;&amp;lt;/tt&amp;gt; list makes for a&lt;br /&gt;
smooth transition into the reflection. We're going to navigate the LDAP&lt;br /&gt;
hierarchy in a similar way to what was described in Section 6.2.5.1. On&lt;br /&gt;
receipt of an initial browse request, ''ldapr'' must return the top&lt;br /&gt;
level of the LDAP hierarchy it has been set up to reflect:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;iq type='get' to='ldap.cicero' id='7'&amp;amp;gt; &amp;amp;lt;query&lt;br /&gt;
xmlns='jabber:iq:browse'/&amp;amp;gt; &amp;amp;lt;/iq&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Figure 10-10 shows the LDAP hierarchy we've discussed in Section&lt;br /&gt;
6.2.5.1. It's part of an imaginary structure devised to represent people&lt;br /&gt;
and departments in an organization. The base distinguished name, or&lt;br /&gt;
''base DN'' (an LDAP term meaning the common suffix used in the&lt;br /&gt;
identifiers of all elements in a particular LDAP structure), is&lt;br /&gt;
&amp;lt;tt&amp;gt;dc=demo,dc=org&amp;lt;/tt&amp;gt;. A DN, or ''distinguished name'', can be thought&lt;br /&gt;
of as a key for a particular element. Levels within the LDAP structure&lt;br /&gt;
are identified with DNs of ever-increasing lengths, as they get more&lt;br /&gt;
specific the deeper the hierarchy is descended.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:jab_1010.png|The LDAP hierarchy|center|350 px]]&amp;lt;br&amp;gt;&amp;lt;/code&amp;gt; If&lt;br /&gt;
&amp;lt;tt&amp;gt;ldapr&amp;lt;/tt&amp;gt; were to reflect this hierarchy, we want the response to&lt;br /&gt;
an initial browse request to return information about the&lt;br /&gt;
&amp;lt;tt&amp;gt;People&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Groups&amp;lt;/tt&amp;gt; nodes. In Example 10-16, we see what&lt;br /&gt;
this response looks like.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''An initial browse request elicits a reflection of the People and&lt;br /&gt;
Groups nodes''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SEND: &amp;amp;lt;iq type=&amp;quot;get&amp;quot; id=&amp;quot;B88&amp;quot; to=&amp;quot;ldap.cicero&amp;quot;&amp;amp;gt; &amp;amp;lt;query&lt;br /&gt;
xmlns=&amp;quot;jabber:iq:browse&amp;quot;/&amp;amp;gt; &amp;amp;lt;/iq&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
RECV: &amp;amp;lt;iq id='B88' type='result' to='dj@cicero/basement'&lt;br /&gt;
from='ldap.cicero'&amp;amp;gt; &amp;amp;lt;query xmlns='jabber:iq:browse'&amp;amp;gt; &amp;amp;lt;item&lt;br /&gt;
jid='ldap.cicero/ou=People' name='ou=People'/&amp;amp;gt; &amp;amp;lt;item&lt;br /&gt;
jid='ldap.cicero/ou=Groups' name='ou=Groups'/&amp;amp;gt; &amp;amp;lt;/query&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/iq&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
In the response, we're returning a single level of the LDAP hierarchy.&lt;br /&gt;
The &amp;lt;tt&amp;gt;People&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Groups&amp;lt;/tt&amp;gt; nodes are represented by&lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;amp;lt;item/&amp;amp;gt;&amp;lt;/tt&amp;gt; tags, within the generic container tag&lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;amp;lt;query/&amp;amp;gt;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
This is in slight contrast to the browse &amp;lt;tt&amp;gt;&amp;amp;lt;iq/&amp;amp;gt;&amp;lt;/tt&amp;gt; elements&lt;br /&gt;
shown in Section 6.2.5.1, in which, effectively, two levels of hierarchy&lt;br /&gt;
are returned:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;RECV: &amp;amp;lt;iq type='result' id='B89' to='dj@cicero/basement'&lt;br /&gt;
from='ldap.cicero'&amp;amp;gt; &amp;amp;lt;item name='root entry'&lt;br /&gt;
xmlns='jabber:iq:browse' jid='ldap.cicero'&amp;amp;gt; &amp;amp;lt;item name='ou=People'&lt;br /&gt;
jid='ou=People@ldap.cicero'/&amp;amp;gt; &amp;amp;lt;item name='ou=Groups'&lt;br /&gt;
jid='ou=Groups@ldap.cicero'/&amp;amp;gt; &amp;amp;lt;/item&amp;amp;gt; &amp;amp;lt;/iq&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
It's really up to you to decide how many levels of information you want&lt;br /&gt;
each browse response to emit. It depends on circumstances (will the&lt;br /&gt;
requester be able to interpret multiple levels of hierarchy?) and the&lt;br /&gt;
type of application scenario in which you're wanting to employ Jabber&lt;br /&gt;
browsing. In this case, despite the difference in appearance, WinJab&lt;br /&gt;
will interpret the information correctly whichever way you play it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Sidebar|No Query Tag?This last example looks slightly odd, because the&lt;br /&gt;
familiar &amp;lt;tt&amp;gt;&amp;amp;lt;query/&amp;amp;gt;&amp;lt;/tt&amp;gt; tag, usually the container for&lt;br /&gt;
information within various IQ namespaces, is conspicuously absent. It's&lt;br /&gt;
actually still there in spirit, in the form of the first&lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;amp;lt;item/&amp;amp;gt;&amp;lt;/tt&amp;gt; tag, which takes the &amp;lt;tt&amp;gt;&amp;amp;lt;query/&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
tag's role in carrying the &amp;lt;tt&amp;gt;xmlns='jabber:iq:browse'&amp;lt;/tt&amp;gt; namespace&lt;br /&gt;
declaration.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
So, we've got our first two LDAP levels back. Figure 10-11 shows how&lt;br /&gt;
they're displayed in WinJab's browser window. The JID we've just browsed&lt;br /&gt;
to—&amp;lt;tt&amp;gt;ldap.cicero&amp;lt;/tt&amp;gt;—is shown in the Jabber Address field. The&lt;br /&gt;
''People'' and ''Groups'' nodes are represented by&lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;amp;lt;item/&amp;amp;gt;&amp;lt;/tt&amp;gt; tags within the&lt;br /&gt;
&amp;lt;tt&amp;gt;jabber:iq:browse&amp;lt;/tt&amp;gt;-qualified result; these are translated into&lt;br /&gt;
folder icons in the browser window.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:jab_1011.png|Showing the first hierarchy level in WinJab's browser|center|350 px]]&amp;lt;br&amp;gt;&amp;lt;/code&amp;gt; The browser displays folder&lt;br /&gt;
icons for these nodes because we've described them using&lt;br /&gt;
&amp;lt;tt&amp;gt;jabber:iq:browse&amp;lt;/tt&amp;gt;'s generic &amp;quot;holder&amp;quot; tag &amp;lt;tt&amp;gt;&amp;amp;lt;item/&amp;amp;gt;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
While the namespace describes many categories to represent many&lt;br /&gt;
different things (service, conference, user, and so on), there's not&lt;br /&gt;
really a category that fits the &amp;quot;LDAP_ hierarchy node&amp;quot; description. So&lt;br /&gt;
we plump for the generic &amp;lt;tt&amp;gt;&amp;amp;lt;item/&amp;amp;gt;&amp;lt;/tt&amp;gt;, reserved specially for&lt;br /&gt;
such occasions.&lt;br /&gt;
&lt;br /&gt;
To navigate to the next level in the hierarchy, all we do is click on&lt;br /&gt;
one of the icons now displayed to us. WinJab will send this next browse&lt;br /&gt;
request to the JID that's associated with the icon we click. In the case&lt;br /&gt;
of the People icon, we know from the browse result shown in Example&lt;br /&gt;
10-16 that the JID is &amp;lt;tt&amp;gt;ldap.cicero/ou=People&amp;lt;/tt&amp;gt;. This is what that&lt;br /&gt;
browse request and response look like:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SEND: &amp;amp;lt;iq type=&amp;quot;get&amp;quot; id=&amp;quot;B105&amp;quot; to=&amp;quot;ldap.cicero/ou=People&amp;quot;&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;query xmlns=&amp;quot;jabber:iq:browse&amp;quot;/&amp;amp;gt; &amp;amp;lt;/iq&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
RECV: &amp;amp;lt;iq id='B105' type='result' to='dj@cicero/basement'&lt;br /&gt;
from='ldap.cicero/ou=People'&amp;amp;gt; &amp;amp;lt;query xmlns='jabber:iq:browse'&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;item jid='ldap.cicero/ou=UK, ou=People' name='ou=UK'/&amp;amp;gt; &amp;amp;lt;item&lt;br /&gt;
jid='ldap.cicero/ou=France, ou=People' name='ou=France'/&amp;amp;gt; &amp;amp;lt;item&lt;br /&gt;
jid='ldap.cicero/ou=Germany, ou=People' name='ou=Germany'/&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/query&amp;amp;gt; &amp;amp;lt;/iq&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The results of this browse request are shown in Figure 10-12. Again,&lt;br /&gt;
notice the JID displayed in the Jabber Address window—it's the JID that&lt;br /&gt;
we've just browsed to. The JIDs that are assigned to the items displayed&lt;br /&gt;
here reflect the next level in the hierarchy. And so it goes on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:jab_1012.png|Showing the first hierarchy level in WinJab's browser|center|350 px]]&amp;lt;br&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== What the reflector is actually doing ==== &lt;br /&gt;
&amp;lt;br&amp;gt;Each of the JIDs that are&lt;br /&gt;
browsed to look like this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; [''component name'']/[''relative LDAP DN'']&amp;lt;/code&amp;gt; such as:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;ldap.cicero/ou=UK, ou=People&amp;lt;/code&amp;gt; The ''hostname'' part of the&lt;br /&gt;
JID—&amp;lt;tt&amp;gt;[&amp;lt;/tt&amp;gt;''component_name''&amp;lt;tt&amp;gt;]&amp;lt;/tt&amp;gt;—is the name of the LDAP&lt;br /&gt;
reflector component, and the ''resource'' part of the&lt;br /&gt;
JID—&amp;lt;tt&amp;gt;[&amp;lt;/tt&amp;gt;''relative_LDAP_DN''&amp;lt;tt&amp;gt;]&amp;lt;/tt&amp;gt;—reflects the DN of the node&lt;br /&gt;
(minus the base DN suffix) within the LDAP structure that the&lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;amp;lt;item/&amp;amp;gt;&amp;lt;/tt&amp;gt; with that JID represents.&lt;br /&gt;
&lt;br /&gt;
The crucial bit is that the &amp;lt;tt&amp;gt;[&amp;lt;/tt&amp;gt;''component_name''&amp;lt;tt&amp;gt;]&amp;lt;/tt&amp;gt; part&lt;br /&gt;
remains the same (&amp;lt;tt&amp;gt;ldap.cicero&amp;lt;/tt&amp;gt;) across every call. This means&lt;br /&gt;
that ''all'' of the &amp;lt;tt&amp;gt;jabber:iq:browse&amp;lt;/tt&amp;gt; requests made in the&lt;br /&gt;
navigation sequence go to the component, in this case, the ''ldapr''&lt;br /&gt;
script.&lt;br /&gt;
&lt;br /&gt;
Once the component receives these requests, it disassembles the JID,&lt;br /&gt;
extracting the resource part, and uses it to query the LDAP server on&lt;br /&gt;
the Jabber client's behalf. It then builds a response, in the form of an&lt;br /&gt;
IQ-result containing the all-important&lt;br /&gt;
&amp;lt;tt&amp;gt;jabber:iq:browse&amp;lt;/tt&amp;gt;-qualified extension, containing the results of&lt;br /&gt;
the LDAP query.&lt;br /&gt;
&lt;br /&gt;
JIDs are used to ''convey information'' to the component, as well as to&lt;br /&gt;
have the request delivered to the right place.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Sidebar|Using JID Parts to Convey InformationThe example from Section&lt;br /&gt;
6.2.5.1 showed the information being conveyed as the ''user'' part of&lt;br /&gt;
the JID:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;item name='ou=People' jid='ou=People@ldap.yak'/&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This is perfectly fine, as long as the information we want to convey&lt;br /&gt;
doesn't contain characters deigned illegal for that part of the JID.&lt;br /&gt;
There are far fewer restrictions on how the resource part of a JID may&lt;br /&gt;
be constructed. So it should usually be your first choice of location&lt;br /&gt;
for piggybacking information:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;item jid='ldap.cicero/ou=People' name='ou=People'/&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== The ldapr script === &lt;br /&gt;
&amp;lt;br&amp;gt;While the explanation might be long, the actual&lt;br /&gt;
script, shown in  Example 10-17, is relatively short. Written in Perl,&lt;br /&gt;
the ''ldapr'' script uses the &amp;lt;tt&amp;gt;Jabber::Connection&amp;lt;/tt&amp;gt; library.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''The ldapr script, written in Perl''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;use strict; use Jabber::Connection; use Jabber::NodeFactory; use&lt;br /&gt;
Jabber::NS qw(:all); use Net::LDAP;&lt;br /&gt;
&lt;br /&gt;
my $ldapsrv = 'cicero'; my $basedn  = 'dc=demo,dc=org';&lt;br /&gt;
&lt;br /&gt;
my $ldap = Net::LDAP-&amp;amp;gt;new($ldapsrv) or die $@;&lt;br /&gt;
&lt;br /&gt;
debug(&amp;quot;connecting to Jabber&amp;quot;); my $c = new Jabber::Connection( server   &lt;br /&gt;
=&amp;amp;gt; 'localhost:9389', localname =&amp;amp;gt; 'ldap.cicero', ns        =&amp;amp;gt;&lt;br /&gt;
'jabber:component:accept', );&lt;br /&gt;
&lt;br /&gt;
unless ($c-&amp;amp;gt;connect()) { die &amp;quot;Oops: &amp;quot;.$c-&amp;amp;gt;lastError; }&lt;br /&gt;
&lt;br /&gt;
debug(&amp;quot;registering IQ handlers&amp;quot;);&lt;br /&gt;
$c-&amp;amp;gt;register_handler('iq',\&amp;amp;amp;iq_browse);&lt;br /&gt;
$c-&amp;amp;gt;register_handler('iq',\&amp;amp;amp;iq_notimpl);&lt;br /&gt;
&lt;br /&gt;
debug(&amp;quot;authenticating&amp;quot;); $c-&amp;amp;gt;auth('pass');&lt;br /&gt;
&lt;br /&gt;
debug(&amp;quot;waiting for requests&amp;quot;); $c-&amp;amp;gt;start;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub iq_browse {&lt;br /&gt;
&lt;br /&gt;
  my $node = shift; return unless $node-&amp;amp;gt;attr('type') eq IQ_GET and&lt;br /&gt;
  my $query = $node-&amp;amp;gt;getTag('', NS_BROWSE);&lt;br /&gt;
&lt;br /&gt;
  my ($obj) = $node-&amp;amp;gt;attr('to') =~ /\/(.*)$/; debug(&amp;quot;request: $obj&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  my $result = $ldap-&amp;amp;gt;search( base   =&amp;amp;gt; $obj ? join(',', $obj,&lt;br /&gt;
  $basedn) : $basedn, filter =&amp;amp;gt; &amp;quot;(objectclass=*)&amp;quot;, scope  =&amp;amp;gt;&lt;br /&gt;
  'one', );&lt;br /&gt;
&lt;br /&gt;
  if ($result-&amp;amp;gt;code) { debug(&amp;quot;search error: &amp;quot;.$result-&amp;amp;gt;error);&lt;br /&gt;
  }&lt;br /&gt;
  else { foreach my $entry ($result-&amp;amp;gt;all_entries) { my $e =&lt;br /&gt;
  strip($entry-&amp;amp;gt;dn, $basedn); debug(&amp;quot;found: $e&amp;quot;); my $item =&lt;br /&gt;
  $query-&amp;amp;gt;insertTag(isUser($e) ? &amp;quot;user&amp;quot; : &amp;quot;item&amp;quot;);&lt;br /&gt;
  $item-&amp;amp;gt;attr('jid', join('/', $ID, $e)); $item-&amp;amp;gt;attr('name',&lt;br /&gt;
  [split(/,/, $e)]-&amp;amp;gt;[0]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  $node = toFrom($node); $node-&amp;amp;gt;attr('type', IQ_RESULT);&lt;br /&gt;
&lt;br /&gt;
  $c-&amp;amp;gt;send($node);&lt;br /&gt;
&lt;br /&gt;
  return r_HANDLED;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub iq_notimpl {&lt;br /&gt;
&lt;br /&gt;
  my $node = shift; $node = toFrom($node); $node-&amp;amp;gt;attr('type',&lt;br /&gt;
  IQ_ERROR); my $error = $node-&amp;amp;gt;insertTag('error');&lt;br /&gt;
  $error-&amp;amp;gt;attr('code', '501'); $error-&amp;amp;gt;data('Not Implemented');&lt;br /&gt;
  $c-&amp;amp;gt;send($node); return r_HANDLED;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub strip {&lt;br /&gt;
&lt;br /&gt;
  my ($fqdn, $basedn) = @_; my @fqdn = split(/,/, $fqdn); my&lt;br /&gt;
  @basedn_elements = split(/,/, $basedn); return join(',', @fqdn[0 ..&lt;br /&gt;
  ($#fqdn - scalar @basedn_elements)]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub toFrom { my $node = shift; my $to = $node-&amp;amp;gt;attr('to');&lt;br /&gt;
$node-&amp;amp;gt;attr('to', $node-&amp;amp;gt;attr('from')); $node-&amp;amp;gt;attr('from',&lt;br /&gt;
$to); return $node;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub isUser {&lt;br /&gt;
&lt;br /&gt;
  my $rdn = shift; return $rdn =~ /^cn/ ? 1 : 0&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub debug {&lt;br /&gt;
&lt;br /&gt;
  print STDERR &amp;quot;debug: &amp;quot;, @_, &amp;quot;\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Looking at ldapr Step by Step === &lt;br /&gt;
&amp;lt;br&amp;gt;Taking the script step by step, we&lt;br /&gt;
start on familiar ground:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;use strict; use Jabber::Connection; use Jabber::NodeFactory; use&lt;br /&gt;
Jabber::NS qw(:all); use Net::LDAP;&lt;br /&gt;
&lt;br /&gt;
my $ldapsrv = 'cicero'; my $basedn  = 'dc=demo,dc=org';&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
After declaring the modules we want to use (the only one we haven't seen&lt;br /&gt;
so far is the &amp;lt;tt&amp;gt;Net::LDAP&amp;lt;/tt&amp;gt; module that we'll need to connect to&lt;br /&gt;
and query an LDAP server), we define a couple of variables.&lt;br /&gt;
&amp;lt;tt&amp;gt;$ldapsrv&amp;lt;/tt&amp;gt; is the name of the LDAP server that ''ldapr'' is going&lt;br /&gt;
to be reflecting, and &amp;lt;tt&amp;gt;$basedn&amp;lt;/tt&amp;gt; is the base distinguished name&lt;br /&gt;
that will be used as the suffix in all of the LDAP queries.&lt;br /&gt;
&lt;br /&gt;
If you don't have an LDAP server of your own, a number of public ones&lt;br /&gt;
are available that you could point this script at. The two variables&lt;br /&gt;
&amp;lt;tt&amp;gt;$ldapsrv&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;$basedn&amp;lt;/tt&amp;gt; go together—make sure you specify&lt;br /&gt;
the correct base DN for the LDAP server you want to reflect.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Note|Depending on the configuration, some LDAP servers will require&lt;br /&gt;
you to ''bind'' to them with a username and password before you can&lt;br /&gt;
perform searches. To do this, you'll need to include an extra step in&lt;br /&gt;
this script, using the &amp;lt;tt&amp;gt;bind()&amp;lt;/tt&amp;gt; method in &amp;lt;tt&amp;gt;Net::LDAP&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Having opened our connection to the LDAP server:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;my $ldap = Net::LDAP-&amp;amp;gt;new($ldapsrv) or die $@;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
we then proceed to connect to the Jabber server as a component. We're&lt;br /&gt;
connecting to &amp;lt;tt&amp;gt;localhost:9389&amp;lt;/tt&amp;gt;, which means this component script&lt;br /&gt;
is going to run on the same host as the Jabber server, and connect to it&lt;br /&gt;
on port 9389:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;debug(&amp;quot;connecting to Jabber&amp;quot;); my $c = new Jabber::Connection(&lt;br /&gt;
server    =&amp;amp;gt; 'localhost:9389', localname =&amp;amp;gt; 'ldap.cicero', ns     &lt;br /&gt;
  =&amp;amp;gt; 'jabber:component:accept', );&lt;br /&gt;
&lt;br /&gt;
unless ($c-&amp;amp;gt;connect()) { die &amp;quot;cannot connect: &amp;quot;.$c-&amp;amp;gt;lastError; }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We'll also need a &amp;lt;tt&amp;gt;&amp;amp;lt;service/&amp;amp;gt;&amp;lt;/tt&amp;gt; stanza in the Jabber&lt;br /&gt;
server's configuration file to describe this component. The stanza in&lt;br /&gt;
Example 10-18 would be appropriate. Refer to Section 9.3.1.1 for more&lt;br /&gt;
details on connecting to Jabber as a component.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''A component instance definition for ldapr''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;service id='ldap.cicero'&amp;amp;gt; &amp;amp;lt;accept&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;ip&amp;amp;gt;localhost&amp;amp;lt;/ip&amp;amp;gt; &amp;amp;lt;port&amp;amp;gt;9389&amp;amp;lt;/port&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;secret&amp;amp;gt;secret&amp;amp;lt;/secret&amp;amp;gt; &amp;amp;lt;/accept&amp;amp;gt; &amp;amp;lt;/service&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The script isn't going to do much apart from reflect&lt;br /&gt;
&amp;lt;tt&amp;gt;jabber:iq:browse&amp;lt;/tt&amp;gt; queries as LDAP searches. Consequently, it&lt;br /&gt;
doesn't need to be able to handle anything apart from incoming IQ&lt;br /&gt;
elements:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;debug(&amp;quot;registering IQ handlers&amp;quot;);&lt;br /&gt;
$c-&amp;amp;gt;register_handler('iq',\&amp;amp;amp;iq_browse);&lt;br /&gt;
$c-&amp;amp;gt;register_handler('iq',\&amp;amp;amp;iq_notimpl);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;iq_browse()&amp;lt;/tt&amp;gt; function is where all the work will be done. As&lt;br /&gt;
in the &amp;lt;tt&amp;gt;newsagent&amp;lt;/tt&amp;gt; recipe (Section 8.3),&amp;quot; we also have a&lt;br /&gt;
&amp;quot;catchall&amp;quot; function (&amp;lt;tt&amp;gt;iq_notimpl()&amp;lt;/tt&amp;gt;) that cleans up any &amp;quot;stray&amp;quot;&lt;br /&gt;
IQ elements that it doesn't know about. Furthermore, because we aren't&lt;br /&gt;
registering any handlers for &amp;lt;tt&amp;gt;&amp;amp;lt;message/&amp;amp;gt;&amp;lt;/tt&amp;gt; or&lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;amp;lt;presence/&amp;amp;gt;&amp;lt;/tt&amp;gt; elements, the dispatcher in&lt;br /&gt;
&amp;lt;tt&amp;gt;Jabber::Connection&amp;lt;/tt&amp;gt; will just throw them away, leaving ''ldapr''&lt;br /&gt;
blissfully ignorant of them—which is what we want.&lt;br /&gt;
&lt;br /&gt;
After authenticating with the server by calling the &amp;lt;tt&amp;gt;auth()&amp;lt;/tt&amp;gt;&lt;br /&gt;
method to send the &amp;lt;tt&amp;gt;&amp;amp;lt;handshake/&amp;amp;gt;&amp;lt;/tt&amp;gt; element:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;debug(&amp;quot;authenticating&amp;quot;); $c-&amp;amp;gt;auth('secret');&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
it's time to set the main event loop going. With a call to&lt;br /&gt;
&amp;lt;tt&amp;gt;start()&amp;lt;/tt&amp;gt;, we hand over control to &amp;lt;tt&amp;gt;Jabber::Connection&amp;lt;/tt&amp;gt;,&lt;br /&gt;
safe in the knowledge that we have a function (&amp;lt;tt&amp;gt;iq_browse()&amp;lt;/tt&amp;gt;) to&lt;br /&gt;
deal with the incoming requests that we're supposed to deal with, and&lt;br /&gt;
that we don't care a hoot about anything else:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;debug(&amp;quot;waiting for requests&amp;quot;); $c-&amp;amp;gt;start;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== Performing the actual reflection ==== &lt;br /&gt;
&amp;lt;br&amp;gt;Now, let's move on to the&lt;br /&gt;
meat of the script. The main handler, &amp;lt;tt&amp;gt;iq_browse()&amp;lt;/tt&amp;gt;, starts by&lt;br /&gt;
making sure it has an IQ element:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sub iq_browse {&lt;br /&gt;
&lt;br /&gt;
  my $node = shift; return unless $node-&amp;amp;gt;attr('type') eq IQ_GET and&lt;br /&gt;
  my $query = $node-&amp;amp;gt;getTag('', NS_BROWSE);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
What we're looking for is an IQ-get with a&lt;br /&gt;
&amp;lt;tt&amp;gt;jabber:iq:browse&amp;lt;/tt&amp;gt;-qualified query extension. If there isn't one,&lt;br /&gt;
we exit out of the function, and dispatching continues to the&lt;br /&gt;
&amp;lt;tt&amp;gt;iq_notimpl()&amp;lt;/tt&amp;gt; function, because we didn't return the special&lt;br /&gt;
value represented by &amp;lt;tt&amp;gt;m_HANDLED&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If we do get a valid request, we first extract the relative DN from the&lt;br /&gt;
''resource'' part of the JID specified in the IQ-get's &amp;lt;tt&amp;gt;to&amp;lt;/tt&amp;gt;&lt;br /&gt;
attribute—the JID. If the request was sent to &amp;lt;tt&amp;gt;ldap.cicero/ou=UK,&lt;br /&gt;
ou=People&amp;lt;/tt&amp;gt;, then we extract the relative DN &amp;lt;tt&amp;gt;ou=UK,&lt;br /&gt;
ou=People&amp;lt;/tt&amp;gt; into &amp;lt;tt&amp;gt;$obj&amp;lt;/tt&amp;gt; like this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;  my ($obj) = $node-&amp;amp;gt;attr('to') =~ /\/(.*)$/; debug(&amp;quot;request:&lt;br /&gt;
$obj&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Armed with a specification of what part of the LDAP hierarchy needs to&lt;br /&gt;
be searched, the next step is to call the &amp;lt;tt&amp;gt;search()&amp;lt;/tt&amp;gt; method on&lt;br /&gt;
the LDAP object in &amp;lt;tt&amp;gt;$ldap&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;  my $result = $ldap-&amp;amp;gt;search( base   =&amp;amp;gt; $obj ? join(',',&lt;br /&gt;
$obj, $basedn) : $basedn, filter =&amp;amp;gt; &amp;quot;(objectclass=*)&amp;quot;, scope  =&amp;amp;gt;&lt;br /&gt;
'one', );&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
As you can see, we're specifying three parameters in the&lt;br /&gt;
&amp;lt;tt&amp;gt;search()&amp;lt;/tt&amp;gt; method:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; base&lt;br /&gt;
: This is the point within the LDAP hierarchy from which to start&lt;br /&gt;
: looking. We must specify this as a full DN, so we append the base DN&lt;br /&gt;
: (&amp;lt;tt&amp;gt;dc=demo,dc=org&amp;lt;/tt&amp;gt;) to the relative DN received in the request&lt;br /&gt;
: to make an absolute DN: &lt;br /&gt;
&amp;lt;code&amp;gt;ou=UK, ou=People, dc=demo, dc=org&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; filter&lt;br /&gt;
: Specifying &amp;lt;tt&amp;gt;(objectclass=*)&amp;lt;/tt&amp;gt; effectively means &amp;quot;look for&lt;br /&gt;
: anything.&amp;quot; &lt;br /&gt;
; scope&lt;br /&gt;
: There may be many levels below the point in the hierarchy that we're&lt;br /&gt;
: going to start searching from. Specifying 1 for the &amp;lt;tt&amp;gt;scope&amp;lt;/tt&amp;gt;&lt;br /&gt;
: parameter tells the search to descend only one level. After all, we&lt;br /&gt;
: want to return only one level back to the requester in the reflection.&lt;br /&gt;
: If the search failed for some reason (e.g., if a relative DN specified&lt;br /&gt;
: in the request didn't exist in the hierarchy),&amp;lt;ref&amp;gt;This is an easy&lt;br /&gt;
: error to simulate using WinJab's browser window, as the Jabber Address&lt;br /&gt;
: bar is (thankfully) editable. &amp;lt;/ref&amp;gt; then don't bother checking the&lt;br /&gt;
: results. Instead, a warning debug message with the error details is&lt;br /&gt;
: issued: &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;  if ($result-&amp;amp;gt;code) { debug(&amp;quot;search error:&lt;br /&gt;
&amp;quot;.$result-&amp;amp;gt;error);&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
However, if the search succeeded, the results should be translated into&lt;br /&gt;
the &amp;lt;tt&amp;gt;jabber:iq:browse&amp;lt;/tt&amp;gt; extension:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;  else { foreach my $entry ($result-&amp;amp;gt;all_entries) { my $e =&lt;br /&gt;
strip($entry-&amp;amp;gt;dn, $basedn); debug(&amp;quot;found: $e&amp;quot;); my $item =&lt;br /&gt;
$query-&amp;amp;gt;insertTag(isUser($e) ? &amp;quot;user&amp;quot; : &amp;quot;item&amp;quot;);&lt;br /&gt;
$item-&amp;amp;gt;attr('jid', join('/', $ID, $e)); $item-&amp;amp;gt;attr('name',&lt;br /&gt;
[split(/,/, $e)]-&amp;amp;gt;[0]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Calling the &amp;lt;tt&amp;gt;all_entries()&amp;lt;/tt&amp;gt; method on the search results returns&lt;br /&gt;
a list of LDAP entries, in the form of objects. Calling the&lt;br /&gt;
&amp;lt;tt&amp;gt;dn()&amp;lt;/tt&amp;gt; method on one of these objects (in &amp;lt;tt&amp;gt;$entry&amp;lt;/tt&amp;gt;)&lt;br /&gt;
returns us its full DN. Searching with a &amp;lt;tt&amp;gt;base&amp;lt;/tt&amp;gt; of:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;ou=UK, ou=People, dc=demo, dc=org&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
in the demonstration database would return two entries:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cn=Janet Abrams, ou=UK, ou=People, dc=demo, dc=org cn=Paul&lt;br /&gt;
Anthill, ou=UK, ou=People, dc=demo, dc=org&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The task of this section of the &amp;lt;tt&amp;gt;iq_browse()&amp;lt;/tt&amp;gt; function is to turn&lt;br /&gt;
the information, in the form of these two entries, into something like&lt;br /&gt;
this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;iq id='B25' type='result' to='dj@cicero/basement'&lt;br /&gt;
from='ldap.cicero/ou=UK, ou=People'&amp;amp;gt; &amp;amp;lt;query&lt;br /&gt;
xmlns='jabber:iq:browse'&amp;amp;gt; &amp;amp;lt;user name='cn=Janet Abrams'&lt;br /&gt;
jid='ldap.cicero/cn=Janet Abrams, ou=UK, ou=People'/&amp;amp;gt; &amp;amp;lt;user&lt;br /&gt;
name='cn=Paul Anthill' jid='ldap.cicero/cn=Paul Anthill, ou=UK,&lt;br /&gt;
ou=People'/&amp;amp;gt; &amp;amp;lt;/query&amp;amp;gt; &amp;amp;lt;/iq&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
which in turn should be rendered into something like the contents of&lt;br /&gt;
WinJab's browser window as shown in Figure 10-13.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:jab_1013.png|Showing the third level of hierarchy in WinJab's browser window|center|350 px]]&amp;lt;br&amp;gt;&amp;lt;/code&amp;gt; The function &amp;lt;tt&amp;gt;strip()&amp;lt;/tt&amp;gt;&lt;br /&gt;
takes two arguments and strips away a base DN from a fully qualified DN&lt;br /&gt;
to leave the significant, relative part. Calling &amp;lt;tt&amp;gt;strip()&amp;lt;/tt&amp;gt; on&lt;br /&gt;
this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cn=Janet Abrams, ou=UK, ou=People, dc=demo, dc=org&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
when specifying the base DN in &amp;lt;tt&amp;gt;$basedn&amp;lt;/tt&amp;gt;, would return this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cn=Janet Abrams, ou=UK, ou=People&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
For each of the entries found, we insert a tag into the&lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;amp;lt;query/&amp;amp;gt;&amp;lt;/tt&amp;gt; extension. The name of the tag is either&lt;br /&gt;
&amp;lt;tt&amp;gt;item&amp;lt;/tt&amp;gt;, if  the entry is simply an LDAP hierarchy node, or&lt;br /&gt;
&amp;lt;tt&amp;gt;user&amp;lt;/tt&amp;gt; (a valid &amp;lt;tt&amp;gt;jabber:iq:browse&amp;lt;/tt&amp;gt; category), if the entry&lt;br /&gt;
points to a person. We make the decision on the basis of the first part&lt;br /&gt;
of the DN—if it's &amp;lt;tt&amp;gt;cn=&amp;lt;/tt&amp;gt;, then it's a reference to a person. The&lt;br /&gt;
&amp;lt;tt&amp;gt;isUser()&amp;lt;/tt&amp;gt; function makes this decision for us.&lt;br /&gt;
&lt;br /&gt;
Once inserted, we embellish the &amp;lt;tt&amp;gt;&amp;amp;lt;item/&amp;amp;gt;&amp;lt;/tt&amp;gt; or&lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;amp;lt;user/&amp;amp;gt;&amp;lt;/tt&amp;gt; tag with &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;jid&amp;lt;/tt&amp;gt;&lt;br /&gt;
attributes. The &amp;lt;tt&amp;gt;jid&amp;lt;/tt&amp;gt; attribute is crucial, as it represents the&lt;br /&gt;
path to further descend within the LDAP hierarchy on the next request.&lt;br /&gt;
It is given the whole of the relative DN as a value. The &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt;&lt;br /&gt;
attribute is simply given the most significant portion of the DN as a&lt;br /&gt;
value.&lt;br /&gt;
&lt;br /&gt;
Whether we found something or not, we still want to return a result to&lt;br /&gt;
the requester:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;  $node = toFrom($node); $node-&amp;amp;gt;attr('type', IQ_RESULT);&lt;br /&gt;
&lt;br /&gt;
  $c-&amp;amp;gt;send($node);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
So we swap around the &amp;lt;tt&amp;gt;to&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;from&amp;lt;/tt&amp;gt; attributes&lt;br /&gt;
(remembering we're a component, and not a client) change the IQ&lt;br /&gt;
element's type from &amp;lt;tt&amp;gt;get&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;result&amp;lt;/tt&amp;gt;, and send it back.&lt;br /&gt;
&lt;br /&gt;
We end the function by telling the dispatcher that the element has been&lt;br /&gt;
handled:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;  return r_HANDLED;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== Supporting functions ==== &lt;br /&gt;
&amp;lt;br&amp;gt;The rest of the script consists of minor&lt;br /&gt;
functions that play roles in assisting the core &amp;lt;tt&amp;gt;iq_browse()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;iq_notimpl()&amp;lt;/tt&amp;gt; function is exactly the same as in the&lt;br /&gt;
newsagent script in Section 8.3; it serves to catch stray IQ elements&lt;br /&gt;
that in this case aren't IQ-gets containing a &amp;lt;tt&amp;gt;jabber:iq:browse&amp;lt;/tt&amp;gt;&lt;br /&gt;
query, and send them back with a &amp;quot;Not Implemented&amp;quot; error. With IQs, this&lt;br /&gt;
is preferable to not responding at all, as responses are usually&lt;br /&gt;
expected, even if those responses are IQ-errors. It's different with&lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;amp;lt;message/&amp;amp;gt;&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;&amp;amp;lt;presence/&amp;amp;gt;&amp;lt;/tt&amp;gt; elements, as&lt;br /&gt;
they can be seen as &amp;quot;one-way&amp;quot; and valid fodder for an element-sink.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sub iq_notimpl {&lt;br /&gt;
&lt;br /&gt;
  my $node = shift; $node = toFrom($node); $node-&amp;amp;gt;attr('type',&lt;br /&gt;
  IQ_ERROR); my $error = $node-&amp;amp;gt;insertTag('error');&lt;br /&gt;
  $error-&amp;amp;gt;attr('code', '501'); $error-&amp;amp;gt;data('Not Implemented');&lt;br /&gt;
  $c-&amp;amp;gt;send($node); return r_HANDLED;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;strip()&amp;lt;/tt&amp;gt; function, as described already, removes a base DN&lt;br /&gt;
from a fully qualified DN:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sub strip {&lt;br /&gt;
&lt;br /&gt;
  my ($fqdn, $basedn) = @_; my @fqdn = split(/,/, $fqdn); my&lt;br /&gt;
  @basedn_elements = split(/,/, $basedn); return join(',', @fqdn[0 ..&lt;br /&gt;
  ($#fqdn - scalar @basedn_elements)]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
As well as sharing the &amp;lt;tt&amp;gt;iq_notimpl()&amp;lt;/tt&amp;gt; function with the&lt;br /&gt;
''newsagent'' script, ''ldapr'' also shares the &amp;lt;tt&amp;gt;toFrom()&amp;lt;/tt&amp;gt;&lt;br /&gt;
function, which flips around the values of the &amp;lt;tt&amp;gt;to&amp;lt;/tt&amp;gt; and&lt;br /&gt;
&amp;lt;tt&amp;gt;from&amp;lt;/tt&amp;gt; attributes of an element:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sub toFrom { my $node = shift; my $to = $node-&amp;amp;gt;attr('to');&lt;br /&gt;
$node-&amp;amp;gt;attr('to', $node-&amp;amp;gt;attr('from')); $node-&amp;amp;gt;attr('from',&lt;br /&gt;
$to); return $node;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;isUser()&amp;lt;/tt&amp;gt; function, also described earlier, makes an&lt;br /&gt;
arbitrary distinction between LDAP nodes that it thinks are&lt;br /&gt;
&amp;lt;tt&amp;gt;People&amp;lt;/tt&amp;gt; and those that it thinks aren't:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sub isUser {&lt;br /&gt;
&lt;br /&gt;
  my $rdn = shift; return $rdn =~ /^cn/ ? 1 : 0&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Last but not least, we have a simple &amp;lt;tt&amp;gt;debug()&amp;lt;/tt&amp;gt; function, which in&lt;br /&gt;
this case is simply an abstraction of the classic &amp;quot;print to STDERR&amp;quot;&lt;br /&gt;
method:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sub debug {&lt;br /&gt;
&lt;br /&gt;
  print STDERR &amp;quot;debug: &amp;quot;, @_, &amp;quot;\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Building an ERP Connection == &lt;br /&gt;
&amp;lt;br&amp;gt;To some extent, SAP's R/3, an&lt;br /&gt;
Enterprise Resource Planning (ERP) system, has until recently been a&lt;br /&gt;
monolithic piece of software, both from an actual and psychological&lt;br /&gt;
perspective.&lt;br /&gt;
&lt;br /&gt;
The drive to replace disparate and incompatible business system&lt;br /&gt;
&amp;quot;islands&amp;quot; with an integrated software solution that covered business&lt;br /&gt;
processes across the board was strong in the 1980s and 1990s. With good&lt;br /&gt;
reason. For example, SAP delivered the ability for companies to manage&lt;br /&gt;
their different end-to-end processes coherently, without requiring&lt;br /&gt;
custom-built interfaces between logistics and financial accounting&lt;br /&gt;
packages. The flow of information was automatic between the application&lt;br /&gt;
subsystems that were standard within SAP's R/2 and R/3 products.&lt;br /&gt;
&lt;br /&gt;
The upside to this was, of course, the seamless integration of data and&lt;br /&gt;
functions within the SAP universe, a universe vast enough to offer&lt;br /&gt;
application coverage for pretty much every conceivable business&lt;br /&gt;
function.&lt;br /&gt;
&lt;br /&gt;
The downside was, ironically, the universe itself. All-encompassing as&lt;br /&gt;
SAP's products were, and indeed they were forever changing and expanding&lt;br /&gt;
to meet business demands, it was never enough, if you wanted to break&lt;br /&gt;
out of the mould formed by the omnipresent standard proprietary client&lt;br /&gt;
called SAPGUI. Sure, these days, with a huge installed base of R/2 and&lt;br /&gt;
R/3 systems in production around the world, there are a multitude of&lt;br /&gt;
ways to get data in and out of SAP systems, but despite the varied&lt;br /&gt;
successes of alternative client initiatives, user interaction with the&lt;br /&gt;
business processes remains largely orientated around the SAPGUI.&lt;br /&gt;
&lt;br /&gt;
This recipe is extremely simple compared to the others in this chapter.&lt;br /&gt;
It breaks out of the SAPGUI mold and the monolithic software culture to&lt;br /&gt;
use open source tools and technologies to add value to our SAP business&lt;br /&gt;
processes. The point of this recipe is not particularly what the script&lt;br /&gt;
looks like or how it's written, but what it does and how it does it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Building an Order Approval Notification Mechanism === &lt;br /&gt;
&amp;lt;br&amp;gt;We're going to&lt;br /&gt;
use a standard Jabber client as an SAP R/3 client—obviously not to&lt;br /&gt;
replace SAPGUI, rather to allow someone who perhaps has a single&lt;br /&gt;
R/3-related task to perform and connects only to SAP occasionally. In&lt;br /&gt;
stark contrast to the SAPGUI client, an off-the-shelf Jabber client is&lt;br /&gt;
much smaller. It takes up less screen space, memory, and CPU and&lt;br /&gt;
generally for focused access is a great way for someone to play his part&lt;br /&gt;
in business processes from the comfort of familiar communication&lt;br /&gt;
surroundings—his IM client.&lt;br /&gt;
&lt;br /&gt;
Of course, the available Jabber clients don't have any built-in R/3&lt;br /&gt;
functionality per se, but as clients that can receive messages and&lt;br /&gt;
recognize URLs,&amp;lt;ref&amp;gt;This recognition is a client feature, not&lt;br /&gt;
necessarily related to the XHTML namespace described in Section 6.5.2.&lt;br /&gt;
&amp;lt;/ref&amp;gt; they provide enough horsepower for us to achieve our goal.&lt;br /&gt;
&lt;br /&gt;
That goal is to notify a supervisor whenever a sales order is placed&lt;br /&gt;
that requires his approval. The notification will arrive in the form of&lt;br /&gt;
a &amp;lt;tt&amp;gt;&amp;amp;lt;message/&amp;amp;gt;&amp;lt;/tt&amp;gt; element, carrying some descriptive text and,&lt;br /&gt;
crucially, a URL, which points to an Apache-based handler. When invoked,&lt;br /&gt;
the handler pulls the relevant information for the order out of R/3,&lt;br /&gt;
requests verification of the viewer's identity, and offers a chance to&lt;br /&gt;
approve the order with the click of a button.&lt;br /&gt;
&lt;br /&gt;
Effectively we're building a miniworkflow scenario: in one direction a&lt;br /&gt;
notification is transmitted out of the bounds of the SAP universe to the&lt;br /&gt;
approver, and in the other direction the notification process is turned&lt;br /&gt;
around in a one-step approval cycle via Apache. Figure 10-14 shows this&lt;br /&gt;
scenario and where our Jabber client and script, called ''approv'', fits&lt;br /&gt;
in.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:jab_1014.png|An external order approval workflow|center|350 px]]&amp;lt;br&amp;gt;&amp;lt;/code&amp;gt; The goal here is to get the&lt;br /&gt;
notification message out of R/3 and send it to the supervisor's JID&lt;br /&gt;
along with a URL that he can follow back into the R/3 system to carry&lt;br /&gt;
out the approval process. The return process via Apache is outside this&lt;br /&gt;
recipe's scope and has been left as an exercise for you.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== Getting the notification out of R/3 ==== &lt;br /&gt;
&amp;lt;br&amp;gt;As we've already&lt;br /&gt;
mentioned, there are many ways of getting data in and out of SAP. We're&lt;br /&gt;
going to use a generic, lowest common denominator feature of the R/3&lt;br /&gt;
Basis system to invoke a script and pass it parameters.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Note|At this stage, if you're squeamish about R/3 Basis or SAP's ABAP&lt;br /&gt;
language or are of another ERP persuasion, it's time to look away. What&lt;br /&gt;
we're going to do here is not rocket science, nor is the general process&lt;br /&gt;
specific to R/3. We're just going to call a script, at the operating&lt;br /&gt;
system level, from within an application inside R/3.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The function group &amp;lt;tt&amp;gt;SXPT&amp;lt;/tt&amp;gt; encompasses a number of function&lt;br /&gt;
modules related to the definition, management, and execution of&lt;br /&gt;
operating system commands. Each of these commands is described within&lt;br /&gt;
sets of configuration parameters that define how and where they can be&lt;br /&gt;
invoked. Using the program ''RSLOGCOM'', you can create definitions for&lt;br /&gt;
these operating system commands manually.&lt;br /&gt;
&lt;br /&gt;
We need to define such a command that refers to the ''approv'' script.&lt;br /&gt;
Figure 10-15 shows the ''RSLOGCOM'' definition of ''approv'' as an&lt;br /&gt;
external command that is called &amp;lt;tt&amp;gt;ZNOTIFY&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:jab_1015.png|Defining approv as an external command with RSLOGCM|center|350 px]]&amp;lt;br&amp;gt;&amp;lt;/code&amp;gt; Once ''approv'' has been defined&lt;br /&gt;
this way, it can be invoked by passing parameters with a call to a&lt;br /&gt;
function module in the &amp;lt;tt&amp;gt;SXPT&amp;lt;/tt&amp;gt; function group&lt;br /&gt;
(&amp;lt;tt&amp;gt;SXPG_EXECUTE_COMMAND&amp;lt;/tt&amp;gt;). Example 10-19 shows how the script&lt;br /&gt;
might be invoked using this function module in ABAP. Code like this&lt;br /&gt;
could typically be installed in a ''customer exit''—a place in a&lt;br /&gt;
standard R/3 application where custom processing can be added without&lt;br /&gt;
having to go through the involved process of creating and carrying out a&lt;br /&gt;
modification request.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''Calling approv, via ZNOTIFY, from within R/3''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;data: sxpg_exec_protocol like btcxpm occurs 0 with header line,&lt;br /&gt;
&lt;br /&gt;
      sxpg_add_parms like SXPGCOLIST-PARAMETERS,&lt;br /&gt;
&lt;br /&gt;
      sxpg_target_system like RFCDISPLAY-RFCHOST value 'gnu.mine.nu'.&lt;br /&gt;
&lt;br /&gt;
concatenate ordernumber approver into sxpg_add_parms separated by space.&lt;br /&gt;
&lt;br /&gt;
call function 'SXPG_COMMAND_EXECUTE' exporting commandname           =&lt;br /&gt;
'ZNOTIFY' additional_parameters = sxpg_add_parms operatingsystem       =&lt;br /&gt;
sy-opsys targetsystem          = sxpg_target_system stdout              &lt;br /&gt;
 = 'X' stderr                = 'X' terminationwait       = 'X' table&lt;br /&gt;
exec_protocol         = sxpg_exec_protocol exception others             &lt;br /&gt;
  = 1.&lt;br /&gt;
&lt;br /&gt;
if sy-subrc &amp;amp;lt;&amp;amp;gt; 0. raise notification_failed. endif.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We pass two parameters to ''approv'' via the&lt;br /&gt;
&amp;lt;tt&amp;gt;SXPG_COMMAND_EXECUTE&amp;lt;/tt&amp;gt;: the number of the order that needs&lt;br /&gt;
approving (from &amp;lt;tt&amp;gt;ordernumber&amp;lt;/tt&amp;gt;) and the JID of the approver (from&lt;br /&gt;
&amp;lt;tt&amp;gt;approver&amp;lt;/tt&amp;gt;). The SXPG mechanism invokes the ''approv'' script&lt;br /&gt;
with the two parameters, and the notification starts its journey.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The approv Script === &lt;br /&gt;
&amp;lt;br&amp;gt;As mentioned already, the ''approv'' script &lt;br /&gt;
(shown in Example 10-20) is rather small and insignificant. Its purpose&lt;br /&gt;
is to take the order number it receives, wrap it in a descriptive&lt;br /&gt;
message that includes a URL, and send it to the approver's JID. Written&lt;br /&gt;
in Perl, the ''approv'' script uses a minimum set of features from the&lt;br /&gt;
&amp;lt;tt&amp;gt;Jabber::Connection&amp;lt;/tt&amp;gt; library.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''The approv script, written in Perl''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;use strict; use Jabber::Connection;&lt;br /&gt;
&lt;br /&gt;
my ($order, $approver) = @ARGV; my $c = new Jabber::Connection(server&lt;br /&gt;
=&amp;amp;gt; 'qmacro.dyndns.org'); die &amp;quot;Cannot connect: &amp;quot;.$c-&amp;amp;gt;lastError&lt;br /&gt;
unless $c-&amp;amp;gt;connect(); $c-&amp;amp;gt;auth('approv','secret','approv');&lt;br /&gt;
&lt;br /&gt;
$c-&amp;amp;gt;send(&amp;amp;lt;&amp;amp;lt;EO_MSG); &amp;amp;lt;message to=&amp;quot;$jid&amp;quot;&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;subject&amp;amp;gt;Order Approval Required&amp;amp;lt;/subject&amp;amp;gt; &amp;amp;lt;body&amp;amp;gt; An&lt;br /&gt;
order ($order) requiring your approval has been placed. Please visit&lt;br /&gt;
http://qmacro.dyndns.org/approv?$order to approve.&lt;br /&gt;
&lt;br /&gt;
Thank you. &amp;amp;lt;/body&amp;amp;gt; &amp;amp;lt;/message&amp;amp;gt; EO_MSG&lt;br /&gt;
&lt;br /&gt;
$c-&amp;amp;gt;disconnect;&amp;lt;/code&amp;gt; The script receives the two parameters passed from&lt;br /&gt;
R/3 into the &amp;lt;tt&amp;gt;$order&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;$approver&amp;lt;/tt&amp;gt; variables. Having&lt;br /&gt;
connected to the Jabber server at &amp;lt;tt&amp;gt;qmacro.dyndns.org&amp;lt;/tt&amp;gt; and&lt;br /&gt;
authenticated as the user &amp;lt;tt&amp;gt;approv&amp;lt;/tt&amp;gt;, it sends off a formatted&lt;br /&gt;
message to the approver, before disconnecting.&lt;br /&gt;
&lt;br /&gt;
The script itself is extremely simple and is not of primary importance.&lt;br /&gt;
What is crucial here is the role that Jabber is playing. The&lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;amp;lt;message/&amp;amp;gt;&amp;lt;/tt&amp;gt; element of Jabber's protocol is used to span&lt;br /&gt;
the R/3 world with the IM world, enabling a business process cycle to&lt;br /&gt;
take place ''outside'' the normal boundaries of R/3 interaction. On a&lt;br /&gt;
simple level, that's all it takes to merge the ERP business process&lt;br /&gt;
world with the world of IM.&lt;br /&gt;
&lt;br /&gt;
The return path to R/3, via the Apache-based CGI application, is&lt;br /&gt;
initiated when the user clicks on the URL in the message, as shown in&lt;br /&gt;
Figure 10-16.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:jab_1016.png|Receipt of an order approval request in Jarl|center|350 px]]&amp;lt;br&amp;gt;&amp;lt;/code&amp;gt; Here we see that Jarl has&lt;br /&gt;
recognized the ''http://'' address and has rendered it as an active&lt;br /&gt;
link. That's all it has to do. There's no attempt on Jarl's part to make&lt;br /&gt;
an HTTP request to the Apache server and render the HTML received.&lt;br /&gt;
Focusing on &amp;quot;the right tools for the right job,&amp;quot; we should leave that&lt;br /&gt;
role to a web browser, as indeed Jarl does, starting up the browser of&lt;br /&gt;
our choice.&amp;lt;ref&amp;gt;Specified in Jarl's configuration options. &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Taking This Further === &lt;br /&gt;
&amp;lt;br&amp;gt;The journey through the recipes in the last&lt;br /&gt;
three chapters of the book has taken us from the simplest CVS&lt;br /&gt;
notification mechanism with the ''cvsmsg'' script (Section 8.1) through&lt;br /&gt;
a fairly involved RSS component (Section 9.3) to the transporting of&lt;br /&gt;
XML-RPC-encoded requests and responses with our ''JabberRPCRequester''&lt;br /&gt;
and  ''JabberRPCResponder'' scripts (Section 10.3).&lt;br /&gt;
&lt;br /&gt;
This chapter, and indeed the book, ends on a simple note, in the form of&lt;br /&gt;
the ''approv'' script. Not without reason, we've completed the circle of&lt;br /&gt;
script and application complexity. While we can build very useful and&lt;br /&gt;
successful applications that are naturally complex, a Jabber-powered&lt;br /&gt;
solution doesn't necessarily have to be. To employ the Jabber&lt;br /&gt;
philosophy, the technology, and the protocol elements to build bridges&lt;br /&gt;
between previously separate systems, and to span different areas of&lt;br /&gt;
technology, open and proprietary alike, using Jabber's open, extensible,&lt;br /&gt;
and flexible protocol, is what it's all about.&lt;br /&gt;
&lt;br /&gt;
Finally, it's hopefully clear from the diversity of recipes shown in&lt;br /&gt;
this part of the book that deploying solutions with Jabber, as noted in&lt;br /&gt;
the preface, really ''is'' fun!&lt;/div&gt;</description>
			<pubDate>Sat, 16 Sep 2006 22:18:00 GMT</pubDate>			<dc:creator>Mikeh</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:JabChapter_10</comments>		</item>
	</channel>
</rss>