Mercurial > libervia-backend
comparison plugins/plugin_xep_0054.py @ 42:874de3020e1c
Initial VCard (XEP-0054) support + misc fixes
- new xep-0054 plugin, avatar are cached, new getProfile bridge method
- gateways plugin (XEP-0100): new __private__ key in resulting data, used to keep target jid
author | Goffi <goffi@goffi.org> |
---|---|
date | Mon, 21 Dec 2009 13:22:11 +1100 |
parents | |
children | 8a438a6ff587 |
comparison
equal
deleted
inserted
replaced
41:d24629c631fc | 42:874de3020e1c |
---|---|
1 #!/usr/bin/python | |
2 # -*- coding: utf-8 -*- | |
3 | |
4 """ | |
5 SAT plugin for managing xep-0054 | |
6 Copyright (C) 2009 Jérôme Poisson (goffi@goffi.org) | |
7 | |
8 This program is free software: you can redistribute it and/or modify | |
9 it under the terms of the GNU General Public License as published by | |
10 the Free Software Foundation, either version 3 of the License, or | |
11 (at your option) any later version. | |
12 | |
13 This program is distributed in the hope that it will be useful, | |
14 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 GNU General Public License for more details. | |
17 | |
18 You should have received a copy of the GNU General Public License | |
19 along with this program. If not, see <http://www.gnu.org/licenses/>. | |
20 """ | |
21 | |
22 from logging import debug, info, error | |
23 from twisted.words.xish import domish | |
24 from twisted.internet import protocol, defer, threads, reactor | |
25 from twisted.words.protocols.jabber import client, jid, xmlstream | |
26 from twisted.words.protocols.jabber import error as jab_error | |
27 from twisted.words.protocols.jabber.xmlstream import IQ | |
28 import os.path | |
29 import pdb | |
30 | |
31 from zope.interface import implements | |
32 | |
33 from wokkel import disco, iwokkel | |
34 | |
35 from base64 import b64decode | |
36 from hashlib import sha1 | |
37 from time import sleep | |
38 | |
39 AVATAR_PATH = "/avatars" | |
40 | |
41 IQ_GET = '/iq[@type="get"]' | |
42 NS_VCARD = 'vcard-temp' | |
43 VCARD_REQUEST = IQ_GET + '/si[@xmlns="' + NS_VCARD + '"]' #TODO: manage requests | |
44 | |
45 PLUGIN_INFO = { | |
46 "name": "XEP 0054 Plugin", | |
47 "import_name": "XEP_0054", | |
48 "type": "XEP", | |
49 "dependencies": [], | |
50 "main": "XEP_0054", | |
51 "description": """Implementation of vcard-temp""" | |
52 } | |
53 | |
54 class XEP_0054(): | |
55 implements(iwokkel.IDisco) | |
56 | |
57 def __init__(self, host): | |
58 info("Plugin XEP_0054 initialization") | |
59 self.host = host | |
60 self.avatar_path = os.path.expanduser(self.host.get_const('local_dir') + AVATAR_PATH) | |
61 if not os.path.exists(self.avatar_path): | |
62 os.makedirs(self.avatar_path) | |
63 host.bridge.addMethod("getProfile", ".communication", in_sign='s', out_sign='s', method=self.getProfile) | |
64 | |
65 def getDiscoInfo(self, requestor, target, nodeIdentifier=''): | |
66 return [disco.DiscoFeature(NS_VCARD)] | |
67 | |
68 def getDiscoItems(self, requestor, target, nodeIdentifier=''): | |
69 return [] | |
70 | |
71 def save_photo(self, photo_xml): | |
72 """Parse a <PHOTO> elem and save the picture""" | |
73 print "save_photo result" | |
74 for elem in photo_xml.elements(): | |
75 if elem.name == 'TYPE': | |
76 info('Photo of type [%s] found' % str(elem)) | |
77 if elem.name == 'BINVAL': | |
78 debug('Decoding binary') | |
79 decoded = b64decode(str(elem)) | |
80 hash = sha1(decoded).hexdigest() | |
81 filename = self.avatar_path+'/'+hash | |
82 if not os.path.exists(filename): | |
83 with open(filename,'wb') as file: | |
84 file.write(decoded) | |
85 debug("file saved to %s" % hash) | |
86 else: | |
87 debug("file [%s] already in cache" % hash) | |
88 return hash | |
89 | |
90 @defer.deferredGenerator | |
91 def vCard2Dict(self, vcard): | |
92 """Convert a VCard to a dict, and save binaries""" | |
93 debug ("parsing vcard") | |
94 dictionary = {} | |
95 d = defer.Deferred() | |
96 | |
97 for elem in vcard.elements(): | |
98 if elem.name == 'FN': | |
99 dictionary['fullname'] = unicode(elem) | |
100 elif elem.name == 'NICKNAME': | |
101 dictionary['nick'] = unicode(elem) | |
102 elif elem.name == 'URL': | |
103 dictionary['website'] = unicode(elem) | |
104 elif elem.name == 'EMAIL': | |
105 dictionary['email'] = unicode(elem) | |
106 elif elem.name == 'BDAY': | |
107 dictionary['birthday'] = unicode(elem) | |
108 elif elem.name == 'PHOTO': | |
109 debug('photo deferred') | |
110 d2 = defer.waitForDeferred( | |
111 threads.deferToThread(self.save_photo, elem)) | |
112 yield d2 | |
113 dictionary["photo"] = d2.getResult() | |
114 else: | |
115 info ('FIXME: [%s] VCard tag is not managed yet' % elem.name) | |
116 | |
117 yield dictionary | |
118 | |
119 def vcard_ok(self, answer): | |
120 """Called after the first get IQ""" | |
121 debug ("VCard found") | |
122 | |
123 if answer.firstChildElement().name == "vCard": | |
124 d = self.vCard2Dict(answer.firstChildElement()) | |
125 d.addCallback(lambda data: self.host.bridge.actionResult("RESULT", answer['id'], data)) | |
126 else: | |
127 error ("FIXME: vCard not found as first child element") | |
128 self.host.bridge.actionResult("SUPPRESS", answer['id'], {}) #FIXME: maybe an error message would be best | |
129 | |
130 def vcard_err(self, failure): | |
131 """Called when something is wrong with registration""" | |
132 error ("Can't find VCard of %s" % failure.value.stanza['from']) | |
133 self.host.bridge.actionResult("SUPPRESS", failure.value.stanza['id'], {}) #FIXME: maybe an error message would be best | |
134 | |
135 def getProfile(self, target): | |
136 """Ask server for VCard | |
137 @param target: jid from which we want the VCard | |
138 @result: id to retrieve the profile""" | |
139 to_jid = jid.JID(target) | |
140 debug("Asking for %s's VCard" % to_jid.full()) | |
141 reg_request=IQ(self.host.xmlstream,'get') | |
142 reg_request["from"]=self.host.me.full() | |
143 reg_request["to"] = to_jid.full() | |
144 query=reg_request.addElement('vCard', NS_VCARD) | |
145 reg_request.send(to_jid.full()).addCallbacks(self.vcard_ok, self.vcard_err) | |
146 return reg_request["id"] | |
147 |