comparison sat.tac @ 50:daa1f01a5332

SàT improvement: - subscription & presence refactoring - multilingual statuses are now correctly sent - registration: error condition now specified in error message
author Goffi <goffi@goffi.org>
date Thu, 07 Jan 2010 00:05:15 +1100
parents d24629c631fc
children 6455fb62ff83
comparison
equal deleted inserted replaced
49:9c79eb49d51f 50:daa1f01a5332
68 sat_id+=1 68 sat_id+=1
69 return "sat_id_"+str(sat_id) 69 return "sat_id_"+str(sat_id)
70 70
71 class SatXMPPClient(client.XMPPClient): 71 class SatXMPPClient(client.XMPPClient):
72 72
73 def __init__(self, jid, password, host=None, port=5222): 73 def __init__(self, user_jid, password, host=None, port=5222):
74 client.XMPPClient.__init__(self, jid, password, host, port) 74 client.XMPPClient.__init__(self, user_jid, password, host, port)
75 self.factory.clientConnectionLost = self.connectionLost 75 self.factory.clientConnectionLost = self.connectionLost
76 self.__connected=False 76 self.__connected=False
77 77
78 def _authd(self, xmlstream): 78 def _authd(self, xmlstream):
79 print "SatXMPPClient" 79 print "SatXMPPClient"
118 def __init__(self, host): 118 def __init__(self, host):
119 xmppim.RosterClientProtocol.__init__(self) 119 xmppim.RosterClientProtocol.__init__(self)
120 self.host = host 120 self.host = host
121 121
122 def rosterCb(self, roster): 122 def rosterCb(self, roster):
123 for jid, item in roster.iteritems(): 123 for raw_jid, item in roster.iteritems():
124 info ("new contact in roster list: %s", jid) 124 self.onRosterSet(item)
125 #FIXME: fill attributes
126 self.host.memory.addContact(jid, {}, item.groups)
127 self.host.bridge.newContact(jid, {}, item.groups)
128 125
129 def requestRoster(self): 126 def requestRoster(self):
130 """ ask the server for Roster list """ 127 """ ask the server for Roster list """
131 debug("requestRoster") 128 debug("requestRoster")
132 self.getRoster().addCallback(self.rosterCb) 129 self.getRoster().addCallback(self.rosterCb)
133 130
134 def removeItem(self, to): 131 def removeItem(self, to):
135 """Remove a contact from roster list""" 132 """Remove a contact from roster list"""
136 to_jid=jid.JID(to) 133 xmppim.RosterClientProtocol.removeItem(self, to)
137 xmppim.RosterClientProtocol.removeItem(self, to_jid)
138 #TODO: check IQ result 134 #TODO: check IQ result
139 135
140 def addItem(self, to): 136 def addItem(self, to):
141 """Add a contact to roster list""" 137 """Add a contact to roster list"""
142 to_jid=jid.JID(to) 138 xmppim.RosterClientProtocol.addItem(self, to)
143 xmppim.RosterClientProtocol.addItem(self, to_jid)
144 #TODO: check IQ result 139 #TODO: check IQ result
140
141 def onRosterSet(self, item):
142 """Called when a new/update roster item is received"""
143 #TODO: send a signal to frontends
144 item_attr = {'to': str(item.subscriptionTo),
145 'from': str(item.subscriptionFrom),
146 'ask': str(item.ask)
147 }
148 if item.name:
149 item_attr['name'] = item.name
150 info ("new contact in roster list: %s", item.jid.full())
151 self.host.memory.addContact(item.jid, item_attr, item.groups)
152 self.host.bridge.newContact(item.jid.full(), item_attr, item.groups)
153
154 def onRosterRemove(self, entity):
155 """Called when a roster removal event is received"""
156 #TODO: send a signal to frontends
157 print "removing %s from roster list" % entity.full()
158 self.host.memory.delContact(entity)
145 159
146 class SatPresenceProtocol(xmppim.PresenceClientProtocol): 160 class SatPresenceProtocol(xmppim.PresenceClientProtocol):
147 161
148 def __init__(self, host): 162 def __init__(self, host):
149 xmppim.PresenceClientProtocol.__init__(self) 163 xmppim.PresenceClientProtocol.__init__(self)
150 self.host = host 164 self.host = host
151 165
152 def availableReceived(self, entity, show=None, statuses=None, priority=0): 166 def availableReceived(self, entity, show=None, statuses=None, priority=0):
153 info ("presence update for [%s]", entity) 167 info ("presence update for [%s]", entity)
154 168
155 ### we check if the status is not about subscription ### 169 if statuses.has_key(None): #we only want string keys
156 #FIXME: type is not needed anymore 170 statuses["default"] = statuses[None]
157 #TODO: management of differents statuses (differents languages) 171 del statuses[None]
158 status = statuses.values()[0] if len(statuses) else "" 172
159 self.host.memory.addPresenceStatus(entity.full(), "", show or "", 173 self.host.memory.addPresenceStatus(entity, show or "",
160 status or "", int(priority)) 174 int(priority), statuses)
161 175
162 #now it's time to notify frontends 176 #now it's time to notify frontends
163 self.host.bridge.presenceUpdate(entity.full(), "", show or "", 177 self.host.bridge.presenceUpdate(entity.full(), show or "",
164 status or "", int(priority)) 178 int(priority), statuses)
165 179
166 def unavailableReceived(self, entity, statuses=None): 180 def unavailableReceived(self, entity, statuses=None):
167 #TODO: management of differents statuses (differents languages) 181 if statuses and statuses.has_key(None): #we only want string keys
168 status = statuses.values()[0] if len(statuses) else "" 182 statuses["default"] = statuses[None]
169 self.host.memory.addPresenceStatus(entity.full(), "unavailable", "", 183 del statuses[None]
170 status or "", 0) 184 self.host.memory.addPresenceStatus(entity, "unavailable", 0, statuses)
171 185
172 #now it's time to notify frontends 186 #now it's time to notify frontends
173 self.host.bridge.presenceUpdate(entity.full(), "unavailable", "", 187 self.host.bridge.presenceUpdate(entity.full(), "unavailable", 0, statuses)
174 status or "", 0) 188
175 189
176 190 def available(self, entity=None, show=None, statuses=None, priority=0):
191 if statuses and statuses.has_key('default'):
192 statuses[None] = statuses['default']
193 del statuses['default']
194 xmppim.PresenceClientProtocol.available(self, entity, show, statuses, priority)
195
177 def subscribedReceived(self, entity): 196 def subscribedReceived(self, entity):
178 debug ("subscription approved for [%s]" % entity) 197 debug ("subscription approved for [%s]" % entity.userhost())
198 self.host.memory.delWaitingSub(entity.userhost())
199 self.host.bridge.subscribe('subscribed', entity.userhost())
179 200
180 def unsubscribedReceived(self, entity): 201 def unsubscribedReceived(self, entity):
181 debug ("unsubscription confirmed for [%s]" % entity) 202 debug ("unsubscription confirmed for [%s]" % entity.userhost())
203 self.host.memory.delWaitingSub(entity.userhost())
204 self.host.bridge.subscribe('unsubscribed', entity.userhost())
182 205
183 def subscribeReceived(self, entity): 206 def subscribeReceived(self, entity):
184 #FIXME: auto answer for subscribe request, must be checked ! 207 debug ("subscription request for [%s]" % entity.userhost())
185 debug ("subscription request for [%s]" % entity) 208 self.host.memory.addWaitingSub('subscribe', entity.userhost())
186 self.subscribed(entity) 209 self.host.bridge.subscribe('subscribe', entity.userhost())
187 210
188 def unsubscribeReceived(self, entity): 211 def unsubscribeReceived(self, entity):
189 debug ("unsubscription asked for [%s]" % entity) 212 debug ("unsubscription asked for [%s]" % entity.userhost())
213 self.host.memory.addWaitingSub('unsubscribe', entity.userhost())
214 self.host.bridge.subscribe('unsubscribe', entity.userhost())
190 215
191 class SatDiscoProtocol(disco.DiscoClientProtocol): 216 class SatDiscoProtocol(disco.DiscoClientProtocol):
192 def __init__(self, host): 217 def __init__(self, host):
193 disco.DiscoClientProtocol.__init__(self) 218 disco.DiscoClientProtocol.__init__(self)
194 219
241 if failure.value.condition == 'conflict': 266 if failure.value.condition == 'conflict':
242 answer_data['reason'] = 'conflict' 267 answer_data['reason'] = 'conflict'
243 answer_data={"message":"Username already exists, please choose an other one"} 268 answer_data={"message":"Username already exists, please choose an other one"}
244 else: 269 else:
245 answer_data['reason'] = 'unknown' 270 answer_data['reason'] = 'unknown'
246 answer_data={"message":"Registration failed"} 271 answer_data={"message":"Registration failed (%s)" % str(failure.value.condition)}
247 self.host.bridge.actionResult(answer_type, self.answer_id, answer_data) 272 self.host.bridge.actionResult(answer_type, self.answer_id, answer_data)
248 self.xmlstream.sendFooter() 273 self.xmlstream.sendFooter()
249 274
250 275
251 class SAT(service.Service): 276 class SAT(service.Service):
287 self.bridge.register("registerNewAccount", self.registerNewAccount) 312 self.bridge.register("registerNewAccount", self.registerNewAccount)
288 self.bridge.register("connect", self.connect) 313 self.bridge.register("connect", self.connect)
289 self.bridge.register("disconnect", self.disconnect) 314 self.bridge.register("disconnect", self.disconnect)
290 self.bridge.register("getContacts", self.memory.getContacts) 315 self.bridge.register("getContacts", self.memory.getContacts)
291 self.bridge.register("getPresenceStatus", self.memory.getPresenceStatus) 316 self.bridge.register("getPresenceStatus", self.memory.getPresenceStatus)
317 self.bridge.register("getWaitingSub", self.memory.getWaitingSub)
292 self.bridge.register("sendMessage", self.sendMessage) 318 self.bridge.register("sendMessage", self.sendMessage)
293 self.bridge.register("setParam", self.setParam) 319 self.bridge.register("setParam", self.setParam)
294 self.bridge.register("getParamA", self.memory.getParamA) 320 self.bridge.register("getParamA", self.memory.getParamA)
295 self.bridge.register("getParams", self.memory.getParams) 321 self.bridge.register("getParams", self.memory.getParams)
296 self.bridge.register("getParamsForCategory", self.memory.getParamsForCategory) 322 self.bridge.register("getParamsForCategory", self.memory.getParamsForCategory)
297 self.bridge.register("getParamsCategories", self.memory.getParamsCategories) 323 self.bridge.register("getParamsCategories", self.memory.getParamsCategories)
298 self.bridge.register("getHistory", self.memory.getHistory) 324 self.bridge.register("getHistory", self.memory.getHistory)
299 self.bridge.register("setPresence", self.setPresence) 325 self.bridge.register("setPresence", self.setPresence)
326 self.bridge.register("subscription", self.subscription)
300 self.bridge.register("addContact", self.addContact) 327 self.bridge.register("addContact", self.addContact)
301 self.bridge.register("delContact", self.delContact) 328 self.bridge.register("delContact", self.delContact)
302 self.bridge.register("isConnected", self.isConnected) 329 self.bridge.register("isConnected", self.isConnected)
303 self.bridge.register("launchAction", self.launchAction) 330 self.bridge.register("launchAction", self.launchAction)
304 self.bridge.register("confirmationAnswer", self.confirmationAnswer) 331 self.bridge.register("confirmationAnswer", self.confirmationAnswer)
521 self.xmlstream.send(message) 548 self.xmlstream.send(message)
522 self.memory.addToHistory(self.me, self.me, jid.JID(to), message["type"], unicode(msg)) 549 self.memory.addToHistory(self.me, self.me, jid.JID(to), message["type"], unicode(msg))
523 self.bridge.newMessage(message['from'], unicode(msg), to=message['to']) #We send back the message, so all clients are aware of it 550 self.bridge.newMessage(message['from'], unicode(msg), to=message['to']) #We send back the message, so all clients are aware of it
524 551
525 552
526 def setPresence(self, to="", type="", show="", status="", priority=0): 553 def setPresence(self, to="", show="", priority = 0, statuses={}):
527 """Send our presence information""" 554 """Send our presence information"""
528 if not type in ["", "unavailable", "subscribed", "subscribe", 555 to_jid = jid.JID(to) if to else None
529 "unsubscribe", "unsubscribed", "prob", "error"]: 556 self.presence.available(to_jid, show, statuses, priority)
530 error("Type error !") 557
531 #TODO: throw an error 558 def subscription(self, type, raw_jid):
532 return 559 """Called to manage subscription"""
533 to_jid=jid.JID(to) 560 to_jid = jid.JID(raw_jid)
534 status = None if not status else {None:status} #FIXME: use the proper way here (change signature to use dict) 561 debug ('subsciption request [%s] for %s', type, to_jid.full())
535 #TODO: refactor subscription bridge API 562 if type=="subscribe":
536 if type=="":
537 self.presence.available(to_jid, show, status, priority)
538 elif type=="subscribe":
539 self.presence.subscribe(to_jid) 563 self.presence.subscribe(to_jid)
540 elif type=="subscribed": 564 elif type=="subscribed":
541 self.presence.subscribed(to_jid) 565 self.presence.subscribed(to_jid)
566 contact = self.memory.getContact(to_jid)
567 if not contact or not bool(contact['to']): #we automatically subscribe to 'to' presence
568 debug('sending automatic "to" subscription request')
569 self.subscription('subscribe', to_jid.userhost())
542 elif type=="unsubscribe": 570 elif type=="unsubscribe":
543 self.presence.unsubscribe(to_jid) 571 self.presence.unsubscribe(to_jid)
544 elif type=="unsubscribed": 572 elif type=="unsubscribed":
545 self.presence.unsubscribed(to_jid) 573 self.presence.unsubscribed(to_jid)
546 574
547 575
548 def addContact(self, to): 576 def addContact(self, to):
549 """Add a contact in roster list""" 577 """Add a contact in roster list"""
550 to_jid=jid.JID(to) 578 to_jid=jid.JID(to)
551 self.roster.addItem(to_jid.userhost()) 579 self.roster.addItem(to_jid)
552 self.setPresence(to_jid.userhost(), "subscribe") 580 self.presence.subscribe(to_jid)
553 581
554 def delContact(self, to): 582 def delContact(self, to):
555 """Remove contact from roster list""" 583 """Remove contact from roster list"""
556 to_jid=jid.JID(to) 584 to_jid=jid.JID(to)
557 self.roster.removeItem(to_jid.userhost()) 585 self.roster.removeItem(to_jid)
586 self.presence.unsubscribe(to_jid)
558 self.bridge.contactDeleted(to) 587 self.bridge.contactDeleted(to)
559 588
560 589
561 ## callbacks ## 590 ## callbacks ##
562 591