roster.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. """
  2. SleekXMPP: The Sleek XMPP Library
  3. Copyright (C) 2010 Nathanael C. Fritz
  4. This file is part of SleekXMPP.
  5. See the file LICENSE for copying permission.
  6. """
  7. from sleekxmpp.stanza import Iq
  8. from sleekxmpp.xmlstream import JID
  9. from sleekxmpp.xmlstream import ET, ElementBase, register_stanza_plugin
  10. class Roster(ElementBase):
  11. """
  12. Example roster stanzas:
  13. <iq type="set">
  14. <query xmlns="jabber:iq:roster">
  15. <item jid="user@example.com" subscription="both" name="User">
  16. <group>Friends</group>
  17. </item>
  18. </query>
  19. </iq>
  20. Stanza Inteface:
  21. items -- A dictionary of roster entries contained
  22. in the stanza.
  23. Methods:
  24. get_items -- Return a dictionary of roster entries.
  25. set_items -- Add <item> elements.
  26. del_items -- Remove all <item> elements.
  27. """
  28. namespace = 'jabber:iq:roster'
  29. name = 'query'
  30. plugin_attrib = 'roster'
  31. interfaces = set(('items', 'ver'))
  32. def get_ver(self):
  33. """
  34. Ensure handling an empty ver attribute propery.
  35. The ver attribute is special in that the presence of the
  36. attribute with an empty value is important for boostrapping
  37. roster versioning.
  38. """
  39. return self.xml.attrib.get('ver', None)
  40. def set_ver(self, ver):
  41. """
  42. Ensure handling an empty ver attribute propery.
  43. The ver attribute is special in that the presence of the
  44. attribute with an empty value is important for boostrapping
  45. roster versioning.
  46. """
  47. if ver is not None:
  48. self.xml.attrib['ver'] = ver
  49. else:
  50. del self.xml.attrib['ver']
  51. def set_items(self, items):
  52. """
  53. Set the roster entries in the <roster> stanza.
  54. Uses a dictionary using JIDs as keys, where each entry is itself
  55. a dictionary that contains:
  56. name -- An alias or nickname for the JID.
  57. subscription -- The subscription type. Can be one of 'to',
  58. 'from', 'both', 'none', or 'remove'.
  59. groups -- A list of group names to which the JID
  60. has been assigned.
  61. Arguments:
  62. items -- A dictionary of roster entries.
  63. """
  64. self.del_items()
  65. for jid in items:
  66. item = RosterItem()
  67. item.values = items[jid]
  68. item['jid'] = jid
  69. self.append(item)
  70. return self
  71. def get_items(self):
  72. """
  73. Return a dictionary of roster entries.
  74. Each item is keyed using its JID, and contains:
  75. name -- An assigned alias or nickname for the JID.
  76. subscription -- The subscription type. Can be one of 'to',
  77. 'from', 'both', 'none', or 'remove'.
  78. groups -- A list of group names to which the JID has
  79. been assigned.
  80. """
  81. items = {}
  82. for item in self['substanzas']:
  83. if isinstance(item, RosterItem):
  84. items[item['jid']] = item.values
  85. # Remove extra JID reference to keep everything
  86. # backward compatible
  87. del items[item['jid']]['jid']
  88. del items[item['jid']]['lang']
  89. return items
  90. def del_items(self):
  91. """
  92. Remove all <item> elements from the roster stanza.
  93. """
  94. for item in self['substanzas']:
  95. if isinstance(item, RosterItem):
  96. self.xml.remove(item.xml)
  97. class RosterItem(ElementBase):
  98. namespace = 'jabber:iq:roster'
  99. name = 'item'
  100. plugin_attrib = 'item'
  101. interfaces = set(('jid', 'name', 'subscription', 'ask',
  102. 'approved', 'groups'))
  103. def get_jid(self):
  104. return JID(self._get_attr('jid', ''))
  105. def set_jid(self, jid):
  106. self._set_attr('jid', str(jid))
  107. def get_groups(self):
  108. groups = []
  109. for group in self.xml.findall('{%s}group' % self.namespace):
  110. if group.text:
  111. groups.append(group.text)
  112. else:
  113. groups.append('')
  114. return groups
  115. def set_groups(self, values):
  116. self.del_groups()
  117. for group in values:
  118. group_xml = ET.Element('{%s}group' % self.namespace)
  119. group_xml.text = group
  120. self.xml.append(group_xml)
  121. def del_groups(self):
  122. for group in self.xml.findall('{%s}group' % self.namespace):
  123. self.xml.remove(group)
  124. register_stanza_plugin(Iq, Roster)
  125. register_stanza_plugin(Roster, RosterItem, iterable=True)
  126. # To comply with PEP8, method names now use underscores.
  127. # Deprecated method names are re-mapped for backwards compatibility.
  128. Roster.setItems = Roster.set_items
  129. Roster.getItems = Roster.get_items
  130. Roster.delItems = Roster.del_items