]>
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
12 from debug
import LogEvent
, INFO
, WARN
, ERROR
13 if utils
. checkTwisted ():
14 from twisted
. words
. protocols
. jabber
import jid
16 from tlib
. jabber
import jid
20 def makeSession ( pytrans
, jabberID
, ulang
):
21 """ Tries to create a session object for the corresponding JabberID. Retrieves information
22 from XDB to create the session. If it fails, then the user is most likely not registered with
24 LogEvent ( INFO
, jabberID
)
25 if pytrans
. sessions
. has_key ( jabberID
):
26 LogEvent ( INFO
, jabberID
, "Removing existing session." )
27 pytrans
. sessions
[ jabberID
]. removeMe ()
28 result
= pytrans
. registermanager
. getRegInfo ( jabberID
)
30 username
, password
= result
31 return Session ( pytrans
, jabberID
, username
, password
, ulang
)
37 class Session ( jabw
. JabberConnection
):
38 """ A class to represent each registered user's session with the legacy network. Exists as long as there
39 is a Jabber resource for the user available """
41 def __init__ ( self
, pytrans
, jabberID
, username
, password
, ulang
):
42 """ Initialises the session object and connects to the legacy network """
43 jabw
. JabberConnection
.__ init
__ ( self
, pytrans
, jabberID
)
44 LogEvent ( INFO
, jabberID
)
46 self
. pytrans
= pytrans
48 self
. ready
= False # Only ready when we're logged into the legacy service
49 self
. jabberID
= jabberID
# the JabberID of the Session's user
50 self
. username
= username
# the legacy network ID of the Session's user
51 self
. password
= password
59 self
. resourceList
= {}
62 self
. legacycon
= legacy
. LegacyConnection ( self
. username
, self
. password
, self
)
63 self
. contactList
= contact
. ContactList ( self
)
64 self
. contactList
. legacyList
= self
. legacycon
. legacyList
66 if config
. sessionGreeting
:
67 self
. sendMessage ( to
= self
. jabberID
, fro
= config
. jid
, body
= config
. sessionGreeting
)
69 self
. updateNickname ( "" )
71 LogEvent ( INFO
, self
. jabberID
, "Created!" )
74 """ Safely removes the session object, including sending <presence type="unavailable"/> messages for each legacy related item on the user's contact list """
75 # Send offline presence to Jabber ID
76 # Delete all objects cleanly
77 # Remove this Session object from the pytrans
79 LogEvent ( INFO
, self
. jabberID
)
85 # Send offline presence to the user
87 self
. sendPresence ( to
= self
. jabberID
, fro
= config
. jid
, ptype
= "unavailable" )
89 # Clean up stuff on the legacy service end (including sending offline presences for all contacts)
91 self
. legacycon
. removeMe ()
95 self
. contactList
. removeMe ()
96 self
. contactList
= None
98 # Remove any groupchats we may be in
99 for groupchat
in self
. groupchats
[:]:
103 # Remove us from the session list
104 del self
. pytrans
. sessions
[ self
. jabberID
]
105 # Clean up the no longer needed reference
108 LogEvent ( INFO
, self
. jabberID
, "Removed!" )
109 utils
. mutilateMe ( self
)
111 def doVCardUpdate ( self
):
112 def vCardReceived ( el
):
113 if not self
. alive
: return
114 LogEvent ( INFO
, self
. jabberID
)
116 for e
in el
. elements ():
117 if e
. name
== "vCard" and e
. defaultUri
== disco
. VCARDTEMP
:
121 self
. legacycon
. updateAvatar () # Default avatar
124 for e
in vCard
. elements ():
125 if e
. name
== "NICKNAME" :
126 self
. updateNickname ( e
.__ str
__ ())
127 if e
. name
== "PHOTO" :
128 imageData
= avatar
. parsePhotoEl ( e
)
130 errback () # Possibly it wasn't in a supported format?
131 self
. avatar
= self
. pytrans
. avatarCache
. setAvatar ( imageData
)
132 self
. legacycon
. updateAvatar ( self
. avatar
)
135 self
. legacycon
. updateAvatar () # Default avatar
137 def errback ( args
= None ):
138 LogEvent ( INFO
, self
. jabberID
, "Error fetching avatar." )
140 self
. legacycon
. updateAvatar ()
142 LogEvent ( INFO
, self
. jabberID
, "Fetching avatar." )
143 d
= self
. sendVCardRequest ( to
= self
. jabberID
, fro
= config
. jid
)
144 d
. addCallback ( vCardReceived
)
145 d
. addErrback ( errback
)
147 def updateNickname ( self
, nickname
):
148 self
. nickname
= nickname
149 if not self
. nickname
:
150 j
= jid
. JID ( self
. jabberID
)
151 self
. nickname
= j
. user
152 self
. setStatus ( self
. show
, self
. status
)
154 def setStatus ( self
, show
, status
):
157 self
. legacycon
. setStatus ( self
. nickname
, show
, status
)
159 def sendNotReadyError ( self
, source
, resource
, dest
, body
):
160 self
. sendErrorMessage ( source
+ '/' + resource
, dest
, "wait" , "not-allowed" , lang
. get ( self
. lang
). waitForLogin
, body
)
162 def findGroupchat ( self
, to
):
169 for groupchat
in self
. groupchats
:
170 if groupchat
. ID
== roomID
:
175 def nicknameReceived ( self
, source
, dest
, nickname
):
176 if dest
. find ( '@' ) > 0 : return # Ignore presence packets sent to users
178 self
. updateNickname ( nickname
)
180 def avatarHashReceived ( self
, source
, dest
, avatarHash
):
181 if dest
. find ( '@' ) > 0 : return # Ignore presence packets sent to users
183 if avatarHash
== " " : # Setting no avatar
184 self
. legacycon
. updateAvatar () # Default
185 elif ( not self
. avatar
) or ( self
. avatar
and self
. avatar
. getImageHash () != avatarHash
):
186 imageData
= self
. pytrans
. avatarCache
. getAvatar ( avatarHash
)
188 self
. avatar
= avatar
. Avatar ( imageData
) # Stuff in the cache is always PNG
189 self
. legacycon
. updateAvatar ( self
. avatar
)
193 def messageReceived ( self
, source
, resource
, dest
, destr
, mtype
, body
, noerror
):
194 if dest
== config
. jid
:
195 if body
. lower (). startswith ( "end" ):
196 LogEvent ( INFO
, self
. jabberID
, "Received 'end' request." )
201 self
. sendNotReadyError ( source
, resource
, dest
, body
)
204 # Sends the message to the legacy translator
205 groupchat
= self
. findGroupchat ( dest
)
207 # It's for a groupchat
208 if destr
and len ( destr
) > 0 and not noerror
:
209 self
. sendErrorMessage ( to
=( source
+ "/" + resource
), fro
= dest
, etype
= "cancel" , condition
= "not-allowed" , explanation
= lang
. get ( self
. lang
). groupchatPrivateError
, body
= body
)
211 LogEvent ( INFO
, self
. jabberID
, "Groupchat." )
212 groupchat
. sendMessage ( body
, noerror
)
214 LogEvent ( INFO
, self
. jabberID
, "Message." )
215 self
. legacycon
. sendMessage ( dest
, resource
, body
, noerror
)
217 def inviteReceived ( self
, source
, resource
, dest
, destr
, roomjid
):
219 self
. sendNotReadyError ( source
, resource
, dest
, roomjid
)
222 if not roomjid
. endswith ( '@' + config
. jid
): # Inviting a MSN user to a Jabber chatroom
223 message
= lang
. get ( self
. lang
). groupchatAdvocacy
% ( self
. jabberID
, config
. website
)
224 self
. legacycon
. sendMessage ( dest
, resource
, message
, True )
227 groupchat
= self
. findGroupchat ( roomjid
)
229 LogEvent ( INFO
, self
. jabberID
, "Groupchat invitation." )
230 groupchat
. sendContactInvite ( dest
)
232 def typingNotificationReceived ( self
, dest
, resource
, composing
):
233 """ The user has sent typing notification to a contact on the legacy service """
234 self
. legacycon
. userTypingNotification ( dest
, resource
, composing
)
236 def presenceReceived ( self
, source
, resource
, to
, tor
, priority
, ptype
, show
, status
):
237 # Checks resources and priorities so that the highest priority resource always appears as the
238 # legacy services status. If there are no more resources then the session is deleted
239 # Additionally checks if the presence is to a groupchat room
240 groupchat
= self
. findGroupchat ( to
)
242 # It's for an existing groupchat
243 if ptype
== "unavailable" :
245 LogEvent ( INFO
, self
. jabberID
, "Killing groupchat." )
248 if source
== self
. jabberID
:
249 LogEvent ( INFO
, self
. jabberID
, "Groupchat presence." )
253 groupchat
. userJoined ( tor
)
255 LogEvent ( INFO
, self
. jabberID
, "Sending groupchat error presence." )
256 self
. sendPresence ( to
=( source
+ "/" + resource
), fro
= to
, ptype
= "error" )
258 elif legacy
. isGroupJID ( to
) and to
!= config
. jid
and not ptype
:
259 # Its to a groupchat JID, and the presence type is available
261 self
. sendNotReadyError ( source
, resource
, to
, to
)
264 # It's a new groupchat
265 gcID
= to
[: to
. find ( '@' )] # Grab the room name
266 LogEvent ( INFO
, self
. jabberID
, "Creating a new groupchat." )
267 groupchat
= legacy
. LegacyGroupchat ( self
, resource
, gcID
) # Creates an empty groupchat
268 groupchat
. userJoined ( tor
)
272 self
. handleResourcePresence ( source
, resource
, to
, tor
, priority
, ptype
, show
, status
)
275 def handleResourcePresence ( self
, source
, resource
, to
, tor
, priority
, ptype
, show
, status
):
276 if ptype
and ptype
!= "unavailable" : return # Ignore presence errors, probes, etc
277 if to
. find ( '@' ) > 0 : return # Ignore presence packets sent to users
279 existing
= self
. resourceList
. has_key ( resource
)
280 if ptype
== "unavailable" :
282 LogEvent ( INFO
, self
. jabberID
, "Resource gone offline." )
283 self
. resourceOffline ( resource
)
285 return # I don't know the resource, and they're leaving, so it's all good
288 LogEvent ( INFO
, self
. jabberID
, "Resource came online." )
289 self
. contactList
. resendLists ( source
+ "/" + resource
)
290 LogEvent ( INFO
, self
. jabberID
, "Setting status." )
291 self
. resourceList
[ resource
] = SessionResource ( show
, status
, priority
)
293 highestActive
= self
. highestResource ()
296 # If we're the highest active resource, we should update the legacy service
297 LogEvent ( INFO
, self
. jabberID
, "Updating status on legacy service." )
298 r
= self
. resourceList
[ highestActive
]
299 self
. setStatus ( r
. show
, r
. status
)
301 LogEvent ( INFO
, self
. jabberID
, "Last resource died. Calling removeMe in 0 seconds." )
302 #reactor.callLater(0, self.removeMe)
304 #FIXME Which of the above?
306 def highestResource ( self
):
307 """ Returns the highest priority resource """
309 for checkR
in self
. resourceList
. keys ():
310 if highestActive
== None or self
. resourceList
[ checkR
]. priority
> self
. resourceList
[ highestActive
]. priority
:
311 highestActive
= checkR
314 # debug.log("Session %s - highest active resource is \"%s\" at %d" % (self.jabberID, highestActive, self.resourceList[highestActive].priority))
319 def resourceOffline ( self
, resource
):
320 del self
. resourceList
[ resource
]
321 self
. legacycon
. resourceOffline ( resource
)
323 def subscriptionReceived ( self
, to
, subtype
):
324 """ Sends the subscription request to the legacy services handler """
326 LogEvent ( INFO
, self
. jabberID
, "Passing subscription to legacy service." )
327 self
. contactList
. jabberSubscriptionReceived ( to
, subtype
)
329 if subtype
== "subscribe" :
330 self
. sendPresence ( to
= self
. jabberID
, fro
= config
. jid
, ptype
= "subscribed" )
331 elif subtype
. startswith ( "unsubscribe" ):
332 # They want to unregister.
334 LogEvent ( INFO
, jid
, "About to unregister." )
335 self
. pytrans
. registermanager
. removeRegInfo ( jid
)
336 LogEvent ( INFO
, jid
, "Just unregistered." )
344 class SessionResource
:
345 """ A convienence class to allow comparisons of Jabber resources """
346 def __init__ ( self
, show
= None , status
= None , priority
= None ):
351 self
. priority
= int ( priority
)
352 except TypeError : pass
353 except ValueError : pass