]>
code.delx.au - pymsnt/blob - src/session.py
1 # Copyright 2004-2006 James Bunton <james@delx.cjb.net>
2 # Licensed for distribution under the GPL version 2, check COPYING for details
4 from twisted
. words
. protocols
. jabber
. jid
import internJID
14 from debug
import LogEvent
, INFO
, WARN
, ERROR
18 def makeSession ( pytrans
, jabberID
, ulang
):
19 """ Tries to create a session object for the corresponding JabberID. Retrieves information
20 from XDB to create the session. If it fails, then the user is most likely not registered with
22 LogEvent ( INFO
, jabberID
)
23 if pytrans
. sessions
. has_key ( jabberID
):
24 LogEvent ( INFO
, jabberID
, "Removing existing session." )
25 pytrans
. sessions
[ jabberID
]. removeMe ()
26 result
= pytrans
. registermanager
. getRegInfo ( jabberID
)
28 username
, password
= result
29 return Session ( pytrans
, jabberID
, username
, password
, ulang
)
35 class Session ( jabw
. JabberConnection
):
36 """ A class to represent each registered user's session with the legacy network. Exists as long as there
37 is a Jabber resource for the user available """
39 def __init__ ( self
, pytrans
, jabberID
, username
, password
, ulang
):
40 """ Initialises the session object and connects to the legacy network """
41 jabw
. JabberConnection
.__ init
__ ( self
, pytrans
, jabberID
)
42 LogEvent ( INFO
, jabberID
)
44 self
. pytrans
= pytrans
46 self
. ready
= False # Only ready when we're logged into the legacy service
47 self
. jabberID
= jabberID
# the JabberID of the Session's user
48 self
. username
= username
# the legacy network ID of the Session's user
49 self
. password
= password
57 self
. resourceList
= {}
60 self
. legacycon
= legacy
. LegacyConnection ( self
. username
, self
. password
, self
)
61 self
. contactList
= contact
. ContactList ( self
)
62 self
. contactList
. legacyList
= self
. legacycon
. legacyList
64 if config
. sessionGreeting
:
65 self
. sendMessage ( to
= self
. jabberID
, fro
= config
. jid
, body
= config
. sessionGreeting
)
67 self
. updateNickname ( "" )
69 LogEvent ( INFO
, self
. jabberID
, "Created!" )
72 """ Safely removes the session object, including sending <presence type="unavailable"/> messages for each legacy related item on the user's contact list """
73 # Send offline presence to Jabber ID
74 # Delete all objects cleanly
75 # Remove this Session object from the pytrans
77 LogEvent ( INFO
, self
. jabberID
)
83 # Send offline presence to the user
85 self
. sendPresence ( to
= self
. jabberID
, fro
= config
. jid
, ptype
= "unavailable" )
87 # Clean up stuff on the legacy service end (including sending offline presences for all contacts)
89 self
. legacycon
. removeMe ()
93 self
. contactList
. removeMe ()
94 self
. contactList
= None
96 # Remove any groupchats we may be in
97 for groupchat
in self
. groupchats
[:]:
101 # Remove us from the session list
102 del self
. pytrans
. sessions
[ self
. jabberID
]
103 # Clean up the no longer needed reference
106 LogEvent ( INFO
, self
. jabberID
, "Removed!" )
108 def doVCardUpdate ( self
):
109 def vCardReceived ( el
):
110 if not self
. alive
: return
111 LogEvent ( INFO
, self
. jabberID
)
113 for e
in el
. elements ():
114 if e
. name
== "vCard" and e
. uri
== disco
. VCARDTEMP
:
118 self
. legacycon
. updateAvatar () # Default avatar
122 for e
in vCard
. elements ():
123 if e
. name
== "NICKNAME" and e
.__ str
__ ():
125 if not name
and e
. name
== "FN" and e
.__ str
__ ():
126 # Give priority to nickname
128 if e
. name
== "PHOTO" :
129 imageData
= avatar
. parsePhotoEl ( e
)
131 errback () # Possibly it wasn't in a supported format?
132 self
. avatar
= self
. pytrans
. avatarCache
. setAvatar ( imageData
)
133 self
. legacycon
. updateAvatar ( self
. avatar
)
136 self
. updateNickname ( name
)
138 self
. legacycon
. updateAvatar () # Default avatar
140 def errback ( args
= None ):
141 LogEvent ( INFO
, self
. jabberID
, "Error fetching avatar." )
143 self
. legacycon
. updateAvatar ()
145 LogEvent ( INFO
, self
. jabberID
, "Fetching avatar." )
146 d
= self
. sendVCardRequest ( to
= self
. jabberID
, fro
= config
. jid
+ "/msn" )
147 d
. addCallback ( vCardReceived
)
148 d
. addErrback ( errback
)
150 def updateNickname ( self
, nickname
):
151 self
. nickname
= nickname
152 if not self
. nickname
:
153 j
= internJID ( self
. jabberID
)
154 self
. nickname
= j
. user
155 self
. setStatus ( self
. show
, self
. status
)
157 def setStatus ( self
, show
, status
):
160 self
. legacycon
. setStatus ( self
. nickname
, show
, status
)
162 def sendNotReadyError ( self
, source
, resource
, dest
, body
):
163 self
. sendErrorMessage ( source
+ '/' + resource
, dest
, "wait" , "not-allowed" , lang
. get ( self
. lang
). waitForLogin
, body
)
165 def findGroupchat ( self
, to
):
172 for groupchat
in self
. groupchats
:
173 if groupchat
. ID
== roomID
:
178 def nicknameReceived ( self
, source
, dest
, nickname
):
179 if dest
. find ( '@' ) > 0 : return # Ignore presence packets sent to users
181 self
. updateNickname ( nickname
)
183 def avatarHashReceived ( self
, source
, dest
, avatarHash
):
184 if dest
. find ( '@' ) > 0 : return # Ignore presence packets sent to users
186 if avatarHash
== " " : # Setting no avatar
187 self
. legacycon
. updateAvatar () # Default
188 elif ( not self
. avatar
) or ( self
. avatar
and self
. avatar
. getImageHash () != avatarHash
):
189 av
= self
. pytrans
. avatarCache
. getAvatar ( avatarHash
)
191 self
. avatar
= av
# Stuff in the cache is always PNG
192 self
. legacycon
. updateAvatar ( self
. avatar
)
196 def messageReceived ( self
, source
, resource
, dest
, destr
, mtype
, body
, noerror
):
197 if dest
== config
. jid
:
198 if body
. lower (). startswith ( "end" ):
199 LogEvent ( INFO
, self
. jabberID
, "Received 'end' request." )
204 self
. sendNotReadyError ( source
, resource
, dest
, body
)
207 # Sends the message to the legacy translator
208 groupchat
= self
. findGroupchat ( dest
)
210 # It's for a groupchat
211 if destr
and len ( destr
) > 0 and not noerror
:
212 self
. sendErrorMessage ( to
=( source
+ "/" + resource
), fro
= dest
, etype
= "cancel" , condition
= "not-allowed" , explanation
= lang
. get ( self
. lang
). groupchatPrivateError
, body
= body
)
214 LogEvent ( INFO
, self
. jabberID
, "Groupchat." )
215 groupchat
. sendMessage ( body
, noerror
)
217 LogEvent ( INFO
, self
. jabberID
, "Message." )
218 self
. legacycon
. sendMessage ( dest
, resource
, body
, noerror
)
220 def inviteReceived ( self
, source
, resource
, dest
, destr
, roomjid
):
222 self
. sendNotReadyError ( source
, resource
, dest
, roomjid
)
225 if not roomjid
. endswith ( '@' + config
. jid
): # Inviting a MSN user to a Jabber chatroom
226 message
= lang
. get ( self
. lang
). groupchatAdvocacy
% ( self
. jabberID
, config
. website
)
227 self
. legacycon
. sendMessage ( dest
, resource
, message
, True )
230 groupchat
= self
. findGroupchat ( roomjid
)
232 LogEvent ( INFO
, self
. jabberID
, "Groupchat invitation." )
233 groupchat
. sendContactInvite ( dest
)
235 def typingNotificationReceived ( self
, dest
, resource
, composing
):
236 """ The user has sent typing notification to a contact on the legacy service """
237 self
. legacycon
. userTypingNotification ( dest
, resource
, composing
)
239 def presenceReceived ( self
, source
, resource
, to
, tor
, priority
, ptype
, show
, status
):
240 # Checks resources and priorities so that the highest priority resource always appears as the
241 # legacy services status. If there are no more resources then the session is deleted
242 # Additionally checks if the presence is to a groupchat room
243 groupchat
= self
. findGroupchat ( to
)
245 # It's for an existing groupchat
246 if ptype
== "unavailable" :
248 LogEvent ( INFO
, self
. jabberID
, "Killing groupchat." )
251 if source
== self
. jabberID
:
252 LogEvent ( INFO
, self
. jabberID
, "Groupchat presence." )
256 groupchat
. userJoined ( tor
)
258 LogEvent ( INFO
, self
. jabberID
, "Sending groupchat error presence." )
259 self
. sendPresence ( to
=( source
+ "/" + resource
), fro
= to
, ptype
= "error" )
261 elif legacy
. isGroupJID ( to
) and to
!= config
. jid
and not ptype
:
262 # Its to a groupchat JID, and the presence type is available
264 self
. sendNotReadyError ( source
, resource
, to
, to
)
267 # It's a new groupchat
268 gcID
= to
[: to
. find ( '@' )] # Grab the room name
269 LogEvent ( INFO
, self
. jabberID
, "Creating a new groupchat." )
270 groupchat
= legacy
. LegacyGroupchat ( self
, resource
, gcID
) # Creates an empty groupchat
271 groupchat
. userJoined ( tor
)
273 elif ptype
== "probe" :
274 LogEvent ( INFO
, self
. jabberID
, "Responding to presence probe" )
276 self
. legacycon
. sendShowStatus ( source
)
278 self
. contactList
. getContact ( to
). sendPresence ( source
)
281 self
. handleResourcePresence ( source
, resource
, to
, tor
, priority
, ptype
, show
, status
)
284 def handleResourcePresence ( self
, source
, resource
, to
, tor
, priority
, ptype
, show
, status
):
285 if ptype
and ptype
!= "unavailable" : return # Ignore presence errors, probes, etc
286 if to
. find ( '@' ) > 0 : return # Ignore presence packets sent to users
288 existing
= self
. resourceList
. has_key ( resource
)
289 if ptype
== "unavailable" :
291 LogEvent ( INFO
, self
. jabberID
, "Resource gone offline." )
292 self
. resourceOffline ( resource
)
294 return # I don't know the resource, and they're leaving, so it's all good
297 LogEvent ( INFO
, self
. jabberID
, "Resource came online." )
298 self
. contactList
. resendLists ( source
+ "/" + resource
)
299 LogEvent ( INFO
, self
. jabberID
, "Setting status." )
300 self
. resourceList
[ resource
] = SessionResource ( show
, status
, priority
)
302 highestActive
= self
. highestResource ()
305 # If we're the highest active resource, we should update the legacy service
306 LogEvent ( INFO
, self
. jabberID
, "Updating status on legacy service." )
307 r
= self
. resourceList
[ highestActive
]
308 self
. setStatus ( r
. show
, r
. status
)
310 LogEvent ( INFO
, self
. jabberID
, "Last resource died. Calling removeMe in 0 seconds." )
311 #reactor.callLater(0, self.removeMe)
313 #FIXME Which of the above?
315 def highestResource ( self
):
316 """ Returns the highest priority resource """
318 for checkR
in self
. resourceList
. keys ():
319 if highestActive
== None or self
. resourceList
[ checkR
]. priority
> self
. resourceList
[ highestActive
]. priority
:
320 highestActive
= checkR
323 # debug.log("Session %s - highest active resource is \"%s\" at %d" % (self.jabberID, highestActive, self.resourceList[highestActive].priority))
328 def resourceOffline ( self
, resource
):
329 del self
. resourceList
[ resource
]
330 self
. legacycon
. resourceOffline ( resource
)
332 def subscriptionReceived ( self
, fro
, to
, subtype
):
333 """ Sends the subscription request to the legacy services handler """
336 LogEvent ( INFO
, self
. jabberID
, "Passing subscription to legacy service." )
337 self
. contactList
. jabberSubscriptionReceived ( to
, subtype
)
339 self
. sendPresence ( fro
, to
, ptype
= "error" )
341 if subtype
== "subscribe" :
342 self
. sendPresence ( to
= self
. jabberID
, fro
= config
. jid
, ptype
= "subscribed" )
343 elif subtype
. startswith ( "unsubscribe" ):
344 # They want to unregister.
346 LogEvent ( INFO
, jid
, "About to unregister." )
347 self
. pytrans
. registermanager
. removeRegInfo ( jid
)
348 LogEvent ( INFO
, jid
, "Just unregistered." )
356 class SessionResource
:
357 """ A convienence class to allow comparisons of Jabber resources """
358 def __init__ ( self
, show
= None , status
= None , priority
= None ):
363 self
. priority
= int ( priority
)
364 except TypeError : pass
365 except ValueError : pass