slidge 0.1.3__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 +107 -40
- 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.3.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 -804
- slidge/util/schema.sql +0 -126
- slidge/util/sql.py +0 -508
- slidge-0.1.3.dist-info/RECORD +0 -96
- slidge-0.1.3.dist-info/entry_points.txt +0 -3
- {slidge-0.1.3.dist-info → slidge-0.2.0.dist-info}/LICENSE +0 -0
- {slidge-0.1.3.dist-info → slidge-0.2.0.dist-info}/WHEEL +0 -0
slidge/core/config.py
CHANGED
@@ -43,11 +43,18 @@ PORT__SHORT = "p"
|
|
43
43
|
|
44
44
|
HOME_DIR: Path
|
45
45
|
HOME_DIR__DOC = (
|
46
|
-
"
|
46
|
+
"Directory where slidge will writes it persistent data and cache. "
|
47
47
|
"Defaults to /var/lib/slidge/${SLIDGE_JID}. "
|
48
48
|
)
|
49
49
|
HOME_DIR__DYNAMIC_DEFAULT = True
|
50
50
|
|
51
|
+
DB_URL: str
|
52
|
+
DB_URL__DOC = (
|
53
|
+
"Database URL, see <https://docs.sqlalchemy.org/en/20/core/engines.html#database-urls>. "
|
54
|
+
"Defaults to sqlite:///${HOME_DIR}/slidge.sqlite"
|
55
|
+
)
|
56
|
+
DB_URL__DYNAMIC_DEFAULT = True
|
57
|
+
|
51
58
|
USER_JID_VALIDATOR: str
|
52
59
|
USER_JID_VALIDATOR__DOC = (
|
53
60
|
"Regular expression to restrict users that can register to the gateway, by JID. "
|
@@ -70,7 +77,7 @@ UPLOAD_SERVICE__DOC = (
|
|
70
77
|
)
|
71
78
|
|
72
79
|
SECRET_KEY: Optional[str] = None
|
73
|
-
SECRET_KEY__DOC = "Encryption for disk storage"
|
80
|
+
SECRET_KEY__DOC = "Encryption for disk storage. Deprecated."
|
74
81
|
|
75
82
|
NO_ROSTER_PUSH = False
|
76
83
|
NO_ROSTER_PUSH__DOC = "Do not fill users' rosters with legacy contacts automatically"
|
@@ -135,19 +142,18 @@ PARTIAL_REGISTRATION_TIMEOUT__DOC = (
|
|
135
142
|
"a single step registration process is not enough."
|
136
143
|
)
|
137
144
|
|
138
|
-
LAST_SEEN_FALLBACK =
|
145
|
+
LAST_SEEN_FALLBACK = False
|
139
146
|
LAST_SEEN_FALLBACK__DOC = (
|
140
147
|
"When using XEP-0319 (Last User Interaction in Presence), use the presence status"
|
141
148
|
" to display the last seen information in the presence status. Useful for clients"
|
142
|
-
" that do not implement XEP-0319."
|
149
|
+
" that do not implement XEP-0319. Because of implementation details, this can increase"
|
150
|
+
" RAM usage and might be deprecated in the future. Ask your client dev for XEP-0319"
|
151
|
+
" support ;o)."
|
143
152
|
)
|
144
153
|
|
145
154
|
QR_TIMEOUT = 60
|
146
155
|
QR_TIMEOUT__DOC = "Timeout for QR code flashing confirmation."
|
147
156
|
|
148
|
-
DOWNLOAD_CHUNK_SIZE = 1024
|
149
|
-
DOWNLOAD_CHUNK_SIZE__DOC = "Chunk size when slidge needs to download files using HTTP."
|
150
|
-
|
151
157
|
LAST_MESSAGE_CORRECTION_RETRACTION_WORKAROUND = False
|
152
158
|
LAST_MESSAGE_CORRECTION_RETRACTION_WORKAROUND__DOC = (
|
153
159
|
"If the legacy service does not support last message correction but supports"
|
@@ -176,10 +182,7 @@ LOG_FORMAT__DOC = (
|
|
176
182
|
)
|
177
183
|
|
178
184
|
MAM_MAX_DAYS = 7
|
179
|
-
MAM_MAX_DAYS__DOC =
|
180
|
-
"Maximum number of days for group archive retention. "
|
181
|
-
"Since all text content stored in RAM right now, "
|
182
|
-
)
|
185
|
+
MAM_MAX_DAYS__DOC = "Maximum number of days for group archive retention."
|
183
186
|
|
184
187
|
CORRECTION_EMPTY_BODY_AS_RETRACTION = True
|
185
188
|
CORRECTION_EMPTY_BODY_AS_RETRACTION__DOC = (
|
@@ -212,5 +215,8 @@ DEV_MODE__DOC = (
|
|
212
215
|
"Not safe to use in prod, but great during dev."
|
213
216
|
)
|
214
217
|
|
215
|
-
|
216
|
-
|
218
|
+
STRIP_LEADING_EMOJI_ADHOC = False
|
219
|
+
STRIP_LEADING_EMOJI_ADHOC__DOC = (
|
220
|
+
"Strip the leading emoji in ad-hoc command names, if present, in case you "
|
221
|
+
"are a emoji-hater."
|
222
|
+
)
|
@@ -5,19 +5,19 @@ from slixmpp import Presence
|
|
5
5
|
from slixmpp.exceptions import XMPPError
|
6
6
|
from slixmpp.xmlstream import StanzaBase
|
7
7
|
|
8
|
-
from
|
8
|
+
from .util import DispatcherMixin
|
9
9
|
|
10
10
|
if TYPE_CHECKING:
|
11
|
-
from .
|
11
|
+
from slidge.core.gateway import BaseGateway
|
12
12
|
|
13
13
|
|
14
|
-
class
|
14
|
+
class CapsMixin(DispatcherMixin):
|
15
15
|
def __init__(self, xmpp: "BaseGateway"):
|
16
|
-
|
16
|
+
super().__init__(xmpp)
|
17
17
|
xmpp.del_filter("out", xmpp.plugin["xep_0115"]._filter_add_caps)
|
18
18
|
xmpp.add_filter("out", self._filter_add_caps) # type:ignore
|
19
19
|
|
20
|
-
async def _filter_add_caps(self, stanza: StanzaBase):
|
20
|
+
async def _filter_add_caps(self, stanza: StanzaBase) -> StanzaBase:
|
21
21
|
# we rolled our own "add caps on presences" filter because
|
22
22
|
# there is too much magic happening in slixmpp
|
23
23
|
# anyway, we probably want to roll our own "dynamic disco"/caps
|
@@ -25,6 +25,9 @@ class Caps:
|
|
25
25
|
if not isinstance(stanza, Presence):
|
26
26
|
return stanza
|
27
27
|
|
28
|
+
if stanza.get_plugin("caps", check=True):
|
29
|
+
return stanza
|
30
|
+
|
28
31
|
if stanza["type"] not in ("available", "chat", "away", "dnd", "xa"):
|
29
32
|
return stanza
|
30
33
|
|
@@ -44,10 +47,11 @@ class Caps:
|
|
44
47
|
|
45
48
|
await session.ready
|
46
49
|
|
47
|
-
|
48
|
-
|
50
|
+
try:
|
51
|
+
contact = await session.contacts.by_jid(pfrom)
|
52
|
+
except XMPPError:
|
49
53
|
return stanza
|
50
|
-
ver = await
|
54
|
+
ver = await contact.get_caps_ver(pfrom)
|
51
55
|
else:
|
52
56
|
ver = await caps.get_verstring(pfrom)
|
53
57
|
|
@@ -5,15 +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
|
8
|
+
from .util import DispatcherMixin
|
9
9
|
|
10
10
|
if TYPE_CHECKING:
|
11
|
-
from .
|
11
|
+
from slidge.core.gateway import BaseGateway
|
12
12
|
|
13
13
|
|
14
|
-
class
|
14
|
+
class DiscoMixin(DispatcherMixin):
|
15
15
|
def __init__(self, xmpp: "BaseGateway"):
|
16
|
-
|
16
|
+
super().__init__(xmpp)
|
17
17
|
|
18
18
|
xmpp.plugin["xep_0030"].set_node_handler(
|
19
19
|
"get_info",
|
@@ -38,15 +38,11 @@ class Disco:
|
|
38
38
|
if ifrom is None:
|
39
39
|
raise XMPPError("subscription-required")
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
raise XMPPError("registration-required")
|
44
|
-
session = self.xmpp.get_session_from_user(user)
|
45
|
-
await session.wait_for_ready()
|
41
|
+
assert jid is not None
|
42
|
+
session = await self._get_session_from_jid(jid=ifrom)
|
46
43
|
|
47
44
|
log.debug("Looking for entity: %s", jid)
|
48
45
|
|
49
|
-
assert jid is not None
|
50
46
|
entity = await session.get_contact_or_group_or_participant(jid)
|
51
47
|
|
52
48
|
if entity is None:
|
@@ -63,16 +59,12 @@ class Disco:
|
|
63
59
|
if jid != self.xmpp.boundjid.bare:
|
64
60
|
return DiscoItems()
|
65
61
|
|
66
|
-
|
67
|
-
|
68
|
-
raise XMPPError("registration-required")
|
69
|
-
|
70
|
-
session = self.xmpp.get_session_from_user(user)
|
71
|
-
await session.wait_for_ready()
|
62
|
+
assert ifrom is not None
|
63
|
+
session = await self._get_session_from_jid(ifrom)
|
72
64
|
|
73
65
|
d = DiscoItems()
|
74
|
-
for
|
75
|
-
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)
|
76
68
|
|
77
69
|
return d
|
78
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
|
+
)
|