summaryrefslogtreecommitdiff
path: root/docs/howto/xmpp_tdg.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/howto/xmpp_tdg.rst')
-rw-r--r--docs/howto/xmpp_tdg.rst249
1 files changed, 249 insertions, 0 deletions
diff --git a/docs/howto/xmpp_tdg.rst b/docs/howto/xmpp_tdg.rst
new file mode 100644
index 00000000..53194e13
--- /dev/null
+++ b/docs/howto/xmpp_tdg.rst
@@ -0,0 +1,249 @@
+Following *XMPP: The Definitive Guide*
+======================================
+
+Slixmpp was featured in the first edition of the O'Reilly book
+`XMPP: The Definitive Guide <http://oreilly.com/catalog/9780596521271/>`_
+by Peter Saint-Andre, Kevin Smith, and Remko Tronçon. The original source code
+for the book's examples can be found at http://github.com/remko/xmpp-tdg. An
+updated version of the source code, maintained to stay current with the latest
+Slixmpp release, is available at http://github.com/legastero/xmpp-tdg.
+
+However, since publication, Slixmpp has advanced from version 0.2.1 to version
+1.0 and there have been several major API changes. The most notable is the
+introduction of :term:`stanza objects <stanza object>` which have simplified and
+standardized interactions with the XMPP XML stream.
+
+What follows is a walk-through of *The Definitive Guide* highlighting the
+changes needed to make the code examples work with version 1.0 of Slixmpp.
+These changes have been kept to a minimum to preserve the correlation with
+the book's explanations, so be aware that some code may not use current best
+practices.
+
+Example 2-2. (Page 26)
+----------------------
+
+**Implementation of a basic bot that echoes all incoming messages back to its sender.**
+
+The echo bot example requires a change to the ``handleIncomingMessage`` method
+to reflect the use of the ``Message`` :term:`stanza object`. The
+``"jid"`` field of the message object should now be ``"from"`` to match the
+``from`` attribute of the actual XML message stanza. Likewise, ``"message"``
+changes to ``"body"`` to match the ``body`` element of the message stanza.
+
+Updated Code
+~~~~~~~~~~~~
+
+.. code-block:: python
+
+ def handleIncomingMessage(self, message):
+ self.xmpp.send_message(message["from"], message["body"])
+
+`View full source (1) <http://github.com/legastero/xmpp-tdg/blob/master/code/EchoBot/EchoBot.py>`_ |
+`View original code (1) <http://github.com/remko/xmpp-tdg/blob/master/code/EchoBot/EchoBot.py>`_
+
+Example 14-1. (Page 215)
+------------------------
+
+**CheshiR IM bot implementation.**
+
+The main event handling method in the Bot class is meant to process both message
+events and presence update events. With the new changes in Slixmpp 1.0,
+extracting a CheshiR status "message" from both types of stanzas
+requires accessing different attributes. In the case of a message stanza, the
+``"body"`` attribute would contain the CheshiR message. For a presence event,
+the information is stored in the ``"status"`` attribute. To handle both cases,
+we can test the type of the given event object and look up the proper attribute
+based on the type.
+
+Like in the EchoBot example, the expression ``event["jid"]`` needs to change
+to ``event["from"]`` in order to get a JID object for the stanza's sender.
+Because other functions in CheshiR assume that the JID is a string, the ``jid``
+attribute is used to access the string version of the JID. A check is also added
+in case ``user`` is ``None``, but the check could (and probably should) be
+placed in ``addMessageFromUser``.
+
+Another change is needed in ``handleMessageAddedToBackend`` where
+an HTML-IM response is created. The HTML content should be enclosed in a single
+element, such as a ``<p>`` tag.
+
+Updated Code
+~~~~~~~~~~~~
+
+.. code-block:: python
+
+ def handleIncomingXMPPEvent(self, event):
+ msgLocations = {slixmpp.stanza.presence.Presence: "status",
+ slixmpp.stanza.message.Message: "body"}
+
+ message = event[msgLocations[type(event)]]
+ user = self.backend.getUserFromJID(event["from"].jid)
+ if user is not None:
+ self.backend.addMessageFromUser(message, user)
+
+ def handleMessageAddedToBackend(self, message) :
+ body = message.user + ": " + message.text
+ htmlBody = "<p><a href='%(uri)s'>%(user)s</a>: %(message)s</p>" % {
+ "uri": self.url + "/" + message.user,
+ "user" : message.user, "message" : message.text }
+ for subscriberJID in self.backend.getSubscriberJIDs(message.user) :
+ self.xmpp.send_message(subscriberJID, body, mhtml=htmlBody)
+
+`View full source (2) <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/Bot.py>`_ |
+`View original code (2) <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/Bot.py>`_
+
+
+Example 14-3. (Page 217)
+------------------------
+**Configurable CheshiR IM bot implementation.**
+
+.. note::
+ Since the CheshiR examples build on each other, see previous sections for
+ corrections to code that is not marked as new in the book example.
+
+The main difference for the configurable IM bot is the handling for the
+data form in ``handleConfigurationCommand``. The test for equality
+with the string ``"1"`` is no longer required; Slixmpp converts
+boolean data form fields to the values ``True`` and ``False``
+automatically.
+
+For the method ``handleIncomingXMPPPresence``, the attribute
+``"jid"`` is again converted to ``"from"`` to get a JID
+object for the presence stanza's sender, and the ``jid`` attribute is
+used to access the string version of that JID object. A check is also added in
+case ``user`` is ``None``, but the check could (and probably
+should) be placed in ``getShouldMonitorPresenceFromUser``.
+
+Updated Code
+~~~~~~~~~~~~
+
+.. code-block:: python
+
+ def handleConfigurationCommand(self, form, sessionId):
+ values = form.getValues()
+ monitorPresence =values["monitorPresence"]
+ jid = self.xmpp.plugin["xep_0050"].sessions[sessionId]["jid"]
+ user = self.backend.getUserFromJID(jid)
+ self.backend.setShouldMonitorPresenceFromUser(user, monitorPresence)
+
+ def handleIncomingXMPPPresence(self, event):
+ user = self.backend.getUserFromJID(event["from"].jid)
+ if user is not None:
+ if self.backend.getShouldMonitorPresenceFromUser(user):
+ self.handleIncomingXMPPEvent(event)
+
+`View full source (3) <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/ConfigurableBot.py>`_ |
+`View original code (3) <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/ConfigurableBot.py>`_
+
+
+Example 14-4. (Page 220)
+------------------------
+**CheshiR IM server component implementation.**
+
+.. note::
+ Since the CheshiR examples build on each other, see previous sections for
+ corrections to code that is not marked as new in the book example.
+
+Like several previous examples, a needed change is to replace
+``subscription["from"]`` with ``subscription["from"].jid`` because the
+``BaseXMPP`` method ``make_presence`` requires the JID to be a string.
+
+A correction needs to be made in ``handleXMPPPresenceProbe`` because a line was
+left out of the original implementation; the variable ``user`` is undefined. The
+JID of the user can be extracted from the presence stanza's ``from`` attribute.
+
+Since this implementation of CheshiR uses an XMPP component, it must
+include a ``from`` attribute in all messages that it sends. Adding the
+``from`` attribute is done by including ``mfrom=self.xmpp.jid`` in calls to
+``self.xmpp.send_message``.
+
+Updated Code
+~~~~~~~~~~~~
+
+.. code-block:: python
+
+ def handleXMPPPresenceProbe(self, event) :
+ self.xmpp.send_presence(pto = event["from"])
+
+ def handleXMPPPresenceSubscription(self, subscription) :
+ if subscription["type"] == "subscribe" :
+ userJID = subscription["from"].jid
+ self.xmpp.send_presence_subscription(pto=userJID, ptype="subscribed")
+ self.xmpp.send_presence(pto = userJID)
+ self.xmpp.send_presence_subscription(pto=userJID, ptype="subscribe")
+
+ def handleMessageAddedToBackend(self, message) :
+ body = message.user + ": " + message.text
+ for subscriberJID in self.backend.getSubscriberJIDs(message.user) :
+ self.xmpp.send_message(subscriberJID, body, mfrom=self.xmpp.jid)
+
+`View full source (4) <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/SimpleComponent.py>`_ |
+`View original code (4) <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/SimpleComponent.py>`_
+
+
+Example 14-6. (Page 223)
+------------------------
+**CheshiR IM server component with in-band registration support.**
+
+.. note::
+ Since the CheshiR examples build on each other, see previous sections for
+ corrections to code that is not marked as new in the book example.
+
+After applying the changes from Example 14-4 above, the registrable component
+implementation should work correctly.
+
+.. tip::
+ To see how to implement in-band registration as a Slixmpp plugin,
+ see the tutorial :ref:`tutorial-create-plugin`.
+
+`View full source (5) <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/RegistrableComponent.py>`_ |
+`View original code (5) <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/RegistrableComponent.py>`_
+
+Example 14-7. (Page 225)
+------------------------
+**Extended CheshiR IM server component implementation.**
+
+.. note::
+ Since the CheshiR examples build on each other, see previous
+ sections for corrections to code that is not marked as new in the book
+ example.
+
+While the final code example can look daunting with all of the changes
+made, it requires very few modifications to work with the latest version of
+Slixmpp. Most differences are the result of CheshiR's backend functions
+expecting JIDs to be strings so that they can be stripped to bare JIDs. To
+resolve these, use the ``jid`` attribute of the JID objects. Also,
+references to ``"message"`` and ``"jid"`` attributes need to
+be changed to either ``"body"`` or ``"status"``, and either
+``"from"`` or ``"to"`` depending on if the object is a message
+or presence stanza and which of the JIDs from the stanza is needed.
+
+Updated Code
+~~~~~~~~~~~~
+
+.. code-block:: python
+
+ def handleIncomingXMPPMessage(self, event) :
+ message = self.addRecipientToMessage(event["body"], event["to"].jid)
+ user = self.backend.getUserFromJID(event["from"].jid)
+ self.backend.addMessageFromUser(message, user)
+
+ def handleIncomingXMPPPresence(self, event) :
+ if event["to"].jid == self.componentDomain :
+ user = self.backend.getUserFromJID(event["from"].jid)
+ self.backend.addMessageFromUser(event["status"], user)
+
+ ...
+
+ def handleXMPPPresenceSubscription(self, subscription) :
+ if subscription["type"] == "subscribe" :
+ userJID = subscription["from"].jid
+ user = self.backend.getUserFromJID(userJID)
+ contactJID = subscription["to"]
+ self.xmpp.send_presence_subscription(
+ pfrom=contactJID, pto=userJID, ptype="subscribed", pnick=user)
+ self.sendPresenceOfContactToUser(contactJID=contactJID, userJID=userJID)
+ if contactJID == self.componentDomain :
+ self.sendAllContactSubscriptionRequestsToUser(userJID)
+
+`View full source (6) <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/Component.py>`_ |
+`View original code (6) <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/Component.py>`_