]>
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 if(utils
.checkTwisted()):
6 from twisted
.xish
.domish
import Element
7 from twisted
.words
.protocols
.jabber
import jid
9 from tlib
.domish
import Element
10 from tlib
.jabber
import jid
11 from debug
import LogEvent
, INFO
, WARN
, ERROR
15 def sendMessage(pytrans
, to
, fro
, body
, mtype
=None, delay
=None):
16 """ Sends a Jabber message """
18 el
= Element((None, "message"))
19 el
.attributes
["to"] = to
20 el
.attributes
["from"] = fro
21 el
.attributes
["id"] = pytrans
.makeMessageID()
23 el
.attributes
["type"] = mtype
26 x
= el
.addElement("x")
27 x
.attributes
["xmlns"] = disco
.XDELAY
28 x
.attributes
["from"] = fro
29 x
.attributes
["stamp"] = delay
31 b
= el
.addElement("body")
33 x
= el
.addElement("x")
34 x
.attributes
["xmlns"] = disco
.XEVENT
35 composing
= x
.addElement("composing")
38 def sendPresence(pytrans
, to
, fro
, show
=None, status
=None, priority
=None, ptype
=None, avatarHash
=None, nickname
=None, payload
=[]):
39 # Strip the resource off any presence subscribes (as per XMPP RFC 3921 Section 5.1.6)
40 # Makes eJabberd behave :)
41 if(ptype
== "subscribe"):
42 (user
,host
,res
) = jid
.parse(to
)
43 to
= "%s@%s" % (user
, host
)
45 el
= Element((None, "presence"))
46 el
.attributes
["to"] = to
47 el
.attributes
["from"] = fro
49 el
.attributes
["type"] = ptype
51 s
= el
.addElement("show")
54 s
= el
.addElement("status")
57 s
= el
.addElement("priority")
58 s
.addContent(priority
)
61 x
= el
.addElement("x")
62 x
.attributes
["xmlns"] = disco
.XVCARDUPDATE
64 xx
= el
.addElement("x")
65 xx
.attributes
["xmlns"] = disco
.XAVATAR
66 h
= xx
.addElement("hash")
67 h
.addContent(avatarHash
)
68 h
= x
.addElement("photo")
69 h
.addContent(avatarHash
)
71 n
= x
.addElement("nickname")
72 n
.addContent(nickname
)
81 def sendErrorMessage(pytrans
, to
, fro
, etype
, condition
, explanation
, body
=None):
82 el
= Element((None, "message"))
83 el
.attributes
["to"] = to
84 el
.attributes
["from"] = fro
85 el
.attributes
["type"] = "error"
86 error
= el
.addElement("error")
87 error
.attributes
["type"] = etype
88 error
.attributes
["code"] = str(utils
.errorCodeMap
[condition
])
89 desc
= error
.addElement(condition
)
90 desc
.attributes
["xmlns"] = "urn:ietf:params:xml:ns:xmpp-stanzas"
91 text
= error
.addElement("text")
92 text
.attributes
["xmlns"] = "urn:ietf:params:xml:ns:xmpp-stanzas"
93 text
.addContent(explanation
)
94 if(body
and len(body
) > 0):
95 b
= el
.addElement("body")
102 class JabberConnection
:
103 """ A class to handle a Jabber "Connection", ie, the Jabber side of the gateway.
104 If you want to send a Jabber event, this is the place, and this is where incoming
105 Jabber events for a session come to. """
107 def __init__(self
, pytrans
, jabberID
):
108 self
.pytrans
= pytrans
109 self
.jabberID
= jabberID
111 self
.typingUser
= False # Whether this user can accept typing notifications
112 self
.messageIDs
= dict() # The ID of the last message the user sent to a particular contact. Indexed by contact JID
114 LogEvent(INFO
, self
.jabberID
)
117 """ Cleanly deletes the object """
118 LogEvent(INFO
, self
.jabberID
)
120 def sendMessage(self
, to
, fro
, body
, mtype
=None, delay
=None):
121 """ Sends a Jabber message
122 For this message to have a <x xmlns="jabber:x:delay"/> you must pass a correctly formatted timestamp (See JEP0091)
124 LogEvent(INFO
, self
.jabberID
)
125 sendMessage(self
.pytrans
, to
, fro
, body
, mtype
, delay
)
127 def sendTypingNotification(self
, to
, fro
, typing
):
128 """ Sends the user the contact's current typing notification status """
130 LogEvent(INFO
, self
.jabberID
)
131 el
= Element((None, "message"))
132 el
.attributes
["to"] = to
133 el
.attributes
["from"] = fro
134 x
= el
.addElement("x")
135 x
.attributes
["xmlns"] = disco
.XEVENT
137 composing
= x
.addElement("composing")
138 id = x
.addElement("id")
139 if(self
.messageIDs
.has_key(fro
) and self
.messageIDs
[fro
]):
140 id.addContent(self
.messageIDs
[fro
])
141 self
.pytrans
.send(el
)
143 def sendVCardRequest(self
, to
, fro
):
144 """ Requests the the vCard of 'to'
145 Returns a Deferred which fires when the vCard has been received.
146 First argument an Element object of the vCard
148 el
= Element((None, "iq"))
149 el
.attributes
["to"] = to
150 el
.attributes
["from"] = fro
151 el
.attributes
["type"] = "get"
152 el
.attributes
["id"] = self
.pytrans
.makeMessageID()
153 vCard
= el
.addElement("vCard")
154 vCard
.attributes
["xmlns"] = "vcard-temp"
155 return self
.pytrans
.discovery
.sendIq(el
)
157 def sendErrorMessage(self
, to
, fro
, etype
, condition
, explanation
, body
=None):
158 LogEvent(INFO
, self
.jabberID
)
159 sendErrorMessage(self
.pytrans
, to
, fro
, etype
, condition
, explanation
, body
)
161 def sendPresence(self
, to
, fro
, show
=None, status
=None, priority
=None, ptype
=None, avatarHash
=None, nickname
=None, payload
=[]):
162 """ Sends a Jabber presence packet """
163 LogEvent(INFO
, self
.jabberID
)
164 sendPresence(self
.pytrans
, to
, fro
, show
, status
, priority
, ptype
, avatarHash
, nickname
, payload
)
166 def sendRosterImport(self
, jid
, ptype
, sub
, name
="", groups
=[]):
167 """ Sends a special presence packet. This will work with all clients, but clients that support roster-import will give a better user experience
168 IMPORTANT - Only ever use this for contacts that have already been authorised on the legacy service """
169 el
= Element((None, "presence"))
170 el
.attributes
["to"] = self
.jabberID
171 el
.attributes
["from"] = jid
172 el
.attributes
["type"] = ptype
173 r
= el
.addElement("x")
174 r
.attributes
["xmlns"] = disco
.SUBSYNC
175 item
= r
.addElement("item")
176 item
.attributes
["subscription"] = sub
178 item
.attributes
["name"] = unicode(name
)
180 g
= item
.addElement("group")
183 self
.pytrans
.send(el
)
185 def onMessage(self
, el
):
186 """ Handles incoming message packets """
187 #LogEvent(INFO, self.jabberID)
188 fro
= el
.getAttribute("from")
189 to
= el
.getAttribute("to")
194 LogEvent(WARN
, self
.jabberID
)
197 mID
= el
.getAttribute("id")
198 mtype
= el
.getAttribute("type")
205 for child
in el
.elements():
206 if(child
.name
== "body"):
207 body
= child
.__str
__()
208 elif(child
.name
== "noerror" and child
.uri
== "sapo:noerror"):
210 elif(child
.name
== "x"):
211 if(child
.uri
== disco
.XCONFERENCE
):
213 inviteRoom
= child
.getAttribute("jid") # The room the contact is being invited to
214 elif(child
.uri
== disco
.MUC_USER
):
215 for child2
in child
.elements():
216 if(child2
.name
== "invite"):
217 inviteTo
= child2
.getAttribute("to")
220 elif(child
.uri
== disco
.XEVENT
):
223 for child2
in child
.elements():
224 if(child2
.name
== "composing"):
228 if(inviteTo
and inviteRoom
):
229 LogEvent(INFO
, self
.jabberID
, "Message groupchat invite packet")
230 self
.inviteReceived(source
=froj
.userhost(), resource
=froj
.resource
, dest
=inviteTo
, destr
="", roomjid
=inviteRoom
)
233 # Check message event stuff
234 if(body
and messageEvent
):
235 self
.typingUser
= True
236 elif(body
and not messageEvent
):
237 self
.typingUser
= False
238 elif(not body
and messageEvent
):
239 LogEvent(INFO
, self
.jabberID
, "Message typing notification packet")
240 self
.typingNotificationReceived(toj
.userhost(), toj
.resource
, composing
)
244 # Save the message ID for later
245 self
.messageIDs
[to
] = mID
246 LogEvent(INFO
, self
.jabberID
, "Message packet")
247 self
.messageReceived(froj
.userhost(), froj
.resource
, toj
.userhost(), toj
.resource
, mtype
, body
, noerror
)
249 def onPresence(self
, el
):
250 """ Handles incoming presence packets """
251 #LogEvent(INFO, self.jabberID)
252 fro
= el
.getAttribute("from")
254 to
= el
.getAttribute("to")
257 # Grab the contents of the <presence/> packet
258 ptype
= el
.getAttribute("type")
259 if ptype
and (ptype
.startswith("subscribe") or ptype
.startswith("unsubscribe")):
260 LogEvent(INFO
, self
.jabberID
, "Parsed subscription presence packet")
261 self
.subscriptionReceived(toj
.userhost(), ptype
)
268 for child
in el
.elements():
269 if(child
.name
== "status"):
270 status
= child
.__str
__()
271 elif(child
.name
== "show"):
272 show
= child
.__str
__()
273 elif(child
.name
== "priority"):
274 priority
= child
.__str
__()
275 elif(child
.defaultUri
== disco
.XVCARDUPDATE
):
277 for child2
in child
.elements():
278 if(child2
.name
== "photo"):
279 avatarHash
= child2
.__str__()
280 elif(child2
.name
== "nickname"):
281 nickname
= child2
.__str__()
286 self
.avatarHashReceived(froj
.userhost(), toj
.userhost(), avatarHash
)
288 self
.nicknameReceived(froj
.userhost(), toj
.userhost(), nickname
)
290 LogEvent(INFO
, self
.jabberID
, "Parsed presence packet")
291 self
.presenceReceived(froj
.userhost(), froj
.resource
, toj
.userhost(), toj
.resource
, priority
, ptype
, show
, status
)
295 def messageReceived(self
, source
, resource
, dest
, destr
, mtype
, body
, noerror
):
296 """ Override this method to be notified when a message is received """
299 def inviteReceived(self
, source
, resource
, dest
, destr
, roomjid
):
300 """ Override this method to be notified when an invitation is received """
303 def presenceReceived(self
, source
, resource
, to
, tor
, priority
, ptype
, show
, status
):
304 """ Override this method to be notified when presence is received """
307 def subscriptionReceived(self
, source
, subtype
):
308 """ Override this method to be notified when a subscription packet is received """
311 def nicknameReceived(self
, source
, dest
, nickname
):
312 """ Override this method to be notified when a nickname has been received """
315 def avatarHashReceieved(self
, source
, dest
, avatarHash
):
316 """ Override this method to be notified when an avatar hash is received """