]>
code.delx.au - pymsnt/blob - src/session.py
1 # Copyright 2004-2005 James Bunton <james@delx.cjb.net>
2 # Licensed for distribution under the GPL version 2, check COPYING for details
11 from debug
import LogEvent
, INFO
, WARN
, ERROR
12 if utils
. checkTwisted ():
13 from twisted
. words
. protocols
. jabber
import jid
15 from tlib
. jabber
import jid
19 def makeSession ( pytrans
, jabberID
, ulang
):
20 """ Tries to create a session object for the corresponding JabberID. Retrieves information
21 from XDB to create the session. If it fails, then the user is most likely not registered with
23 LogEvent ( INFO
, jabberID
)
24 if pytrans
. sessions
. has_key ( jabberID
):
25 LogEvent ( INFO
, jabberID
, "Removing existing session." )
26 pytrans
. sessions
[ jabberID
]. removeMe ()
27 result
= pytrans
. registermanager
. getRegInfo ( jabberID
)
29 username
, password
= result
30 return Session ( pytrans
, jabberID
, username
, password
, ulang
)
36 class Session ( jabw
. JabberConnection
):
37 """ A class to represent each registered user's session with the legacy network. Exists as long as there
38 is a Jabber resource for the user available """
40 def __init__ ( self
, pytrans
, jabberID
, username
, password
, ulang
):
41 """ Initialises the session object and connects to the legacy network """
42 jabw
. JabberConnection
.__ init
__ ( self
, pytrans
, jabberID
)
43 LogEvent ( INFO
, jabberID
)
45 self
. pytrans
= pytrans
47 self
. ready
= False # Only ready when we're logged into the legacy service
48 self
. jabberID
= jabberID
# the JabberID of the Session's user
49 self
. username
= username
# the legacy network ID of the Session's user
50 self
. password
= password
58 self
. resourceList
= {}
61 self
. legacycon
= legacy
. LegacyConnection ( self
. username
, self
. password
, self
)
62 self
. contactList
= contact
. ContactList ( self
)
63 self
. contactList
. legacyList
= self
. legacycon
. legacyList
65 if config
. sessionGreeting
:
66 self
. sendMessage ( to
= self
. jabberID
, fro
= config
. jid
, body
= config
. sessionGreeting
)
68 self
. updateNickname ( "" )
70 LogEvent ( INFO
, self
. jabberID
, "Created!" )
73 """ Safely removes the session object, including sending <presence type="unavailable"/> messages for each legacy related item on the user's contact list """
74 # Send offline presence to Jabber ID
75 # Delete all objects cleanly
76 # Remove this Session object from the pytrans
78 LogEvent ( INFO
, self
. jabberID
)
84 # Send offline presence to the user
86 self
. sendPresence ( to
= self
. jabberID
, fro
= config
. jid
, ptype
= "unavailable" )
88 # Clean up stuff on the legacy service end (including sending offline presences for all contacts)
90 self
. legacycon
. removeMe ()
94 self
. contactList
. removeMe ()
95 self
. contactList
= None
97 # Remove any groupchats we may be in
98 for groupchat
in self
. groupchats
[:]:
102 # Remove us from the session list
103 del self
. pytrans
. sessions
[ self
. jabberID
]
104 # Clean up the no longer needed reference
107 LogEvent ( INFO
, self
. jabberID
, "Removed!" )
108 utils
. mutilateMe ( self
)
110 def doVCardUpdate ( self
):
111 def vCardReceived ( el
):
112 if not self
. alive
: return
113 LogEvent ( INFO
, self
. jabberID
)
115 for e
in el
. elements ():
116 if e
. name
== "vCard" and e
. defaultUri
== disco
. VCARDTEMP
:
120 self
. legacycon
. updateAvatar () # Default avatar
123 for e
in vCard
. elements ():
124 if e
. name
== "NICKNAME" :
125 self
. updateNickname ( e
.__ str
__ ())
126 if e
. name
== "PHOTO" :
127 imageData
= avatar
. parsePhotoEl ( e
)
129 errback () # Possibly it wasn't in a supported format?
130 self
. avatar
= self
. pytrans
. avatarCache
. setAvatar ( imageData
)
131 self
. legacycon
. updateAvatar ( self
. avatar
)
134 self
. legacycon
. updateAvatar () # Default avatar
136 def errback ( args
= None ):
137 LogEvent ( INFO
, self
. jabberID
, "Error fetching avatar." )
139 self
. legacycon
. updateAvatar ()
141 LogEvent ( INFO
, self
. jabberID
, "Fetching avatar." )
142 d
= self
. sendVCardRequest ( to
= self
. jabberID
, fro
= config
. jid
)
143 d
. addCallback ( vCardReceived
)
144 d
. addErrback ( errback
)
146 def updateNickname ( self
, nickname
):
147 self
. nickname
= nickname
148 if not self
. nickname
:
149 j
= jid
. JID ( self
. jabberID
)
150 self
. nickname
= j
. user
151 self
. setStatus ( self
. show
, self
. status
)
153 def setStatus ( self
, show
, status
):
156 self
. legacycon
. setStatus ( self
. nickname
, show
, status
)
158 def sendNotReadyError ( self
, source
, resource
, dest
, body
):
159 self
. sendErrorMessage ( source
+ '/' + resource
, dest
, "wait" , "not-allowed" , lang
. get ( self
. lang
). waitForLogin
, body
)
161 def findGroupchat ( self
, to
):
168 for groupchat
in self
. groupchats
:
169 if groupchat
. ID
== roomID
:
174 def nicknameReceived ( self
, source
, dest
, nickname
):
175 if dest
. find ( '@' ) > 0 : return # Ignore presence packets sent to users
177 self
. updateNickname ( nickname
)
179 def avatarHashReceived ( self
, source
, dest
, avatarHash
):
180 if dest
. find ( '@' ) > 0 : return # Ignore presence packets sent to users
182 if avatarHash
== " " : # Setting no avatar
183 self
. legacycon
. updateAvatar () # Default
184 elif ( not self
. avatar
) or ( self
. avatar
and self
. avatar
. getImageHash () != avatarHash
):
185 imageData
= self
. pytrans
. avatarCache
. getAvatar ( avatarHash
)
187 self
. avatar
= avatar
. Avatar ( imageData
) # Stuff in the cache is always PNG
188 self
. legacycon
. updateAvatar ( self
. avatar
)
192 def messageReceived ( self
, source
, resource
, dest
, destr
, mtype
, body
, noerror
):
193 if dest
== config
. jid
:
194 if body
. lower (). startswith ( "end" ):
195 LogEvent ( INFO
, self
. jabberID
, "Received 'end' request." )
200 self
. sendNotReadyError ( source
, resource
, dest
, body
)
203 # Sends the message to the legacy translator
204 groupchat
= self
. findGroupchat ( dest
)
206 # It's for a groupchat
207 if destr
and len ( destr
) > 0 and not noerror
:
208 self
. sendErrorMessage ( to
=( source
+ "/" + resource
), fro
= dest
, etype
= "cancel" , condition
= "not-allowed" , explanation
= lang
. get ( self
. lang
). groupchatPrivateError
, body
= body
)
210 LogEvent ( INFO
, self
. jabberID
, "Groupchat." )
211 groupchat
. sendMessage ( body
, noerror
)
213 LogEvent ( INFO
, self
. jabberID
, "Message." )
214 self
. legacycon
. sendMessage ( dest
, resource
, body
, noerror
)
216 def inviteReceived ( self
, source
, resource
, dest
, destr
, roomjid
):
218 self
. sendNotReadyError ( source
, resource
, dest
, roomjid
)
221 if not roomjid
. endswith ( '@' + config
. jid
): # Inviting a MSN user to a Jabber chatroom
222 message
= lang
. get ( self
. lang
). groupchatAdvocacy
% ( self
. jabberID
, config
. website
)
223 self
. legacycon
. sendMessage ( dest
, resource
, message
, True )
226 groupchat
= self
. findGroupchat ( roomjid
)
228 LogEvent ( INFO
, self
. jabberID
, "Groupchat invitation." )
229 groupchat
. sendContactInvite ( dest
)
231 def typingNotificationReceived ( self
, dest
, resource
, composing
):
232 """ The user has sent typing notification to a contact on the legacy service """
233 self
. legacycon
. userTypingNotification ( dest
, resource
, composing
)
235 def presenceReceived ( self
, source
, resource
, to
, tor
, priority
, ptype
, show
, status
):
236 # Checks resources and priorities so that the highest priority resource always appears as the
237 # legacy services status. If there are no more resources then the session is deleted
238 # Additionally checks if the presence is to a groupchat room
239 groupchat
= self
. findGroupchat ( to
)
241 # It's for an existing groupchat
242 if ptype
== "unavailable" :
244 LogEvent ( INFO
, self
. jabberID
, "Killing groupchat." )
247 if source
== self
. jabberID
:
248 LogEvent ( INFO
, self
. jabberID
, "Groupchat presence." )
252 groupchat
. userJoined ( tor
)
254 LogEvent ( INFO
, self
. jabberID
, "Sending groupchat error presence." )
255 self
. sendPresence ( to
=( source
+ "/" + resource
), fro
= to
, ptype
= "error" )
257 elif legacy
. isGroupJID ( to
) and to
!= config
. jid
and not ptype
:
258 # Its to a groupchat JID, and the presence type is available
260 self
. sendNotReadyError ( source
, resource
, to
, to
)
263 # It's a new groupchat
264 gcID
= to
[: to
. find ( '@' )] # Grab the room name
265 LogEvent ( INFO
, self
. jabberID
, "Creating a new groupchat." )
266 groupchat
= legacy
. LegacyGroupchat ( self
, resource
, gcID
) # Creates an empty groupchat
267 groupchat
. userJoined ( tor
)
271 self
. handleResourcePresence ( source
, resource
, to
, tor
, priority
, ptype
, show
, status
)
274 def handleResourcePresence ( self
, source
, resource
, to
, tor
, priority
, ptype
, show
, status
):
275 if ptype
and ptype
!= "unavailable" : return # Ignore presence errors, probes, etc
276 if to
. find ( '@' ) > 0 : return # Ignore presence packets sent to users
278 existing
= self
. resourceList
. has_key ( resource
)
279 if ptype
== "unavailable" :
281 LogEvent ( INFO
, self
. jabberID
, "Resource gone offline." )
282 self
. resourceOffline ( resource
)
284 return # I don't know the resource, and they're leaving, so it's all good
287 LogEvent ( INFO
, self
. jabberID
, "Resource came online." )
288 self
. contactList
. resendLists ( source
+ "/" + resource
)
289 LogEvent ( INFO
, self
. jabberID
, "Setting status." )
290 self
. resourceList
[ resource
] = SessionResource ( show
, status
, priority
)
292 highestActive
= self
. highestResource ()
295 # If we're the highest active resource, we should update the legacy service
296 LogEvent ( INFO
, self
. jabberID
, "Updating status on legacy service." )
297 r
= self
. resourceList
[ highestActive
]
298 self
. setStatus ( r
. show
, r
. status
)
300 LogEvent ( INFO
, self
. jabberID
, "Last resource died. Calling removeMe in 0 seconds." )
301 #reactor.callLater(0, self.removeMe)
303 #FIXME Which of the above?
305 def highestResource ( self
):
306 """ Returns the highest priority resource """
308 for checkR
in self
. resourceList
. keys ():
309 if highestActive
== None or self
. resourceList
[ checkR
]. priority
> self
. resourceList
[ highestActive
]. priority
:
310 highestActive
= checkR
313 # debug.log("Session %s - highest active resource is \"%s\" at %d" % (self.jabberID, highestActive, self.resourceList[highestActive].priority))
318 def resourceOffline ( self
, resource
):
319 del self
. resourceList
[ resource
]
320 self
. legacycon
. resourceOffline ( resource
)
322 def subscriptionReceived ( self
, to
, subtype
):
323 """ Sends the subscription request to the legacy services handler """
325 LogEvent ( INFO
, self
. jabberID
, "Passing subscription to legacy service." )
326 self
. contactList
. jabberSubscriptionReceived ( to
, subtype
)
328 if subtype
== "subscribe" :
329 self
. sendPresence ( to
= self
. jabberID
, fro
= config
. jid
, ptype
= "subscribed" )
330 elif subtype
. startswith ( "unsubscribe" ):
331 # They want to unregister.
333 LogEvent ( INFO
, jid
, "About to unregister." )
334 self
. pytrans
. registermanager
. removeRegInfo ( jid
)
335 LogEvent ( INFO
, jid
, "Just unregistered." )
343 class SessionResource
:
344 """ A convienence class to allow comparisons of Jabber resources """
345 def __init__ ( self
, show
= None , status
= None , priority
= None ):
350 self
. priority
= int ( priority
)
351 except TypeError : pass
352 except ValueError : pass