comparison wokkel/mam.py @ 3:7eb4d15650dc

tmp: update wokkel MAM implementation
author souliane <souliane@mailoo.org>
date Thu, 15 Jan 2015 21:02:41 +0100
parents 4369549244e8
children 66a7586e49f8
comparison
equal deleted inserted replaced
2:4369549244e8 3:7eb4d15650dc
9 This protocol is specified in 9 This protocol is specified in
10 U{XEP-0313<http://xmpp.org/extensions/xep-0313.html>}. 10 U{XEP-0313<http://xmpp.org/extensions/xep-0313.html>}.
11 """ 11 """
12 12
13 from dateutil.tz import tzutc 13 from dateutil.tz import tzutc
14
14 from zope.interface import Interface, implements 15 from zope.interface import Interface, implements
16
15 from twisted.words.protocols.jabber.xmlstream import IQ, toResponse 17 from twisted.words.protocols.jabber.xmlstream import IQ, toResponse
16 from twisted.words.xish import domish 18 from twisted.words.xish import domish
17 from twisted.words.protocols.jabber import jid 19 from twisted.words.protocols.jabber import jid
20 from twisted.python import log
21
18 from wokkel.subprotocols import IQHandlerMixin, XMPPHandler 22 from wokkel.subprotocols import IQHandlerMixin, XMPPHandler
19 from wokkel import disco, data_form 23 from wokkel import disco, data_form, delay
24
20 import rsm 25 import rsm
21 26
22 NS_MAM = 'urn:xmpp:mam:0' 27 NS_MAM = 'urn:xmpp:mam:0'
28 NS_FORWARD = 'urn:xmpp:forward:0'
23 29
24 FIELDS_REQUEST = "/iq[@type='get']/query[@xmlns='%s']" % NS_MAM 30 FIELDS_REQUEST = "/iq[@type='get']/query[@xmlns='%s']" % NS_MAM
25 ARCHIVE_REQUEST = "/iq[@type='set']/query[@xmlns='%s']" % NS_MAM 31 ARCHIVE_REQUEST = "/iq[@type='set']/query[@xmlns='%s']" % NS_MAM
26 PREFS_GET_REQUEST = "/iq[@type='get']/prefs[@xmlns='%s']" % NS_MAM 32 PREFS_GET_REQUEST = "/iq[@type='get']/prefs[@xmlns='%s']" % NS_MAM
27 PREFS_SET_REQUEST = "/iq[@type='set']/prefs[@xmlns='%s']" % NS_MAM 33 PREFS_SET_REQUEST = "/iq[@type='set']/prefs[@xmlns='%s']" % NS_MAM
66 form = None 72 form = None
67 rsm = None 73 rsm = None
68 node = None 74 node = None
69 75
70 def __init__(self, form=None, rsm=None, node=None): 76 def __init__(self, form=None, rsm=None, node=None):
77 if form is not None:
78 assert(form.formType == 'submit')
71 self.form = form 79 self.form = form
72 self.rsm = rsm 80 self.rsm = rsm
73 self.node = node 81 self.node = node
74 82
75 @classmethod 83 @classmethod
313 return iq.send(to=service.full() if service else None) 321 return iq.send(to=service.full() if service else None)
314 322
315 323
316 class IMAMResource(Interface): 324 class IMAMResource(Interface):
317 325
318 def onArchiveRequest(self, mam, rsm, requestor): 326 def onArchiveRequest(self, mam, requestor):
319 """ 327 """
320 328
321 @param mam: The MAM <query/> request. 329 @param mam: The MAM <query/> request.
322 @type mam: L{MAMQueryReques<wokkel.mam.MAMQueryRequest>} 330 @type mam: L{MAMQueryReques<wokkel.mam.MAMQueryRequest>}
323
324 @param rsm: The RSM request.
325 @type rsm: L{RSMRequest<wokkel.rsm.RSMRequest>}
326 331
327 @param requestor: JID of the requestor. 332 @param requestor: JID of the requestor.
328 @type requestor: L{JID<twisted.words.protocols.jabber.jid.JID>} 333 @type requestor: L{JID<twisted.words.protocols.jabber.jid.JID>}
329 334
330 @return: The RSM answer. 335 @return: The RSM answer.
385 'label': 'Entity', 390 'label': 'Entity',
386 'desc': 'Entity against which to match message.', 391 'desc': 'Entity against which to match message.',
387 }, 392 },
388 } 393 }
389 394
390 extra_filters = [] 395 extra_filters = {}
391 396
392 def __init__(self, resource): 397 def __init__(self, resource):
393 """ 398 """
394 @param resource: instance implementing IMAMResource 399 @param resource: instance implementing IMAMResource
395 @type resource: L{object} 400 @type resource: L{object}
413 418
414 @param field: dictionary specifying the attributes to build a 419 @param field: dictionary specifying the attributes to build a
415 wokkel.data_form.Field. 420 wokkel.data_form.Field.
416 @type field: C{dict} 421 @type field: C{dict}
417 """ 422 """
418 self.extra_filters.append(field) 423 self.extra_filters[field.var] = field
419 424
420 def _onFieldsRequest(self, iq): 425 def _onFieldsRequest(self, iq):
421 """ 426 """
422 Called when a fields request has been received. 427 Called when a fields request has been received.
423 428
438 """ 443 """
439 response = toResponse(iq, 'result') 444 response = toResponse(iq, 'result')
440 self.xmlstream.send(response) 445 self.xmlstream.send(response)
441 446
442 mam_ = MAMQueryRequest.parse(iq.query) 447 mam_ = MAMQueryRequest.parse(iq.query)
443 try:
444 rsm_ = rsm.RSMRequest.parse(iq.query)
445 except rsm.RSMNotFoundError:
446 rsm_ = None
447 requestor = jid.JID(iq['from']) 448 requestor = jid.JID(iq['from'])
448 rsm_response = self.resource.onArchiveRequest(mam_, rsm_, requestor) 449
449 450 # remove unsupported filters
450 msg = domish.Element((None, 'message')) 451 unsupported_fields = []
451 fin = msg.addElement('fin', NS_MAM) 452 if mam_.form:
452 if iq.hasAttribute('queryid'): 453 for key, field in mam_.form.fields.iteritems():
453 fin['queryid'] = iq.query['queryid'] 454 if key not in self._legacyFilters and key not in self.extra_filters:
454 if rsm_response is not None: 455 log.msg('Ignored unsupported MAM filter: %s' % field)
455 fin.addChild(rsm_response.toElement()) 456 unsupported_fields.append(key)
456 self.xmlstream.send(msg) 457 for key in unsupported_fields:
457 458 del mam_.form.fields[key]
459
460 def forward_message(id_, elt, date):
461 msg = domish.Element((None, 'message'))
462 msg['to'] = iq['from']
463 result = msg.addElement('result', NS_MAM)
464 if iq.hasAttribute('queryid'):
465 result['queryid'] = iq.query['queryid']
466 result['id'] = id_
467 forward = result.addElement('forwarded', NS_FORWARD)
468 forward.addChild(delay.Delay(date).toElement())
469 forward.addChild(elt)
470 self.xmlstream.send(msg)
471
472 def cb(result):
473 msg_data, rsm_elt = result
474 for data in msg_data:
475 forward_message(*data)
476 msg = domish.Element((None, 'message'))
477 msg['to'] = iq['from']
478 fin = msg.addElement('fin', NS_MAM)
479 if iq.hasAttribute('queryid'):
480 fin['queryid'] = iq.query['queryid']
481 if rsm_elt is not None:
482 fin.addChild(rsm_elt)
483 self.xmlstream.send(msg)
484
485 self.resource.onArchiveRequest(mam_, requestor).addCallback(cb)
458 iq.handled = True 486 iq.handled = True
459 487
460 def _onPrefsGetRequest(self, iq): 488 def _onPrefsGetRequest(self, iq):
461 """ 489 """
462 Called when a prefs get request has been received. 490 Called when a prefs get request has been received.
464 This immediately replies with a result response. 492 This immediately replies with a result response.
465 """ 493 """
466 response = toResponse(iq, 'result') 494 response = toResponse(iq, 'result')
467 495
468 requestor = jid.JID(iq['from']) 496 requestor = jid.JID(iq['from'])
469 prefs = self.resource.onPrefsGetRequest(requestor) 497
470 498 def cb(prefs):
471 response.addChild(prefs.toElement()) 499 response.addChild(prefs.toElement())
472 self.xmlstream.send(response) 500 self.xmlstream.send(response)
501
502 self.resource.onPrefsGetRequest(requestor).addCallback(cb)
473 iq.handled = True 503 iq.handled = True
474 504
475 def _onPrefsSetRequest(self, iq): 505 def _onPrefsSetRequest(self, iq):
476 """ 506 """
477 Called when a prefs get request has been received. 507 Called when a prefs get request has been received.
480 """ 510 """
481 response = toResponse(iq, 'result') 511 response = toResponse(iq, 'result')
482 512
483 prefs = MAMPrefs.parse(iq.prefs) 513 prefs = MAMPrefs.parse(iq.prefs)
484 requestor = jid.JID(iq['from']) 514 requestor = jid.JID(iq['from'])
485 prefs = self.resource.onPrefsSetRequest(prefs, requestor) 515
486 516 def cb(prefs):
487 response.addChild(prefs.toElement()) 517 response.addChild(prefs.toElement())
488 self.xmlstream.send(response) 518 self.xmlstream.send(response)
519
520 self.resource.onPrefsSetRequest(prefs, requestor).addCallback(cb)
489 iq.handled = True 521 iq.handled = True
490 522
491 def getDiscoInfo(self, requestor, target, nodeIdentifier=''): 523 def getDiscoInfo(self, requestor, target, nodeIdentifier=''):
492 return [disco.DiscoFeature(NS_MAM)] 524 return [disco.DiscoFeature(NS_MAM)]
493 525