diff options
Diffstat (limited to 'xmpp/roster.py')
-rw-r--r-- | xmpp/roster.py | 564 |
1 files changed, 282 insertions, 282 deletions
diff --git a/xmpp/roster.py b/xmpp/roster.py index b91000e..5d4209a 100644 --- a/xmpp/roster.py +++ b/xmpp/roster.py @@ -1,282 +1,282 @@ -## roster.py
-##
-## Copyright (C) 2003-2005 Alexey "Snake" Nezhdanov
-##
-## This program is free software; you can redistribute it and/or modify
-## it under the terms of the GNU General Public License as published by
-## the Free Software Foundation; either version 2, or (at your option)
-## any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-## GNU General Public License for more details.
-
-# $Id: roster.py, v1.21 2013/10/21 alkorgun Exp $
-
-"""
-Simple roster implementation. Can be used though for different tasks like
-mass-renaming of contacts.
-"""
-
-from .plugin import PlugIn
-from .protocol import *
-
-class Roster(PlugIn):
- """
- Defines a plenty of methods that will allow you to manage roster.
- Also automatically track presences from remote JIDs taking into
- account that every JID can have multiple resources connected. Does not
- currently support "error" presences.
- You can also use mapping interface for access to the internal representation of
- contacts in roster.
- """
- def __init__(self):
- """
- Init internal variables.
- """
- PlugIn.__init__(self)
- self.DBG_LINE = "roster"
- self._data = {}
- self.set = None
- self._exported_methods = [self.getRoster]
-
- def plugin(self, owner, request=1):
- """
- Register presence and subscription trackers in the owner's dispatcher.
- Also request roster from server if the "request" argument is set.
- Used internally.
- """
- self._owner.RegisterHandler("iq", self.RosterIqHandler, "result", NS_ROSTER)
- self._owner.RegisterHandler("iq", self.RosterIqHandler, "set", NS_ROSTER)
- self._owner.RegisterHandler("presence", self.PresenceHandler)
- if request:
- self.Request()
-
- def Request(self, force=0):
- """
- Request roster from server if it were not yet requested
- (or if the "force" argument is set).
- """
- if self.set is None:
- self.set = 0
- elif not force:
- return None
- self._owner.send(Iq("get", NS_ROSTER))
- self.DEBUG("Roster requested from server", "start")
-
- def getRoster(self):
- """
- Requests roster from server if neccessary and returns self.
- """
- if not self.set:
- self.Request()
- while not self.set:
- self._owner.Process(10)
- return self
-
- def RosterIqHandler(self, dis, stanza):
- """
- Subscription tracker. Used internally for setting items state in
- internal roster representation.
- """
- if not stanza or not stanza.getTag("query"):
- raise NodeProcessed()
- for item in stanza.getTag("query").getTags("item"):
- jid = item.getAttr("jid")
- if item.getAttr("subscription") == "remove":
- if jid in self._data:
- del self._data[jid]
- raise NodeProcessed() # a MUST
- self.DEBUG("Setting roster item %s..." % jid, "ok")
- if jid not in self._data:
- self._data[jid] = {}
- self._data[jid]["name"] = item.getAttr("name")
- self._data[jid]["ask"] = item.getAttr("ask")
- self._data[jid]["subscription"] = item.getAttr("subscription")
- self._data[jid]["groups"] = []
- if "resources" not in self._data[jid]:
- self._data[jid]["resources"] = {}
- for group in item.getTags("group"):
- self._data[jid]["groups"].append(group.getData())
- self._data["@".join((self._owner.User, self._owner.Server))] = {"resources": {}, "name": None, "ask": None, "subscription": None, "groups": None, }
- self.set = 1
- raise NodeProcessed() # a MUST. Otherwise you'll get back an <iq type='error'/>
-
- def PresenceHandler(self, dis, pres):
- """
- Presence tracker. Used internally for setting items' resources state in
- internal roster representation.
- """
- jid = JID(pres.getFrom())
- if jid.getStripped() not in self._data:
- self._data[jid.getStripped()] = {"name": None, "ask": None, "subscription": "none", "groups": ["Not in roster"], "resources": {}}
- item = self._data[jid.getStripped()]
- typ = pres.getType()
- if not typ:
- self.DEBUG("Setting roster item %s for resource %s..." % (jid.getStripped(), jid.getResource()), "ok")
- item["resources"][jid.getResource()] = res = {"show": None, "status": None, "priority": "0", "timestamp": None}
- if pres.getTag("show"):
- res["show"] = pres.getShow()
- if pres.getTag("status"):
- res["status"] = pres.getStatus()
- if pres.getTag("priority"):
- res["priority"] = pres.getPriority()
- if not pres.getTimestamp():
- pres.setTimestamp()
- res["timestamp"] = pres.getTimestamp()
- elif typ == "unavailable" and jid.getResource() in item["resources"]:
- del item["resources"][jid.getResource()]
- # Need to handle type="error" also
-
- def _getItemData(self, jid, dataname):
- """
- Return specific jid's representation in internal format. Used internally.
- """
- jid = jid[:(jid + "/").find("/")]
- return self._data[jid][dataname]
-
- def _getResourceData(self, jid, dataname):
- """
- Return specific jid's resource representation in internal format. Used internally.
- """
- if jid.find("/") + 1:
- jid, resource = jid.split("/", 1)
- if resource in self._data[jid]["resources"]:
- return self._data[jid]["resources"][resource][dataname]
- elif self._data[jid]["resources"].keys():
- lastpri = -129
- for r in self._data[jid]["resources"].keys():
- if int(self._data[jid]["resources"][r]["priority"]) > lastpri:
- resource, lastpri = r, int(self._data[jid]["resources"][r]["priority"])
- return self._data[jid]["resources"][resource][dataname]
-
- def delItem(self, jid):
- """
- Delete contact "jid" from roster.
- """
- self._owner.send(Iq("set", NS_ROSTER, payload=[Node("item", {"jid": jid, "subscription": "remove"})]))
-
- def getAsk(self, jid):
- """
- Returns "ask" value of contact "jid".
- """
- return self._getItemData(jid, "ask")
-
- def getGroups(self, jid):
- """
- Returns groups list that contact "jid" belongs to.
- """
- return self._getItemData(jid, "groups")
-
- def getName(self, jid):
- """
- Returns name of contact "jid".
- """
- return self._getItemData(jid, "name")
-
- def getPriority(self, jid):
- """
- Returns priority of contact "jid". "jid" should be a full (not bare) JID.
- """
- return self._getResourceData(jid, "priority")
-
- def getRawRoster(self):
- """
- Returns roster representation in internal format.
- """
- return self._data
-
- def getRawItem(self, jid):
- """
- Returns roster item "jid" representation in internal format.
- """
- return self._data[jid[:(jid + "/").find("/")]]
-
- def getShow(self, jid):
- """
- Returns "show" value of contact "jid". "jid" should be a full (not bare) JID.
- """
- return self._getResourceData(jid, "show")
-
- def getStatus(self, jid):
- """
- Returns "status" value of contact "jid". "jid" should be a full (not bare) JID.
- """
- return self._getResourceData(jid, "status")
-
- def getSubscription(self, jid):
- """
- Returns "subscription" value of contact "jid".
- """
- return self._getItemData(jid, "subscription")
-
- def getResources(self, jid):
- """
- Returns list of connected resources of contact "jid".
- """
- return self._data[jid[:(jid + "/").find("/")]]["resources"].keys()
-
- def setItem(self, jid, name=None, groups=[]):
- """
- Creates/renames contact "jid" and sets the groups list that it now belongs to.
- """
- iq = Iq("set", NS_ROSTER)
- query = iq.getTag("query")
- attrs = {"jid": jid}
- if name:
- attrs["name"] = name
- item = query.setTag("item", attrs)
- for group in groups:
- item.addChild(node=Node("group", payload=[group]))
- self._owner.send(iq)
-
- def getItems(self):
- """
- Return list of all [bare] JIDs that the roster is currently tracks.
- """
- return self._data.keys()
-
- def keys(self):
- """
- Same as getItems. Provided for the sake of dictionary interface.
- """
- return self._data.keys()
-
- def __getitem__(self, item):
- """
- Get the contact in the internal format. Raises KeyError if JID "item" is not in roster.
- """
- return self._data[item]
-
- def getItem(self, item):
- """
- Get the contact in the internal format (or None if JID "item" is not in roster).
- """
- if item in self._data:
- return self._data[item]
-
- def Subscribe(self, jid):
- """
- Send subscription request to JID "jid".
- """
- self._owner.send(Presence(jid, "subscribe"))
-
- def Unsubscribe(self, jid):
- """
- Ask for removing our subscription for JID "jid".
- """
- self._owner.send(Presence(jid, "unsubscribe"))
-
- def Authorize(self, jid):
- """
- Authorise JID "jid". Works only if these JID requested auth previously.
- """
- self._owner.send(Presence(jid, "subscribed"))
-
- def Unauthorize(self, jid):
- """
- Unauthorise JID "jid". Use for declining authorisation request
- or for removing existing authorization.
- """
- self._owner.send(Presence(jid, "unsubscribed"))
+## roster.py +## +## Copyright (C) 2003-2005 Alexey "Snake" Nezhdanov +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2, or (at your option) +## any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. + +# $Id: roster.py, v1.21 2013/10/21 alkorgun Exp $ + +""" +Simple roster implementation. Can be used though for different tasks like +mass-renaming of contacts. +""" + +from .plugin import PlugIn +from .protocol import * + +class Roster(PlugIn): + """ + Defines a plenty of methods that will allow you to manage roster. + Also automatically track presences from remote JIDs taking into + account that every JID can have multiple resources connected. Does not + currently support "error" presences. + You can also use mapping interface for access to the internal representation of + contacts in roster. + """ + def __init__(self): + """ + Init internal variables. + """ + PlugIn.__init__(self) + self.DBG_LINE = "roster" + self._data = {} + self.set = None + self._exported_methods = [self.getRoster] + + def plugin(self, owner, request=1): + """ + Register presence and subscription trackers in the owner's dispatcher. + Also request roster from server if the "request" argument is set. + Used internally. + """ + self._owner.RegisterHandler("iq", self.RosterIqHandler, "result", NS_ROSTER) + self._owner.RegisterHandler("iq", self.RosterIqHandler, "set", NS_ROSTER) + self._owner.RegisterHandler("presence", self.PresenceHandler) + if request: + self.Request() + + def Request(self, force=0): + """ + Request roster from server if it were not yet requested + (or if the "force" argument is set). + """ + if self.set is None: + self.set = 0 + elif not force: + return None + self._owner.send(Iq("get", NS_ROSTER)) + self.DEBUG("Roster requested from server", "start") + + def getRoster(self): + """ + Requests roster from server if neccessary and returns self. + """ + if not self.set: + self.Request() + while not self.set: + self._owner.Process(10) + return self + + def RosterIqHandler(self, dis, stanza): + """ + Subscription tracker. Used internally for setting items state in + internal roster representation. + """ + if not stanza or not stanza.getTag("query"): + raise NodeProcessed() + for item in stanza.getTag("query").getTags("item"): + jid = item.getAttr("jid") + if item.getAttr("subscription") == "remove": + if jid in self._data: + del self._data[jid] + raise NodeProcessed() # a MUST + self.DEBUG("Setting roster item %s..." % jid, "ok") + if jid not in self._data: + self._data[jid] = {} + self._data[jid]["name"] = item.getAttr("name") + self._data[jid]["ask"] = item.getAttr("ask") + self._data[jid]["subscription"] = item.getAttr("subscription") + self._data[jid]["groups"] = [] + if "resources" not in self._data[jid]: + self._data[jid]["resources"] = {} + for group in item.getTags("group"): + self._data[jid]["groups"].append(group.getData()) + self._data["@".join((self._owner.User, self._owner.Server))] = {"resources": {}, "name": None, "ask": None, "subscription": None, "groups": None, } + self.set = 1 + raise NodeProcessed() # a MUST. Otherwise you'll get back an <iq type='error'/> + + def PresenceHandler(self, dis, pres): + """ + Presence tracker. Used internally for setting items' resources state in + internal roster representation. + """ + jid = JID(pres.getFrom()) + if jid.getStripped() not in self._data: + self._data[jid.getStripped()] = {"name": None, "ask": None, "subscription": "none", "groups": ["Not in roster"], "resources": {}} + item = self._data[jid.getStripped()] + typ = pres.getType() + if not typ: + self.DEBUG("Setting roster item %s for resource %s..." % (jid.getStripped(), jid.getResource()), "ok") + item["resources"][jid.getResource()] = res = {"show": None, "status": None, "priority": "0", "timestamp": None} + if pres.getTag("show"): + res["show"] = pres.getShow() + if pres.getTag("status"): + res["status"] = pres.getStatus() + if pres.getTag("priority"): + res["priority"] = pres.getPriority() + if not pres.getTimestamp(): + pres.setTimestamp() + res["timestamp"] = pres.getTimestamp() + elif typ == "unavailable" and jid.getResource() in item["resources"]: + del item["resources"][jid.getResource()] + # Need to handle type="error" also + + def _getItemData(self, jid, dataname): + """ + Return specific jid's representation in internal format. Used internally. + """ + jid = jid[:(jid + "/").find("/")] + return self._data[jid][dataname] + + def _getResourceData(self, jid, dataname): + """ + Return specific jid's resource representation in internal format. Used internally. + """ + if jid.find("/") + 1: + jid, resource = jid.split("/", 1) + if resource in self._data[jid]["resources"]: + return self._data[jid]["resources"][resource][dataname] + elif self._data[jid]["resources"].keys(): + lastpri = -129 + for r in self._data[jid]["resources"].keys(): + if int(self._data[jid]["resources"][r]["priority"]) > lastpri: + resource, lastpri = r, int(self._data[jid]["resources"][r]["priority"]) + return self._data[jid]["resources"][resource][dataname] + + def delItem(self, jid): + """ + Delete contact "jid" from roster. + """ + self._owner.send(Iq("set", NS_ROSTER, payload=[Node("item", {"jid": jid, "subscription": "remove"})])) + + def getAsk(self, jid): + """ + Returns "ask" value of contact "jid". + """ + return self._getItemData(jid, "ask") + + def getGroups(self, jid): + """ + Returns groups list that contact "jid" belongs to. + """ + return self._getItemData(jid, "groups") + + def getName(self, jid): + """ + Returns name of contact "jid". + """ + return self._getItemData(jid, "name") + + def getPriority(self, jid): + """ + Returns priority of contact "jid". "jid" should be a full (not bare) JID. + """ + return self._getResourceData(jid, "priority") + + def getRawRoster(self): + """ + Returns roster representation in internal format. + """ + return self._data + + def getRawItem(self, jid): + """ + Returns roster item "jid" representation in internal format. + """ + return self._data[jid[:(jid + "/").find("/")]] + + def getShow(self, jid): + """ + Returns "show" value of contact "jid". "jid" should be a full (not bare) JID. + """ + return self._getResourceData(jid, "show") + + def getStatus(self, jid): + """ + Returns "status" value of contact "jid". "jid" should be a full (not bare) JID. + """ + return self._getResourceData(jid, "status") + + def getSubscription(self, jid): + """ + Returns "subscription" value of contact "jid". + """ + return self._getItemData(jid, "subscription") + + def getResources(self, jid): + """ + Returns list of connected resources of contact "jid". + """ + return self._data[jid[:(jid + "/").find("/")]]["resources"].keys() + + def setItem(self, jid, name=None, groups=[]): + """ + Creates/renames contact "jid" and sets the groups list that it now belongs to. + """ + iq = Iq("set", NS_ROSTER) + query = iq.getTag("query") + attrs = {"jid": jid} + if name: + attrs["name"] = name + item = query.setTag("item", attrs) + for group in groups: + item.addChild(node=Node("group", payload=[group])) + self._owner.send(iq) + + def getItems(self): + """ + Return list of all [bare] JIDs that the roster is currently tracks. + """ + return self._data.keys() + + def keys(self): + """ + Same as getItems. Provided for the sake of dictionary interface. + """ + return self._data.keys() + + def __getitem__(self, item): + """ + Get the contact in the internal format. Raises KeyError if JID "item" is not in roster. + """ + return self._data[item] + + def getItem(self, item): + """ + Get the contact in the internal format (or None if JID "item" is not in roster). + """ + if item in self._data: + return self._data[item] + + def Subscribe(self, jid): + """ + Send subscription request to JID "jid". + """ + self._owner.send(Presence(jid, "subscribe")) + + def Unsubscribe(self, jid): + """ + Ask for removing our subscription for JID "jid". + """ + self._owner.send(Presence(jid, "unsubscribe")) + + def Authorize(self, jid): + """ + Authorise JID "jid". Works only if these JID requested auth previously. + """ + self._owner.send(Presence(jid, "subscribed")) + + def Unauthorize(self, jid): + """ + Unauthorise JID "jid". Use for declining authorisation request + or for removing existing authorization. + """ + self._owner.send(Presence(jid, "unsubscribed")) |