At times, sending something more than plain text is desirable. XEP-0071 XHTML-IM provides for that with Jabber. And sending such XHTML enriched messages with xmpppy turns out to be fairly straightforward. In fact, I’ve now set up my weblog so that I get notified whenever I’m online and a comment is made. Here’s how it works.
First, create a bare-bones text message, specifying the destination and some text. In my case, titles may contain numeric entities such as ’
, but as this is relatively rare, and this is only the fall-back for clients that don’t support XHTML (and GAIM does), so I’m not overly worried about it.
message=xmpp.protocol.Message('rubys@rubix/Laptop', title)
Now I build a payload containing some markup, and add it to the message. UTF-8 and numeric entities works just fine. This data, however, absolutely must be well formed, so a try:/except:
block may be in order for in most applications. Fortunately, mine is safe.
payload=xmpp.simplexml.XML2Node('<body xmlns="%s">%s</body>' % (xml.dom.XML_NAMESPACE, '<a href="%s">%s</a>: %s' % (link, title, byline))) message.addChild('html', {}, [payload], xmpp.NS_XHTML_IM)
Specify the sending Jabber ID.
jid=xmpp.protocol.JID('rubys@rubix/intertwingly') cl=xmpp.Client(jid.getDomain(), debug=[])
Connect to the Jabber server. In most cases, you can simply call cl.connect()
as the host and port can be determined from the JID. But if you have punched a hole in your firewall, you can specify the ip address and port number where your jabber server can be reached. Again, most people won’t need to do this as they can readily obtain public jabber IDs, but it is nice to know that it can be done. Note that the address and port are separated by a comma, not a colon as the documentation incorrectly states.
con=cl.connect((address,port)) if not con: return
Now, authorize yourself:
auth=cl.auth(jid.getNode(), 'password', resource=jid.getResource()) if not auth: return
Finally, send the message:
cl.send(message) time.sleep(1) cl.disconnect()
Cool, you could use the the rst_xhtml_generator
from gajim, if you prefer writing ReStructured Text over xhtml.
So, if I type in gajim:
Am I the only one to relate `O'Reilly's news on the demise of the PC, greatly exaggerated <http://radar.oreilly.com/archives/2007/08/yahoos_bet_on_h.html>`_ with your `personal jabber server <http://intertwingly.net/blog/2007/08/08/Personal-Jabber-Server>`_ entry?
I get (and send in xhtml-im enclosure):
Am I the only one to relate O’Reilly’s news on the demise of the PC, greatly exaggerated with your personal jabber server entry?
(modulo class="reference" and " in timo’s name that I needed to remove for mombo to take the anchors as valid.)
The dark side of it is having to know rst, not always trivial; the luminous side is that the result can be read even by xmpp clients not supporting :XEP:`71`, like gmail’s.
Haven’t completely tracked this down. I get notifications to entries that are “Posted By” (which are created by Apache CGI processes), but not to entries that are “Excerpt from” (which are created by a cron job). Here’s the relevant portion of the traceback:
File "/web/script/rubys/intertwingly.net/mombo/xnotify.py", line 26, in send con=cl.connect((address,port)) File "/home/rubys/xmpppy-0.4.0/xmpp/client.py", line 200, in connect while not self.TLS.starttls and self.Process(1): pass File "/home/rubys/xmpppy-0.4.0/xmpp/dispatcher.py", line 302, in dispatch handler['func'](session,stanza) File "/home/rubys/xmpppy-0.4.0/xmpp/transports.py", line 327, in StartTLSHandler self._startSSL() File "/home/rubys/xmpppy-0.4.0/xmpp/transports.py", line 305, in _startSSL tcpsock._sslObj = socket.ssl(tcpsock._sock, None, None) TypeError: ssl() argument 1 must be _socket.socket, not instance