Cutting corners with xmpp4r-simple
July 3, 2008
xmpp4r-simple aims to provide a wrapper around the powerful and well maintained xmpp4r library, "making it dead-simple to send and receive Jabber messages".
Unfortunately, the abstraction and simplification provided by xmpp4r-simple is leaky, missing the principles of jabber protocol. The result - the naive implementation (from the tutorial) did not work for me:
# Send a message to a friend, asking for authorization if necessary:
im = Jabber::Simple.new("[email protected]", "password")
im.deliver("[email protected]", "Hey there friend!")
Yes, I did replace the example.com
with the name of my server. ;-)
Result - response 406 "Not Acceptable"
The problem
Jabber::ClientAuthenticationFailure: : Not Acceptable
from /usr/lib/ruby/gems/1.8/gems/xmpp4r-0.3.2.99/lib/xmpp4r/client.rb:116:in `auth'
from /usr/lib/ruby/gems/1.8/gems/xmpp4r-simple-0.8.7/lib/xmpp4r-simple.rb:391:in `connect!'
from /usr/lib/ruby/gems/1.8/gems/xmpp4r-simple-0.8.7/lib/xmpp4r-simple.rb:322:in `client'
from /usr/lib/ruby/gems/1.8/gems/xmpp4r-simple-0.8.7/lib/xmpp4r-simple.rb:331:in `send!'
from /usr/lib/ruby/gems/1.8/gems/xmpp4r-simple-0.8.7/lib/xmpp4r-simple.rb:147:in `status'
from /usr/lib/ruby/gems/1.8/gems/xmpp4r-simple-0.8.7/lib/xmpp4r-simple.rb:90:in `initialize'
from (irb):3:in `new'
from (irb):3
The trace
So I had to go couple of abstraction layers deeper to get it running. At the end I am glad about that. The best opportunity to learn a protocol - to read the documentation in connection with the problem at hand and by observing the actual communication.
Using Gajim's XML Console you can trace the communication between the client and the server:
Client: connecting...
<iq type="get" id="29">
<query xmlns="jabber:iq:auth">
<username>johndoe</username>
</query>
</iq>
Server tells, which information the client should provide:
<iq type='result' id='29'>
<query xmlns='jabber:iq:auth'>
<username>johndoe</username>
<digest/>
<password/>
<resource/>
</query>
</iq>
Client fills in the blanks providing the needed information:
<iq type="set" id="30">
<query xmlns="jabber:iq:auth">
<username>johndoe</username>
<digest>c26789d0exyz4adf8c61e62e8fef27e6d0de</digest>
<resource>Gajim</resource>
</query>
</iq>
Server: connection succeeded:
My server is a jabberd14 (the original reference
implementation of the Jabber protocol), easily installable on Ubuntu
by sudo aptitude install jabber
.
As seen in the log, it requires the resource-clause - some sort of subnamespace. Gajim and Pidgin and probably all other Clients are smart enough to provide it if requested by the server. xmpp4r-simple is not.
The solution
The solution was to provide the required information from the beginning
on, because xmpp4r ignores the Jabber typical handshake. Please
note the /Home
after the jabber id.
im = Jabber::Simple.new("[email protected]/Home", "password")
im.deliver("[email protected]", "Hey there friend!")
Trackback Pings
TrackBack URL for this entry:
http://www.innoq.com/movabletype/mt-tb.cgi/3053