slidge 0.1.2__py3-none-any.whl → 0.2.0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- slidge/__init__.py +3 -5
- slidge/__main__.py +2 -197
- slidge/__version__.py +5 -0
- slidge/command/adhoc.py +40 -17
- slidge/command/admin.py +24 -12
- slidge/command/base.py +10 -8
- slidge/command/categories.py +13 -3
- slidge/command/chat_command.py +29 -2
- slidge/command/register.py +32 -16
- slidge/command/user.py +106 -13
- slidge/contact/contact.py +254 -50
- slidge/contact/roster.py +124 -53
- slidge/core/config.py +19 -13
- slidge/core/dispatcher/__init__.py +3 -0
- slidge/core/{gateway → dispatcher}/caps.py +12 -8
- slidge/core/{gateway → dispatcher}/disco.py +10 -18
- slidge/core/dispatcher/message/__init__.py +10 -0
- slidge/core/dispatcher/message/chat_state.py +40 -0
- slidge/core/dispatcher/message/marker.py +62 -0
- slidge/core/dispatcher/message/message.py +397 -0
- slidge/core/dispatcher/muc/__init__.py +12 -0
- slidge/core/dispatcher/muc/admin.py +98 -0
- slidge/core/{gateway → dispatcher/muc}/mam.py +25 -17
- slidge/core/dispatcher/muc/misc.py +121 -0
- slidge/core/dispatcher/muc/owner.py +96 -0
- slidge/core/{gateway → dispatcher/muc}/ping.py +11 -17
- slidge/core/dispatcher/presence.py +176 -0
- slidge/core/dispatcher/registration.py +85 -0
- slidge/core/{gateway → dispatcher}/search.py +9 -16
- slidge/core/dispatcher/session_dispatcher.py +84 -0
- slidge/core/dispatcher/util.py +174 -0
- slidge/core/{gateway/vcard_temp.py → dispatcher/vcard.py} +35 -19
- slidge/core/{gateway/base.py → gateway.py} +176 -153
- slidge/core/mixins/__init__.py +11 -1
- slidge/core/mixins/attachment.py +106 -67
- slidge/core/mixins/avatar.py +94 -25
- slidge/core/mixins/base.py +10 -4
- slidge/core/mixins/db.py +18 -0
- slidge/core/mixins/disco.py +0 -10
- slidge/core/mixins/lock.py +10 -8
- slidge/core/mixins/message.py +11 -195
- slidge/core/mixins/message_maker.py +17 -9
- slidge/core/mixins/message_text.py +211 -0
- slidge/core/mixins/presence.py +17 -4
- slidge/core/pubsub.py +114 -288
- slidge/core/session.py +101 -40
- slidge/db/__init__.py +4 -0
- slidge/db/alembic/__init__.py +0 -0
- slidge/db/alembic/env.py +64 -0
- slidge/db/alembic/old_user_store.py +183 -0
- slidge/db/alembic/script.py.mako +26 -0
- slidge/db/alembic/versions/09f27f098baa_add_missing_attributes_in_room.py +36 -0
- slidge/db/alembic/versions/15b0bd83407a_remove_bogus_unique_constraints_on_room_.py +85 -0
- slidge/db/alembic/versions/2461390c0af2_store_contacts_caps_verstring_in_db.py +36 -0
- slidge/db/alembic/versions/29f5280c61aa_store_subject_setter_in_room.py +37 -0
- slidge/db/alembic/versions/2b1f45ab7379_store_room_subject_setter_by_nickname.py +41 -0
- slidge/db/alembic/versions/3071e0fa69d4_add_contact_client_type.py +52 -0
- slidge/db/alembic/versions/45c24cc73c91_add_bob.py +42 -0
- slidge/db/alembic/versions/5bd48bfdffa2_lift_room_legacy_id_constraint.py +61 -0
- slidge/db/alembic/versions/82a4af84b679_add_muc_history_filled.py +48 -0
- slidge/db/alembic/versions/8b993243a536_add_vcard_content_to_contact_table.py +43 -0
- slidge/db/alembic/versions/8d2ced764698_rely_on_db_to_store_contacts_rooms_and_.py +139 -0
- slidge/db/alembic/versions/aa9d82a7f6ef_db_creation.py +101 -0
- slidge/db/alembic/versions/abba1ae0edb3_store_avatar_legacy_id_in_the_contact_.py +79 -0
- slidge/db/alembic/versions/b33993e87db3_move_everything_to_persistent_db.py +214 -0
- slidge/db/alembic/versions/b64b1a793483_add_source_and_legacy_id_for_archived_.py +52 -0
- slidge/db/alembic/versions/c4a8ec35a0e8_per_room_user_nick.py +34 -0
- slidge/db/alembic/versions/e91195719c2c_store_users_avatars_persistently.py +26 -0
- slidge/db/avatar.py +205 -0
- slidge/db/meta.py +72 -0
- slidge/db/models.py +405 -0
- slidge/db/store.py +1257 -0
- slidge/group/archive.py +58 -14
- slidge/group/bookmarks.py +89 -65
- slidge/group/participant.py +111 -44
- slidge/group/room.py +402 -213
- slidge/main.py +202 -0
- slidge/migration.py +45 -1
- slidge/slixfix/__init__.py +31 -1
- slidge/{core/gateway → slixfix}/delivery_receipt.py +1 -1
- slidge/slixfix/roster.py +13 -4
- slidge/slixfix/xep_0292/vcard4.py +1 -87
- slidge/util/archive_msg.py +2 -1
- slidge/util/db.py +4 -228
- slidge/util/test.py +91 -4
- slidge/util/types.py +39 -4
- slidge/util/util.py +45 -2
- {slidge-0.1.2.dist-info → slidge-0.2.0.dist-info}/METADATA +10 -5
- slidge-0.2.0.dist-info/RECORD +131 -0
- slidge-0.2.0.dist-info/entry_points.txt +3 -0
- slidge/core/cache.py +0 -183
- slidge/core/gateway/__init__.py +0 -3
- slidge/core/gateway/muc_admin.py +0 -35
- slidge/core/gateway/presence.py +0 -95
- slidge/core/gateway/registration.py +0 -53
- slidge/core/gateway/session_dispatcher.py +0 -795
- slidge/util/schema.sql +0 -126
- slidge/util/sql.py +0 -508
- slidge-0.1.2.dist-info/RECORD +0 -96
- slidge-0.1.2.dist-info/entry_points.txt +0 -3
- {slidge-0.1.2.dist-info → slidge-0.2.0.dist-info}/LICENSE +0 -0
- {slidge-0.1.2.dist-info → slidge-0.2.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,84 @@
|
|
1
|
+
import logging
|
2
|
+
from typing import TYPE_CHECKING
|
3
|
+
|
4
|
+
from slixmpp import Message
|
5
|
+
from slixmpp.exceptions import IqError
|
6
|
+
from slixmpp.plugins.xep_0084.stanza import Info
|
7
|
+
|
8
|
+
from ..session import BaseSession
|
9
|
+
from .caps import CapsMixin
|
10
|
+
from .disco import DiscoMixin
|
11
|
+
from .message import MessageMixin
|
12
|
+
from .muc import MucMixin
|
13
|
+
from .presence import PresenceHandlerMixin
|
14
|
+
from .registration import RegistrationMixin
|
15
|
+
from .search import SearchMixin
|
16
|
+
from .util import exceptions_to_xmpp_errors
|
17
|
+
from .vcard import VCardMixin
|
18
|
+
|
19
|
+
if TYPE_CHECKING:
|
20
|
+
from slidge.core.gateway import BaseGateway
|
21
|
+
|
22
|
+
|
23
|
+
class SessionDispatcher(
|
24
|
+
CapsMixin,
|
25
|
+
DiscoMixin,
|
26
|
+
RegistrationMixin,
|
27
|
+
MessageMixin,
|
28
|
+
MucMixin,
|
29
|
+
PresenceHandlerMixin,
|
30
|
+
SearchMixin,
|
31
|
+
VCardMixin,
|
32
|
+
):
|
33
|
+
def __init__(self, xmpp: "BaseGateway"):
|
34
|
+
super().__init__(xmpp)
|
35
|
+
xmpp.add_event_handler(
|
36
|
+
"avatar_metadata_publish", self.on_avatar_metadata_publish
|
37
|
+
)
|
38
|
+
|
39
|
+
@exceptions_to_xmpp_errors
|
40
|
+
async def on_avatar_metadata_publish(self, m: Message):
|
41
|
+
session = await self._get_session(m, timeout=None)
|
42
|
+
if not session.user.preferences.get("sync_avatar", False):
|
43
|
+
session.log.debug("User does not want to sync their avatar")
|
44
|
+
return
|
45
|
+
info = m["pubsub_event"]["items"]["item"]["avatar_metadata"]["info"]
|
46
|
+
|
47
|
+
await self.on_avatar_metadata_info(session, info)
|
48
|
+
|
49
|
+
async def on_avatar_metadata_info(self, session: BaseSession, info: Info):
|
50
|
+
hash_ = info["id"]
|
51
|
+
|
52
|
+
if session.user.avatar_hash == hash_:
|
53
|
+
session.log.debug("We already know this avatar hash")
|
54
|
+
return
|
55
|
+
self.xmpp.store.users.set_avatar_hash(session.user_pk, None)
|
56
|
+
|
57
|
+
if hash_:
|
58
|
+
try:
|
59
|
+
iq = await self.xmpp.plugin["xep_0084"].retrieve_avatar(
|
60
|
+
session.user_jid, hash_, ifrom=self.xmpp.boundjid.bare
|
61
|
+
)
|
62
|
+
except IqError as e:
|
63
|
+
session.log.warning("Could not fetch the user's avatar: %s", e)
|
64
|
+
return
|
65
|
+
bytes_ = iq["pubsub"]["items"]["item"]["avatar_data"]["value"]
|
66
|
+
type_ = info["type"]
|
67
|
+
height = info["height"]
|
68
|
+
width = info["width"]
|
69
|
+
else:
|
70
|
+
bytes_ = type_ = height = width = hash_ = None
|
71
|
+
try:
|
72
|
+
await session.on_avatar(bytes_, hash_, type_, width, height)
|
73
|
+
except NotImplementedError:
|
74
|
+
pass
|
75
|
+
except Exception as e:
|
76
|
+
# If something goes wrong here, replying an error stanza will to the
|
77
|
+
# avatar update will likely not show in most clients, so let's send
|
78
|
+
# a normal message from the component to the user.
|
79
|
+
session.send_gateway_message(
|
80
|
+
f"Something went wrong trying to set your avatar: {e!r}"
|
81
|
+
)
|
82
|
+
|
83
|
+
|
84
|
+
log = logging.getLogger(__name__)
|
@@ -0,0 +1,174 @@
|
|
1
|
+
import logging
|
2
|
+
from functools import wraps
|
3
|
+
from typing import TYPE_CHECKING, Any, Awaitable, Callable, TypeVar
|
4
|
+
|
5
|
+
from slixmpp import JID, Iq, Message, Presence
|
6
|
+
from slixmpp.exceptions import XMPPError
|
7
|
+
from slixmpp.xmlstream import StanzaBase
|
8
|
+
|
9
|
+
from ...util.types import Recipient, RecipientType
|
10
|
+
from ..session import BaseSession
|
11
|
+
|
12
|
+
if TYPE_CHECKING:
|
13
|
+
from slidge import BaseGateway
|
14
|
+
from slidge.group import LegacyMUC
|
15
|
+
|
16
|
+
|
17
|
+
class Ignore(BaseException):
|
18
|
+
pass
|
19
|
+
|
20
|
+
|
21
|
+
class DispatcherMixin:
|
22
|
+
def __init__(self, xmpp: "BaseGateway"):
|
23
|
+
self.xmpp = xmpp
|
24
|
+
|
25
|
+
async def _get_session(
|
26
|
+
self,
|
27
|
+
stanza: Message | Presence | Iq,
|
28
|
+
timeout: int | None = 10,
|
29
|
+
wait_for_ready=True,
|
30
|
+
logged=False,
|
31
|
+
) -> BaseSession:
|
32
|
+
xmpp = self.xmpp
|
33
|
+
if stanza.get_from().server == xmpp.boundjid.bare:
|
34
|
+
log.debug("Ignoring echo")
|
35
|
+
raise Ignore
|
36
|
+
if (
|
37
|
+
isinstance(stanza, Message)
|
38
|
+
and stanza.get_type() == "chat"
|
39
|
+
and stanza.get_to() == xmpp.boundjid.bare
|
40
|
+
):
|
41
|
+
log.debug("Ignoring message to component")
|
42
|
+
raise Ignore
|
43
|
+
session = await self._get_session_from_jid(
|
44
|
+
stanza.get_from(), timeout, wait_for_ready, logged
|
45
|
+
)
|
46
|
+
if isinstance(stanza, Message) and _ignore(session, stanza):
|
47
|
+
raise Ignore
|
48
|
+
return session
|
49
|
+
|
50
|
+
async def _get_session_from_jid(
|
51
|
+
self,
|
52
|
+
jid: JID,
|
53
|
+
timeout: int | None = 10,
|
54
|
+
wait_for_ready=True,
|
55
|
+
logged=False,
|
56
|
+
) -> BaseSession:
|
57
|
+
session = self.xmpp.get_session_from_jid(jid)
|
58
|
+
if session is None:
|
59
|
+
raise XMPPError("registration-required")
|
60
|
+
if logged:
|
61
|
+
session.raise_if_not_logged()
|
62
|
+
if wait_for_ready:
|
63
|
+
await session.wait_for_ready(timeout)
|
64
|
+
return session
|
65
|
+
|
66
|
+
async def get_muc_from_stanza(self, iq: Iq | Message | Presence) -> "LegacyMUC":
|
67
|
+
ito = iq.get_to()
|
68
|
+
if ito == self.xmpp.boundjid.bare:
|
69
|
+
raise XMPPError("bad-request", text="This is only handled for MUCs")
|
70
|
+
|
71
|
+
session = await self._get_session(iq, logged=True)
|
72
|
+
muc = await session.bookmarks.by_jid(ito)
|
73
|
+
return muc
|
74
|
+
|
75
|
+
def _xmpp_msg_id_to_legacy(self, session: "BaseSession", xmpp_id: str):
|
76
|
+
sent = self.xmpp.store.sent.get_legacy_id(session.user_pk, xmpp_id)
|
77
|
+
if sent is not None:
|
78
|
+
return self.xmpp.LEGACY_MSG_ID_TYPE(sent)
|
79
|
+
|
80
|
+
multi = self.xmpp.store.multi.get_legacy_id(session.user_pk, xmpp_id)
|
81
|
+
if multi:
|
82
|
+
return self.xmpp.LEGACY_MSG_ID_TYPE(multi)
|
83
|
+
|
84
|
+
try:
|
85
|
+
return session.xmpp_to_legacy_msg_id(xmpp_id)
|
86
|
+
except XMPPError:
|
87
|
+
raise
|
88
|
+
except Exception as e:
|
89
|
+
log.debug("Couldn't convert xmpp msg ID to legacy ID.", exc_info=e)
|
90
|
+
raise XMPPError(
|
91
|
+
"internal-server-error", "Couldn't convert xmpp msg ID to legacy ID."
|
92
|
+
)
|
93
|
+
|
94
|
+
async def _get_session_entity_thread(
|
95
|
+
self, msg: Message
|
96
|
+
) -> tuple["BaseSession", Recipient, int | str]:
|
97
|
+
session = await self._get_session(msg)
|
98
|
+
e: Recipient = await _get_entity(session, msg)
|
99
|
+
legacy_thread = await self._xmpp_to_legacy_thread(session, msg, e)
|
100
|
+
return session, e, legacy_thread
|
101
|
+
|
102
|
+
async def _xmpp_to_legacy_thread(
|
103
|
+
self, session: "BaseSession", msg: Message, recipient: RecipientType
|
104
|
+
):
|
105
|
+
xmpp_thread = msg["thread"]
|
106
|
+
if not xmpp_thread:
|
107
|
+
return None
|
108
|
+
|
109
|
+
if session.MESSAGE_IDS_ARE_THREAD_IDS:
|
110
|
+
return self._xmpp_msg_id_to_legacy(session, xmpp_thread)
|
111
|
+
|
112
|
+
legacy_thread_str = session.xmpp.store.sent.get_legacy_thread(
|
113
|
+
session.user_pk, xmpp_thread
|
114
|
+
)
|
115
|
+
if legacy_thread_str is not None:
|
116
|
+
return session.xmpp.LEGACY_MSG_ID_TYPE(legacy_thread_str)
|
117
|
+
async with session.thread_creation_lock:
|
118
|
+
legacy_thread = await recipient.create_thread(xmpp_thread)
|
119
|
+
session.xmpp.store.sent.set_thread(
|
120
|
+
session.user_pk, str(legacy_thread), xmpp_thread
|
121
|
+
)
|
122
|
+
return legacy_thread
|
123
|
+
|
124
|
+
|
125
|
+
def _ignore(session: "BaseSession", msg: Message):
|
126
|
+
i = msg.get_id()
|
127
|
+
if i.startswith("slidge-carbon-"):
|
128
|
+
return True
|
129
|
+
if i not in session.ignore_messages:
|
130
|
+
return False
|
131
|
+
session.log.debug("Ignored sent carbon: %s", i)
|
132
|
+
session.ignore_messages.remove(i)
|
133
|
+
return True
|
134
|
+
|
135
|
+
|
136
|
+
async def _get_entity(session: "BaseSession", m: Message) -> RecipientType:
|
137
|
+
session.raise_if_not_logged()
|
138
|
+
if m.get_type() == "groupchat":
|
139
|
+
muc = await session.bookmarks.by_jid(m.get_to())
|
140
|
+
r = m.get_from().resource
|
141
|
+
if r not in muc.get_user_resources():
|
142
|
+
session.create_task(muc.kick_resource(r))
|
143
|
+
raise XMPPError("not-acceptable", "You are not connected to this chat")
|
144
|
+
return muc
|
145
|
+
else:
|
146
|
+
return await session.contacts.by_jid(m.get_to())
|
147
|
+
|
148
|
+
|
149
|
+
StanzaType = TypeVar("StanzaType", bound=StanzaBase)
|
150
|
+
HandlerType = Callable[[Any, StanzaType], Awaitable[None]]
|
151
|
+
|
152
|
+
|
153
|
+
def exceptions_to_xmpp_errors(cb: HandlerType) -> HandlerType:
|
154
|
+
@wraps(cb)
|
155
|
+
async def wrapped(*args):
|
156
|
+
try:
|
157
|
+
await cb(*args)
|
158
|
+
except Ignore:
|
159
|
+
pass
|
160
|
+
except XMPPError:
|
161
|
+
raise
|
162
|
+
except NotImplementedError:
|
163
|
+
log.debug("NotImplementedError raised in %s", cb)
|
164
|
+
raise XMPPError(
|
165
|
+
"feature-not-implemented", "Not implemented by the legacy module"
|
166
|
+
)
|
167
|
+
except Exception as e:
|
168
|
+
log.error("Failed to handle incoming stanza: %s", args, exc_info=e)
|
169
|
+
raise XMPPError("internal-server-error", str(e))
|
170
|
+
|
171
|
+
return wrapped
|
172
|
+
|
173
|
+
|
174
|
+
log = logging.getLogger(__name__)
|
@@ -1,5 +1,4 @@
|
|
1
1
|
from copy import copy
|
2
|
-
from typing import TYPE_CHECKING
|
3
2
|
|
4
3
|
from slixmpp import CoroutineCallback, Iq, StanzaPath, register_stanza_plugin
|
5
4
|
from slixmpp.exceptions import XMPPError
|
@@ -9,21 +8,23 @@ from slixmpp.plugins.xep_0292.stanza import NS as VCard4NS
|
|
9
8
|
from ...contact import LegacyContact
|
10
9
|
from ...core.session import BaseSession
|
11
10
|
from ...group import LegacyParticipant
|
11
|
+
from .util import DispatcherMixin, exceptions_to_xmpp_errors
|
12
12
|
|
13
|
-
if TYPE_CHECKING:
|
14
|
-
from .base import BaseGateway
|
15
13
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
14
|
+
class VCardMixin(DispatcherMixin):
|
15
|
+
def __init__(self, xmpp):
|
16
|
+
super().__init__(xmpp)
|
17
|
+
xmpp.register_handler(
|
18
|
+
CoroutineCallback(
|
19
|
+
"get_vcard", StanzaPath("iq@type=get/vcard"), self.on_get_vcard
|
20
|
+
)
|
21
|
+
)
|
22
|
+
xmpp.remove_handler("VCardTemp")
|
22
23
|
xmpp.register_handler(
|
23
24
|
CoroutineCallback(
|
24
25
|
"VCardTemp",
|
25
26
|
StanzaPath("iq/vcard_temp"),
|
26
|
-
self.
|
27
|
+
self.__vcard_temp_handler,
|
27
28
|
)
|
28
29
|
)
|
29
30
|
# TODO: MR to slixmpp adding this to XEP-0084
|
@@ -32,7 +33,20 @@ class VCardTemp:
|
|
32
33
|
MetaData,
|
33
34
|
)
|
34
35
|
|
35
|
-
|
36
|
+
@exceptions_to_xmpp_errors
|
37
|
+
async def on_get_vcard(self, iq: Iq):
|
38
|
+
session = await self._get_session(iq, logged=True)
|
39
|
+
contact = await session.contacts.by_jid(iq.get_to())
|
40
|
+
vcard = await contact.get_vcard()
|
41
|
+
reply = iq.reply()
|
42
|
+
if vcard:
|
43
|
+
reply.append(vcard)
|
44
|
+
else:
|
45
|
+
reply.enable("vcard")
|
46
|
+
reply.send()
|
47
|
+
|
48
|
+
@exceptions_to_xmpp_errors
|
49
|
+
async def __vcard_temp_handler(self, iq: Iq):
|
36
50
|
if iq["type"] == "get":
|
37
51
|
return await self.__handle_get_vcard_temp(iq)
|
38
52
|
|
@@ -40,11 +54,13 @@ class VCardTemp:
|
|
40
54
|
return await self.__handle_set_vcard_temp(iq)
|
41
55
|
|
42
56
|
async def __fetch_user_avatar(self, session: BaseSession):
|
43
|
-
hash_ = session.avatar_hash
|
57
|
+
hash_ = session.user.avatar_hash
|
44
58
|
if not hash_:
|
45
|
-
raise XMPPError(
|
59
|
+
raise XMPPError(
|
60
|
+
"item-not-found", "The slidge user does not have any avatar set"
|
61
|
+
)
|
46
62
|
meta_iq = await self.xmpp.plugin["xep_0060"].get_item(
|
47
|
-
session.
|
63
|
+
session.user_jid,
|
48
64
|
MetaData.namespace,
|
49
65
|
hash_,
|
50
66
|
ifrom=self.xmpp.boundjid.bare,
|
@@ -52,14 +68,14 @@ class VCardTemp:
|
|
52
68
|
info = meta_iq["pubsub"]["items"]["item"]["avatar_metadata"]["info"]
|
53
69
|
type_ = info["type"]
|
54
70
|
data_iq = await self.xmpp.plugin["xep_0084"].retrieve_avatar(
|
55
|
-
session.
|
71
|
+
session.user_jid, hash_, ifrom=self.xmpp.boundjid.bare
|
56
72
|
)
|
57
73
|
bytes_ = data_iq["pubsub"]["items"]["item"]["avatar_data"]["value"]
|
58
74
|
return bytes_, type_
|
59
75
|
|
60
76
|
async def __handle_get_vcard_temp(self, iq: Iq):
|
61
77
|
session = self.xmpp.get_session_from_stanza(iq)
|
62
|
-
entity = await session.get_contact_or_group_or_participant(iq.get_to())
|
78
|
+
entity = await session.get_contact_or_group_or_participant(iq.get_to(), False)
|
63
79
|
if not entity:
|
64
80
|
raise XMPPError("item-not-found")
|
65
81
|
|
@@ -77,14 +93,14 @@ class VCardTemp:
|
|
77
93
|
elif not (contact := entity.contact):
|
78
94
|
raise XMPPError("item-not-found", "This participant has no contact")
|
79
95
|
else:
|
80
|
-
vcard = await
|
96
|
+
vcard = await contact.get_vcard()
|
81
97
|
avatar = contact.get_avatar()
|
82
98
|
type_ = "image/png"
|
83
99
|
else:
|
84
100
|
avatar = entity.get_avatar()
|
85
101
|
type_ = "image/png"
|
86
102
|
if isinstance(entity, LegacyContact):
|
87
|
-
vcard = await
|
103
|
+
vcard = await entity.get_vcard(fetch=False)
|
88
104
|
else:
|
89
105
|
vcard = None
|
90
106
|
v = self.xmpp.plugin["xep_0054"].make_vcard()
|
@@ -103,7 +119,7 @@ class VCardTemp:
|
|
103
119
|
reply.send()
|
104
120
|
|
105
121
|
async def __handle_set_vcard_temp(self, iq: Iq):
|
106
|
-
muc = await self.
|
122
|
+
muc = await self.get_muc_from_stanza(iq)
|
107
123
|
to = iq.get_to()
|
108
124
|
|
109
125
|
if to.resource:
|