In the section called CVS notification earlier in this chapter we replaced the email-based CVS notification mechanism with a Jabber-based one. The script used was extremely simple—it connected to the Jabber server specified, authenticated, and sent off the notification message to the recipient JID.
What if we wanted to make the script "sensitive"? Jabber's presence concept could help us here; if we extended the mechanism to allow for the building of presence-based relationships between the notification script and the notification recipients, we can make the sending of the notification message dependent on the recipient's availability. "Presence-based relationships" refers to the presence subscription mechanism described in the sidebar in the section called Presence Attributes in Chapter 5.
Here's how it would work:
Each potential recipient adds the JID used by the CVS notification script to their roster, and sends a subscription request to it. [1]
The notification script, on receipt of the presence subscription from a recipient, accepts the request and reciprocates by sending a subscription request back to that recipient.
On receipt of the presence subscription from the notification script, the recipient accepts the request.
When the notification script starts up to send a message, it announces its own availability with a <presence/> element, which causes the availability of the JIDs to which it has a presence subscription to be sent to it. Based on these <presence/> packets received, it can make a decision as to whether to send the notification message or not.
The decision we're going to use here is an arbitrary one: If the recipient is online, we'll send the message, unless they've specified that they don't want to be disturbed, with the <show>dnd</show> element.
This method will result in "balanced" subscription relationships between script and recipients. In other words, the script is subscribed to a recipient's presence, and vice versa.
Of the two presence subscription "directions", the one where the notification script subscribes to the recipient's presence (as opposed to the one where the recipient subscribes to the notification script's presence) is by far the most important. While it's not critical that the recipients know when the notification script is connected and active, it's essential that the notification script know about a recipient's availability at the time it wants to send a message.
So would it be more appropriate to create "unbalanced" subscription relationships?
An unbalanced relationship is one where one party knows about the other party's availability, but not vice versa. The idea for sensitizing our notification script will work as long as the script can know about the availability of the recipients. Whether or not the opposite is true is largely irrelevant.
Nevertheless, it's worth basing the interaction on balanced, or reciprocal, presence subscriptions, primarily for simplicity's sake, and also for the fact that most Jabber clients (and most users of these clients) tend to cope well and consistently with "balanced" subscriptions, whereby the representation and interpretation of unbalanced relationships is dealt with and understood in different manners. Some clients use a "Lurker" group to classify one-way presence subscriptions from other JIDs: a "lurker" being one that can see you while you can't see it.
Far from being nebulous concepts, balanced and unbalanced subscription relationships are characterized technically by values of a certain attribute specified in each item—each JID—in a roster: the subscription attribute of the <item/> tags within the roster. As we progress through the extensions to our CVS notification script, we'll pause at various stages to examine these values.
Anthropomorphism: It's worth pointing out at this stage that adding a JID that's used by a script to connect to Jabber is slightly symbolic of the extension of the instant messaging world into the wider arena of A2P messaging. Adding a service JID to your roster and sharing presence information with that service is such a powerful concept and one which can be used to base A2P solutions upon.
The script, as it stands in the section called The script in its entirety, is what we want to extend and make sensitive to presence. We'll walk through the additions, and then present the extended script at the end of this section.
We bring in a string function that we'll be needing later in the script to chop up JIDs into their component parts (username, hostname, and resource):
import Jabber, XMLStream import sys from string import split cvsuser = sys.argv[1] message = ''
The next addition to the script is a callback to handle <presence/> elements. The callback in this script takes the form of a subroutine called presenceCB() ("presence CallBack").
Jabber programming and callbacks When programming all but the simplest Jabber scripts, you're going to be using callbacks. Callbacks are also known as handlers. Rather than purely procedural programming ("do this, then do that, then do the other"), we need a different model to cope with the event-based nature of Jabber, or more precisely, the event-based nature of how we converse using the Jabber protocol over an XML stream. Although we control what we send over the XML stream connection that we've established with the Jabber server, we can't control what we receive, and more importantly, we can't control when we receive it. We need an event-based programming model to be able to handle the protocol elements as they arrive. The libraries available for programming with Jabber offer callback mechanisms. With these callback mechanisms we can register subroutines with the mechanism that's handling the reception of XML stream fragments, so that when an element appears on the incoming stream (a fragment in the stream document that the Jabber server is sending to us—see the section called XML Streams in Chapter 5), the Jabber library can pass it to the appropriate subroutine in our script for us to act upon. Figure 7-5 shows the relationship between the library and script, and the sequence of events surrounding registering a handler and having it called. Here are the steps shown:
|
Figure 7-5. Handlers and the relationship between the Jabber library and your script
+---------------------------+ +---------------------+
| Jabber library | | Your script |
|---------------------------| |---------------------|
| | | |
| | | [1] |
| +----------------------- register handler |
| | | | |
| +-V-------+ | | |
| |presence ........................ |
| +---------+ | | : |
| |message | | | +------------+ |
XML | +---------+ | | +->|presenceCB()| |
stream | |iq | | | | |------------| |
| | +---------+ | | | | | |
V | ^ | | | | | |
============== | | | | +------------+ |
[2] <presence/> +-------+ | | | |
element arrives | | | | |
----------------> [3] parse, and | | | | |
============== create node | | | | |
| [4] determine handler | | | |
| [5] call handler ---------------+ |
| | | |
| | | |
+---------------------------+ +---------------------+
This is what the callback for handling <presence/> elements looks like:
def presenceCB(con, prs):
type = prs.getType()
parts = split(prs.getFrom(), '/')
who = parts[0]
if type == None: type = 'available'
# subscription request:
# - accept their subscription
# - send request for subscription to their presence
if type == 'subscribe':
print "subscribe request from %s" % (who)
con.send(Jabber.Presence(to=who, type='subscribed'))
con.send(Jabber.Presence(to=who, type='subscribe'))
# unsubscription request:
# - accept their unsubscription
# - send request for unsubscription to their presence
elif type == 'unsubscribe':
print "unsubscribe request from %s" % (who)
con.send(Jabber.Presence(to=who, type='unsubscribed'))
con.send(Jabber.Presence(to=who, type='unsubscribe'))
elif type == 'subscribed':
print "we are now subscribed to %s" % (who)
elif type == 'unsubscribed':
print "we are now unsubscribed to %s" % (who)
elif type == 'available':
print "%s is available (%s/%s)" % (who, prs.getShow(), prs.getStatus())
if prs.getShow() != 'dnd' and who == cvsuser:
con.send(Jabber.Message(cvsuser, message, subject="CVS Watch Alarm"))
elif type == 'unavailable':
print "%s is unavailable" % (who)
Phew! Let's take it a bit at at time. The first thing to note is what's specified in the subroutine declaration:
def presenceCB(con, prs):
As a handler, the subroutine presenceCB() will be passed the connection object in con and the presence node in prs. con is the same connection object that is created later in the script (con = Jabber.Connection(host=Server)) and is passed in for convenience, as it's quite likely we're going to want to use it, say, to send something back over the stream.
The presence node in prs is an object representation of the XML fragment that came in over the stream and was parsed into its component parts. The object is an instance of the Jabber.Presence class, which is simply a specialization of the more generic Jabber.Protocol class, as are the other classes that represent the other two Jabber protocol elements that are to be expected: Jabber.Message and Jabber.Iq. The Jabber.Protocol class represents protocol elements in general.
As such, there are a number of <presence/> element-specific methods we can call on the prs object, such as getShow() and getStatus() (which return the values of the <show/> and <status/> tags—children of the <presence/> element—respectively), and general element methods such as getID, which returns the value of any id attribute assigned to the element, and setTo() which can be used to address the element—to set the value of the to attribute.
The first thing the handler does is to call a few of these element methods to determine the type of <presence/> element (presence types are described in the section called The Presence Element in Chapter 5), and who it's coming from:
type = prs.getType()
parts = split(prs.getFrom(), '/')
who = parts[0]
When the notification script is called, the JID found in the CVS users file is substituted for the %s in the formula contained in the CVS notify file. So if the user dj were to be notified, the JID passed to the script would be dj@gnu.pipetree.com.
The way JIDs are passed around independently of the context of a Jabber session is usually in the simpler form: username@hostname. That is, without the resource suffix: username@hostname/resource. As described in Chapter 5, the resource is primarily used to distinguish individual sessions belonging to one Jabber user.
But when our Jabber library—and subsequently a handler subroutine in our script—receives an element, it contains a from attribute whose value has been stamped by the Jabber server as it passes through. [3] The value represents the session, the connection, from which the <presence/> element was sent, and as such, includes a resource suffix. So in order to properly match up the source JID for any incoming <presence/> element with the JID specified when the script was invoked (contained in the cvsuser variable), we need to strip off this resource suffix. The remaining username@hostname part is captured in the who variable.
There's one more step to determine the presence type. The type attribute is optional, and its absence signifies the default presence type, which is "available". So we effect this default substitution here to make the subsequent code clearer:
if type == None: type = 'available'
At this stage, we want to take different actions depending on what sort of presence information has arrived. Recalling the sequence of events in the reciprocal presence subscription exchange described earlier in this chapter, one of the activities is for a potential notification recipient to subscribe to the presence of the script's JID.
Request to subscribe
This subscription request is carried in a <presence/> element, with a type of "subscribe". Example 7-5 shows what a typical subscription request would look like.
Example 7-5. A presence subscription request from dj@gnu.pipetree.com
<presence type='subscribe' to='cvsmsg@gnu.pipetree.com'
from='dj@gnu.pipetree.com/work'/>At this stage, dj@gnu.pipetree.com has just sent a request to subscribe to the script's presence. The subscription relationship between the two parties is nondescript, and this is reflected in the details of the item in dj's roster that relates to the script's JID:
<item jid='cvsmsg@gnu.pipetree.com' subscription='none' ask='subscribe'/>
The relationship itself is reflected in the subscription attribute, and the current state of the relationship is reflected in the ask attribute.
If one of these is received, we want the script to respond by accepting their subscription request and requesting a subscription to their presence in return.
This incoming subscription request is handled here:
# subscription request:
# - accept their subscription
# - send request for subscription to their presence
if type == 'subscribe':
print "subscribe request from %s" % (who)
con.send(Jabber.Presence(to=who, type='subscribed'))
con.send(Jabber.Presence(to=who, type='subscribe'))
Each call to the Jabber.Presence class constructor creates a node representing a <presence/> element. The two parameters passed in the call are fairly self-explanatory: we specify to whom the <presence/> element should be sent, and the type.
If the presence subscription request came in from the JID dj@gnu.pipetree.com, then the XML represented by the node created in the first call here (specifying a presence type of "subscribed") would look something like that in Example 7-6.
Example 7-6. Acceptance of a presence subscription request from dj@gnu.pipetree.com
<presence type='subscribed' to='dj@gnu.pipetree.com'/>
Addressing <presence/> elements It's worth pointing out here that there's a subtle difference between sending <presence/> elements in a presence subscription conversation, and sending general "availability" <presence/> elements. In the first case, we use a to attribute, because our conversation is one-to-one. In the second, we don't; Our unaddressed availability information is caught by the server and in turn sent on to those entities that are subscribed to your presence. Although you can send <presence/> elements that convey availability information directly to a JID, it's not normal. However, explicitly addressing the elements in a subscription scenario is essential. There's another situation in which such "directed" (explicitly addressed) <presence/> elements are used - to partake of the services of the Availability Tracker. This is described in the "Availability Tracker" sidebar in the section called Presence Attributes in Chapter 5. |
Once constructed, each of the Jabber.Presence nodes are sent back along the stream with the con.send() calls.
Now the script has accepted dj's subscription request, dj's roster item for the script now reflects the new relationship:
<item jid='cvsmsg@gnu.pipetree.com' subscription='to'/>
subscription='to' denotes that the subscription relationship is currently one way—dj has a subscription to the script. There's no ask attribute as there's no current request going from dj to the script.
While dj's roster item for the script shows a subscription value of "to", the script's roster item for dj shows a subscription value of "from":
<item jid='dj@gnu.pipetree.com' subscription='from' ask='subscribe'/>
which shows that the script has a subscription from dj.
Furthermore, remember that the script not only accepts dj's subscription request, but sends a reciprocal one of its own. (Hence the ask='subscribe' status in the item.) When dj accepts this request, the roster item changes yet again to reflect the balanced relationship:
<item jid='cvsmsg@gnu.pipetree.com' subscription='both'/>
Request to unsubscribe
We want the script to handle requests to unsubscribe from its presence in the same way:
# unsubscription request:
# - accept their unsubscription
# - send request for unsubscription to their presence
elif type == 'unsubscribe':
print "unsubscribe request from %s" % (who)
con.send(Jabber.Presence(to=who, type='unsubscribed'))
con.send(Jabber.Presence(to=who, type='unsubscribe'))
The only difference between this section and the previous one is that it deals with requests to unsubscribe as opposed to subscribe to presence. Otherwise it works in exactly the same way. A sequence of <presence/> elements used in an "unsubscription conversation" between dj and the script, and the changes to the roster <item/> tags on each side, is shown in Figure 7-6.
Figure 7-6. <presence/> elements and roster <item/>s in an "unsubscription conversation"
NOTE: This diagram needs some design explanation and help! +------------------------------------------------------------------------------------------+ | Elements from dj Elements from cvsmsg | | +-------------------------------------------------------------+ | | | dj's roster items cvsmsg's roster items | | | +-------------------------------------------------------------+ | | | | | | | <item <item | | | | jid='cvsmsg@gnu.pipetree.com' jid='dj@gnu.pipetree.com' | | | | subscription='both'/> subscription='both'/> | | | | | |<presence | | | type='unsubscribe' | | | to='cvsmsg@gnu.pipetree.com'/> | | | | | | | <item <item | | | | jid='cvsmsg@gnu.pipetree.com' jid='dj@gnu.pipetree.com' | | | | subscription='both' subscription='both'/> | | | | ask='unsubscribe'/> | | | | | | | <presence | | | type='unsubscribed' | | | to='dj@gnu.pipetree.com'/>| | | | | | <item <item | | | | jid='cvsmsg@gnu.pipetree.com' jid='dj@gnu.pipetree.com' | | | | subscription='from'/> subscription='to'/> | | | | | | | <presence | | | type='unsubscribe' | | | to='dj@gnu.pipetree.com'/>| | | | | | <item <item | | | | jid='cvsmsg@gnu.pipetree.com' jid='dj@gnu.pipetree.com' | | | | subscription='from'/> subscription='to' | | | | ask='unsubscribe'/> | | | | | |<presence | | | type='unsubscribed' | | | to='cvsmsg@gnu.pipetree.com'/> | | | | | | | <item <item | | | | jid='cvsmsg@gnu.pipetree.com' jid='dj@gnu.pipetree.com' | | | | subscription='none'/> subscription='none'/> | | | | | | | +-------------------------------------------------------------+ | | | +------------------------------------------------------------------------------------------+
Accepted subscription or unsubscription
While we must take action on presence types subscribe and unsubscribe we don't really need to do anything for their acknowledgement counterparts. We can see these counterparts - subscribed and unsubscribed ("I have accepted your request and you are now (un)subscribed to my presence.")
Just for illustration purposes, we'll include a couple of conditions to let us know what's going on when the script runs:
elif type == 'subscribed':
print "we are now subscribed to %s" % (who)
elif type == 'unsubscribed':
print "we are now unsubscribed to %s" % (who)
Apart from the types of <presence/> element covering the presence subscription process, we should also expect the basic availability elements:
<presence>...</presence>
and
<presence type='unavailable'/>
Availability
It is an available <presence/> element on which the functionality of the script hinges.
elif type == 'available':
print "%s is available (%s/%s)" % (who, prs.getShow(), prs.getStatus())
if prs.getShow() != 'dnd' and who == cvsuser:
con.send(Jabber.Message(cvsuser, message, subject="CVS Watch Alarm"))
This presenceCB() subroutine is set up to handle <presence/> elements. In a typical execution scenario, where the script is subscribed to the presence of many potential CVS notification recipients, the subroutine is going to be called to handle the availability information of all those recipients that happen to be connected to Jabber at the moment of notification. We're only interested in the availability information of one particular recipient (who == cvsuser) as well as checking on the contents of the <show/> tag.
If we get a match, we can send the notification message by creating a Jabber.Message node that will look like this:
<message to='dj@gnu.pipetree.com'>
<subject>CVS Watch Alarm</subject>
<body>
testproject file4
---
Triggered edit watch on /usr/local/cvsroot/testproject
By piers
</body>
</message>As before, once created, the node can be sent with the con.send() method call.
Unavailability
Like the conditions for the presence subscription and unsubscription acknowledgements, we're including a final condition to deal with the case where a recipient disconnects from the Jabber server during the execution of our script: an unavailable <presence/> element will be sent:
elif type == 'unavailable':
print "%s is unavailable" % (who)
We're simply logging such an event for illustration purposes.
Most of the main part of the script is the same as the non-sensitive version from the section called CVS notification; reading in the notification message, preparing a connection to the Jabber server, and trying to connect.
for line in sys.stdin.readlines(): message = message + line
con = Jabber.Connection(host=Server)
try:
con.connect()
except XMLStream.error, e:
print "Couldn't connect: %s" % e
sys.exit(0)
con.auth(Username,Password,Resource)
While we've defined our presenceCB() subroutine to handle <presence/> packets, we haven't actually told the Jabber library about it. The call to the setPresenceHandler() method of the connection object does this for us, performing the "Register handler" step shown in Figure 7-5:
con.setPresenceHandler(presenceCB)
It's easy to guess what the next method call does:
con.requestRoster()
It makes a request for the roster by sending an IQ-get with a query qualified by the jabber:iq:roster namespace:
<iq type='get' id='3'> <query xmlns='jabber:iq:roster'/> </iq>
to which the server responds with an IQ-result:
<iq type='result' id='3'>
<query xmlns='jabber:iq:roster'>
<item jid='dj@gnu.pipetree.com' subscription='both'/>
<item jid='piers@jabber.org' subscription='both'/>
<item jid='shiels@jabber.org' subscription='both'/>
...
</query>
</iq>However, as there are no explicit references to the roster anywhere in the script, it's not as easy to guess why we request the roster in the first place. We know that our client-side copy is merely a "slave" copy, and even more relevant here, we know that subscription information in the roster <item/> tags is managed by the server—we as a client don't need to (in fact, shouldn't) do anything to maintain the subscription and ask attributes and keep them up to date.
So why do we request it?
Basically, it's because there's a fundamental difference between <presence/> elements used to convey availability information, and <presence/> elements used to convey presence subscription information. If John sends Jim availability information in a <presence/> element, whether directly (with a to attribute) or indirectly (through the distribution of that element by the server to Jim as a subscriber to John's presence), and Jim's offline, on holiday, it doesn't make much sense to store and forward it to him when he next connects:
[Jim connects to Jabber after being away for two weeks]
Jabber server: "Here's some availability information for John, dated 9 days ago."
Jim: "Who cares?"
<presence/> elements conveying availability information are not stored and forwarded if they can't be delivered because the intended recipient is offline. What would be the point?
However, <presence/> elements that convey subscription information are a different kettle of fish. While it's not important that I'm punted out of date availability information when I next connect to my Jabber client, any subscription (or unsubscription) requests or confirmations that were sent to me are important. So they need to be stored and forwarded.
As we've already seen, the presence subscription mechanism and rosters are inextricably linked. And if we look briefly under the covers, we see how this is so. When a presence subscription request is sent to a user, it runs the gauntlet of modules in the JSM (see the section called Component Connection Method in Chapter 4 for details on what these modules are). The roster-handling module mod_roster grabs this request, and, just in case the recipient turns out not to be connected, stores it.
And here's how intertwined the presence subscription mechanism and rosters really are: The request is stored as a cluster of attribute details within an <item/> tag in the roster belonging to the recipient of the presence subscription request. It looks like this:
<item jid='user@hostname' subscription='none' subscribe='' hidden=''/>
On receipt of a presence subscription request, the mod_roster module will create the roster item if it doesn't exist already, and then assign the attributes related to presence subscription—subscription='none' and subscribe=''—to it. There's no ask attribute, as this is only assigned to the item on the roster belonging to the sender, not the receiver, of the subscription request.
The subscribe attribute is used to store the reason for the request, that, if specified, is carried in the <status/> tag of the <presence/> element that conveys the request. If no reason is given, the value for the attribute is empty, as shown here. Otherwise it will contain what was stored in the <status/> tag. Example 7-7 shows a presence subscription request that carries a reason.
Example 7-7. A presence subscription request with a reason
<presence to='dj@gnu.pipetree.com'> <status>I'd like to keep my eye on you!</status> </presence>
The hidden attribute is used internally by mod_roster to mark the item as non-displayable; it effectively is a pseudo <item/>, that, when brought to life, actually turns out to be a <presence/> element. So when a request for the roster is made, mod_roster makes sure that it doesn't send these "hidden" items. The hidden attribute always has an empty value, as shown here.
After storing the subscription request, mod_roster will actually send the original <presence/> element that conveyed that request. If the recipient is online, and if the recipient has already made a request for their roster. As sending an availability presence packet:
<presence/>
is a kick to the mod_offline module to punt any messages stored offline in that user's absence, so requesting the roster:
<iq type='get'><query xmlns='jabber:iq:roster'/></iq>
is a kick to the mod_roster module to punt any subscription requests stored offline in that user's absence.
Ok. We've connected, authenticated, defined and registered our <presence/> callback, and kicked mod_roster. Now we need to announce our own availability in the form of a simple <presence/> element:
<presence/>
We can do this by calling the sendInitPresence() method on our connection object:
con.sendInitPresence()
This availability information will be distributed to all the entities that are subscribed to the script's presence and are online at that moment. It will also signify to the Jabber server that we are properly online—in which case it can forward to us any messages that had been stored up in our absence.
We're not really expecting any <message/> elements; indeed, we haven't set up any subroutine to handle them so they'd just be thrown away by the library anyway. The real reason for sending presence is so that the server will actively go and probe those in a presence subscription relationship with the script and report back on those who are available (who have themselves sent their presence during their current session). This causes <presence/> elements to arrive on the stream, which make their way to our presenceCB() handler.
Once eveything is set up, and the script has announced its presence, it really just needs to sit back and listen to the <presence/> elements that come in. If one of these is from our intended notification recipient, and the availability state is right (i.e., not in "Do Not Disturb" mode), bingo.
But the elements being sent over the stream from the server don't spontaneously get received, parsed, and dispatched; we can control when that happens from our script. This is the nub of the symbiosis between the element events and our procedural routines, and it's name is process().
Calling process() will check on the stream to see if any XML fragments have arrived and are waiting to be picked up. If there are any, steps 3 through 5, shown in Figure 7-5, are executed. The numeric value specified in the call to process() is the number of seconds to wait for incoming fragments if none are currently waiting to be picked up. Specifying no value (or zero) means that the method won't hang around if nothing has arrived. Specifying a value of 30 means that it will wait up to half a minute. We really want something in between, and it turns out that waiting for up to a second for fragments in a finite loop like this:
for i in range(5): con.process(1)
will allow for a slightly stuttered arrival of the <presence/> elements that are punted to the script as a result of the server-initiated probes.
We're just about done. The <presence/> elements that arrive and find their way to our callback are examined, and the CVS notification message is sent off if appropriate. Once the process() calls have finished, and, implicitly, the (potentially) multiple calls to presenceCB, there's nothing left to do. So we simply disconnect from the Jabber server, as before:
con.disconnect()
As that was probably a little disjointed, here's the presence-sensitive version of the CVS notification script in its entirety.
import Jabber, XMLStream
import sys
from string import split
cvsuser = sys.argv[1]
message = ''
def presenceCB(con, prs):
type = prs.getType()
parts = split(prs.getFrom(), '/')
who = parts[0]
if type == None: type = 'available'
# subscription request:
# - accept their subscription
# - send request for subscription to their presence
if type == 'subscribe':
print "subscribe request from %s" % (who)
con.send(Jabber.Presence(to=who, type='subscribed'))
con.send(Jabber.Presence(to=who, type='subscribe'))
# unsubscription request:
# - accept their unsubscription
# - send request for unsubscription to their presence
elif type == 'unsubscribe':
print "unsubscribe request from %s" % (who)
con.send(Jabber.Presence(to=who, type='unsubscribed'))
con.send(Jabber.Presence(to=who, type='unsubscribe'))
elif type == 'subscribed':
print "we are now subscribed to %s" % (who)
elif type == 'unsubscribed':
print "we are now unsubscribed to %s" % (who)
elif type == 'available':
print "%s is available (%s/%s)" % (who, prs.getShow(), prs.getStatus())
if prs.getShow() != 'dnd' and who == cvsuser:
con.send(Jabber.Message(cvsuser, message, subject="CVS Watch Alarm"))
elif type == 'unavailable':
print "%s is unavailable" % (who)
for line in sys.stdin.readlines(): message = message + line
con = Jabber.Connection(host=Server)
try:
con.connect()
except XMLStream.error, e:
print "Couldn't connect: %s" % e
sys.exit(0)
con.auth(Username,Password,Resource)
con.setPresenceHandler(presenceCB)
con.requestRoster()
con.sendInitPresence()
for i in range(5):
con.process(1)
con.disconnect()| [1] | The process of adding a JID to the roster and making a subscription request is an atomic action in many clients. It is generally assumed that adding a JID to your roster means that you're going to want to know when that entity is available, so the action of adding a JID to the roster will often generate a presence subscription request automatically. |
| [2] | This session ID is currently part of a new development within the Net::Jabber library and is currently not used for anything. |
| [3] | This is to reduce the possibility of JID spoofing. |