Package pyxmpp :: Package jabber :: Module disco
[hide private]

Source Code for Module pyxmpp.jabber.disco

  1  # 
  2  # (C) Copyright 2003-2006 Jacek Konieczny <jajcus@jajcus.net> 
  3  # 
  4  # This program is free software; you can redistribute it and/or modify 
  5  # it under the terms of the GNU Lesser General Public License Version 
  6  # 2.1 as published by the Free Software Foundation. 
  7  # 
  8  # This program is distributed in the hope that it will be useful, 
  9  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 10  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 11  # GNU Lesser General Public License for more details. 
 12  # 
 13  # You should have received a copy of the GNU Lesser General Public 
 14  # License along with this program; if not, write to the Free Software 
 15  # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
 16  # 
 17  # pylint: disable-msg=W0201 
 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 666 2006-12-03 15:40:54Z 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   
43 -class DiscoItem(StanzaPayloadWrapperObject):
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
105 - def __del__(self):
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
114 - def __str__(self):
115 return self.xmlnode.serialize()
116
117 - def remove(self):
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
128 - def get_name(self):
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
138 - def set_name(self, name):
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
154 - def get_node(self):
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
164 - def set_node(self,node):
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
181 - def get_action(self):
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
191 - def set_action(self,action):
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
210 - def get_jid(self):
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
218 - def set_jid(self,jid):
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
230 -class DiscoIdentity(StanzaPayloadWrapperObject):
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
290 - def __del__(self):
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
299 - def __str__(self):
300 return self.xmlnode.serialize()
301
302 - def remove(self):
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
313 - def get_name(self):
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
323 - def set_name(self,name):
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
337 - def get_category(self):
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
347 - def set_category(self, category):
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
361 - def get_type(self):
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
371 - def set_type(self, item_type):
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
385 -class DiscoItems(StanzaPayloadWrapperObject):
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
425 - def __del__(self):
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
434 - def get_node(self):
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
444 - def set_node(self, node):
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
461 - def get_items(self):
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
473 - def set_items(self, item_list):
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
494 - def invalidate_items(self):
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
516 - def has_item(self,jid,node=None):
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
537 -class DiscoInfo(StanzaPayloadWrapperObject):
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
588 - def __del__(self):
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
597 - def get_node(self):
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
608 - def set_node(self,node):
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
625 - def get_features(self):
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
637 - def set_features(self, features):
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
655 - def has_feature(self,var):
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
680 - def invalidate_features(self):
681 """Clear cached feature list.""" 682 warnings.warn("DiscoInfo.invalidate_features() is deprecated and not needed any more.", DeprecationWarning, stacklevel=1)
683
684 - def add_feature(self,var):
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
696 - def remove_feature(self,var):
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
720 - def get_identities(self):
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
732 - def set_identities(self,identities):
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
753 - def identity_is(self,item_category,item_type=None):
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
791 - def invalidate_identities(self):
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
811 -class DiscoCacheFetcherBase(cache.CacheFetcher):
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
823 - def fetch(self):
824 """Initialize the Service Discovery process.""" 825 from pyxmpp.iq import Iq 826 jid,node = self.address 827 iq = Iq(to_jid = jid, stanza_type = "get") 828 disco = self.disco_class(node) 829 iq.add_content(disco.xmlnode) 830 self.stream.set_response_handlers(iq,self.__response, self.__error, 831 self.__timeout) 832 self.stream.send(iq)
833
834 - def __response(self,stanza):
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
847 - def __error(self,stanza):
848 """Handle disco error response. 849 850 :Parameters: 851 - `stanza`: the stanza received. 852 :Types: 853 - `stanza`: `pyxmpp.stanza.Stanza`""" 854 try: 855 self.error(stanza.get_error()) 856 except ProtocolError: 857 from pyxmpp.error import StanzaErrorNode 858 self.error(StanzaErrorNode("undefined-condition"))
859
860 - def __timeout(self,stanza):
861 """Handle disco timeout.""" 862 pass
863
864 -def register_disco_cache_fetchers(cache_suite,stream):
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 # vi: sts=4 et sw=4 889