slidge 0.1.0rc1__py3-none-any.whl → 0.1.1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) hide show
  1. slidge/__init__.py +54 -31
  2. slidge/__main__.py +51 -5
  3. slidge/command/__init__.py +28 -0
  4. slidge/command/adhoc.py +258 -0
  5. slidge/command/admin.py +193 -0
  6. slidge/command/base.py +441 -0
  7. slidge/command/categories.py +3 -0
  8. slidge/command/chat_command.py +288 -0
  9. slidge/command/register.py +179 -0
  10. slidge/command/user.py +250 -0
  11. slidge/contact/__init__.py +8 -0
  12. slidge/contact/contact.py +452 -0
  13. slidge/contact/roster.py +192 -0
  14. slidge/core/__init__.py +2 -0
  15. slidge/core/cache.py +121 -39
  16. slidge/core/config.py +116 -11
  17. slidge/core/gateway/__init__.py +3 -0
  18. slidge/core/gateway/base.py +895 -0
  19. slidge/core/gateway/caps.py +63 -0
  20. slidge/core/gateway/delivery_receipt.py +52 -0
  21. slidge/core/gateway/disco.py +80 -0
  22. slidge/core/gateway/mam.py +75 -0
  23. slidge/core/gateway/muc_admin.py +35 -0
  24. slidge/core/gateway/ping.py +66 -0
  25. slidge/core/gateway/presence.py +95 -0
  26. slidge/core/gateway/registration.py +53 -0
  27. slidge/core/gateway/search.py +102 -0
  28. slidge/core/gateway/session_dispatcher.py +789 -0
  29. slidge/core/gateway/vcard_temp.py +130 -0
  30. slidge/core/mixins/__init__.py +9 -1
  31. slidge/core/mixins/attachment.py +506 -0
  32. slidge/core/mixins/avatar.py +167 -0
  33. slidge/core/mixins/base.py +6 -19
  34. slidge/core/mixins/disco.py +66 -15
  35. slidge/core/mixins/lock.py +31 -0
  36. slidge/core/mixins/message.py +254 -252
  37. slidge/core/mixins/message_maker.py +154 -0
  38. slidge/core/mixins/presence.py +128 -31
  39. slidge/core/mixins/recipient.py +43 -0
  40. slidge/core/pubsub.py +275 -116
  41. slidge/core/session.py +586 -518
  42. slidge/group/__init__.py +10 -0
  43. slidge/group/archive.py +125 -0
  44. slidge/group/bookmarks.py +163 -0
  45. slidge/group/participant.py +458 -0
  46. slidge/group/room.py +1103 -0
  47. slidge/migration.py +18 -0
  48. slidge/slixfix/__init__.py +68 -0
  49. slidge/{util/xep_0050 → slixfix/link_preview}/__init__.py +4 -5
  50. slidge/slixfix/link_preview/link_preview.py +17 -0
  51. slidge/slixfix/link_preview/stanza.py +99 -0
  52. slidge/slixfix/roster.py +60 -0
  53. slidge/{util → slixfix}/xep_0077/register.py +1 -2
  54. slidge/slixfix/xep_0077/stanza.py +104 -0
  55. slidge/{util → slixfix}/xep_0100/gateway.py +17 -12
  56. slidge/slixfix/xep_0153/__init__.py +10 -0
  57. slidge/slixfix/xep_0153/stanza.py +25 -0
  58. slidge/slixfix/xep_0153/vcard_avatar.py +23 -0
  59. slidge/slixfix/xep_0264/__init__.py +5 -0
  60. slidge/slixfix/xep_0264/stanza.py +36 -0
  61. slidge/slixfix/xep_0264/thumbnail.py +23 -0
  62. slidge/slixfix/xep_0292/__init__.py +5 -0
  63. slidge/slixfix/xep_0292/vcard4.py +100 -0
  64. slidge/slixfix/xep_0313/__init__.py +12 -0
  65. slidge/slixfix/xep_0313/mam.py +262 -0
  66. slidge/slixfix/xep_0313/stanza.py +359 -0
  67. slidge/slixfix/xep_0317/__init__.py +5 -0
  68. slidge/slixfix/xep_0317/hats.py +17 -0
  69. slidge/slixfix/xep_0317/stanza.py +28 -0
  70. slidge/{util → slixfix}/xep_0356_old/privilege.py +9 -7
  71. slidge/slixfix/xep_0424/__init__.py +9 -0
  72. slidge/slixfix/xep_0424/retraction.py +77 -0
  73. slidge/slixfix/xep_0424/stanza.py +28 -0
  74. slidge/slixfix/xep_0490/__init__.py +8 -0
  75. slidge/slixfix/xep_0490/mds.py +47 -0
  76. slidge/slixfix/xep_0490/stanza.py +17 -0
  77. slidge/util/__init__.py +4 -6
  78. slidge/util/archive_msg.py +61 -0
  79. slidge/util/conf.py +25 -4
  80. slidge/util/db.py +23 -69
  81. slidge/util/schema.sql +126 -0
  82. slidge/util/sql.py +508 -0
  83. slidge/util/test.py +136 -86
  84. slidge/util/types.py +155 -14
  85. slidge/util/util.py +225 -51
  86. slidge-0.1.1.dist-info/METADATA +110 -0
  87. slidge-0.1.1.dist-info/RECORD +96 -0
  88. {slidge-0.1.0rc1.dist-info → slidge-0.1.1.dist-info}/WHEEL +1 -1
  89. slidge/core/adhoc.py +0 -492
  90. slidge/core/chat_command.py +0 -197
  91. slidge/core/contact.py +0 -441
  92. slidge/core/disco.py +0 -59
  93. slidge/core/gateway.py +0 -899
  94. slidge/core/muc/__init__.py +0 -3
  95. slidge/core/muc/bookmarks.py +0 -74
  96. slidge/core/muc/participant.py +0 -152
  97. slidge/core/muc/room.py +0 -348
  98. slidge/plugins/discord/__init__.py +0 -121
  99. slidge/plugins/discord/client.py +0 -121
  100. slidge/plugins/discord/session.py +0 -172
  101. slidge/plugins/dummy.py +0 -334
  102. slidge/plugins/facebook.py +0 -591
  103. slidge/plugins/hackernews.py +0 -209
  104. slidge/plugins/mattermost/__init__.py +0 -1
  105. slidge/plugins/mattermost/api.py +0 -288
  106. slidge/plugins/mattermost/gateway.py +0 -417
  107. slidge/plugins/mattermost/websocket.py +0 -248
  108. slidge/plugins/signal/__init__.py +0 -4
  109. slidge/plugins/signal/config.py +0 -4
  110. slidge/plugins/signal/contact.py +0 -104
  111. slidge/plugins/signal/gateway.py +0 -379
  112. slidge/plugins/signal/group.py +0 -76
  113. slidge/plugins/signal/session.py +0 -515
  114. slidge/plugins/signal/txt.py +0 -13
  115. slidge/plugins/signal/util.py +0 -32
  116. slidge/plugins/skype.py +0 -310
  117. slidge/plugins/steam.py +0 -400
  118. slidge/plugins/telegram/__init__.py +0 -6
  119. slidge/plugins/telegram/client.py +0 -325
  120. slidge/plugins/telegram/config.py +0 -21
  121. slidge/plugins/telegram/contact.py +0 -154
  122. slidge/plugins/telegram/gateway.py +0 -182
  123. slidge/plugins/telegram/group.py +0 -184
  124. slidge/plugins/telegram/session.py +0 -275
  125. slidge/plugins/telegram/util.py +0 -153
  126. slidge/plugins/whatsapp/__init__.py +0 -6
  127. slidge/plugins/whatsapp/config.py +0 -17
  128. slidge/plugins/whatsapp/contact.py +0 -33
  129. slidge/plugins/whatsapp/event.go +0 -455
  130. slidge/plugins/whatsapp/gateway.go +0 -156
  131. slidge/plugins/whatsapp/gateway.py +0 -69
  132. slidge/plugins/whatsapp/go.mod +0 -17
  133. slidge/plugins/whatsapp/go.sum +0 -22
  134. slidge/plugins/whatsapp/session.go +0 -371
  135. slidge/plugins/whatsapp/session.py +0 -370
  136. slidge/util/xep_0030/__init__.py +0 -13
  137. slidge/util/xep_0030/disco.py +0 -811
  138. slidge/util/xep_0030/stanza/__init__.py +0 -7
  139. slidge/util/xep_0030/stanza/info.py +0 -270
  140. slidge/util/xep_0030/stanza/items.py +0 -147
  141. slidge/util/xep_0030/static.py +0 -467
  142. slidge/util/xep_0050/adhoc.py +0 -631
  143. slidge/util/xep_0050/stanza.py +0 -180
  144. slidge/util/xep_0077/stanza.py +0 -71
  145. slidge/util/xep_0292/__init__.py +0 -1
  146. slidge/util/xep_0292/stanza.py +0 -167
  147. slidge/util/xep_0292/vcard4.py +0 -74
  148. slidge/util/xep_0356/__init__.py +0 -7
  149. slidge/util/xep_0356/permissions.py +0 -35
  150. slidge/util/xep_0356/privilege.py +0 -160
  151. slidge/util/xep_0356/stanza.py +0 -44
  152. slidge/util/xep_0461/__init__.py +0 -6
  153. slidge/util/xep_0461/reply.py +0 -48
  154. slidge/util/xep_0461/stanza.py +0 -80
  155. slidge-0.1.0rc1.dist-info/METADATA +0 -171
  156. slidge-0.1.0rc1.dist-info/RECORD +0 -99
  157. /slidge/{plugins/__init__.py → py.typed} +0 -0
  158. /slidge/{util → slixfix}/xep_0077/__init__.py +0 -0
  159. /slidge/{util → slixfix}/xep_0100/__init__.py +0 -0
  160. /slidge/{util → slixfix}/xep_0100/stanza.py +0 -0
  161. /slidge/{util → slixfix}/xep_0356_old/__init__.py +0 -0
  162. /slidge/{util → slixfix}/xep_0356_old/stanza.py +0 -0
  163. {slidge-0.1.0rc1.dist-info → slidge-0.1.1.dist-info}/LICENSE +0 -0
  164. {slidge-0.1.0rc1.dist-info → slidge-0.1.1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,10 @@
1
+ """
2
+ Everything related to groups.
3
+ """
4
+
5
+ from ..util.types import MucType
6
+ from .bookmarks import LegacyBookmarks
7
+ from .participant import LegacyParticipant
8
+ from .room import LegacyMUC
9
+
10
+ __all__ = ("LegacyBookmarks", "LegacyParticipant", "LegacyMUC", "MucType")
@@ -0,0 +1,125 @@
1
+ import logging
2
+ import uuid
3
+ from copy import copy
4
+ from datetime import datetime
5
+ from typing import TYPE_CHECKING, Collection, Optional
6
+
7
+ from slixmpp import Iq, Message
8
+
9
+ from ..util.archive_msg import HistoryMessage
10
+ from ..util.db import GatewayUser
11
+ from ..util.sql import db
12
+
13
+ if TYPE_CHECKING:
14
+ from .participant import LegacyParticipant
15
+
16
+
17
+ class MessageArchive:
18
+ def __init__(self, db_id: str, user: GatewayUser):
19
+ self.db_id = db_id
20
+ self.user = user
21
+ db.mam_add_muc(db_id, user)
22
+
23
+ def add(
24
+ self,
25
+ msg: Message,
26
+ participant: Optional["LegacyParticipant"] = None,
27
+ ):
28
+ """
29
+ Add a message to the archive if it is deemed archivable
30
+
31
+ :param msg:
32
+ :param participant:
33
+ """
34
+ if not archivable(msg):
35
+ return
36
+ new_msg = copy(msg)
37
+ if participant and not participant.muc.is_anonymous:
38
+ new_msg["muc"]["role"] = participant.role
39
+ new_msg["muc"]["affiliation"] = participant.affiliation
40
+ if participant.contact:
41
+ new_msg["muc"]["jid"] = participant.contact.jid.bare
42
+ elif participant.is_user:
43
+ new_msg["muc"]["jid"] = participant.user.jid.bare
44
+ elif participant.is_system:
45
+ new_msg["muc"]["jid"] = participant.muc.jid
46
+ else:
47
+ log.warning("No real JID for participant in this group")
48
+ new_msg["muc"][
49
+ "jid"
50
+ ] = f"{uuid.uuid4()}@{participant.xmpp.boundjid.bare}"
51
+
52
+ db.mam_add_msg(self.db_id, HistoryMessage(new_msg), self.user)
53
+
54
+ def __iter__(self):
55
+ return iter(self.get_all())
56
+
57
+ def get_all(
58
+ self,
59
+ start_date: Optional[datetime] = None,
60
+ end_date: Optional[datetime] = None,
61
+ before_id: Optional[str] = None,
62
+ after_id: Optional[str] = None,
63
+ ids: Collection[str] = (),
64
+ last_page_n: Optional[int] = None,
65
+ sender: Optional[str] = None,
66
+ flip=False,
67
+ ):
68
+ for msg in db.mam_get_messages(
69
+ self.user,
70
+ self.db_id,
71
+ before_id=before_id,
72
+ after_id=after_id,
73
+ ids=ids,
74
+ last_page_n=last_page_n,
75
+ sender=sender,
76
+ start_date=start_date,
77
+ end_date=end_date,
78
+ flip=flip,
79
+ ):
80
+ yield msg
81
+
82
+ async def send_metadata(self, iq: Iq):
83
+ """
84
+ Send archive extent, as per the spec
85
+
86
+ :param iq:
87
+ :return:
88
+ """
89
+ reply = iq.reply()
90
+ messages = db.mam_get_first_and_last(self.db_id)
91
+ if messages:
92
+ for x, m in [("start", messages[0]), ("end", messages[-1])]:
93
+ reply["mam_metadata"][x]["id"] = m.id
94
+ reply["mam_metadata"][x]["timestamp"] = m.sent_on
95
+ else:
96
+ reply.enable("mam_metadata")
97
+ reply.send()
98
+
99
+
100
+ def archivable(msg: Message):
101
+ """
102
+ Determine if a message stanza is worth archiving, ie, convey meaningful
103
+ info
104
+
105
+ :param msg:
106
+ :return:
107
+ """
108
+
109
+ if msg.get_plugin("hint", check=True) and msg["hint"] == "no-store":
110
+ return False
111
+
112
+ if msg["body"]:
113
+ return True
114
+
115
+ if msg.get_plugin("apply_to", check=True):
116
+ # retractions
117
+ return True
118
+
119
+ if msg.get_plugin("reactions", check=True):
120
+ return True
121
+
122
+ return False
123
+
124
+
125
+ log = logging.getLogger(__name__)
@@ -0,0 +1,163 @@
1
+ import abc
2
+ import logging
3
+ from typing import TYPE_CHECKING, Generic, Type
4
+
5
+ from slixmpp import JID
6
+ from slixmpp.jid import _unescape_node
7
+
8
+ from ..contact.roster import ESCAPE_TABLE
9
+ from ..core.mixins.lock import NamedLockMixin
10
+ from ..util import SubclassableOnce
11
+ from ..util.types import LegacyGroupIdType, LegacyMUCType
12
+ from .room import LegacyMUC
13
+
14
+ if TYPE_CHECKING:
15
+ from slidge.core.session import BaseSession
16
+
17
+
18
+ class LegacyBookmarks(
19
+ Generic[LegacyGroupIdType, LegacyMUCType],
20
+ NamedLockMixin,
21
+ metaclass=SubclassableOnce,
22
+ ):
23
+ """
24
+ This is instantiated once per :class:`~slidge.BaseSession`
25
+ """
26
+
27
+ def __init__(self, session: "BaseSession"):
28
+ self.session = session
29
+ self.xmpp = session.xmpp
30
+ self.user = session.user
31
+
32
+ self._mucs_by_legacy_id = dict[LegacyGroupIdType, LegacyMUCType]()
33
+ self._mucs_by_bare_jid = dict[str, LegacyMUCType]()
34
+
35
+ self._muc_class: Type[LegacyMUCType] = LegacyMUC.get_self_or_unique_subclass()
36
+
37
+ self._user_nick: str = self.session.user.jid.node
38
+
39
+ super().__init__()
40
+ self.log = logging.getLogger(f"{self.user.bare_jid}:bookmarks")
41
+ self.ready = self.session.xmpp.loop.create_future()
42
+ if not self.xmpp.GROUPS:
43
+ self.ready.set_result(True)
44
+
45
+ @property
46
+ def user_nick(self):
47
+ return self._user_nick
48
+
49
+ @user_nick.setter
50
+ def user_nick(self, nick: str):
51
+ self._user_nick = nick
52
+
53
+ def __iter__(self):
54
+ return iter(self._mucs_by_legacy_id.values())
55
+
56
+ def __repr__(self):
57
+ return f"<Bookmarks of {self.user}>"
58
+
59
+ async def __finish_init_muc(self, legacy_id: LegacyGroupIdType, jid: JID):
60
+ muc = self._muc_class(self.session, legacy_id=legacy_id, jid=jid)
61
+ await muc.avatar_wrap_update_info()
62
+ if not muc.user_nick:
63
+ muc.user_nick = self._user_nick
64
+ self.log.debug("MUC created: %r", muc)
65
+ self._mucs_by_legacy_id[muc.legacy_id] = muc
66
+ self._mucs_by_bare_jid[muc.jid.bare] = muc
67
+ return muc
68
+
69
+ async def legacy_id_to_jid_local_part(self, legacy_id: LegacyGroupIdType):
70
+ return await self.legacy_id_to_jid_username(legacy_id)
71
+
72
+ async def jid_local_part_to_legacy_id(self, local_part: str):
73
+ return await self.jid_username_to_legacy_id(local_part)
74
+
75
+ async def legacy_id_to_jid_username(self, legacy_id: LegacyGroupIdType):
76
+ """
77
+ The default implementation calls ``str()`` on the legacy_id and
78
+ escape characters according to :xep:`0106`.
79
+
80
+ You can override this class and implement a more subtle logic to raise
81
+ an :class:`~slixmpp.exceptions.XMPPError` early
82
+
83
+ :param legacy_id:
84
+ :return:
85
+ """
86
+ return str(legacy_id).translate(ESCAPE_TABLE)
87
+
88
+ async def jid_username_to_legacy_id(self, username: str):
89
+ """
90
+
91
+ :param username:
92
+ :return:
93
+ """
94
+ return _unescape_node(username)
95
+
96
+ async def by_jid(self, jid: JID) -> LegacyMUCType:
97
+ bare = jid.bare
98
+ async with self.lock(("bare", bare)):
99
+ muc = self._mucs_by_bare_jid.get(bare)
100
+ if muc is None:
101
+ self.log.debug("Attempting to instantiate a new MUC for JID %s", jid)
102
+ local_part = jid.node
103
+ legacy_id = await self.jid_local_part_to_legacy_id(local_part)
104
+ if self.get_lock(("legacy_id", legacy_id)):
105
+ self.log.debug("Not instantiating %s after all", jid)
106
+ return await self.by_legacy_id(legacy_id)
107
+ self.log.debug("%r is group %r", local_part, legacy_id)
108
+ muc = await self.__finish_init_muc(legacy_id, JID(bare))
109
+ else:
110
+ self.log.trace("Found an existing MUC instance: %s", muc) # type:ignore
111
+ return muc
112
+
113
+ async def by_legacy_id(self, legacy_id: LegacyGroupIdType) -> LegacyMUCType:
114
+ async with self.lock(("legacy_id", legacy_id)):
115
+ muc = self._mucs_by_legacy_id.get(legacy_id)
116
+ if muc is None:
117
+ self.log.debug("Create new MUC instance for legacy ID %s", legacy_id)
118
+ local = await self.legacy_id_to_jid_local_part(legacy_id)
119
+ bare = f"{local}@{self.xmpp.boundjid}"
120
+ jid = JID(bare)
121
+ if self.get_lock(("bare", bare)):
122
+ self.log.debug("Not instantiating %s after all", legacy_id)
123
+ return await self.by_jid(jid)
124
+ muc = await self.__finish_init_muc(legacy_id, jid)
125
+ else:
126
+ self.log.trace("Found an existing MUC instance: %s", muc) # type:ignore
127
+
128
+ return muc
129
+
130
+ @abc.abstractmethod
131
+ async def fill(self):
132
+ """
133
+ Establish a user's known groups.
134
+
135
+ This has to be overridden in plugins with group support and at the
136
+ minimum, this should ``await self.by_legacy_id(group_id)`` for all
137
+ the groups a user is part of.
138
+
139
+ Slidge internals will call this on successful :meth:`BaseSession.login`
140
+
141
+ """
142
+ if self.xmpp.GROUPS:
143
+ raise NotImplementedError(
144
+ "The plugin advertised support for groups but"
145
+ " LegacyBookmarks.fill() was not overridden."
146
+ )
147
+
148
+ def remove(self, muc: LegacyMUC):
149
+ try:
150
+ del self._mucs_by_legacy_id[muc.legacy_id]
151
+ except KeyError:
152
+ self.log.warning("Removed a MUC that we didn't store by legacy ID")
153
+ try:
154
+ del self._mucs_by_bare_jid[muc.jid.bare]
155
+ except KeyError:
156
+ self.log.warning("Removed a MUC that we didn't store by JID")
157
+ for part in muc._participants_by_contacts.values():
158
+ try:
159
+ part.contact.participants.remove(part)
160
+ except KeyError:
161
+ part.log.warning(
162
+ "That participant wasn't stored in the contact's participants attribute"
163
+ )