]> code.delx.au - pymsnt/blob - src/session.py
59b672af53207d8283ffecb33d47f29fe01b1eb3
[pymsnt] / src / session.py
1 # Copyright 2004 James Bunton <james@delx.cjb.net>
2 # Licensed for distribution under the GPL version 2, check COPYING for details
3
4 import utils
5 import legacy
6 import jabw
7 import debug
8 import config
9 import lang
10
11
12
13 def makeSession(pytrans, jabberID, ulang):
14 """ Tries to create a session object for the corresponding JabberID. Retrieves information
15 from XDB to create the session. If it fails, then the user is most likely not registered with
16 the transport """
17 debug.log("session: makeSession(\"%s\")" % (jabberID))
18 if(pytrans.sessions.has_key(jabberID)):
19 debug.log("session: makeSession() - removing existing session")
20 pytrans.sessions[jabberID].removeMe()
21 result = pytrans.registermanager.getRegInfo(jabberID)
22 if(result):
23 username, password, nickname = result
24 return Session(pytrans, jabberID, username, password, nickname, ulang)
25 else:
26 return None
27
28
29
30 class Session(jabw.JabberConnection):
31 """ A class to represent each registered user's session with the legacy network. Exists as long as there
32 is a Jabber resource for the user available """
33
34 def __init__(self, pytrans, jabberID, username, password, nickname, ulang):
35 """ Initialises the session object and connects to the legacy network """
36 jabw.JabberConnection.__init__(self, pytrans, jabberID)
37 debug.log("Session: Creating new session \"%s\"" % (jabberID))
38
39 self.pytrans = pytrans
40 self.alive = True
41 self.ready = False # Only ready when we're logged into the legacy service
42 self.jabberID = jabberID # the JabberID of the Session's user
43 self.username = username # the legacy network ID of the Session's user
44 self.password = password
45 self.nickname = nickname
46 self.lang = ulang
47
48 self.show = None
49 self.status = None
50
51 self.resourceList = {}
52 self.groupchats = []
53
54 self.legacycon = legacy.LegacyConnection(self.username, self.password, self)
55
56 if(config.sessionGreeting):
57 self.sendMessage(to=self.jabberID, fro=config.jid, body=config.sessionGreeting)
58 debug.log("Session: New session created \"%s\" \"%s\" \"%s\" \"%s\"" % (jabberID, username, password, nickname))
59
60 def removeMe(self):
61 """ Safely removes the session object, including sending <presence type="unavailable"/> messages for each legacy related item on the user's contact list """
62 # Send offline presence to Jabber ID
63 # Delete all objects cleanly
64 # Remove this Session object from the pytrans
65
66 debug.log("Session: Removing \"%s\"" % (self.jabberID))
67
68 # Mark as dead
69 self.alive = False
70 self.ready = False
71
72 # Send offline presence to the user
73 if(self.pytrans):
74 self.sendPresence(to=self.jabberID, fro=config.jid, ptype="unavailable")
75
76 # Clean up stuff on the legacy service end (including sending offline presences for all contacts)
77 if(self.legacycon):
78 self.legacycon.removeMe()
79 self.legacycon = None
80
81 # Remove any groupchats we may be in
82 for groupchat in utils.copyList(self.groupchats):
83 groupchat.removeMe()
84
85 if(self.pytrans):
86 # Remove us from the session list
87 del self.pytrans.sessions[self.jabberID]
88 # Clean up the no longer needed reference
89 self.pytrans = None
90
91 debug.log("Session: Completed removal \"%s\"" % (self.jabberID))
92 utils.mutilateMe(self)
93
94 def updateNickname(self, nickname):
95 self.nickname = nickname
96 self.setStatus(self.show, self.status)
97
98 def setStatus(self, show, status):
99 self.show = show
100 self.status = status
101 self.legacycon.setStatus(show, status)
102
103 def sendNotReadyError(self, source, resource, dest, body):
104 self.sendErrorMessage(source + '/' + resource, dest, "wait", "not-allowed", lang.get(self.lang).waitForLogin, body)
105
106 def findGroupchat(self, to):
107 pos = to.find('@')
108 if(pos > 0):
109 roomID = to[:pos]
110 else:
111 roomID = to
112
113 for groupchat in self.groupchats:
114 if(groupchat.ID == roomID):
115 return groupchat
116
117 return None
118
119 def messageReceived(self, source, resource, dest, destr, mtype, body, noerror):
120 if(dest == config.jid):
121 if(body.lower().startswith("end")):
122 debug.log("Session: Received 'end' request. Killing session %s" % (self.jabberID))
123 self.removeMe()
124 return
125
126 if(not self.ready):
127 self.sendNotReadyError(source, resource, dest, body)
128 return
129
130 # Sends the message to the legacy translator
131 groupchat = self.findGroupchat(dest)
132 if(groupchat):
133 # It's for a groupchat
134 if(destr and len(destr) > 0 and not noerror):
135 self.sendErrorMessage(to=(source + "/" + resource), fro=dest, etype="cancel", condition="not-allowed", explanation=lang.get(self.lang).groupchatPrivateError, body=body)
136 else:
137 debug.log("Session: Message received for groupchat \"%s\" \"%s\"" % (self.jabberID, groupchat.ID))
138 groupchat.sendMessage(body, noerror)
139 else:
140 debug.log("Session: messageReceived(), passing onto legacycon.sendMessage()")
141 self.legacycon.sendMessage(dest, resource, body, noerror)
142
143 def inviteReceived(self, source, resource, dest, destr, roomjid):
144 if(not self.ready):
145 self.sendNotReadyError(source, resource, dest, roomjid)
146 return
147
148 if(not roomjid.endswith('@' + config.jid)):
149 message = lang.get(self.lang).groupchatAdvocacy % (self.jabberID, config.website)
150 self.legacycon.sendMessage(dest, resource, message, True)
151 return
152
153 groupchat = self.findGroupchat(roomjid)
154 if(groupchat):
155 debug.log("Session: inviteReceived(\"%s\", \"%s\", \"%s\", \"%s\", \"%s\")" % (source, resource, dest, destr, roomjid))
156 groupchat.sendContactInvite(dest)
157
158 def typingNotificationReceived(self, dest, resource, composing):
159 """ The user has sent typing notification to a contact on the legacy service """
160 self.legacycon.userTypingNotification(dest, resource, composing)
161
162 def presenceReceived(self, source, resource, to, tor, priority, ptype, show, status):
163 # Checks resources and priorities so that the highest priority resource always appears as the
164 # legacy services status. If there are no more resources then the session is deleted
165 # Additionally checks if the presence is to a groupchat room
166 groupchat = self.findGroupchat(to)
167 if(groupchat):
168 # It's for an existing groupchat
169 if(ptype == "unavailable"):
170 # Kill the groupchat
171 debug.log("Session: Presence received to kill groupchat \"%s\" \"%s\"" % (self.jabberID, groupchat.ID))
172 groupchat.removeMe()
173 else:
174 if(source == self.jabberID):
175 debug.log("Session: Presence for groupchat \"%s\" \"%s\"" % (self.jabberID, groupchat.ID))
176 if(ptype == "error"):
177 groupchat.removeMe()
178 else:
179 groupchat.userJoined(tor)
180 else:
181 debug.log("Session: Sending error presence for groupchat (user not allowed) \"%s\" \"%s\"" % (self.jabberID, groupchat.ID))
182 self.sendPresence(to=(source + "/" + resource), fro=to, ptype="error")
183
184 elif(legacy.isGroupJID(to) and to != config.jid and ptype not in ["error", "unavailable"]):
185 if(not self.ready):
186 self.sendNotReadyError(source, resource, to, to)
187 return
188 # It's a new groupchat
189 gcID = to[:to.find('@')] # Grab the room name
190 debug.log("Session: Creating a new groupchat \"%s\" \"%s\"" % (self.jabberID, gcID))
191 groupchat = legacy.LegacyGroupchat(self, resource, gcID) # Creates an empty groupchat
192 groupchat.userJoined(tor)
193
194 else:
195 # Not for groupchat
196 self.handleResourcePresence(source, resource, to, tor, priority, ptype, show, status)
197
198
199 def handleResourcePresence(self, source, resource, to, tor, priority, ptype, show, status):
200 if(not ptype in [None, "unavailable"]): return # Ignore presence errors, probes, etc
201 if(to.find('@') > 0): return # Ignore presence packets sent to users
202
203 existing = self.resourceList.has_key(resource)
204 if(ptype == "unavailable"):
205 if(existing):
206 debug.log("Session: %s - resource \"%s\" gone offline" % (self.jabberID, resource))
207 self.resourceOffline(resource)
208 else:
209 return # I don't know the resource, and they're leaving, so it's all good
210 else:
211 if(not existing):
212 debug.log("Session %s - resource \"%s\" has come online" % (self.jabberID, resource))
213 self.legacycon.newResourceOnline(resource)
214 debug.log("Session %s - resource \"%s\" setting \"%s\" \"%s\" \"%s\"" % (self.jabberID, resource, show, status, priority))
215 self.resourceList[resource] = SessionResource(show, status, priority)
216
217 highestActive = self.highestResource()
218
219 if(highestActive):
220 # If we're the highest active resource, we should update the legacy service
221 debug.log("Session %s - updating status on legacy service, resource %s" % (self.jabberID, highestActive))
222 r = self.resourceList[highestActive]
223 self.setStatus(r.show, r.status)
224 else:
225 debug.log("Session %s - tearing down, last resource gone offline")
226 self.removeMe()
227
228 def highestResource(self):
229 """ Returns the highest priority resource """
230 highestActive = None
231 for checkR in self.resourceList.keys():
232 if(highestActive == None or self.resourceList[checkR].priority > self.resourceList[highestActive].priority):
233 highestActive = checkR
234
235 if(highestActive):
236 debug.log("Session %s - highest active resource is \"%s\" at %d" % (self.jabberID, highestActive, self.resourceList[highestActive].priority))
237
238 return highestActive
239
240
241 def resourceOffline(self, resource):
242 del self.resourceList[resource]
243 self.legacycon.resourceOffline(resource)
244
245 def subscriptionReceived(self, to, subtype):
246 """ Sends the subscription request to the legacy services handler """
247 debug.log("Session: \"%s\" subscriptionReceived(), passing onto legacycon.jabberSubscriptionReceived()" % (self.jabberID))
248 self.legacycon.jabberSubscriptionReceived(to, subtype)
249
250
251
252
253
254
255 class SessionResource:
256 """ A convienence class to allow comparisons of Jabber resources """
257 def __init__(self, show=None, status=None, priority=None):
258 self.show = show
259 self.status = status
260 self.priority = 0
261 try:
262 self.priority = int(priority)
263 except TypeError: pass
264 except ValueError: pass
265
266