A Practical Guide To Xmpppy
A Practical Guide To Xmpppy
A Practical Guide To Xmpppy
Sebastian Moors
09.10.2006
Version 0.02b
http://xmpppy-guide.berlios.de/
Contents
1 Introduction 2
1.1 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2 What’s so cool about jabber ? . . . . . . . . . . . . . . . . . . . . 2
1.3 Why xmpppy ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.4 Existing documentation . . . . . . . . . . . . . . . . . . . . . . . 3
1.5 License . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.6 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2 Installation 4
3 Prerequisites 5
4 Basic concepts 6
4.1 Sending messages . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
4.1.1 Connecting to the server . . . . . . . . . . . . . . . . . . . 8
4.1.2 Messages and message types . . . . . . . . . . . . . . . . . 8
4.2 Receiving messages . . . . . . . . . . . . . . . . . . . . . . . . . . 9
4.3 Setting the resource . . . . . . . . . . . . . . . . . . . . . . . . . 10
4.4 Handling presence events . . . . . . . . . . . . . . . . . . . . . . 11
4.4.1 Simple presence handling . . . . . . . . . . . . . . . . . . 11
4.4.2 Retrieving the status . . . . . . . . . . . . . . . . . . . . . 13
4.5 Roster management . . . . . . . . . . . . . . . . . . . . . . . . . 13
4.6 Disconnect handling . . . . . . . . . . . . . . . . . . . . . . . . . 13
5 Advanced concepts 14
5.1 Groupchat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
5.2 Something about Knigge . . . . . . . . . . . . . . . . . . . . . . . 17
6 Resources 18
6.1 Websites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
6.2 Books . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
6.3 Projects using xmpppy . . . . . . . . . . . . . . . . . . . . . . . . 18
1
Chapter 1
Introduction
1.1 Motivation
This tutorial was started because there was a need for a small xmpppy-tutorial
fitting the gap between the small examples and the bare api specs. The small
examples distributed with it are fine, but when you’re building you’re own bot
and fiddling around with things like rostermanagement, you wish that there’s
something between the bare API-Specs and the small examples. So i decided
to write down my experiences and publish them..
This paper should help you to get started and covers the basic issues of pro-
gramming with xmpppy. If you want to programm a bot, you will find some
hints in the last chapters. I assume that you have already python knowledge,
python basics are not covered by this tutorial.
This tutorial was written for a linux audience. I don’t know if xmpppy works
on Windows or *nix, so you’ve got to solve os-dependend problems by yourself.
If you like to contribute to this document or found a bug feel free to contact
me.
Mail: [email protected]
2
1.3 Why xmpppy ?
I used xmpppy because it was available as a debian package and it’s small. The
design of xmpppy was exactly the thing i was looking for. There are high level
functions for sending messages, but you can also build your messages as xml-
strings if you wish to or if you need special features.
xmpppy is the inofficial successor of jabber.py, which i used before. The jab-
ber.py project is dead now, so i migrated to xmpppy, which inherited some code
from jabber.py and has a similar API.
If you’re interested in other libraries, have a look at http://www.jabber.org.
Spend some time on the jabber.org or ask the wikipedia. If you’re not new
to this things, skip this..
For the best available documentation on jabber in general you should take a
look at the RFCs. They’re easier to read than you might expect and contain a
lot of useful informations.
If you want to get in contact with the xmpppy developers or just want to
keep track of the current development, join the xmpppy-devel mailing list at
https://lists.sourceforge.net/lists/listinfo/xmpppy-devel.
1.5 License
This work is licensed under the creative commons license Attribution-NonCommercial
2.5. You can obtain it at http://creativecommons.org/licenses/by-nc/2.5/
1.6 Examples
All example scripts used in this tutorial can be obtained from the projects
homepage ( http://xmpppy-guide.berlios.de).
If you copy and paste code from the tutorial, remember that the line numbers
are not used in python and are only used for referencing.
3
Chapter 2
Installation
4
Chapter 3
Prerequisites
Before we start with coding, you should check some preconditions. An impor-
tant thing is the right jabber client. I would therefore recommend the use of
psi. Psi is a feature-rich jabber-only client. It supports service browsing and
it implements the most features as described in the RFC. Especially the group
chat support is better implemented than in the most other clients.
Of course you can use a mutliprotocol client like Gaim or kopete too, but they
implement some things on a different way.. For example gaim makes no differ-
ence between the multiple message types (chat, message..).
If you want to develop something with groupchat, you may want to setup your
own jabber server. This may be recommended if you’re new to xmpppy and you
don’t know exactly what you’re doing. Think about the possibility of disturb-
ing other people or - in the worst case - killing a server. If your bot gets out of
control and sends every 10ms a message to the server, the server admin might
be a little bit disgusted of your public beta testing. So keep in mind that there
are other people (and of course bots) out there while your bot uses a public
server.
If you’re completely new to jabber, you should read something about the under-
lying techniques such as XML-Streams. A good starting point is the xmpp-core
RFC.
5
Chapter 4
Basic concepts
6
4.1 Sending messages
And now for something completely different. Every tutorial on programming
starts with a tiny ”Hello World” program, so why break with this tradition.
Our program connects to a jabber server, authenticates itself with a user-
name/password combination and sends a ”Hello World!” message to a specified
jid. It doesn’t make much sense, but its a good start. Maybe you can use it in
shell scripts or something..
01 #!/usr/bin/python
02 import sys,os,xmpp
03
04 msg="Hello World!"
05 jid="[email protected]"
06 pwd="secret"
07
08 recipient="[email protected]"
09
10 jid=xmpp.protocol.JID(jid)
11
12 cl=xmpp.Client(jid.getDomain(),debug=[])
13
14 if cl.connect() == "":
15 print "not connected"
16 sys.exit(0)
17
18 if cl.auth(jid.getNode(),pwd) == None:
19 print "authentication failed"
20 sys.exit(0)
21
22
23 cl.send(xmpp.protocol.Message(recipient,msg))
24
25 cl.disconnect()
26
7
4.1.1 Connecting to the server
The first thing to do in every jabber session is to connect to your jabber server.
Line 11 shows you how to do this. xmpp.Client() returns a Client instance,
which is our basic object. You can think of the client-object as your connec-
tion to the server. If your server uses an unusual port, you can pass it to the
xmpp.Client constructor. Its signature is: xmpp.Client(server,port,debug).
The most work happens in Line 14 and 18. We’re connecting to the server
and trying to authenticate. That means the server just checks if our password
is correct. jid.getNode() returns everything before the ”@” in your jid.
You should check the return types of cl.connect() and cl.auth(). If you omit
these checks strange errors could appear. If the cl.connect() fails (maybe be-
cause the jabber server is offline) it returns an empty string. cl.auth() returns
”None”, for example if you provide a wrong password.
Line 23 finally does the magic: It sends a message (with content msg) to re-
cipient. After that, we should disconnect from the server to make a gracefull
exit.
8
4.2 Receiving messages
Receiving messages is a little bit more complicated than sending messages. You
need an event loop and an handler to do this.
Message handlers are a basic concept for acting on events. This means that you
have to tell the xmpp.Client Object which method it should call if a message
arrives. But first of all explanations, have a look at the code:
01 #!/usr/bin/python
02 import sys
03 import xmpp
04 import os
05 import signal
06 import time
07
08 def messageCB(conn,msg):
09 print "Sender: " + str(msg.getFrom())
10 print "Content: " + str(msg.getBody())
11 print msg
12
13
14 def StepOn(conn):
15 try:
16 conn.Process(1)
17 except KeyboardInterrupt:
18 return 0
19 return 1
20
21 def GoOn(conn):
22 while StepOn(conn):
23 pass
24
25 def main():
26
27 jid="[email protected]"
28 pwd="secret"
29
30 jid=xmpp.protocol.JID(jid)
31
32 cl = xmpp.Client(jid.getDomain(), debug=[])
33
34 if cl.connect() == "":
35 print "not connected"
36 sys.exit(0)
37
38 if cl.auth(jid.getNode(),pwd) == None:
39 print "authentication failed"
40 sys.exit(0)
9
41 bla
42 cl.RegisterHandler(’message’, messageCB)
43
44 #cl.sendInitPresence()
45
46 GoOn(cl)
47
48 main()
If this example doesn’t work for you, uncomment line 38. cl.sendInitPresence()
tells our server that we’re online. Some servers (for example Google’s gtalk
service) won’t send messages to you if you’re not marked as ’online’. A detailed
look on presence handling is given in the next chapter.
cl.auth(jid.getNode(),pwd,"laptop")
10
4.4 Handling presence events
4.4.1 Simple presence handling
Presence events are those messages which contain informations about your sta-
tus and subscription. You may have wondered why our bot from example 2
wasn’t shown as ”online” in your contact list. This was because we didn’t
notify the server that the bot is online. This could be done by ”sendInitPres-
ence()”. Go back to example 2 and uncomment the appropriate line. If the bot
is in your roster, he will be marked as ”online”.
11
36
37 if cl.connect() == "":
38 print "not connected"
39 sys.exit(0)
40
41 if cl.auth(jid.getNode(),pwd) == None:
42 print "authentication failed"
43 sys.exit(0)
44
45 cl.RegisterHandler(’presence’, presenceCB)
46 cl.sendInitPresence()
47
48 GoOn(cl)
49
50 main()
This is the most simple presence handler. When you receive a message con-
taining ”subscribe”, return a ”subscribed” answer and ask him for subscription.
That means subscribing everyone who asks. You can imagine that this is not
the right thing for real world applications. I prefer limits like a maximal roster
size and a policy to add users to the roster. This may differ for your bot..
Think about who should be able to use your bot and block everyone else.
12
4.4.2 Retrieving the status
Many applications need the status of an user. They want to know if he’s online
or offline or maybe only away. This is not as easy as it seems. There’s no direct
way to get the Status of a given jid. You have to analyse the presence messages
the oponnents send. If a user gets online or if you go online, everyone who has
subscribed to you will send a presence message. Of course this works only if
the user is online. If a user logs out, he sends you a presence message with
the Status ”Logged out”. Everytime he changes his status, you will receive a
corresponding status message. My workaround for the problem: keep track of
the actual status with a dictionary. Take the jid as the key and set their value
if you receive a presence message for the jid.
13
Chapter 5
Advanced concepts
14
5.1 Groupchat
I suppose most of you have experiences with many-to-many chats like IRC.
Jabber has its own many-to-many chat which is implement by two protocols:
groupchat 1.0 and multi user chat (MUC). The MUC protocol is based on
groupchat and allows a lot of advanced features like user privileges and passwort-
protected rooms. Because of the simple implementation groupchat will fo-
cused here. If you need MUC, have a look at http://www.jabber.org/jeps/jep-
0045.html.
Using groupchat 1.0 is very easy because it is based on presence messages. First
we have to think about what we want to do. Let’s imagine that we want to
join the room ”castle anthrax” with the nickname ”zoot”. The server is called
”conference.holy-gra.il”. To enter a room, the only thing to do is sending a
presence message with the room and your nickname to your conference server.
To speak in python:
room = "[email protected]/zoot"
cl.send(xmpp.Presence(to=room))
Of course it could happen that someone in this room has already chosen the
nickname ”zoot”. This will cause an error 409 (”Conflict”) and we have to try
another nickname.
If nobody named ”zoot” is in there, we’ll receive a presence message from ev-
erybody in that room (including yourself). The ”from” attribut of the message
looks like this: castle [email protected]/galahad, which means that
somebody named galahad is already in this room.This might be interesting for
you if you write a jabber client and you have to keep track of the nicks in the
room.
Receiving messages is divided in 2 parts. If someone sends a public message,
you’ll receive a message with the type ”groupchat”.This message will be sent to
every user in that room.A private message is send as a chat type message.
Sending message is as easy as receiving messages. Just send a groupchat mes-
sage to the room-jid or send a chat message to a room-member, if you like some
private chit-chat..
The following example is based on recv.py, the script used in chapter 2: re-
ceiving messages.
01 #!/usr/bin/python
02 import sys
03 import xmpp
04 import os
05 import signal
06 import time
07
08 def messageCB(conn,msg):
09 if msg.getType() == "groupchat":
10 print str(msg.getFrom()) +": "+ str(msg.getBody())
11 if msg.getType() == "chat":
12 print "private: " + str(msg.getFrom()) + ":" +str(msg.getBody())
15
13
14 def presenceCB(conn,msg):
15 print msg
16
17
18
19
20 def StepOn(conn):
21 try:
22 conn.Process(1)
23 except KeyboardInterrupt:
24 return 0
25 return 1
26
27 def GoOn(conn):
28 while StepOn(conn):
29 pass
30
31
32 def main():
33
34 jid="[email protected]"
35 pwd="secret"
36
37 jid=xmpp.protocol.JID(jid)
38
39 cl = xmpp.Client(jid.getDomain(), debug=[])
40
41 cl.connect()
42
43 cl.auth(jid.getNode(),pwd)
44
45
46 cl.sendInitPresence()
47
48 cl.RegisterHandler(’message’, messageCB)
49
50 room = "[email protected]/zoot"
51 print "Joining " + room
52
53 cl.send(xmpp.Presence(to=room))
54
55
56 GoOn(cl)
57
58 main()
16
5.2 Something about Knigge
If you don’t know Knigge, see http://en.wikipedia.org/wiki/Knigge.
His main work is a book called ”Ueber den Umgang mit Menschen” (”On Hu-
man Relations”).
As it appears clear that there are (social) rules for human relation, not every-
body knows that there a rules for bot communication too.
17
Chapter 6
Resources
6.1 Websites
xmpppy homepage: http://xmpppy.sourceforge.net
Jabber foundation: http://jabber.org
6.2 Books
Adams,DJ: Programming jabber http://www.oreilly.com/catalog/jabber/
18