comparison plugins/plugin_xep_0054.py @ 64:d46f849664aa

SàT: multi-profile, plugins updated - core: 2 new convenient methods: getJidNStream and getClient - new param in plugin info: "handler" to know if there is a handler to plug on profiles clients - plugins with handler now use an other class which is returned to profile client with the new method "getHandler" and pluged when connecting
author Goffi <goffi@goffi.org>
date Sat, 30 Jan 2010 16:17:33 +1100
parents a5b5fb5fc9fd
children 8147b4f40809
comparison
equal deleted inserted replaced
63:0db25931b60d 64:d46f849664aa
56 "import_name": "XEP_0054", 56 "import_name": "XEP_0054",
57 "type": "XEP", 57 "type": "XEP",
58 "protocols": ["XEP-0054", "XEP-0153"], 58 "protocols": ["XEP-0054", "XEP-0153"],
59 "dependencies": [], 59 "dependencies": [],
60 "main": "XEP_0054", 60 "main": "XEP_0054",
61 "handler": "yes",
61 "description": """Implementation of vcard-temp""" 62 "description": """Implementation of vcard-temp"""
62 } 63 }
63 64
64 class XEP_0054(XMPPHandler): 65 class XEP_0054():
65 implements(iwokkel.IDisco)
66 66
67 def __init__(self, host): 67 def __init__(self, host):
68 info("Plugin XEP_0054 initialization") 68 info("Plugin XEP_0054 initialization")
69 self.host = host 69 self.host = host
70 self.avatar_path = os.path.expanduser(self.host.get_const('local_dir') + AVATAR_PATH) 70 self.avatar_path = os.path.expanduser(self.host.get_const('local_dir') + AVATAR_PATH)
71 self.vcard_cache = host.memory.getPrivate("vcard_cache") or {} #used to store nicknames and avatar, key = jid 71 self.vcard_cache = host.memory.getPrivate("vcard_cache") or {} #used to store nicknames and avatar, key = jid
72 if not os.path.exists(self.avatar_path): 72 if not os.path.exists(self.avatar_path):
73 os.makedirs(self.avatar_path) 73 os.makedirs(self.avatar_path)
74 host.bridge.addMethod("getProfile", ".communication", in_sign='s', out_sign='s', method=self.getProfile) 74 host.bridge.addMethod("getCard", ".communication", in_sign='ss', out_sign='s', method=self.getCard)
75 host.bridge.addMethod("getAvatarFile", ".communication", in_sign='s', out_sign='s', method=self.getAvatarFile) 75 host.bridge.addMethod("getAvatarFile", ".communication", in_sign='s', out_sign='s', method=self.getAvatarFile)
76 host.bridge.addMethod("getProfileCache", ".communication", in_sign='s', out_sign='a{ss}', method=self.getProfileCache) 76 host.bridge.addMethod("getCardCache", ".communication", in_sign='s', out_sign='a{ss}', method=self.getCardCache)
77
78 def getHandler(self):
79 return XEP_0054_handler(self)
77 80
78 def update_cache(self, jid, name, value): 81 def update_cache(self, jid, name, value):
79 """update cache value 82 """update cache value
80 - save value in memory in case of change 83 - save value in memory in case of change
81 - send updatedValue signal if the value is new or updated 84 - send updatedValue signal if the value is new or updated
98 try: 101 try:
99 return self.vcard_cache[jid.userhost()][name] 102 return self.vcard_cache[jid.userhost()][name]
100 except KeyError: 103 except KeyError:
101 return None 104 return None
102 105
103
104 def connectionInitialized(self):
105 self.xmlstream.addObserver(VCARD_UPDATE, self.update)
106
107 def getDiscoInfo(self, requestor, target, nodeIdentifier=''):
108 return [disco.DiscoFeature(NS_VCARD)]
109
110 def getDiscoItems(self, requestor, target, nodeIdentifier=''):
111 return []
112 106
113 def save_photo(self, photo_xml): 107 def save_photo(self, photo_xml):
114 """Parse a <PHOTO> elem and save the picture""" 108 """Parse a <PHOTO> elem and save the picture"""
115 for elem in photo_xml.elements(): 109 for elem in photo_xml.elements():
116 if elem.name == 'TYPE': 110 if elem.name == 'TYPE':
175 def vcard_err(self, failure): 169 def vcard_err(self, failure):
176 """Called when something is wrong with registration""" 170 """Called when something is wrong with registration"""
177 error ("Can't find VCard of %s" % failure.value.stanza['from']) 171 error ("Can't find VCard of %s" % failure.value.stanza['from'])
178 self.host.bridge.actionResult("SUPPRESS", failure.value.stanza['id'], {}) #FIXME: maybe an error message would be best 172 self.host.bridge.actionResult("SUPPRESS", failure.value.stanza['id'], {}) #FIXME: maybe an error message would be best
179 173
180 def getProfile(self, target): 174 def getCard(self, target, profile_key='@DEFAULT@'):
181 """Ask server for VCard 175 """Ask server for VCard
182 @param target: jid from which we want the VCard 176 @param target: jid from which we want the VCard
183 @result: id to retrieve the profile""" 177 @result: id to retrieve the profile"""
178 current_jid, xmlstream = self.host.getJidNStream(profile_key)
179 if not xmlstream:
180 error ('Asking profile for an non-existant or not connected profile')
181 return ""
184 to_jid = jid.JID(target) 182 to_jid = jid.JID(target)
185 debug("Asking for %s's VCard" % to_jid.userhost()) 183 debug("Asking for %s's VCard" % to_jid.userhost())
186 reg_request=IQ(self.host.xmlstream,'get') 184 reg_request=IQ(xmlstream,'get')
187 reg_request["from"]=self.host.me.full() 185 reg_request["from"]=current_jid.full()
188 reg_request["to"] = to_jid.userhost() 186 reg_request["to"] = to_jid.userhost()
189 query=reg_request.addElement('vCard', NS_VCARD) 187 query=reg_request.addElement('vCard', NS_VCARD)
190 reg_request.send(to_jid.userhost()).addCallbacks(self.vcard_ok, self.vcard_err) 188 reg_request.send(to_jid.userhost()).addCallbacks(self.vcard_ok, self.vcard_err)
191 return reg_request["id"] 189 return reg_request["id"]
192 190
199 if not os.path.exists(filename): 197 if not os.path.exists(filename):
200 error ("Asking for an uncached avatar [%s]" % hash) 198 error ("Asking for an uncached avatar [%s]" % hash)
201 return "" 199 return ""
202 return filename 200 return filename
203 201
204 def getProfileCache(self, target): 202 def getCardCache(self, target):
205 """Request for cached values of profile 203 """Request for cached values of profile
206 return the cached nickname and avatar if exists, else get VCard 204 return the cached nickname and avatar if exists, else get VCard
207 """ 205 """
208 to_jid = jid.JID(target) 206 to_jid = jid.JID(target)
209 result = {} 207 result = {}
213 avatar = self.get_cache(to_jid, 'avatar') 211 avatar = self.get_cache(to_jid, 'avatar')
214 if avatar: 212 if avatar:
215 result['avatar'] = avatar 213 result['avatar'] = avatar
216 return result 214 return result
217 215
216
217
218 class XEP_0054_handler(XMPPHandler):
219 implements(iwokkel.IDisco)
220
221 def __init__(self, plugin_parent):
222 self.plugin_parent = plugin_parent
223 self.host = plugin_parent.host
224
225 def connectionInitialized(self):
226 self.xmlstream.addObserver(VCARD_UPDATE, self.update)
227
228 def getDiscoInfo(self, requestor, target, nodeIdentifier=''):
229 return [disco.DiscoFeature(NS_VCARD)]
230
231 def getDiscoItems(self, requestor, target, nodeIdentifier=''):
232 return []
233
218 def update(self, presence): 234 def update(self, presence):
219 """Request for VCard's nickname 235 """Request for VCard's nickname
220 return the cached nickname if exists, else get VCard 236 return the cached nickname if exists, else get VCard
221 """ 237 """
222 to_jid = jid.JID(presence['from']) 238 to_jid = jid.JID(presence['from'])
223 x_elem = filter (lambda x:x.name == "x", presence.elements())[0] #We only want the "x" element 239 x_elem = filter (lambda x:x.name == "x", presence.elements())[0] #We only want the "x" element
224 for elem in x_elem.elements(): 240 for elem in x_elem.elements():
225 if elem.name == 'photo': 241 if elem.name == 'photo':
226 hash = str(elem) 242 hash = str(elem)
227 old_avatar = self.get_cache(to_jid, 'avatar') 243 old_avatar = self.plugin_parent.get_cache(to_jid, 'avatar')
228 if not old_avatar or old_avatar != hash: 244 if not old_avatar or old_avatar != hash:
229 debug('New avatar found, requesting vcard') 245 debug('New avatar found, requesting vcard')
230 self.getProfile(to_jid.userhost()) 246 self.plugin_parent.getCard(to_jid.userhost(), self.parent.profile)
231