comparison src/plugins/plugin_xep_0115.py @ 594:e629371a28d3

Fix pep8 support in src/plugins.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Fri, 18 Jan 2013 17:55:35 +0100
parents beaf6bec2fcd
children 84a6e83157c2
comparison
equal deleted inserted replaced
593:70bae685d05c 594:e629371a28d3
40 except ImportError: 40 except ImportError:
41 from wokkel.subprotocols import XMPPHandler 41 from wokkel.subprotocols import XMPPHandler
42 42
43 PRESENCE = '/presence' 43 PRESENCE = '/presence'
44 NS_ENTITY_CAPABILITY = 'http://jabber.org/protocol/caps' 44 NS_ENTITY_CAPABILITY = 'http://jabber.org/protocol/caps'
45 CAPABILITY_UPDATE = PRESENCE + '/c[@xmlns="' + NS_ENTITY_CAPABILITY + '"]' 45 CAPABILITY_UPDATE = PRESENCE + '/c[@xmlns="' + NS_ENTITY_CAPABILITY + '"]'
46 46
47 PLUGIN_INFO = { 47 PLUGIN_INFO = {
48 "name": "XEP 0115 Plugin", 48 "name": "XEP 0115 Plugin",
49 "import_name": "XEP-0115", 49 "import_name": "XEP-0115",
50 "type": "XEP", 50 "type": "XEP",
51 "protocols": ["XEP-0115"], 51 "protocols": ["XEP-0115"],
52 "dependencies": [], 52 "dependencies": [],
53 "main": "XEP_0115", 53 "main": "XEP_0115",
54 "handler": "yes", 54 "handler": "yes",
55 "description": _("""Implementation of entity capabilities""") 55 "description": _("""Implementation of entity capabilities""")
56 } 56 }
57
57 58
58 class HashGenerationError(Exception): 59 class HashGenerationError(Exception):
59 pass 60 pass
61
60 62
61 class ByteIdentity(object): 63 class ByteIdentity(object):
62 """This class manage identity as bytes (needed for i;octet sort), 64 """This class manage identity as bytes (needed for i;octet sort),
63 it is used for the hash generation""" 65 it is used for the hash generation"""
64 66
72 def __str__(self): 74 def __str__(self):
73 return "%s/%s/%s/%s" % (self.category, self.idType, self.lang, self.name) 75 return "%s/%s/%s/%s" % (self.category, self.idType, self.lang, self.name)
74 76
75 77
76 class XEP_0115(object): 78 class XEP_0115(object):
77 cap_hash = None #capabilities hash is class variable as it is common to all profiles 79 cap_hash = None # capabilities hash is class variable as it is common to all profiles
78 #TODO: this code is really dirty, need to clean it and try to move it to Wokkel 80 #TODO: this code is really dirty, need to clean it and try to move it to Wokkel
79 81
80 def __init__(self, host): 82 def __init__(self, host):
81 info(_("Plugin XEP_0115 initialization")) 83 info(_("Plugin XEP_0115 initialization"))
82 self.host = host 84 self.host = host
83 host.trigger.add("Disco Handled", self.checkHash) 85 host.trigger.add("Disco Handled", self.checkHash)
84 self.hash_cache = PersistentBinaryDict(NS_ENTITY_CAPABILITY) #key = hash or jid, value = features 86 self.hash_cache = PersistentBinaryDict(NS_ENTITY_CAPABILITY) # key = hash or jid, value = features
85 self.hash_cache.load() 87 self.hash_cache.load()
86 self.jid_hash = {} #jid to hash mapping, map to a discoInfo features if the hash method is unknown 88 self.jid_hash = {} # jid to hash mapping, map to a discoInfo features if the hash method is unknown
87 89
88 def checkHash(self, profile): 90 def checkHash(self, profile):
89 if not XEP_0115.cap_hash: 91 if not XEP_0115.cap_hash:
90 XEP_0115.cap_hash = self.generateHash(profile) 92 XEP_0115.cap_hash = self.generateHash(profile)
91 else: 93 else:
95 def getHandler(self, profile): 97 def getHandler(self, profile):
96 return XEP_0115_handler(self, profile) 98 return XEP_0115_handler(self, profile)
97 99
98 def presenceHack(self, profile): 100 def presenceHack(self, profile):
99 """modify SatPresenceProtocol to add capabilities data""" 101 """modify SatPresenceProtocol to add capabilities data"""
100 client=self.host.getClient(profile) 102 client = self.host.getClient(profile)
101 presenceInst = client.presence 103 presenceInst = client.presence
102 c_elt = domish.Element((NS_ENTITY_CAPABILITY,'c')) 104 c_elt = domish.Element((NS_ENTITY_CAPABILITY, 'c'))
103 c_elt['hash']='sha-1' 105 c_elt['hash'] = 'sha-1'
104 c_elt['node']='http://wiki.goffi.org/wiki/Salut_%C3%A0_Toi' 106 c_elt['node'] = 'http://wiki.goffi.org/wiki/Salut_%C3%A0_Toi'
105 c_elt['ver']=XEP_0115.cap_hash 107 c_elt['ver'] = XEP_0115.cap_hash
106 presenceInst._c_elt = c_elt 108 presenceInst._c_elt = c_elt
107 if "_legacy_send" in dir(presenceInst): 109 if "_legacy_send" in dir(presenceInst):
108 debug('capabilities already added to presence instance') 110 debug('capabilities already added to presence instance')
109 return 111 return
112
110 def hacked_send(self, obj): 113 def hacked_send(self, obj):
111 obj.addChild(self._c_elt) 114 obj.addChild(self._c_elt)
112 self._legacy_send(obj) 115 self._legacy_send(obj)
113 new_send = types.MethodType(hacked_send, presenceInst, presenceInst.__class__) 116 new_send = types.MethodType(hacked_send, presenceInst, presenceInst.__class__)
114 presenceInst._legacy_send = presenceInst.send 117 presenceInst._legacy_send = presenceInst.send
115 presenceInst.send = new_send 118 presenceInst.send = new_send
116 119
117
118 def generateHash(self, profile_key="@DEFAULT@"): 120 def generateHash(self, profile_key="@DEFAULT@"):
119 """This method generate a sha1 hash as explained in xep-0115 #5.1 121 """This method generate a sha1 hash as explained in xep-0115 #5.1
120 it then store it in XEP_0115.cap_hash""" 122 it then store it in XEP_0115.cap_hash"""
121 profile = self.host.memory.getProfileName(profile_key) 123 profile = self.host.memory.getProfileName(profile_key)
122 if not profile: 124 if not profile:
123 error ('Requesting hash for an inexistant profile') 125 error('Requesting hash for an inexistant profile')
124 raise HashGenerationError 126 raise HashGenerationError
125 127
126 client = self.host.getClient(profile_key) 128 client = self.host.getClient(profile_key)
127 if not client: 129 if not client:
128 error ('Requesting hash for an inexistant client') 130 error('Requesting hash for an inexistant client')
129 raise HashGenerationError 131 raise HashGenerationError
130 132
131 def generateHash_2(services, profile): 133 def generateHash_2(services, profile):
132 _s=[] 134 _s = []
133 byte_identities = [ByteIdentity(identity) for identity in filter(lambda x:isinstance(x,disco.DiscoIdentity),services)] #FIXME: lang must be managed here 135 byte_identities = [ByteIdentity(identity) for identity in filter(lambda x: isinstance(x, disco.DiscoIdentity), services)] # FIXME: lang must be managed here
134 byte_identities.sort(key=lambda i:i.lang) 136 byte_identities.sort(key=lambda i: i.lang)
135 byte_identities.sort(key=lambda i:i.idType) 137 byte_identities.sort(key=lambda i: i.idType)
136 byte_identities.sort(key=lambda i:i.category) 138 byte_identities.sort(key=lambda i: i.category)
137 for identity in byte_identities: 139 for identity in byte_identities:
138 _s.append(str(identity)) 140 _s.append(str(identity))
139 _s.append('<') 141 _s.append('<')
140 byte_features = [feature.encode('utf-8') for feature in filter(lambda x:isinstance(x,disco.DiscoFeature),services)] 142 byte_features = [feature.encode('utf-8') for feature in filter(lambda x: isinstance(x, disco.DiscoFeature), services)]
141 byte_features.sort() #XXX: the default sort has the same behaviour as the requested RFC 4790 i;octet sort 143 byte_features.sort() # XXX: the default sort has the same behaviour as the requested RFC 4790 i;octet sort
142 for feature in byte_features: 144 for feature in byte_features:
143 _s.append(feature) 145 _s.append(feature)
144 _s.append('<') 146 _s.append('<')
145 #TODO: manage XEP-0128 data form here 147 #TODO: manage XEP-0128 data form here
146 XEP_0115.cap_hash = b64encode(sha1(''.join(_s)).digest()) 148 XEP_0115.cap_hash = b64encode(sha1(''.join(_s)).digest())
147 debug(_('Capability hash generated: [%s]') % XEP_0115.cap_hash) 149 debug(_('Capability hash generated: [%s]') % XEP_0115.cap_hash)
148 self.presenceHack(profile) 150 self.presenceHack(profile)
149 151
150 services = client.discoHandler.info(client.jid, client.jid, '').addCallback(generateHash_2, profile) 152 services = client.discoHandler.info(client.jid, client.jid, '').addCallback(generateHash_2, profile)
153
151 154
152 class XEP_0115_handler(XMPPHandler): 155 class XEP_0115_handler(XMPPHandler):
153 implements(iwokkel.IDisco) 156 implements(iwokkel.IDisco)
154 157
155 def __init__(self, plugin_parent, profile): 158 def __init__(self, plugin_parent, profile):
174 self.plugin_parent.hash_cache[key] = discoResult.features 177 self.plugin_parent.hash_cache[key] = discoResult.features
175 else: 178 else:
176 #No key, that means unknown hash method 179 #No key, that means unknown hash method
177 self.plugin_parent.jid_hash[from_jid] = discoResult.features 180 self.plugin_parent.jid_hash[from_jid] = discoResult.features
178 181
179
180 def update(self, presence): 182 def update(self, presence):
181 """ 183 """
182 Manage the capabilities of the entity 184 Manage the capabilities of the entity
183 Check if we know the version of this capatilities 185 Check if we know the version of this capatilities
184 and get the capibilities if necessary 186 and get the capibilities if necessary
185 """ 187 """
186 from_jid = jid.JID(presence['from']) 188 from_jid = jid.JID(presence['from'])
187 c_elem = filter (lambda x:x.name == "c", presence.elements())[0] #We only want the "c" element 189 c_elem = filter(lambda x: x.name == "c", presence.elements())[0] # We only want the "c" element
188 try: 190 try:
189 ver=c_elem['ver'] 191 ver = c_elem['ver']
190 hash=c_elem['hash'] 192 hash = c_elem['hash']
191 node=c_elem['node'] 193 node = c_elem['node']
192 except KeyError: 194 except KeyError:
193 warning('Received invalid capabilities tag') 195 warning('Received invalid capabilities tag')
194 return 196 return
195 if not from_jid in self.plugin_parent.jid_hash: 197 if not from_jid in self.plugin_parent.jid_hash:
196 if ver in self.plugin_parent.hash_cache: 198 if ver in self.plugin_parent.hash_cache:
197 #we know that hash, we just link it with the jid 199 #we know that hash, we just link it with the jid
198 self.plugin_parent.jid_hash[from_jid] = ver 200 self.plugin_parent.jid_hash[from_jid] = ver
199 else: 201 else:
200 if hash!='sha-1': 202 if hash != 'sha-1':
201 #unknown hash method 203 #unknown hash method
202 warning('Unknown hash for entity capabilities: [%s]' % hash) 204 warning('Unknown hash for entity capabilities: [%s]' % hash)
203 self.parent.disco.requestInfo(from_jid).addCallback(self._updateCache, from_jid, ver if hash=='sha-1' else None ) 205 self.parent.disco.requestInfo(from_jid).addCallback(self._updateCache, from_jid, ver if hash == 'sha-1' else None)
204 #TODO: me must manage the full algorithm described at XEP-0115 #5.4 part 3 206 #TODO: me must manage the full algorithm described at XEP-0115 #5.4 part 3
205