1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 """Jabber Service Discovery support.
19
20 Normative reference:
21 - `JEP 30 <http://www.jabber.org/jeps/jep-0030.html>`__
22 """
23
24 __revision__="$Id: disco.py 714 2010-04-05 10:20:10Z jajcus $"
25 __docformat__="restructuredtext en"
26
27 import warnings
28
29 import libxml2
30
31 from pyxmpp.xmlextra import common_doc,common_root
32 from pyxmpp.jid import JID
33 from pyxmpp import cache
34
35 from pyxmpp.utils import to_utf8
36 from pyxmpp.objects import StanzaPayloadWrapperObject
37 from pyxmpp.exceptions import ProtocolError
38
39 DISCO_NS="http://jabber.org/protocol/disco"
40 DISCO_ITEMS_NS=DISCO_NS+"#items"
41 DISCO_INFO_NS=DISCO_NS+"#info"
42
44 """An item of disco#items reply.
45
46 :Ivariables:
47 - `jid`: the JID of the item.
48 - `node`: node name of the item.
49 - `name`: name of the item.
50 - `action`: action of the item.
51 - `disco`: the disco reply this is the part of.
52 - `xmlnode`: XML element describing the item.
53 :Types:
54 - `jid`: `JID`
55 - `node`: `unicode`
56 - `name`: `unicode`
57 - `action`: `unicode`
58 - `disco`: `DiscoItems`
59 - `xmlnode`: `libxml2.xmlNode`
60 """
61 - def __init__(self,disco,xmlnode_or_jid,node=None,name=None,action=None):
62 """Initialize an `DiscoItem` object.
63
64 :Parameters:
65 - `disco`: the disco#items reply `self` is a part of.
66 - `xmlnode_or_jid`: XML element describing the item or the JID of
67 the item.
68 - `node`: disco node of the item.
69 - `name`: name of the item.
70 - `action`: 'action' attribute of the item.
71 :Types:
72 - `disco`: `DiscoItems`
73 - `xmlnode_or_jid`: `libxml2.xmlNode` or `JID`
74 - `node`: `unicode`
75 - `name`: `unicode`
76 - `action`: `unicode`
77 """
78 self.disco=disco
79 if isinstance(xmlnode_or_jid,JID):
80 if disco:
81 self.xmlnode=disco.xmlnode.newChild(None,"item",None)
82 else:
83 self.xmlnode=common_root.newChild(None,"item",None)
84 ns=self.xmlnode.newNs(DISCO_ITEMS_NS,None)
85 self.xmlnode.setNs(ns)
86 self.set_jid(xmlnode_or_jid)
87 self.set_name(name)
88 self.set_node(node)
89 self.set_action(action)
90 else:
91 if disco is None:
92 self.xmlnode=xmlnode_or_jid.copyNode(1)
93 else:
94 self.xmlnode=xmlnode_or_jid
95 if name:
96 self.set_name(name)
97 if node:
98 self.set_node(node)
99 if action:
100 self.set_action(action)
101 self.xpath_ctxt=common_doc.xpathNewContext()
102 self.xpath_ctxt.setContextNode(self.xmlnode)
103 self.xpath_ctxt.xpathRegisterNs("d",DISCO_ITEMS_NS)
104
106 if self.disco is None:
107 if self.xmlnode:
108 self.xmlnode.unlinkNode()
109 self.xmlnode.freeNode()
110 self.xmlnode=None
111 if self.xpath_ctxt:
112 self.xpath_ctxt.xpathFreeContext()
113
116
118 """Remove `self` from the containing `DiscoItems` object."""
119 if self.disco is None:
120 return
121 self.xmlnode.unlinkNode()
122 oldns=self.xmlnode.ns()
123 ns=self.xmlnode.newNs(oldns.getContent(),None)
124 self.xmlnode.replaceNs(oldns,ns)
125 common_root.addChild(self.xmlnode())
126 self.disco=None
127
129 """Get the name of the item.
130
131 :return: the name of the item or `None`.
132 :returntype: `unicode`"""
133 name = self.xmlnode.prop("name")
134 if name is None:
135 return None
136 return name.decode("utf-8")
137
139 """Set the name of the item.
140
141 :Parameters:
142 - `name`: the new name or `None`.
143 :Types:
144 - `name`: `unicode` """
145 if name is None:
146 if self.xmlnode.hasProp("name"):
147 self.xmlnode.unsetProp("name")
148 return
149 name = unicode(name)
150 self.xmlnode.setProp("name", name.encode("utf-8"))
151
152 name = property(get_name, set_name)
153
155 """Get the node of the item.
156
157 :return: the node of the item or `None`.
158 :returntype: `unicode`"""
159 node = self.xmlnode.prop("node")
160 if node is None:
161 return None
162 return node.decode("utf-8")
163
165 """Set the node of the item.
166
167 :Parameters:
168 - `node`: the new node or `None`.
169 :Types:
170 - `node`: `unicode`
171 """
172 if node is None:
173 if self.xmlnode.hasProp("node"):
174 self.xmlnode.unsetProp("node")
175 return
176 node = unicode(node)
177 self.xmlnode.setProp("node", node.encode("utf-8"))
178
179 node = property(get_node, set_node)
180
182 """Get the action attribute of the item.
183
184 :return: the action of the item or `None`.
185 :returntype: `unicode`"""
186 action=self.xmlnode.prop("action")
187 if action is None:
188 return None
189 return action.decode("utf-8")
190
192 """Set the action of the item.
193
194 :Parameters:
195 - `action`: the new action or `None`.
196 :Types:
197 - `action`: `unicode`
198 """
199 if action is None:
200 if self.xmlnode.hasProp("action"):
201 self.xmlnode.unsetProp("action")
202 return
203 if action not in ("remove","update"):
204 raise ValueError, "Action must be 'update' or 'remove'"
205 action = unicode(action)
206 self.xmlnode.setProp("action", action.encode("utf-8"))
207
208 action = property(get_action, set_action)
209
211 """Get the JID of the item.
212
213 :return: the JID of the item.
214 :returntype: `JID`"""
215 jid = self.xmlnode.prop("jid")
216 return JID( jid.decode("utf-8") )
217
219 """Set the JID of the item.
220
221 :Parameters:
222 - `jid`: the new jid.
223 :Types:
224 - `jid`: `JID`
225 """
226 self.xmlnode.setProp("jid", jid.as_unicode().encode("utf-8"))
227
228 jid = property(get_jid, set_jid)
229
231 """An <identity/> element of disco#info reply.
232
233 Identifies an item by its name, category and type.
234
235 :Ivariables:
236 - `disco`: the disco reply this is the part of.
237 - `xmlnode`: XML element describing the identity.
238 :Types:
239 - `disco`: `DiscoInfo`
240 - `xmlnode`: `libxml2.xmlNode`
241 """
242 - def __init__(self, disco, xmlnode_or_name, item_category=None, item_type=None, replace=False):
243 """Initialize an `DiscoIdentity` object.
244
245 :Parameters:
246 - `disco`: the disco#info reply `self` is a part of.
247 - `xmlnode_or_name`: XML element describing the identity or the
248 name of the item described.
249 - `item_category`: category of the item described.
250 - `item_type`: type of the item described.
251 - `replace`: if `True` than all other <identity/> elements in
252 `disco` will be removed.
253 :Types:
254 - `disco`: `DiscoItems`
255 - `xmlnode_or_name`: `libxml2.xmlNode` or `unicode`
256 - `item_category`: `unicode`
257 - `item_type`: `unicode`
258 - `replace`: `bool`
259 """
260 self.disco=disco
261 if disco and replace:
262 old=disco.xpath_ctxt.xpathEval("d:identity")
263 if old:
264 for n in old:
265 n.unlinkNode()
266 n.freeNode()
267 if isinstance(xmlnode_or_name,libxml2.xmlNode):
268 if disco is None:
269 self.xmlnode=xmlnode_or_name.copyNode(1)
270 else:
271 self.xmlnode=xmlnode_or_name
272 elif not item_category:
273 raise ValueError,"DiscoInfo requires category"
274 elif not item_type:
275 raise ValueError,"DiscoInfo requires type"
276 else:
277 if disco:
278 self.xmlnode=disco.xmlnode.newChild(None,"identity",None)
279 else:
280 self.xmlnode=common_root.newChild(None,"identity",None)
281 ns=self.xmlnode.newNs(DISCO_INFO_NS,None)
282 self.xmlnode.setNs(ns)
283 self.set_name(xmlnode_or_name)
284 self.set_category(item_category)
285 self.set_type(item_type)
286 self.xpath_ctxt=common_doc.xpathNewContext()
287 self.xpath_ctxt.setContextNode(self.xmlnode)
288 self.xpath_ctxt.xpathRegisterNs("d",DISCO_INFO_NS)
289
291 if self.disco is None:
292 if self.xmlnode:
293 self.xmlnode.unlinkNode()
294 self.xmlnode.freeNode()
295 self.xmlnode=None
296 if self.xpath_ctxt:
297 self.xpath_ctxt.xpathFreeContext()
298
301
303 """Remove `self` from the containing `DiscoInfo` object."""
304 if self.disco is None:
305 return
306 self.xmlnode.unlinkNode()
307 oldns=self.xmlnode.ns()
308 ns=self.xmlnode.newNs(oldns.getContent(),None)
309 self.xmlnode.replaceNs(oldns,ns)
310 common_root.addChild(self.xmlnode())
311 self.disco=None
312
314 """Get the name of the item.
315
316 :return: the name of the item or `None`.
317 :returntype: `unicode`"""
318 var = self.xmlnode.prop("name")
319 if not var:
320 var = ""
321 return var.decode("utf-8")
322
324 """Set the name of the item.
325
326 :Parameters:
327 - `name`: the new name or `None`.
328 :Types:
329 - `name`: `unicode` """
330 if not name:
331 raise ValueError, "name is required in DiscoIdentity"
332 name = unicode(name)
333 self.xmlnode.setProp("name", name.encode("utf-8"))
334
335 name = property(get_name, set_name)
336
338 """Get the category of the item.
339
340 :return: the category of the item.
341 :returntype: `unicode`"""
342 var = self.xmlnode.prop("category")
343 if not var:
344 var = "?"
345 return var.decode("utf-8")
346
348 """Set the category of the item.
349
350 :Parameters:
351 - `category`: the new category.
352 :Types:
353 - `category`: `unicode` """
354 if not category:
355 raise ValueError, "Category is required in DiscoIdentity"
356 category = unicode(category)
357 self.xmlnode.setProp("category", category.encode("utf-8"))
358
359 category = property(get_category, set_category)
360
362 """Get the type of the item.
363
364 :return: the type of the item.
365 :returntype: `unicode`"""
366 item_type = self.xmlnode.prop("type")
367 if not item_type:
368 item_type = "?"
369 return item_type.decode("utf-8")
370
372 """Set the type of the item.
373
374 :Parameters:
375 - `item_type`: the new type.
376 :Types:
377 - `item_type`: `unicode` """
378 if not item_type:
379 raise ValueError,"Type is required in DiscoIdentity"
380 item_type = unicode(item_type)
381 self.xmlnode.setProp("type", item_type.encode("utf-8"))
382
383 type = property(get_type, set_type)
384
386 """A disco#items response or publish-request object.
387
388 :Ivariables:
389 - `node`: node name of the disco#items element.
390 - `items`: items in the disco#items element.
391 - `xmlnode`: XML element listing the items.
392 :Types:
393 - `node`: `unicode`
394 - `items`: `tuple` of `DiscoItem`
395 - `xmlnode`: `libxml2.xmlNode`
396 """
397 - def __init__(self,xmlnode_or_node=None):
398 """Initialize an `DiscoItems` object.
399
400 Wrap an existing disco#items XML element or create a new one.
401
402 :Parameters:
403 - `xmlnode_or_node`: XML node to be wrapped into `self` or an item
404 node name.
405 :Types:
406 - `xmlnode_or_node`: `libxml2.xmlNode` or `unicode`"""
407 self.xmlnode=None
408 self.xpath_ctxt=None
409 if isinstance(xmlnode_or_node,libxml2.xmlNode):
410 ns=xmlnode_or_node.ns()
411 if ns.getContent() != DISCO_ITEMS_NS:
412 raise ValueError, "Bad disco-items namespace"
413 self.xmlnode=xmlnode_or_node.docCopyNode(common_doc,1)
414 common_root.addChild(self.xmlnode)
415 self.ns=self.xmlnode.ns()
416 else:
417 self.xmlnode=common_root.newChild(None,"query",None)
418 self.ns=self.xmlnode.newNs(DISCO_ITEMS_NS,None)
419 self.xmlnode.setNs(self.ns)
420 self.set_node(xmlnode_or_node)
421 self.xpath_ctxt=common_doc.xpathNewContext()
422 self.xpath_ctxt.setContextNode(self.xmlnode)
423 self.xpath_ctxt.xpathRegisterNs("d",DISCO_ITEMS_NS)
424
426 if self.xmlnode:
427 self.xmlnode.unlinkNode()
428 self.xmlnode.freeNode()
429 self.xmlnode=None
430 if self.xpath_ctxt:
431 self.xpath_ctxt.xpathFreeContext()
432 self.xpath_ctxt=None
433
435 """Get the node address of the `DiscoItems` object.
436
437 :return: the node name.
438 :returntype: `unicode`"""
439 node = self.xmlnode.prop("node")
440 if not node:
441 return None
442 return node.decode("utf-8")
443
445 """Set the node of the disco#item element.
446
447 :Parameters:
448 - `node`: the new node or `None`.
449 :Types:
450 - `node`: `unicode`
451 """
452 if node is None:
453 if self.xmlnode.hasProp("node"):
454 self.xmlnode.unsetProp("node")
455 return
456 node = unicode(node)
457 self.xmlnode.setProp("node", node.encode("utf-8"))
458
459 node = property(get_node, set_node)
460
462 """Get the items contained in `self`.
463
464 :return: the items contained.
465 :returntype: `list` of `DiscoItem`"""
466 ret=[]
467 l=self.xpath_ctxt.xpathEval("d:item")
468 if l is not None:
469 for i in l:
470 ret.append(DiscoItem(self, i))
471 return ret
472
474 """Set items in the disco#items object.
475
476 All previous items are removed.
477
478 :Parameters:
479 - `item_list`: list of items or item properties
480 (jid,node,name,action).
481 :Types:
482 - `item_list`: sequence of `DiscoItem` or sequence of sequences
483 """
484 for item in self.items:
485 item.remove()
486 for item in item_list:
487 try:
488 self.add_item(item.jid,item.node,item.name,item.action)
489 except AttributeError:
490 self.add_item(*item)
491
492 items = property(get_items, set_items, doc = "List of `DiscoItems`")
493
495 """Clear cached item list."""
496 warnings.warn("DiscoItems.invalidate_items() is deprecated and not needed any more.", DeprecationWarning, stacklevel=1)
497
498 - def add_item(self,jid,node=None,name=None,action=None):
499 """Add a new item to the `DiscoItems` object.
500
501 :Parameters:
502 - `jid`: item JID.
503 - `node`: item node name.
504 - `name`: item name.
505 - `action`: action for a "disco push".
506 :Types:
507 - `jid`: `pyxmpp.JID`
508 - `node`: `unicode`
509 - `name`: `unicode`
510 - `action`: `unicode`
511
512 :returns: the item created.
513 :returntype: `DiscoItem`."""
514 return DiscoItem(self,jid,node,name,action)
515
517 """Check if `self` contains an item.
518
519 :Parameters:
520 - `jid`: JID of the item.
521 - `node`: node name of the item.
522 :Types:
523 - `jid`: `JID`
524 - `node`: `libxml2.xmlNode`
525
526 :return: `True` if the item is found in `self`.
527 :returntype: `bool`"""
528 l=self.xpath_ctxt.xpathEval("d:item")
529 if l is None:
530 return False
531 for it in l:
532 di=DiscoItem(self,it)
533 if di.jid==jid and di.node==node:
534 return True
535 return False
536
538 """A disco#info response object.
539
540 :Ivariables:
541 - `node`: node name of the disco#info element (cached).
542 - `identities`: identities in the disco#info object.
543 - `features`: features in the disco#info object.
544 - `xmlnode`: XML element listing the items.
545 :Types:
546 - `node`: `unicode`
547 - `identities`: `tuple` of `DiscoIdentity`
548 - `features`: `tuple` of `unicode`
549 - `xmlnode`: `libxml2.xmlNode`
550 """
551 - def __init__(self,xmlnode_or_node=None, parent=None, doc=None):
552 """Initialize an `DiscoInfo` object.
553
554 Wrap an existing disco#info XML element or create a new one.
555
556 :Parameters:
557 - `xmlnode_or_node`: XML node to be wrapped into `self` or an item
558 node name.
559 - `parent`: parent node for the `DiscoInfo` element.
560 - `doc`: document for the `DiscoInfo` element.
561 :Types:
562 - `xmlnode_or_node`: `libxml2.xmlNode` or `unicode`
563 - `parent`: `libxml2.xmlNode`
564 - `doc`: `libxml2.xmlDoc`
565 """
566 self.xmlnode=None
567 self.xpath_ctxt=None
568 if not doc:
569 doc=common_doc
570 if not parent:
571 parent=common_root
572 if isinstance(xmlnode_or_node,libxml2.xmlNode):
573 ns=xmlnode_or_node.ns()
574 if ns.getContent() != DISCO_INFO_NS:
575 raise ValueError, "Bad disco-info namespace"
576 self.xmlnode=xmlnode_or_node.docCopyNode(doc,1)
577 parent.addChild(self.xmlnode)
578 else:
579 self.xmlnode=parent.newChild(None,"query",None)
580 self.ns=self.xmlnode.newNs(DISCO_INFO_NS,None)
581 self.xmlnode.setNs(self.ns)
582 self.set_node(xmlnode_or_node)
583
584 self.xpath_ctxt=doc.xpathNewContext()
585 self.xpath_ctxt.setContextNode(self.xmlnode)
586 self.xpath_ctxt.xpathRegisterNs("d",DISCO_INFO_NS)
587
589 if self.xmlnode:
590 self.xmlnode.unlinkNode()
591 self.xmlnode.freeNode()
592 self.xmlnode=None
593 if self.xpath_ctxt:
594 self.xpath_ctxt.xpathFreeContext()
595 self.xpath_ctxt=None
596
598 """Get the node address of the `DiscoInfo` object.
599
600 :return: the node name.
601 :returntype: `unicode`"""
602
603 node=self.xmlnode.prop("node")
604 if not node:
605 return None
606 return node.decode("utf-8")
607
609 """Set the node of the disco#info element.
610
611 :Parameters:
612 - `node`: the new node or `None`.
613 :Types:
614 - `node`: `unicode`
615 """
616 if node is None:
617 if self.xmlnode.hasProp("node"):
618 self.xmlnode.unsetProp("node")
619 return
620 node = unicode(node)
621 self.xmlnode.setProp("node", node.encode("utf-8"))
622
623 node = property(get_node, set_node)
624
626 """Get the features contained in `self`.
627
628 :return: the list of features.
629 :returntype: `list` of `unicode`"""
630 l = self.xpath_ctxt.xpathEval("d:feature")
631 ret = []
632 for f in l:
633 if f.hasProp("var"):
634 ret.append( f.prop("var").decode("utf-8") )
635 return ret
636
638 """Set features in the disco#info object.
639
640 All existing features are removed from `self`.
641
642 :Parameters:
643 - `features`: list of features.
644 :Types:
645 - `features`: sequence of `unicode`
646 """
647 for var in self.features:
648 self.remove_feature(var)
649
650 for var in features:
651 self.add_feature(var)
652
653 features = property(get_features, set_features)
654
656 """Check if `self` contains the named feature.
657
658 :Parameters:
659 - `var`: the feature name.
660 :Types:
661 - `var`: `unicode`
662
663 :return: `True` if the feature is found in `self`.
664 :returntype: `bool`"""
665 if not var:
666 raise ValueError,"var is None"
667 if '"' not in var:
668 expr=u'd:feature[@var="%s"]' % (var,)
669 elif "'" not in var:
670 expr=u"d:feature[@var='%s']" % (var,)
671 else:
672 raise ValueError, "Invalid feature name"
673
674 l=self.xpath_ctxt.xpathEval(to_utf8(expr))
675 if l:
676 return True
677 else:
678 return False
679
681 """Clear cached feature list."""
682 warnings.warn("DiscoInfo.invalidate_features() is deprecated and not needed any more.", DeprecationWarning, stacklevel=1)
683
685 """Add a feature to `self`.
686
687 :Parameters:
688 - `var`: the feature name.
689 :Types:
690 - `var`: `unicode`"""
691 if self.has_feature(var):
692 return
693 n=self.xmlnode.newChild(None, "feature", None)
694 n.setProp("var", to_utf8(var))
695
697 """Remove a feature from `self`.
698
699 :Parameters:
700 - `var`: the feature name.
701 :Types:
702 - `var`: `unicode`"""
703 if not var:
704 raise ValueError,"var is None"
705 if '"' not in var:
706 expr='d:feature[@var="%s"]' % (var,)
707 elif "'" not in var:
708 expr="d:feature[@var='%s']" % (var,)
709 else:
710 raise ValueError, "Invalid feature name"
711
712 l=self.xpath_ctxt.xpathEval(expr)
713 if not l:
714 return
715
716 for f in l:
717 f.unlinkNode()
718 f.freeNode()
719
721 """List the identity objects contained in `self`.
722
723 :return: the list of identities.
724 :returntype: `list` of `DiscoIdentity`"""
725 ret=[]
726 l=self.xpath_ctxt.xpathEval("d:identity")
727 if l is not None:
728 for i in l:
729 ret.append(DiscoIdentity(self,i))
730 return ret
731
733 """Set identities in the disco#info object.
734
735 Remove all existing identities from `self`.
736
737 :Parameters:
738 - `identities`: list of identities or identity properties
739 (jid,node,category,type,name).
740 :Types:
741 - `identities`: sequence of `DiscoIdentity` or sequence of sequences
742 """
743 for identity in self.identities:
744 identity.remove()
745 for identity in identities:
746 try:
747 self.add_identity(identity.name,identity.category,identity.type)
748 except AttributeError:
749 self.add_identity(*identity)
750
751 identities = property(get_identities, set_identities)
752
754 """Check if the item described by `self` belongs to the given category
755 and type.
756
757 :Parameters:
758 - `item_category`: the category name.
759 - `item_type`: the type name. If `None` then only the category is
760 checked.
761 :Types:
762 - `item_category`: unicode
763 - `item_type`: unicode
764
765 :return: `True` if `self` contains at least one <identity/> object with
766 given type and category.
767 :returntype: `bool`"""
768 if not item_category:
769 raise ValueError, "bad category"
770 if not item_type:
771 type_expr=u""
772 elif '"' not in item_type:
773 type_expr=u' and @type="%s"' % (item_type,)
774 elif "'" not in type:
775 type_expr=u" and @type='%s'" % (item_type,)
776 else:
777 raise ValueError, "Invalid type name"
778 if '"' not in item_category:
779 expr=u'd:identity[@category="%s"%s]' % (item_category,type_expr)
780 elif "'" not in item_category:
781 expr=u"d:identity[@category='%s'%s]" % (item_category,type_expr)
782 else:
783 raise ValueError, "Invalid category name"
784
785 l=self.xpath_ctxt.xpathEval(to_utf8(expr))
786 if l:
787 return True
788 else:
789 return False
790
792 """Clear cached identity list."""
793 warnings.warn("DiscoInfo.invalidate_identities() is deprecated and not needed any more.", DeprecationWarning, stacklevel=1)
794
795 - def add_identity(self,item_name,item_category=None,item_type=None):
796 """Add an identity to the `DiscoInfo` object.
797
798 :Parameters:
799 - `item_name`: name of the item.
800 - `item_category`: category of the item.
801 - `item_type`: type of the item.
802 :Types:
803 - `item_name`: `unicode`
804 - `item_category`: `unicode`
805 - `item_type`: `unicode`
806
807 :returns: the identity created.
808 :returntype: `DiscoIdentity`"""
809 return DiscoIdentity(self,item_name,item_category,item_type)
810
812 """Base class for disco cache fetchers.
813
814 :Cvariables:
815 - `stream`: stream used by the fetcher.
816 - `disco_class`: disco class to be used (`DiscoInfo` or `DiscoItems`).
817 :Types:
818 - `stream`: `pyxmpp.stream.Stream`
819 - `disco_class`: `classobj`
820 """
821 stream=None
822 disco_class=None
833
835 """Handle successful disco response.
836
837 :Parameters:
838 - `stanza`: the stanza received.
839 :Types:
840 - `stanza`: `pyxmpp.stanza.Stanza`"""
841 try:
842 d=self.disco_class(stanza.get_query())
843 self.got_it(d)
844 except ValueError,e:
845 self.error(e)
846
859
861 """Handle disco timeout."""
862 pass
863
865 """Register Service Discovery cache fetchers into given
866 cache suite and using the stream provided.
867
868 :Parameters:
869 - `cache_suite`: the cache suite where the fetchers are to be
870 registered.
871 - `stream`: the stream to be used by the fetchers.
872 :Types:
873 - `cache_suite`: `cache.CacheSuite`
874 - `stream`: `pyxmpp.stream.Stream`
875 """
876 tmp=stream
877 class DiscoInfoCacheFetcher(DiscoCacheFetcherBase):
878 """Cache fetcher for DiscoInfo."""
879 stream=tmp
880 disco_class=DiscoInfo
881 class DiscoItemsCacheFetcher(DiscoCacheFetcherBase):
882 """Cache fetcher for DiscoItems."""
883 stream=tmp
884 disco_class=DiscoItems
885 cache_suite.register_fetcher(DiscoInfo,DiscoInfoCacheFetcher)
886 cache_suite.register_fetcher(DiscoItems,DiscoItemsCacheFetcher)
887
888
889