Welcome to mirror list, hosted at ThFree Co, Russian Federation.

dev.gajim.org/gajim/python-nbxmpp.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlovetox <philipp@hoerist.com>2020-08-02 14:29:31 +0300
committerlovetox <philipp@hoerist.com>2020-09-23 00:28:00 +0300
commit1b5bfca911f1fc13d382f833eedbef230df3e075 (patch)
tree3eff6d777cc8d204be6a674e589535b83ff338cf
parent397d7c5abe0d8b75351047f8d1e429f0fad34a45 (diff)
Add VCard Temp (XEP-0054) support
-rw-r--r--nbxmpp/dispatcher.py2
-rw-r--r--nbxmpp/modules/vcard_temp.py143
2 files changed, 145 insertions, 0 deletions
diff --git a/nbxmpp/dispatcher.py b/nbxmpp/dispatcher.py
index 0dbc5a7..678f26f 100644
--- a/nbxmpp/dispatcher.py
+++ b/nbxmpp/dispatcher.py
@@ -75,6 +75,7 @@ from nbxmpp.modules.chatstates import Chatstates
from nbxmpp.modules.register import Register
from nbxmpp.modules.http_upload import HTTPUpload
from nbxmpp.modules.mam import MAM
+from nbxmpp.modules.vcard_temp import VCardTemp
from nbxmpp.modules.misc import unwrap_carbon
from nbxmpp.modules.misc import unwrap_mam
from nbxmpp.structs import StanzaTimeoutError
@@ -180,6 +181,7 @@ class StanzaDispatcher(Observable):
self._modules['Register'] = Register(self._client)
self._modules['HTTPUpload'] = HTTPUpload(self._client)
self._modules['MAM'] = MAM(self._client)
+ self._modules['VCardTemp'] = VCardTemp(self._client)
for instance in self._modules.values():
for handler in instance.handlers:
diff --git a/nbxmpp/modules/vcard_temp.py b/nbxmpp/modules/vcard_temp.py
new file mode 100644
index 0000000..7d3483b
--- /dev/null
+++ b/nbxmpp/modules/vcard_temp.py
@@ -0,0 +1,143 @@
+# Copyright (C) 2020 Philipp Hörist <philipp AT hoerist.com>
+#
+# This file is part of nbxmpp.
+#
+# 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 3
+# of the License, 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+import hashlib
+from dataclasses import dataclass
+from dataclasses import field
+
+from nbxmpp.task import iq_request_task
+from nbxmpp.util import b64decode
+from nbxmpp.util import b64encode
+from nbxmpp.errors import StanzaError
+from nbxmpp.errors import MalformedStanzaError
+from nbxmpp.protocol import Iq
+from nbxmpp.simplexml import Node
+from nbxmpp.namespaces import Namespace
+from nbxmpp.modules.base import BaseModule
+from nbxmpp.modules.util import process_response
+
+
+class VCardTemp(BaseModule):
+ def __init__(self, client):
+ BaseModule.__init__(self, client)
+
+ self._client = client
+ self.handlers = []
+
+ @iq_request_task
+ def request_vcard(self, jid=None):
+ _task = yield
+
+ response = yield _make_vcard_request(jid)
+
+ if response.isError():
+ raise StanzaError(response)
+
+ vcard_node = _get_vcard_node(response)
+ yield VCard.from_node(vcard_node)
+
+ @iq_request_task
+ def set_vcard(self, vcard, jid=None):
+ _task = yield
+
+ response = yield _make_vcard_publish(jid, vcard)
+ yield process_response(response)
+
+
+def _make_vcard_request(jid):
+ iq = Iq(typ='get', to=jid)
+ iq.addChild('vCard', namespace=Namespace.VCARD)
+ return iq
+
+
+def _get_vcard_node(response):
+ vcard_node = response.getTag('vCard', namespace=Namespace.VCARD)
+ if vcard_node is None:
+ raise MalformedStanzaError('vCard node missing', response)
+ return vcard_node
+
+
+def _make_vcard_publish(jid, vcard):
+ iq = Iq(typ='set', to=jid)
+ iq.addChild(node=vcard.to_node())
+ return iq
+
+
+@dataclass
+class VCard:
+ data: dict = field(default_factory=dict)
+
+ @classmethod
+ def from_node(cls, node):
+ dict_ = {}
+ for info in node.getChildren():
+ name = info.getName()
+ if name in ('ADR', 'TEL', 'EMAIL'):
+ dict_.setdefault(name, [])
+ entry = {}
+ for child in info.getChildren():
+ entry[child.getName()] = child.getData()
+ dict_[name].append(entry)
+ elif info.getChildren() == []:
+ dict_[name] = info.getData()
+ else:
+ dict_[name] = {}
+ for child in info.getChildren():
+ dict_[name][child.getName()] = child.getData()
+
+ return cls(data=dict_)
+
+ def to_node(self):
+ vcard = Node(tag='vCard', attrs={'xmlns': Namespace.VCARD})
+ for i in self.data:
+ if i == 'jid':
+ continue
+ if isinstance(self.data[i], dict):
+ child = vcard.addChild(i)
+ for j in self.data[i]:
+ child.addChild(j).setData(self.data[i][j])
+ elif isinstance(self.data[i], list):
+ for j in self.data[i]:
+ child = vcard.addChild(i)
+ for k in j:
+ child.addChild(k).setData(j[k])
+ else:
+ vcard.addChild(i).setData(self.data[i])
+ return vcard
+
+ def set_avatar(self, avatar, type_=None):
+ avatar = b64encode(avatar)
+ if 'PHOTO' not in self.data:
+ self.data['PHOTO'] = {}
+
+ self.data['PHOTO']['BINVAL'] = avatar
+
+ if type_ is not None:
+ self.data['PHOTO']['TYPE'] = type_
+
+ def get_avatar(self):
+ try:
+ avatar = self.data['PHOTO']['BINVAL']
+ except Exception:
+ return None, None
+
+ if not avatar:
+ return None, None
+
+ avatar = b64decode(avatar, return_type=bytes)
+ avatar_sha = hashlib.sha1(avatar).hexdigest()
+ return avatar, avatar_sha