slidge 0.2.0a9__py3-none-any.whl → 0.2.0b0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- slidge/__main__.py +2 -3
- slidge/__version__.py +1 -1
- slidge/command/adhoc.py +1 -1
- slidge/command/base.py +4 -4
- slidge/command/user.py +5 -1
- slidge/contact/roster.py +9 -0
- slidge/core/config.py +0 -3
- slidge/core/dispatcher/__init__.py +3 -0
- slidge/core/{gateway → dispatcher}/caps.py +6 -4
- slidge/core/{gateway → dispatcher}/disco.py +11 -17
- 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 +26 -15
- slidge/core/dispatcher/muc/misc.py +121 -0
- slidge/core/dispatcher/muc/owner.py +96 -0
- slidge/core/{gateway → dispatcher/muc}/ping.py +10 -15
- slidge/core/dispatcher/presence.py +177 -0
- slidge/core/{gateway → dispatcher}/registration.py +23 -2
- slidge/core/{gateway → dispatcher}/search.py +9 -14
- slidge/core/dispatcher/session_dispatcher.py +84 -0
- slidge/core/dispatcher/util.py +174 -0
- slidge/core/{gateway/vcard_temp.py → dispatcher/vcard.py} +26 -12
- slidge/core/{gateway/base.py → gateway.py} +42 -137
- slidge/core/mixins/attachment.py +24 -8
- slidge/core/mixins/base.py +2 -2
- slidge/core/mixins/lock.py +10 -8
- slidge/core/mixins/message.py +9 -203
- slidge/core/mixins/message_text.py +211 -0
- slidge/core/pubsub.py +2 -1
- slidge/core/session.py +28 -2
- slidge/db/alembic/versions/15b0bd83407a_remove_bogus_unique_constraints_on_room_.py +83 -0
- slidge/db/alembic/versions/45c24cc73c91_add_bob.py +42 -0
- slidge/db/alembic/versions/5bd48bfdffa2_lift_room_legacy_id_constraint.py +12 -1
- slidge/db/models.py +16 -1
- slidge/db/store.py +144 -11
- slidge/group/bookmarks.py +23 -1
- slidge/group/participant.py +5 -5
- slidge/group/room.py +10 -1
- slidge/{core/gateway → slixfix}/delivery_receipt.py +1 -1
- slidge/util/test.py +9 -5
- slidge/util/types.py +6 -0
- slidge/util/util.py +5 -2
- {slidge-0.2.0a9.dist-info → slidge-0.2.0b0.dist-info}/METADATA +2 -1
- {slidge-0.2.0a9.dist-info → slidge-0.2.0b0.dist-info}/RECORD +51 -40
- slidge-0.2.0b0.dist-info/entry_points.txt +3 -0
- 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/session_dispatcher.py +0 -895
- slidge-0.2.0a9.dist-info/entry_points.txt +0 -3
- {slidge-0.2.0a9.dist-info → slidge-0.2.0b0.dist-info}/LICENSE +0 -0
- {slidge-0.2.0a9.dist-info → slidge-0.2.0b0.dist-info}/WHEEL +0 -0
slidge/__main__.py
CHANGED
slidge/__version__.py
CHANGED
slidge/command/adhoc.py
CHANGED
@@ -13,7 +13,7 @@ from . import Command, CommandResponseType, Confirmation, Form, TableResult
|
|
13
13
|
from .base import FormField
|
14
14
|
|
15
15
|
if TYPE_CHECKING:
|
16
|
-
from ..core.gateway
|
16
|
+
from ..core.gateway import BaseGateway
|
17
17
|
from ..core.session import BaseSession
|
18
18
|
|
19
19
|
|
slidge/command/base.py
CHANGED
@@ -6,9 +6,9 @@ from typing import (
|
|
6
6
|
Any,
|
7
7
|
Awaitable,
|
8
8
|
Callable,
|
9
|
-
Collection,
|
10
9
|
Iterable,
|
11
10
|
Optional,
|
11
|
+
Sequence,
|
12
12
|
Type,
|
13
13
|
TypedDict,
|
14
14
|
Union,
|
@@ -54,11 +54,11 @@ class TableResult:
|
|
54
54
|
Structured data as the result of a command
|
55
55
|
"""
|
56
56
|
|
57
|
-
fields:
|
57
|
+
fields: Sequence["FormField"]
|
58
58
|
"""
|
59
59
|
The 'columns names' of the table.
|
60
60
|
"""
|
61
|
-
items:
|
61
|
+
items: Sequence[dict[str, Union[str, JID]]]
|
62
62
|
"""
|
63
63
|
The rows of the table. Each row is a dict where keys are the fields ``var``
|
64
64
|
attribute.
|
@@ -149,7 +149,7 @@ class Form:
|
|
149
149
|
|
150
150
|
title: str
|
151
151
|
instructions: str
|
152
|
-
fields:
|
152
|
+
fields: Sequence["FormField"]
|
153
153
|
handler: FormHandlerType
|
154
154
|
handler_args: Iterable[Any] = field(default_factory=list)
|
155
155
|
handler_kwargs: dict[str, Any] = field(default_factory=dict)
|
slidge/command/user.py
CHANGED
@@ -305,7 +305,10 @@ class LeaveGroup(Command):
|
|
305
305
|
FormField(
|
306
306
|
"group",
|
307
307
|
"Group name",
|
308
|
-
|
308
|
+
type="list-single",
|
309
|
+
options=[
|
310
|
+
{"label": g.name, "value": str(i)} for i, g in enumerate(groups)
|
311
|
+
],
|
309
312
|
)
|
310
313
|
],
|
311
314
|
handler=self.confirm, # type:ignore
|
@@ -329,3 +332,4 @@ class LeaveGroup(Command):
|
|
329
332
|
@staticmethod
|
330
333
|
async def finish(session: AnyBaseSession, _ifrom, group: LegacyMUC):
|
331
334
|
await session.on_leave_group(group.legacy_id)
|
335
|
+
await session.bookmarks.remove(group, reason="You left this group via slidge.")
|
slidge/contact/roster.py
CHANGED
@@ -92,6 +92,13 @@ class LegacyRoster(
|
|
92
92
|
stored = self.__store.get_by_jid(self.session.user_pk, contact_jid)
|
93
93
|
return await self.__update_contact(stored, legacy_id, username)
|
94
94
|
|
95
|
+
def by_jid_only_if_exists(self, contact_jid: JID) -> LegacyContactType | None:
|
96
|
+
with self.__store.session():
|
97
|
+
stored = self.__store.get_by_jid(self.session.user_pk, contact_jid)
|
98
|
+
if stored is not None and stored.updated:
|
99
|
+
return self._contact_cls.from_store(self.session, stored)
|
100
|
+
return None
|
101
|
+
|
95
102
|
async def by_legacy_id(
|
96
103
|
self, legacy_id: LegacyUserIdType, *args, **kwargs
|
97
104
|
) -> LegacyContactType:
|
@@ -147,6 +154,8 @@ class LegacyRoster(
|
|
147
154
|
try:
|
148
155
|
with contact.updating_info():
|
149
156
|
await contact.avatar_wrap_update_info()
|
157
|
+
except XMPPError:
|
158
|
+
raise
|
150
159
|
except Exception as e:
|
151
160
|
raise XMPPError("internal-server-error", str(e))
|
152
161
|
contact._caps_ver = await contact.get_caps_ver(contact.jid)
|
slidge/core/config.py
CHANGED
@@ -154,9 +154,6 @@ LAST_SEEN_FALLBACK__DOC = (
|
|
154
154
|
QR_TIMEOUT = 60
|
155
155
|
QR_TIMEOUT__DOC = "Timeout for QR code flashing confirmation."
|
156
156
|
|
157
|
-
DOWNLOAD_CHUNK_SIZE = 1024
|
158
|
-
DOWNLOAD_CHUNK_SIZE__DOC = "Chunk size when slidge needs to download files using HTTP."
|
159
|
-
|
160
157
|
LAST_MESSAGE_CORRECTION_RETRACTION_WORKAROUND = False
|
161
158
|
LAST_MESSAGE_CORRECTION_RETRACTION_WORKAROUND__DOC = (
|
162
159
|
"If the legacy service does not support last message correction but supports"
|
@@ -5,17 +5,19 @@ from slixmpp import Presence
|
|
5
5
|
from slixmpp.exceptions import XMPPError
|
6
6
|
from slixmpp.xmlstream import StanzaBase
|
7
7
|
|
8
|
+
from .util import DispatcherMixin
|
9
|
+
|
8
10
|
if TYPE_CHECKING:
|
9
|
-
from .
|
11
|
+
from slidge.core.gateway import BaseGateway
|
10
12
|
|
11
13
|
|
12
|
-
class
|
14
|
+
class CapsMixin(DispatcherMixin):
|
13
15
|
def __init__(self, xmpp: "BaseGateway"):
|
14
|
-
|
16
|
+
super().__init__(xmpp)
|
15
17
|
xmpp.del_filter("out", xmpp.plugin["xep_0115"]._filter_add_caps)
|
16
18
|
xmpp.add_filter("out", self._filter_add_caps) # type:ignore
|
17
19
|
|
18
|
-
async def _filter_add_caps(self, stanza: StanzaBase):
|
20
|
+
async def _filter_add_caps(self, stanza: StanzaBase) -> StanzaBase:
|
19
21
|
# we rolled our own "add caps on presences" filter because
|
20
22
|
# there is too much magic happening in slixmpp
|
21
23
|
# anyway, we probably want to roll our own "dynamic disco"/caps
|
@@ -5,13 +5,15 @@ from slixmpp.exceptions import XMPPError
|
|
5
5
|
from slixmpp.plugins.xep_0030.stanza.items import DiscoItems
|
6
6
|
from slixmpp.types import OptJid
|
7
7
|
|
8
|
+
from .util import DispatcherMixin
|
9
|
+
|
8
10
|
if TYPE_CHECKING:
|
9
|
-
from .
|
11
|
+
from slidge.core.gateway import BaseGateway
|
10
12
|
|
11
13
|
|
12
|
-
class
|
14
|
+
class DiscoMixin(DispatcherMixin):
|
13
15
|
def __init__(self, xmpp: "BaseGateway"):
|
14
|
-
|
16
|
+
super().__init__(xmpp)
|
15
17
|
|
16
18
|
xmpp.plugin["xep_0030"].set_node_handler(
|
17
19
|
"get_info",
|
@@ -36,15 +38,11 @@ class Disco:
|
|
36
38
|
if ifrom is None:
|
37
39
|
raise XMPPError("subscription-required")
|
38
40
|
|
39
|
-
|
40
|
-
|
41
|
-
raise XMPPError("registration-required")
|
42
|
-
session = self.xmpp.get_session_from_user(user)
|
43
|
-
await session.wait_for_ready()
|
41
|
+
assert jid is not None
|
42
|
+
session = await self._get_session_from_jid(jid=ifrom)
|
44
43
|
|
45
44
|
log.debug("Looking for entity: %s", jid)
|
46
45
|
|
47
|
-
assert jid is not None
|
48
46
|
entity = await session.get_contact_or_group_or_participant(jid)
|
49
47
|
|
50
48
|
if entity is None:
|
@@ -61,16 +59,12 @@ class Disco:
|
|
61
59
|
if jid != self.xmpp.boundjid.bare:
|
62
60
|
return DiscoItems()
|
63
61
|
|
64
|
-
|
65
|
-
|
66
|
-
raise XMPPError("registration-required")
|
67
|
-
|
68
|
-
session = self.xmpp.get_session_from_user(user)
|
69
|
-
await session.wait_for_ready()
|
62
|
+
assert ifrom is not None
|
63
|
+
session = await self._get_session_from_jid(ifrom)
|
70
64
|
|
71
65
|
d = DiscoItems()
|
72
|
-
for
|
73
|
-
d.add_item(
|
66
|
+
for room in self.xmpp.store.rooms.get_all_jid_and_names(session.user_pk):
|
67
|
+
d.add_item(room.jid, name=room.name)
|
74
68
|
|
75
69
|
return d
|
76
70
|
|
@@ -0,0 +1,40 @@
|
|
1
|
+
from slixmpp import Message
|
2
|
+
from slixmpp.xmlstream import StanzaBase
|
3
|
+
|
4
|
+
from ..util import DispatcherMixin, exceptions_to_xmpp_errors
|
5
|
+
|
6
|
+
|
7
|
+
class ChatStateMixin(DispatcherMixin):
|
8
|
+
def __init__(self, xmpp) -> None:
|
9
|
+
super().__init__(xmpp)
|
10
|
+
xmpp.add_event_handler("chatstate_active", self.on_chatstate_active)
|
11
|
+
xmpp.add_event_handler("chatstate_inactive", self.on_chatstate_inactive)
|
12
|
+
xmpp.add_event_handler("chatstate_composing", self.on_chatstate_composing)
|
13
|
+
xmpp.add_event_handler("chatstate_paused", self.on_chatstate_paused)
|
14
|
+
|
15
|
+
@exceptions_to_xmpp_errors
|
16
|
+
async def on_chatstate_active(self, msg: StanzaBase) -> None:
|
17
|
+
assert isinstance(msg, Message)
|
18
|
+
if msg["body"]:
|
19
|
+
# if there is a body, it's handled in on_legacy_message()
|
20
|
+
return
|
21
|
+
session, entity, thread = await self._get_session_entity_thread(msg)
|
22
|
+
await session.on_active(entity, thread)
|
23
|
+
|
24
|
+
@exceptions_to_xmpp_errors
|
25
|
+
async def on_chatstate_inactive(self, msg: StanzaBase) -> None:
|
26
|
+
assert isinstance(msg, Message)
|
27
|
+
session, entity, thread = await self._get_session_entity_thread(msg)
|
28
|
+
await session.on_inactive(entity, thread)
|
29
|
+
|
30
|
+
@exceptions_to_xmpp_errors
|
31
|
+
async def on_chatstate_composing(self, msg: StanzaBase) -> None:
|
32
|
+
assert isinstance(msg, Message)
|
33
|
+
session, entity, thread = await self._get_session_entity_thread(msg)
|
34
|
+
await session.on_composing(entity, thread)
|
35
|
+
|
36
|
+
@exceptions_to_xmpp_errors
|
37
|
+
async def on_chatstate_paused(self, msg: StanzaBase) -> None:
|
38
|
+
assert isinstance(msg, Message)
|
39
|
+
session, entity, thread = await self._get_session_entity_thread(msg)
|
40
|
+
await session.on_paused(entity, thread)
|
@@ -0,0 +1,62 @@
|
|
1
|
+
from slixmpp import JID, Message
|
2
|
+
from slixmpp.xmlstream import StanzaBase
|
3
|
+
|
4
|
+
from ....group.room import LegacyMUC
|
5
|
+
from ....util.types import Recipient
|
6
|
+
from ..util import DispatcherMixin, _get_entity, exceptions_to_xmpp_errors
|
7
|
+
|
8
|
+
|
9
|
+
class MarkerMixin(DispatcherMixin):
|
10
|
+
def __init__(self, xmpp) -> None:
|
11
|
+
super().__init__(xmpp)
|
12
|
+
xmpp.add_event_handler("marker_displayed", self.on_marker_displayed)
|
13
|
+
xmpp.add_event_handler(
|
14
|
+
"message_displayed_synchronization_publish",
|
15
|
+
self.on_message_displayed_synchronization_publish,
|
16
|
+
)
|
17
|
+
|
18
|
+
@exceptions_to_xmpp_errors
|
19
|
+
async def on_marker_displayed(self, msg: StanzaBase) -> None:
|
20
|
+
assert isinstance(msg, Message)
|
21
|
+
session = await self._get_session(msg)
|
22
|
+
|
23
|
+
e: Recipient = await _get_entity(session, msg)
|
24
|
+
legacy_thread = await self._xmpp_to_legacy_thread(session, msg, e)
|
25
|
+
displayed_msg_id = msg["displayed"]["id"]
|
26
|
+
if not isinstance(e, LegacyMUC) and self.xmpp.MARK_ALL_MESSAGES:
|
27
|
+
to_mark = e.get_msg_xmpp_id_up_to(displayed_msg_id) # type: ignore
|
28
|
+
if to_mark is None:
|
29
|
+
session.log.debug("Can't mark all messages up to %s", displayed_msg_id)
|
30
|
+
to_mark = [displayed_msg_id]
|
31
|
+
else:
|
32
|
+
to_mark = [displayed_msg_id]
|
33
|
+
for xmpp_id in to_mark:
|
34
|
+
await session.on_displayed(
|
35
|
+
e, self._xmpp_msg_id_to_legacy(session, xmpp_id), legacy_thread
|
36
|
+
)
|
37
|
+
if isinstance(e, LegacyMUC):
|
38
|
+
await e.echo(msg, None)
|
39
|
+
|
40
|
+
@exceptions_to_xmpp_errors
|
41
|
+
async def on_message_displayed_synchronization_publish(
|
42
|
+
self, msg: StanzaBase
|
43
|
+
) -> None:
|
44
|
+
assert isinstance(msg, Message)
|
45
|
+
chat_jid = JID(msg["pubsub_event"]["items"]["item"]["id"])
|
46
|
+
if chat_jid.server != self.xmpp.boundjid.bare:
|
47
|
+
return
|
48
|
+
|
49
|
+
session = await self._get_session(msg, timeout=None)
|
50
|
+
|
51
|
+
if chat_jid == self.xmpp.boundjid.bare:
|
52
|
+
return
|
53
|
+
|
54
|
+
chat = await session.get_contact_or_group_or_participant(chat_jid)
|
55
|
+
if not isinstance(chat, LegacyMUC):
|
56
|
+
session.log.debug("Ignoring non-groupchat MDS event")
|
57
|
+
return
|
58
|
+
|
59
|
+
stanza_id = msg["pubsub_event"]["items"]["item"]["displayed"]["stanza_id"]["id"]
|
60
|
+
await session.on_displayed(
|
61
|
+
chat, self._xmpp_msg_id_to_legacy(session, stanza_id)
|
62
|
+
)
|