slidge 0.1.0rc1__py3-none-any.whl → 0.1.2__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 +795 -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.2.dist-info/METADATA +111 -0
  87. slidge-0.1.2.dist-info/RECORD +96 -0
  88. {slidge-0.1.0rc1.dist-info → slidge-0.1.2.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.2.dist-info}/LICENSE +0 -0
  164. {slidge-0.1.0rc1.dist-info → slidge-0.1.2.dist-info}/entry_points.txt +0 -0
@@ -4,16 +4,15 @@ from collections import defaultdict
4
4
 
5
5
  from slixmpp import JID, Iq, Message
6
6
  from slixmpp.plugins.base import BasePlugin
7
- from slixmpp.types import JidStr
8
- from slixmpp.xmlstream import StanzaBase
9
- from slixmpp.xmlstream.handler import Callback
10
- from slixmpp.xmlstream.matcher import StanzaPath
11
-
12
- from slidge.util.xep_0356.permissions import (
7
+ from slixmpp.plugins.xep_0356.permissions import (
13
8
  MessagePermission,
14
9
  Permissions,
15
10
  RosterAccess,
16
11
  )
12
+ from slixmpp.types import JidStr
13
+ from slixmpp.xmlstream import StanzaBase
14
+ from slixmpp.xmlstream.handler import Callback
15
+ from slixmpp.xmlstream.matcher import StanzaPath
17
16
 
18
17
  from . import stanza
19
18
 
@@ -72,7 +71,10 @@ class XEP_0356_OLD(BasePlugin):
72
71
  self.xmpp.event("privileges_advertised_old")
73
72
 
74
73
  def send_privileged_message(self, msg: Message):
75
- if self.granted_privileges[msg.get_from().domain].message != MessagePermission.OUTGOING:
74
+ if (
75
+ self.granted_privileges[msg.get_from().domain].message
76
+ != MessagePermission.OUTGOING
77
+ ):
76
78
  raise PermissionError(
77
79
  "The server hasn't authorized us to send messages on behalf of other users"
78
80
  )
@@ -0,0 +1,9 @@
1
+ # Slixmpp: The Slick XMPP Library
2
+ # Copyright (C) 2020 Mathieu Pasquet <mathieui@mathieui.net>
3
+ # This file is part of Slixmpp.
4
+ # See the file LICENSE for copying permission.
5
+ from slixmpp.plugins.base import register_plugin
6
+
7
+ from .retraction import XEP_0424
8
+
9
+ register_plugin(XEP_0424)
@@ -0,0 +1,77 @@
1
+ # Slixmpp: The Slick XMPP Library
2
+ # Copyright (C) 2020 Mathieu Pasquet <mathieui@mathieui.net>
3
+ # This file is part of Slixmpp.
4
+ # See the file LICENSE for copying permission.
5
+ from typing import Optional
6
+
7
+ from slixmpp import JID, Message
8
+ from slixmpp.exceptions import IqError, IqTimeout
9
+ from slixmpp.plugins import BasePlugin
10
+ from slixmpp.xmlstream.handler import Callback
11
+ from slixmpp.xmlstream.matcher import StanzaPath
12
+
13
+ from . import stanza
14
+
15
+ DEFAULT_FALLBACK = (
16
+ "This person attempted to retract a previous message, but your client "
17
+ "does not support it."
18
+ )
19
+
20
+
21
+ class XEP_0424(BasePlugin):
22
+ """XEP-0424: Message Retraction"""
23
+
24
+ name = "xep_0424"
25
+ description = "XEP-0424: Message Retraction (fix Slidge)"
26
+ dependencies = {"xep_0422", "xep_0030", "xep_0359", "xep_0428", "xep_0334"}
27
+ stanza = stanza
28
+ namespace = stanza.NS
29
+
30
+ def plugin_init(self) -> None:
31
+ stanza.register_plugins()
32
+ self.xmpp.register_handler(
33
+ Callback(
34
+ "Message Retracted",
35
+ StanzaPath("message/retract"),
36
+ self._handle_retract_message,
37
+ )
38
+ )
39
+
40
+ def session_bind(self, jid):
41
+ self.xmpp.plugin["xep_0030"].add_feature(feature=stanza.NS)
42
+
43
+ def plugin_end(self):
44
+ self.xmpp.plugin["xep_0030"].del_feature(feature=stanza.NS)
45
+
46
+ def _handle_retract_message(self, message: Message):
47
+ self.xmpp.event("message_retract", message)
48
+
49
+ def send_retraction(
50
+ self,
51
+ mto: JID,
52
+ id: str,
53
+ mtype: str = "chat",
54
+ include_fallback: bool = True,
55
+ fallback_text: Optional[str] = None,
56
+ *,
57
+ mfrom: Optional[JID] = None
58
+ ):
59
+ """
60
+ Send a message retraction
61
+
62
+ :param JID mto: The JID to retract the message from
63
+ :param str id: Message ID to retract
64
+ :param str mtype: Message type
65
+ :param bool include_fallback: Whether to include a fallback body
66
+ :param Optional[str] fallback_text: The content of the fallback
67
+ body. None will set the default value.
68
+ """
69
+ if fallback_text is None:
70
+ fallback_text = DEFAULT_FALLBACK
71
+ msg = self.xmpp.make_message(mto=mto, mtype=mtype, mfrom=mfrom)
72
+ if include_fallback:
73
+ msg["body"] = fallback_text
74
+ msg.enable("fallback")
75
+ msg["retract"]["id"] = id
76
+ msg.enable("store")
77
+ msg.send()
@@ -0,0 +1,28 @@
1
+ # Slixmpp: The Slick XMPP Library
2
+ # Copyright (C) 2020 Mathieu Pasquet <mathieui@mathieui.net>
3
+ # This file is part of Slixmpp.
4
+ # See the file LICENSE for copying permissio
5
+ from slixmpp.plugins.xep_0359 import OriginID
6
+ from slixmpp.stanza import Message
7
+ from slixmpp.xmlstream import ElementBase, register_stanza_plugin
8
+
9
+ NS = "urn:xmpp:message-retract:1"
10
+
11
+
12
+ class Retract(ElementBase):
13
+ namespace = NS
14
+ name = "retract"
15
+ plugin_attrib = "retract"
16
+
17
+
18
+ class Retracted(ElementBase):
19
+ namespace = NS
20
+ name = "retracted"
21
+ plugin_attrib = "retracted"
22
+ interfaces = {"stamp"}
23
+
24
+
25
+ def register_plugins():
26
+ register_stanza_plugin(Message, Retract)
27
+ register_stanza_plugin(Message, Retracted)
28
+ register_stanza_plugin(Retracted, OriginID)
@@ -0,0 +1,8 @@
1
+ from slixmpp.plugins.base import register_plugin
2
+
3
+ from . import stanza
4
+ from .mds import XEP_0490
5
+
6
+ register_plugin(XEP_0490)
7
+
8
+ __all__ = ["stanza", "XEP_0490"]
@@ -0,0 +1,47 @@
1
+ from slixmpp import Iq
2
+ from slixmpp.plugins import BasePlugin
3
+ from slixmpp.plugins.xep_0004 import Form
4
+ from slixmpp.types import JidStr
5
+
6
+ from . import stanza
7
+
8
+
9
+ class XEP_0490(BasePlugin):
10
+ """
11
+ XEP-0490: Message Displayed Synchronization
12
+ """
13
+
14
+ name = "xep_0490"
15
+ description = "XEP-0490: Message Displayed Synchronization"
16
+ dependencies = {"xep_0060", "xep_0163", "xep_0359"}
17
+ stanza = stanza
18
+
19
+ def plugin_init(self):
20
+ stanza.register_plugin()
21
+ self.xmpp.plugin["xep_0163"].register_pep(
22
+ "message_displayed_synchronization",
23
+ stanza.Displayed,
24
+ )
25
+
26
+ def flag_chat(self, chat: JidStr, stanza_id: str, **kwargs) -> Iq:
27
+ displayed = stanza.Displayed()
28
+ displayed["stanza_id"]["id"] = stanza_id
29
+ return self.xmpp.plugin["xep_0163"].publish(
30
+ displayed, node=stanza.NS, options=PUBLISH_OPTIONS, id=str(chat), **kwargs
31
+ )
32
+
33
+ def catch_up(self, **kwargs):
34
+ return self.xmpp.plugin["xep_0060"].get_items(
35
+ self.xmpp.boundjid.bare, stanza.NS, **kwargs
36
+ )
37
+
38
+
39
+ PUBLISH_OPTIONS = Form()
40
+ PUBLISH_OPTIONS["type"] = "submit"
41
+ PUBLISH_OPTIONS.add_field(
42
+ "FORM_TYPE", "hidden", value="http://jabber.org/protocol/pubsub#publish-options"
43
+ )
44
+ PUBLISH_OPTIONS.add_field("pubsub#persist_items", value="true")
45
+ PUBLISH_OPTIONS.add_field("pubsub#max_items", value="max")
46
+ PUBLISH_OPTIONS.add_field("pubsub#send_last_published_item", value="never")
47
+ PUBLISH_OPTIONS.add_field("pubsub#access_model", value="whitelist")
@@ -0,0 +1,17 @@
1
+ from slixmpp import register_stanza_plugin
2
+ from slixmpp.plugins.xep_0060.stanza import Item
3
+ from slixmpp.plugins.xep_0359.stanza import StanzaID
4
+ from slixmpp.xmlstream import ElementBase
5
+
6
+ NS = "urn:xmpp:mds:displayed:0"
7
+
8
+
9
+ class Displayed(ElementBase):
10
+ namespace = NS
11
+ name = "displayed"
12
+ plugin_attrib = "displayed"
13
+
14
+
15
+ def register_plugin():
16
+ register_stanza_plugin(Displayed, StanzaID)
17
+ register_stanza_plugin(Item, Displayed)
slidge/util/__init__.py CHANGED
@@ -1,17 +1,15 @@
1
1
  from .util import (
2
2
  ABCSubclassableOnceAtMost,
3
- BiDict,
4
- FormField,
5
- SearchResult,
6
3
  SubclassableOnce,
7
4
  is_valid_phone_number,
5
+ replace_mentions,
6
+ strip_illegal_chars,
8
7
  )
9
8
 
10
9
  __all__ = [
11
- "BiDict",
12
- "SearchResult",
13
- "FormField",
14
10
  "SubclassableOnce",
15
11
  "ABCSubclassableOnceAtMost",
16
12
  "is_valid_phone_number",
13
+ "replace_mentions",
14
+ "strip_illegal_chars",
17
15
  ]
@@ -0,0 +1,61 @@
1
+ from copy import copy
2
+ from datetime import datetime, timezone
3
+ from typing import Optional, Union
4
+ from xml.etree import ElementTree as ET
5
+
6
+ from slixmpp import Message
7
+ from slixmpp.plugins.xep_0297 import Forwarded
8
+
9
+
10
+ def fix_namespaces(xml, old="{jabber:component:accept}", new="{jabber:client}"):
11
+ """
12
+ Hack to fix namespaces between jabber:component and jabber:client
13
+
14
+ Acts in-place.
15
+
16
+ :param xml:
17
+ :param old:
18
+ :param new:
19
+ """
20
+ xml.tag = xml.tag.replace(old, new)
21
+ for child in xml:
22
+ fix_namespaces(child, old, new)
23
+
24
+
25
+ class HistoryMessage:
26
+ def __init__(self, stanza: Union[Message, str], when: Optional[datetime] = None):
27
+ if isinstance(stanza, str):
28
+ from_db = True
29
+ stanza = Message(xml=ET.fromstring(stanza))
30
+ else:
31
+ from_db = False
32
+
33
+ self.id = stanza["stanza_id"]["id"]
34
+ self.when: datetime = (
35
+ when or stanza["delay"]["stamp"] or datetime.now(tz=timezone.utc)
36
+ )
37
+
38
+ if not from_db:
39
+ del stanza["delay"]
40
+ del stanza["markable"]
41
+ del stanza["hint"]
42
+ del stanza["chat_state"]
43
+ if not stanza["body"]:
44
+ del stanza["body"]
45
+ fix_namespaces(stanza.xml)
46
+
47
+ self.stanza: Message = stanza
48
+
49
+ @property
50
+ def stanza_component_ns(self):
51
+ stanza = copy(self.stanza)
52
+ fix_namespaces(
53
+ stanza.xml, old="{jabber:client}", new="{jabber:component:accept}"
54
+ )
55
+ return stanza
56
+
57
+ def forwarded(self):
58
+ forwarded = Forwarded()
59
+ forwarded["delay"]["stamp"] = self.when
60
+ forwarded.append(self.stanza)
61
+ return forwarded
slidge/util/conf.py CHANGED
@@ -97,7 +97,6 @@ class ConfigModule:
97
97
  def __init__(
98
98
  self, config_obj, parser: Optional[configargparse.ArgumentParser] = None
99
99
  ):
100
-
101
100
  self.config_obj = config_obj
102
101
  if parser is None:
103
102
  parser = configargparse.ArgumentParser()
@@ -127,13 +126,25 @@ class ConfigModule:
127
126
  if skip_next:
128
127
  skip_next = False
129
128
  continue
129
+ force_keep = False
130
130
  if "=" in a:
131
131
  real_name, _value = a.split("=")
132
132
  opt: Optional[Option] = options_long.get(
133
133
  _argv_to_option_name(real_name)
134
134
  )
135
135
  if opt and opt.type is bool:
136
- a = real_name
136
+ if opt.default:
137
+ if _value in _TRUEISH or not _value:
138
+ continue
139
+ else:
140
+ a = real_name
141
+ force_keep = True
142
+ else:
143
+ if _value in _TRUEISH:
144
+ a = real_name
145
+ force_keep = True
146
+ else:
147
+ continue
137
148
  else:
138
149
  upper = _argv_to_option_name(a)
139
150
  opt = options_long.get(upper)
@@ -142,7 +153,14 @@ class ConfigModule:
142
153
  log.debug("Removing %s from argv", aa)
143
154
  skip_next = True
144
155
 
145
- no_explicit_bool.append(a)
156
+ if opt:
157
+ if opt.type is bool:
158
+ if force_keep or not opt.default:
159
+ no_explicit_bool.append(a)
160
+ else:
161
+ no_explicit_bool.append(a)
162
+ else:
163
+ no_explicit_bool.append(a)
146
164
  log.debug("Removed boolean values from %s to %s", argv, no_explicit_bool)
147
165
  argv = no_explicit_bool
148
166
 
@@ -163,7 +181,7 @@ class ConfigModule:
163
181
 
164
182
  def add_options_to_parser(self):
165
183
  p = self.parser
166
- for o in self.options:
184
+ for o in sorted(self.options, key=lambda x: (not x.required, x.name)):
167
185
  p.add_argument(*o.names, **o.kwargs)
168
186
 
169
187
  def update_dynamic_defaults(self, args):
@@ -182,4 +200,7 @@ def _argv_to_option_name(arg: str):
182
200
  return arg.upper().removeprefix("--").replace("-", "_")
183
201
 
184
202
 
203
+ _TRUEISH = {"true", "True", "1", "on", "enabled"}
204
+
205
+
185
206
  log = logging.getLogger(__name__)
slidge/util/db.py CHANGED
@@ -15,6 +15,8 @@ from typing import Iterable, Optional, Union
15
15
  from pickle_secure import Pickler, Unpickler
16
16
  from slixmpp import JID, Iq, Message, Presence
17
17
 
18
+ from .sql import db
19
+
18
20
 
19
21
  # noinspection PyUnresolvedReferences
20
22
  class EncryptedShelf(shelve.DbfilenameShelf):
@@ -35,7 +37,7 @@ class EncryptedShelf(shelve.DbfilenameShelf):
35
37
  value = self.cache[key]
36
38
  except KeyError:
37
39
  f = BytesIO(self.dict[key.encode(self.keyencoding)])
38
- value = Unpickler(f, key=self.secret_key).load()
40
+ value = Unpickler(f, key=self.secret_key).load() # type:ignore
39
41
  if self.writeback:
40
42
  self.cache[key] = value
41
43
  return value
@@ -44,7 +46,7 @@ class EncryptedShelf(shelve.DbfilenameShelf):
44
46
  if self.writeback:
45
47
  self.cache[key] = value
46
48
  f = BytesIO()
47
- p = Pickler(f, self._protocol, key=self.secret_key)
49
+ p = Pickler(f, self._protocol, key=self.secret_key) # type:ignore
48
50
  p.dump(value)
49
51
  self.dict[key.encode(self.keyencoding)] = f.getvalue()
50
52
 
@@ -52,7 +54,7 @@ class EncryptedShelf(shelve.DbfilenameShelf):
52
54
  @dataclasses.dataclass
53
55
  class GatewayUser:
54
56
  """
55
- A dataclass representing a gateway user
57
+ A gateway user
56
58
  """
57
59
 
58
60
  bare_jid: str
@@ -82,17 +84,18 @@ class GatewayUser:
82
84
  return JID(self.bare_jid)
83
85
 
84
86
  def get(self, field: str, default: str = "") -> Optional[str]:
85
- """
86
- Get fields from the registration form (required to comply with slixmpp backend protocol)
87
-
88
- :param field: Name of the field
89
- :param default: Default value to return if the field is not present
90
-
91
- :return: Value of the field
92
- """
87
+ # """
88
+ # Get fields from the registration form (required to comply with slixmpp backend protocol)
89
+ #
90
+ # :param field: Name of the field
91
+ # :param default: Default value to return if the field is not present
92
+ #
93
+ # :return: Value of the field
94
+ # """
93
95
  return self.registration_form.get(field, default)
94
96
 
95
97
  def commit(self):
98
+ db.user_store(self)
96
99
  user_store.commit(self)
97
100
 
98
101
 
@@ -123,6 +126,8 @@ class UserStore:
123
126
  self._users = EncryptedShelf(filename, key=secret_key)
124
127
  else:
125
128
  self._users = shelve.open(str(filename))
129
+ for user in self._users.values():
130
+ db.user_store(user)
126
131
  log.info("Registered users in the DB: %s", list(self._users.keys()))
127
132
 
128
133
  def get_all(self) -> Iterable[GatewayUser]:
@@ -144,12 +149,13 @@ class UserStore:
144
149
  :param registration_form: Content of the registration form (:xep:`0077`)
145
150
  """
146
151
  log.debug("Adding user %s", jid)
147
- self._users[jid.bare] = GatewayUser(
152
+ self._users[jid.bare] = user = GatewayUser(
148
153
  bare_jid=jid.bare,
149
154
  registration_form=registration_form,
150
155
  registration_date=datetime.datetime.now(),
151
156
  )
152
157
  self._users.sync()
158
+ user.commit()
153
159
  log.debug("Store: %s", self._users)
154
160
 
155
161
  def commit(self, user: GatewayUser):
@@ -187,6 +193,7 @@ class UserStore:
187
193
  """
188
194
  j = jid.bare
189
195
  log.debug("Removing user %s", j)
196
+ db.user_del(self._users[j])
190
197
  del self._users[j]
191
198
  self._users.sync()
192
199
 
@@ -213,63 +220,10 @@ class UserStore:
213
220
  self._users.close()
214
221
 
215
222
 
216
- class YesSet(set):
217
- """
218
- A pseudo-set which always test True for membership
219
- """
220
-
221
- def __contains__(self, item):
222
- log.debug("Test in")
223
- return True
224
-
225
-
226
- class RosterBackend:
227
- """
228
- A pseudo-roster for the gateway component.
229
-
230
- If a user is in the user store, this will behave as if the user is part of the
231
- roster with subscription "both", and "none" otherwise.
232
-
233
- This is rudimentary but the only sane way I could come up with so far.
234
- """
235
-
236
- @staticmethod
237
- def entries(_owner_jid, _default=None):
238
- return YesSet()
239
-
240
- @staticmethod
241
- def save(_owner_jid, _jid, _item_state, _db_state):
242
- pass
243
-
244
- @staticmethod
245
- def load(_owner_jid, jid, _db_state):
246
- log.debug("Load %s", jid)
247
- user = user_store.get_by_jid(JID(jid))
248
- log.debug("User %s", user)
249
- if user is None:
250
- return {
251
- "name": "",
252
- "groups": [],
253
- "from": False,
254
- "to": False,
255
- "pending_in": False,
256
- "pending_out": False,
257
- "whitelisted": False,
258
- "subscription": "both",
259
- }
260
- else:
261
- return {
262
- "name": "",
263
- "groups": [],
264
- "from": True,
265
- "to": True,
266
- "pending_in": False,
267
- "pending_out": False,
268
- "whitelisted": False,
269
- "subscription": "none",
270
- }
271
-
272
-
273
223
  user_store = UserStore()
224
+ """
225
+ A persistent store for slidge users. Not public, but I didn't find how to hide
226
+ it from the docs!
227
+ """
274
228
 
275
229
  log = logging.getLogger(__name__)
slidge/util/schema.sql ADDED
@@ -0,0 +1,126 @@
1
+ CREATE TABLE user(
2
+ id INTEGER PRIMARY KEY,
3
+ jid TEXT UNIQUE
4
+ );
5
+
6
+ CREATE TABLE muc(
7
+ id INTEGER PRIMARY KEY,
8
+ jid TEXT,
9
+ user_id INTEGER,
10
+ FOREIGN KEY(user_id) REFERENCES user(id),
11
+ UNIQUE(user_id, jid)
12
+ );
13
+
14
+ CREATE TABLE mam_message(
15
+ id INTEGER PRIMARY KEY,
16
+ message_id TEXT,
17
+ sent_on INTEGER,
18
+ sender_jid TEXT,
19
+ xml TEXT,
20
+ muc_id INTEGER,
21
+ user_id INTEGER,
22
+ FOREIGN KEY(muc_id) REFERENCES muc(id),
23
+ FOREIGN KEY(user_id) REFERENCES user(id),
24
+ UNIQUE(user_id, muc_id, message_id)
25
+ );
26
+
27
+ CREATE INDEX mam_sent_on ON mam_message(sent_on);
28
+ CREATE INDEX muc_jid ON muc(jid);
29
+
30
+ CREATE TABLE session_message_sent(
31
+ id INTEGER PRIMARY KEY,
32
+ legacy_id UNIQUE,
33
+ xmpp_id TEXT,
34
+ user_id INTEGER,
35
+ FOREIGN KEY(user_id) REFERENCES user(id)
36
+ );
37
+
38
+ CREATE INDEX session_message_sent_legacy_id
39
+ ON session_message_sent(legacy_id);
40
+ CREATE INDEX session_message_sent_xmpp_id
41
+ ON session_message_sent(xmpp_id);
42
+
43
+ CREATE TABLE session_message_sent_muc(
44
+ id INTEGER PRIMARY KEY,
45
+ legacy_id UNIQUE,
46
+ xmpp_id TEXT,
47
+ user_id INTEGER,
48
+ FOREIGN KEY(user_id) REFERENCES user(id)
49
+ );
50
+
51
+ CREATE INDEX session_message_sent_muc_legacy_id
52
+ ON session_message_sent_muc(legacy_id);
53
+ CREATE INDEX session_message_sent_muc_xmpp_id
54
+ ON session_message_sent_muc(xmpp_id);
55
+
56
+ CREATE TABLE session_thread_sent_muc(
57
+ id INTEGER PRIMARY KEY,
58
+ legacy_id UNIQUE,
59
+ xmpp_id TEXT,
60
+ user_id INTEGER,
61
+ FOREIGN KEY(user_id) REFERENCES user(id)
62
+ );
63
+
64
+ CREATE INDEX session_thread_sent_muc_legacy_id
65
+ ON session_thread_sent_muc(legacy_id);
66
+ CREATE INDEX session_thread_sent_muc_xmpp_id
67
+ ON session_thread_sent_muc(xmpp_id);
68
+
69
+
70
+ CREATE TABLE attachment(
71
+ id INTEGER PRIMARY KEY,
72
+ legacy_id UNIQUE,
73
+ url TEXT UNIQUE,
74
+ sims TEXT,
75
+ sfs TEXT
76
+ );
77
+
78
+ CREATE INDEX attachment_legacy_id ON attachment(legacy_id);
79
+ CREATE INDEX attachment_url ON attachment(url);
80
+
81
+ CREATE TABLE attachment_legacy_msg_id(
82
+ id INTEGER PRIMARY KEY,
83
+ legacy_id UNIQUE
84
+ );
85
+
86
+ CREATE TABLE attachment_xmpp_ids(
87
+ id INTEGER PRIMARY KEY,
88
+ legacy_msg_id INTEGER,
89
+ xmpp_id TEXT,
90
+ FOREIGN KEY(legacy_msg_id) REFERENCES attachment_legacy_msg_id(id)
91
+ );
92
+
93
+ CREATE TABLE nick(
94
+ id INTEGER PRIMARY KEY,
95
+ jid UNIQUE,
96
+ nick TEXT,
97
+ user_id INTEGER,
98
+ FOREIGN KEY(user_id) REFERENCES user(id),
99
+ UNIQUE(jid, user_id)
100
+ );
101
+
102
+ CREATE INDEX nick_jid ON nick(jid);
103
+
104
+
105
+ CREATE TABLE avatar(
106
+ id INTEGER PRIMARY KEY,
107
+ jid TEXT UNIQUE,
108
+ cached_id TEXT
109
+ );
110
+
111
+ CREATE INDEX avatar_jid ON avatar(jid);
112
+
113
+
114
+ CREATE TABLE presence(
115
+ id INTEGER PRIMARY KEY,
116
+ jid TEXT,
117
+ last_seen INTEGER,
118
+ ptype TEXT,
119
+ pstatus TEXT,
120
+ pshow TEXT,
121
+ user_id INTEGER,
122
+ FOREIGN KEY(user_id) REFERENCES user(id),
123
+ UNIQUE(jid, user_id)
124
+ );
125
+
126
+ CREATE INDEX presence_jid ON presence(jid);