]>
code.delx.au - pymsnt/blob - src/jabw.py
1 # Copyright 2004-2005 James Bunton <james@delx.cjb.net>
2 # Licensed for distribution under the GPL version 2, check COPYING for details
5 from twisted
.words
.xish
.domish
import Element
6 from twisted
.words
.protocols
.jabber
.jid
import internJID
7 from debug
import LogEvent
, INFO
, WARN
, ERROR
11 def sendMessage(pytrans
, to
, fro
, body
, mtype
=None, delay
=None):
12 """ Sends a Jabber message """
14 el
= Element((None, "message"))
15 el
.attributes
["to"] = to
16 el
.attributes
["from"] = fro
17 el
.attributes
["id"] = pytrans
.makeMessageID()
19 el
.attributes
["type"] = mtype
22 x
= el
.addElement("x")
23 x
.attributes
["xmlns"] = disco
.XDELAY
24 x
.attributes
["from"] = fro
25 x
.attributes
["stamp"] = delay
27 b
= el
.addElement("body")
29 x
= el
.addElement("x")
30 x
.attributes
["xmlns"] = disco
.XEVENT
31 composing
= x
.addElement("composing")
34 def sendPresence(pytrans
, to
, fro
, show
=None, status
=None, priority
=None, ptype
=None, avatarHash
=None, nickname
=None, payload
=[]):
35 # Strip the resource off any presence subscribes (as per XMPP RFC 3921 Section 5.1.6)
36 # Makes eJabberd behave :)
37 if ptype
in ("subscribe", "subscribed", "unsubscribe", "unsubscribed"):
38 to
= internJID(to
).userhost()
39 fro
= internJID(fro
).userhost()
41 el
= Element((None, "presence"))
42 el
.attributes
["to"] = to
43 el
.attributes
["from"] = fro
45 el
.attributes
["type"] = ptype
47 s
= el
.addElement("show")
50 s
= el
.addElement("status")
53 s
= el
.addElement("priority")
54 s
.addContent(priority
)
57 x
= el
.addElement("x")
58 x
.attributes
["xmlns"] = disco
.XVCARDUPDATE
60 xx
= el
.addElement("x")
61 xx
.attributes
["xmlns"] = disco
.XAVATAR
62 h
= xx
.addElement("hash")
63 h
.addContent(avatarHash
)
64 h
= x
.addElement("photo")
65 h
.addContent(avatarHash
)
67 n
= x
.addElement("nickname")
68 n
.addContent(nickname
)
77 def sendErrorMessage(pytrans
, to
, fro
, etype
, condition
, explanation
, body
=None):
78 el
= Element((None, "message"))
79 el
.attributes
["to"] = to
80 el
.attributes
["from"] = fro
81 el
.attributes
["type"] = "error"
82 error
= el
.addElement("error")
83 error
.attributes
["type"] = etype
84 error
.attributes
["code"] = str(utils
.errorCodeMap
[condition
])
85 desc
= error
.addElement(condition
)
86 desc
.attributes
["xmlns"] = disco
.XMPP_STANZAS
87 text
= error
.addElement("text")
88 text
.attributes
["xmlns"] = disco
.XMPP_STANZAS
89 text
.addContent(explanation
)
90 if(body
and len(body
) > 0):
91 b
= el
.addElement("body")
98 class JabberConnection
:
99 """ A class to handle a Jabber "Connection", ie, the Jabber side of the gateway.
100 If you want to send a Jabber event, this is the place, and this is where incoming
101 Jabber events for a session come to. """
103 def __init__(self
, pytrans
, jabberID
):
104 self
.pytrans
= pytrans
105 self
.jabberID
= jabberID
107 self
.typingUser
= False # Whether this user can accept typing notifications
108 self
.messageIDs
= dict() # The ID of the last message the user sent to a particular contact. Indexed by contact JID
110 LogEvent(INFO
, self
.jabberID
)
113 """ Cleanly deletes the object """
114 LogEvent(INFO
, self
.jabberID
)
116 def sendMessage(self
, to
, fro
, body
, mtype
=None, delay
=None):
117 """ Sends a Jabber message
118 For this message to have a <x xmlns="jabber:x:delay"/> you must pass a correctly formatted timestamp (See JEP0091)
120 LogEvent(INFO
, self
.jabberID
)
121 sendMessage(self
.pytrans
, to
, fro
, body
, mtype
, delay
)
123 def sendTypingNotification(self
, to
, fro
, typing
):
124 """ Sends the user the contact's current typing notification status """
126 LogEvent(INFO
, self
.jabberID
)
127 el
= Element((None, "message"))
128 el
.attributes
["to"] = to
129 el
.attributes
["from"] = fro
130 x
= el
.addElement("x")
131 x
.attributes
["xmlns"] = disco
.XEVENT
133 composing
= x
.addElement("composing")
134 id = x
.addElement("id")
135 if(self
.messageIDs
.has_key(fro
) and self
.messageIDs
[fro
]):
136 id.addContent(self
.messageIDs
[fro
])
137 self
.pytrans
.send(el
)
139 def sendVCardRequest(self
, to
, fro
):
140 """ Requests the the vCard of 'to'
141 Returns a Deferred which fires when the vCard has been received.
142 First argument an Element object of the vCard
144 el
= Element((None, "iq"))
145 el
.attributes
["to"] = to
146 el
.attributes
["from"] = fro
147 el
.attributes
["type"] = "get"
148 el
.attributes
["id"] = self
.pytrans
.makeMessageID()
149 vCard
= el
.addElement("vCard")
150 vCard
.attributes
["xmlns"] = "vcard-temp"
151 return self
.pytrans
.discovery
.sendIq(el
)
153 def sendErrorMessage(self
, to
, fro
, etype
, condition
, explanation
, body
=None):
154 LogEvent(INFO
, self
.jabberID
)
155 sendErrorMessage(self
.pytrans
, to
, fro
, etype
, condition
, explanation
, body
)
157 def sendPresence(self
, to
, fro
, show
=None, status
=None, priority
=None, ptype
=None, avatarHash
=None, nickname
=None, payload
=[]):
158 """ Sends a Jabber presence packet """
159 LogEvent(INFO
, self
.jabberID
)
160 sendPresence(self
.pytrans
, to
, fro
, show
, status
, priority
, ptype
, avatarHash
, nickname
, payload
)
162 def sendRosterImport(self
, jid
, ptype
, sub
, name
="", groups
=[]):
163 """ Sends a special presence packet. This will work with all clients, but clients that support roster-import will give a better user experience
164 IMPORTANT - Only ever use this for contacts that have already been authorised on the legacy service """
165 x
= Element((None, "x"))
166 x
.attributes
["xmlns"] = disco
.SUBSYNC
167 item
= x
.addElement("item")
168 item
.attributes
["subscription"] = sub
170 item
.attributes
["name"] = unicode(name
)
172 g
= item
.addElement("group")
175 self
.sendPresence(to
=self
.jabberID
, fro
=jid
, ptype
=ptype
, payload
=[x
])
177 def onMessage(self
, el
):
178 """ Handles incoming message packets """
179 #LogEvent(INFO, self.jabberID)
180 fro
= el
.getAttribute("from")
181 to
= el
.getAttribute("to")
183 froj
= internJID(fro
)
186 LogEvent(WARN
, self
.jabberID
)
189 mID
= el
.getAttribute("id")
190 mtype
= el
.getAttribute("type")
197 for child
in el
.elements():
198 if(child
.name
== "body"):
199 body
= child
.__str
__()
200 elif(child
.name
== "noerror" and child
.uri
== "sapo:noerror"):
202 elif(child
.name
== "x"):
203 if(child
.uri
== disco
.XCONFERENCE
):
205 inviteRoom
= child
.getAttribute("jid") # The room the contact is being invited to
206 elif(child
.uri
== disco
.MUC_USER
):
207 for child2
in child
.elements():
208 if(child2
.name
== "invite"):
209 inviteTo
= child2
.getAttribute("to")
212 elif(child
.uri
== disco
.XEVENT
):
215 for child2
in child
.elements():
216 if(child2
.name
== "composing"):
220 if(inviteTo
and inviteRoom
):
221 LogEvent(INFO
, self
.jabberID
, "Message groupchat invite packet")
222 self
.inviteReceived(source
=froj
.userhost(), resource
=froj
.resource
, dest
=inviteTo
, destr
="", roomjid
=inviteRoom
)
225 # Check message event stuff
226 if(body
and messageEvent
):
227 self
.typingUser
= True
228 elif(body
and not messageEvent
):
229 self
.typingUser
= False
230 elif(not body
and messageEvent
):
231 LogEvent(INFO
, self
.jabberID
, "Message typing notification packet")
232 self
.typingNotificationReceived(toj
.userhost(), toj
.resource
, composing
)
236 # Save the message ID for later
237 self
.messageIDs
[to
] = mID
238 LogEvent(INFO
, self
.jabberID
, "Message packet")
239 self
.messageReceived(froj
.userhost(), froj
.resource
, toj
.userhost(), toj
.resource
, mtype
, body
, noerror
)
241 def onPresence(self
, el
):
242 """ Handles incoming presence packets """
243 #LogEvent(INFO, self.jabberID)
244 fro
= el
.getAttribute("from")
245 froj
= internJID(fro
)
246 to
= el
.getAttribute("to")
249 # Grab the contents of the <presence/> packet
250 ptype
= el
.getAttribute("type")
251 if ptype
and (ptype
.startswith("subscribe") or ptype
.startswith("unsubscribe")):
252 LogEvent(INFO
, self
.jabberID
, "Parsed subscription presence packet")
253 self
.subscriptionReceived(fro
, toj
.userhost(), ptype
)
260 for child
in el
.elements():
261 if(child
.name
== "status"):
262 status
= child
.__str
__()
263 elif(child
.name
== "show"):
264 show
= child
.__str
__()
265 elif(child
.name
== "priority"):
266 priority
= child
.__str
__()
267 elif(child
.uri
== disco
.XVCARDUPDATE
):
269 for child2
in child
.elements():
270 if(child2
.name
== "photo"):
271 avatarHash
= child2
.__str__()
272 elif(child2
.name
== "nickname"):
273 nickname
= child2
.__str__()
278 self
.avatarHashReceived(froj
.userhost(), toj
.userhost(), avatarHash
)
280 self
.nicknameReceived(froj
.userhost(), toj
.userhost(), nickname
)
282 LogEvent(INFO
, self
.jabberID
, "Parsed presence packet")
283 self
.presenceReceived(froj
.userhost(), froj
.resource
, toj
.userhost(), toj
.resource
, priority
, ptype
, show
, status
)
287 def messageReceived(self
, source
, resource
, dest
, destr
, mtype
, body
, noerror
):
288 """ Override this method to be notified when a message is received """
291 def inviteReceived(self
, source
, resource
, dest
, destr
, roomjid
):
292 """ Override this method to be notified when an invitation is received """
295 def presenceReceived(self
, source
, resource
, to
, tor
, priority
, ptype
, show
, status
):
296 """ Override this method to be notified when presence is received """
299 def subscriptionReceived(self
, source
, dest
, subtype
):
300 """ Override this method to be notified when a subscription packet is received """
303 def nicknameReceived(self
, source
, dest
, nickname
):
304 """ Override this method to be notified when a nickname has been received """
307 def avatarHashReceieved(self
, source
, dest
, avatarHash
):
308 """ Override this method to be notified when an avatar hash is received """