slidge 0.2.0a10__tar.gz → 0.2.0b0__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. {slidge-0.2.0a10 → slidge-0.2.0b0}/PKG-INFO +1 -1
  2. {slidge-0.2.0a10 → slidge-0.2.0b0}/pyproject.toml +2 -3
  3. slidge-0.2.0b0/slidge/__main__.py +3 -0
  4. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/__version__.py +1 -1
  5. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/command/user.py +5 -1
  6. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/contact/roster.py +2 -0
  7. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/config.py +0 -3
  8. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/dispatcher/message/marker.py +2 -7
  9. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/dispatcher/muc/misc.py +3 -0
  10. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/dispatcher/muc/owner.py +1 -1
  11. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/dispatcher/util.py +23 -23
  12. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/mixins/attachment.py +24 -8
  13. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/mixins/lock.py +10 -8
  14. slidge-0.2.0b0/slidge/core/mixins/message.py +214 -0
  15. slidge-0.2.0a10/slidge/core/mixins/message.py → slidge-0.2.0b0/slidge/core/mixins/message_text.py +5 -208
  16. slidge-0.2.0b0/slidge/db/alembic/versions/15b0bd83407a_remove_bogus_unique_constraints_on_room_.py +83 -0
  17. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/db/alembic/versions/5bd48bfdffa2_lift_room_legacy_id_constraint.py +12 -1
  18. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/db/models.py +3 -1
  19. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/db/store.py +16 -9
  20. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/group/bookmarks.py +23 -1
  21. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/group/participant.py +5 -5
  22. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/group/room.py +10 -1
  23. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/util/test.py +4 -4
  24. slidge-0.2.0a10/slidge/__main__.py +0 -4
  25. {slidge-0.2.0a10 → slidge-0.2.0b0}/LICENSE +0 -0
  26. {slidge-0.2.0a10 → slidge-0.2.0b0}/README.md +0 -0
  27. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/__init__.py +0 -0
  28. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/command/__init__.py +0 -0
  29. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/command/adhoc.py +0 -0
  30. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/command/admin.py +0 -0
  31. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/command/base.py +0 -0
  32. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/command/categories.py +0 -0
  33. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/command/chat_command.py +0 -0
  34. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/command/register.py +0 -0
  35. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/contact/__init__.py +0 -0
  36. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/contact/contact.py +0 -0
  37. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/__init__.py +0 -0
  38. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/dispatcher/__init__.py +0 -0
  39. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/dispatcher/caps.py +0 -0
  40. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/dispatcher/disco.py +0 -0
  41. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/dispatcher/message/__init__.py +0 -0
  42. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/dispatcher/message/chat_state.py +0 -0
  43. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/dispatcher/message/message.py +0 -0
  44. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/dispatcher/muc/__init__.py +0 -0
  45. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/dispatcher/muc/admin.py +0 -0
  46. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/dispatcher/muc/mam.py +0 -0
  47. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/dispatcher/muc/ping.py +0 -0
  48. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/dispatcher/presence.py +0 -0
  49. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/dispatcher/registration.py +0 -0
  50. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/dispatcher/search.py +0 -0
  51. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/dispatcher/session_dispatcher.py +0 -0
  52. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/dispatcher/vcard.py +0 -0
  53. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/gateway.py +0 -0
  54. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/mixins/__init__.py +0 -0
  55. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/mixins/avatar.py +0 -0
  56. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/mixins/base.py +0 -0
  57. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/mixins/db.py +0 -0
  58. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/mixins/disco.py +0 -0
  59. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/mixins/message_maker.py +0 -0
  60. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/mixins/presence.py +0 -0
  61. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/mixins/recipient.py +0 -0
  62. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/pubsub.py +0 -0
  63. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/core/session.py +0 -0
  64. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/db/__init__.py +0 -0
  65. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/db/alembic/__init__.py +0 -0
  66. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/db/alembic/env.py +0 -0
  67. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/db/alembic/old_user_store.py +0 -0
  68. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/db/alembic/script.py.mako +0 -0
  69. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/db/alembic/versions/09f27f098baa_add_missing_attributes_in_room.py +0 -0
  70. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/db/alembic/versions/2461390c0af2_store_contacts_caps_verstring_in_db.py +0 -0
  71. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/db/alembic/versions/29f5280c61aa_store_subject_setter_in_room.py +0 -0
  72. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/db/alembic/versions/2b1f45ab7379_store_room_subject_setter_by_nickname.py +0 -0
  73. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/db/alembic/versions/3071e0fa69d4_add_contact_client_type.py +0 -0
  74. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/db/alembic/versions/45c24cc73c91_add_bob.py +0 -0
  75. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/db/alembic/versions/82a4af84b679_add_muc_history_filled.py +0 -0
  76. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/db/alembic/versions/8b993243a536_add_vcard_content_to_contact_table.py +0 -0
  77. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/db/alembic/versions/8d2ced764698_rely_on_db_to_store_contacts_rooms_and_.py +0 -0
  78. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/db/alembic/versions/aa9d82a7f6ef_db_creation.py +0 -0
  79. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/db/alembic/versions/abba1ae0edb3_store_avatar_legacy_id_in_the_contact_.py +0 -0
  80. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/db/alembic/versions/b33993e87db3_move_everything_to_persistent_db.py +0 -0
  81. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/db/alembic/versions/b64b1a793483_add_source_and_legacy_id_for_archived_.py +0 -0
  82. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/db/alembic/versions/c4a8ec35a0e8_per_room_user_nick.py +0 -0
  83. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/db/alembic/versions/e91195719c2c_store_users_avatars_persistently.py +0 -0
  84. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/db/avatar.py +0 -0
  85. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/db/meta.py +0 -0
  86. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/group/__init__.py +0 -0
  87. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/group/archive.py +0 -0
  88. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/main.py +0 -0
  89. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/migration.py +0 -0
  90. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/py.typed +0 -0
  91. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/__init__.py +0 -0
  92. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/delivery_receipt.py +0 -0
  93. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/link_preview/__init__.py +0 -0
  94. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/link_preview/link_preview.py +0 -0
  95. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/link_preview/stanza.py +0 -0
  96. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/roster.py +0 -0
  97. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0077/__init__.py +0 -0
  98. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0077/register.py +0 -0
  99. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0077/stanza.py +0 -0
  100. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0100/__init__.py +0 -0
  101. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0100/gateway.py +0 -0
  102. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0100/stanza.py +0 -0
  103. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0153/__init__.py +0 -0
  104. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0153/stanza.py +0 -0
  105. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0153/vcard_avatar.py +0 -0
  106. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0264/__init__.py +0 -0
  107. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0264/stanza.py +0 -0
  108. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0264/thumbnail.py +0 -0
  109. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0292/__init__.py +0 -0
  110. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0292/vcard4.py +0 -0
  111. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0313/__init__.py +0 -0
  112. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0313/mam.py +0 -0
  113. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0313/stanza.py +0 -0
  114. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0317/__init__.py +0 -0
  115. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0317/hats.py +0 -0
  116. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0317/stanza.py +0 -0
  117. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0356_old/__init__.py +0 -0
  118. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0356_old/privilege.py +0 -0
  119. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0356_old/stanza.py +0 -0
  120. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0424/__init__.py +0 -0
  121. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0424/retraction.py +0 -0
  122. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0424/stanza.py +0 -0
  123. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0490/__init__.py +0 -0
  124. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0490/mds.py +0 -0
  125. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/slixfix/xep_0490/stanza.py +0 -0
  126. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/util/__init__.py +0 -0
  127. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/util/archive_msg.py +0 -0
  128. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/util/conf.py +0 -0
  129. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/util/db.py +0 -0
  130. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/util/types.py +0 -0
  131. {slidge-0.2.0a10 → slidge-0.2.0b0}/slidge/util/util.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: slidge
3
- Version: 0.2.0a10
3
+ Version: 0.2.0b0
4
4
  Summary: XMPP bridging framework
5
5
  Home-page: https://sr.ht/~nicoco/slidge/
6
6
  License: AGPL-3.0-or-later
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "slidge"
3
- version = "0.2.0alpha10"
3
+ version = "0.2.0beta0"
4
4
  description = "XMPP bridging framework"
5
5
  authors = ["Nicolas Cedilnik <nicoco@nicoco.fr>"]
6
6
  readme = "README.md"
@@ -57,7 +57,7 @@ git = "https://git.sr.ht/~nicoco/slidge-dev-helpers"
57
57
  branch = "master"
58
58
 
59
59
  [tool.poetry.scripts]
60
- slidge = 'slidge.__main__:main'
60
+ slidge = 'slidge.main:main'
61
61
 
62
62
  [tool.mypy]
63
63
  check_untyped_defs = true
@@ -89,7 +89,6 @@ exclude_lines = [
89
89
  ]
90
90
 
91
91
  [tool.pytest.ini_options]
92
- log_cli = true
93
92
  log_level = "DEBUG"
94
93
  asyncio_mode = "strict"
95
94
  filterwarnings = [
@@ -0,0 +1,3 @@
1
+ from slidge.main import main
2
+
3
+ main()
@@ -2,4 +2,4 @@ from slidge.util.util import get_version # noqa: F401
2
2
 
3
3
  # this is modified before publish, but if someone cloned from the repo,
4
4
  # it can help
5
- __version__ = "0.2.0alpha10"
5
+ __version__ = "0.2.0beta0"
@@ -305,7 +305,10 @@ class LeaveGroup(Command):
305
305
  FormField(
306
306
  "group",
307
307
  "Group name",
308
- options=[{"label": g.name, "value": g.name} for g in groups],
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.")
@@ -154,6 +154,8 @@ class LegacyRoster(
154
154
  try:
155
155
  with contact.updating_info():
156
156
  await contact.avatar_wrap_update_info()
157
+ except XMPPError:
158
+ raise
157
159
  except Exception as e:
158
160
  raise XMPPError("internal-server-error", str(e))
159
161
  contact._caps_ver = await contact.get_caps_ver(contact.jid)
@@ -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"
@@ -3,12 +3,7 @@ from slixmpp.xmlstream import StanzaBase
3
3
 
4
4
  from ....group.room import LegacyMUC
5
5
  from ....util.types import Recipient
6
- from ..util import (
7
- DispatcherMixin,
8
- _get_entity,
9
- _xmpp_to_legacy_thread,
10
- exceptions_to_xmpp_errors,
11
- )
6
+ from ..util import DispatcherMixin, _get_entity, exceptions_to_xmpp_errors
12
7
 
13
8
 
14
9
  class MarkerMixin(DispatcherMixin):
@@ -26,7 +21,7 @@ class MarkerMixin(DispatcherMixin):
26
21
  session = await self._get_session(msg)
27
22
 
28
23
  e: Recipient = await _get_entity(session, msg)
29
- legacy_thread = await _xmpp_to_legacy_thread(session, msg, e)
24
+ legacy_thread = await self._xmpp_to_legacy_thread(session, msg, e)
30
25
  displayed_msg_id = msg["displayed"]["id"]
31
26
  if not isinstance(e, LegacyMUC) and self.xmpp.MARK_ALL_MESSAGES:
32
27
  to_mark = e.get_msg_xmpp_id_up_to(displayed_msg_id) # type: ignore
@@ -54,6 +54,9 @@ class MucMiscMixin(DispatcherMixin):
54
54
  muc = await self.get_muc_from_stanza(iq)
55
55
  await muc.session.on_leave_group(muc.legacy_id)
56
56
  iq.reply().send()
57
+ await muc.session.bookmarks.remove(
58
+ muc, "You left this chat from an XMPP client."
59
+ )
57
60
  return
58
61
 
59
62
  raise XMPPError("feature-not-implemented")
@@ -88,7 +88,7 @@ class MucOwnerMixin(DispatcherMixin):
88
88
  if reason is not None:
89
89
  presence["muc"]["destroy"]["reason"] = reason
90
90
  user_participant._send(presence)
91
- muc.session.bookmarks.remove(muc)
91
+ await muc.session.bookmarks.remove(muc, kick=False)
92
92
  clear = True
93
93
  else:
94
94
  raise XMPPError("bad-request")
@@ -96,9 +96,31 @@ class DispatcherMixin:
96
96
  ) -> tuple["BaseSession", Recipient, int | str]:
97
97
  session = await self._get_session(msg)
98
98
  e: Recipient = await _get_entity(session, msg)
99
- legacy_thread = await _xmpp_to_legacy_thread(session, msg, e)
99
+ legacy_thread = await self._xmpp_to_legacy_thread(session, msg, e)
100
100
  return session, e, legacy_thread
101
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
+
102
124
 
103
125
  def _ignore(session: "BaseSession", msg: Message):
104
126
  i = msg.get_id()
@@ -111,28 +133,6 @@ def _ignore(session: "BaseSession", msg: Message):
111
133
  return True
112
134
 
113
135
 
114
- async def _xmpp_to_legacy_thread(
115
- session: "BaseSession", msg: Message, recipient: RecipientType
116
- ):
117
- xmpp_thread = msg["thread"]
118
- if not xmpp_thread:
119
- return
120
-
121
- if session.MESSAGE_IDS_ARE_THREAD_IDS:
122
- return session.xmpp.store.sent.get_legacy_thread(session.user_pk, xmpp_thread)
123
-
124
- async with session.thread_creation_lock:
125
- legacy_thread_str = session.xmpp.store.sent.get_legacy_thread(
126
- session.user_pk, xmpp_thread
127
- )
128
- if legacy_thread_str is None:
129
- legacy_thread = str(await recipient.create_thread(xmpp_thread))
130
- session.xmpp.store.sent.set_thread(
131
- session.user_pk, xmpp_thread, legacy_thread
132
- )
133
- return session.xmpp.LEGACY_MSG_ID_TYPE(legacy_thread)
134
-
135
-
136
136
  async def _get_entity(session: "BaseSession", m: Message) -> RecipientType:
137
137
  session.raise_if_not_logged()
138
138
  if m.get_type() == "groupchat":
@@ -33,17 +33,14 @@ from ...util.types import (
33
33
  )
34
34
  from ...util.util import fix_suffix
35
35
  from .. import config
36
- from .message_maker import MessageMaker
36
+ from .message_text import TextMessageMixin
37
37
 
38
38
 
39
- class AttachmentMixin(MessageMaker):
39
+ class AttachmentMixin(TextMessageMixin):
40
40
  def __init__(self, *a, **kw):
41
41
  super().__init__(*a, **kw)
42
42
  self.__store = self.xmpp.store.attachments
43
43
 
44
- def send_text(self, *_, **k) -> Optional[Message]:
45
- raise NotImplementedError
46
-
47
44
  async def __upload(
48
45
  self,
49
46
  file_path: Path,
@@ -261,7 +258,7 @@ class AttachmentMixin(MessageMaker):
261
258
  thumbnail["width"] = x
262
259
  thumbnail["height"] = y
263
260
  thumbnail["media-type"] = "image/thumbhash"
264
- thumbnail["uri"] = "data:image/thumbhash," + urlquote(h)
261
+ thumbnail["uri"] = "data:image/thumbhash;base64," + urlquote(h)
265
262
 
266
263
  self.__store.set_sims(uploaded_url, str(ref))
267
264
 
@@ -304,6 +301,7 @@ class AttachmentMixin(MessageMaker):
304
301
  caption: Optional[str] = None,
305
302
  carbon=False,
306
303
  when: Optional[datetime] = None,
304
+ correction=False,
307
305
  **kwargs,
308
306
  ) -> list[Message]:
309
307
  msg["oob"]["url"] = uploaded_url
@@ -311,11 +309,19 @@ class AttachmentMixin(MessageMaker):
311
309
  if caption:
312
310
  m1 = self._send(msg, carbon=carbon, **kwargs)
313
311
  m2 = self.send_text(
314
- caption, legacy_msg_id=legacy_msg_id, when=when, carbon=carbon, **kwargs
312
+ caption,
313
+ legacy_msg_id=legacy_msg_id,
314
+ when=when,
315
+ carbon=carbon,
316
+ correction=correction,
317
+ **kwargs,
315
318
  )
316
319
  return [m1, m2] if m2 else [m1]
317
320
  else:
318
- self._set_msg_id(msg, legacy_msg_id)
321
+ if correction:
322
+ msg["replace"]["id"] = self._replace_id(legacy_msg_id)
323
+ else:
324
+ self._set_msg_id(msg, legacy_msg_id)
319
325
  return [self._send(msg, carbon=carbon, **kwargs)]
320
326
 
321
327
  async def send_file(
@@ -358,6 +364,16 @@ class AttachmentMixin(MessageMaker):
358
364
  carbon = kwargs.pop("carbon", False)
359
365
  mto = kwargs.pop("mto", None)
360
366
  store_multi = kwargs.pop("store_multi", True)
367
+ correction = kwargs.get("correction", False)
368
+ if correction and (original_xmpp_id := self._legacy_to_xmpp(legacy_msg_id)):
369
+ xmpp_ids = self.xmpp.store.multi.get_xmpp_ids(
370
+ self.session.user_pk, original_xmpp_id
371
+ )
372
+
373
+ for xmpp_id in xmpp_ids:
374
+ if xmpp_id == original_xmpp_id:
375
+ continue
376
+ self.retract(xmpp_id, thread)
361
377
  msg = self._make_message(
362
378
  when=when,
363
379
  reply_to=reply_to,
@@ -15,14 +15,16 @@ class NamedLockMixin:
15
15
  locks = self.__locks
16
16
  if not locks.get(id_):
17
17
  locks[id_] = asyncio.Lock()
18
- async with locks[id_]:
19
- log.trace("acquired %s", id_) # type:ignore
20
- yield
21
- log.trace("releasing %s", id_) # type:ignore
22
- waiters = locks[id_]._waiters # type:ignore
23
- if not waiters:
24
- del locks[id_]
25
- log.trace("erasing %s", id_) # type:ignore
18
+ try:
19
+ async with locks[id_]:
20
+ log.trace("acquired %s", id_) # type:ignore
21
+ yield
22
+ finally:
23
+ log.trace("releasing %s", id_) # type:ignore
24
+ waiters = locks[id_]._waiters # type:ignore
25
+ if not waiters:
26
+ del locks[id_]
27
+ log.trace("erasing %s", id_) # type:ignore
26
28
 
27
29
  def get_lock(self, id_: Hashable):
28
30
  return self.__locks.get(id_)
@@ -0,0 +1,214 @@
1
+ import logging
2
+ import uuid
3
+ import warnings
4
+ from typing import TYPE_CHECKING, Optional
5
+
6
+ from slixmpp import Iq, Message
7
+
8
+ from ...slixfix.xep_0490.mds import PUBLISH_OPTIONS
9
+ from ...util.types import ChatState, LegacyMessageType, Marker
10
+ from .attachment import AttachmentMixin
11
+ from .message_maker import MessageMaker
12
+ from .message_text import TextMessageMixin
13
+
14
+ if TYPE_CHECKING:
15
+ from ...group import LegacyMUC
16
+
17
+
18
+ class ChatStateMixin(MessageMaker):
19
+ def __init__(self):
20
+ super().__init__()
21
+ self.__last_chat_state: Optional[ChatState] = None
22
+
23
+ def _chat_state(self, state: ChatState, forced=False, **kwargs):
24
+ carbon = kwargs.get("carbon", False)
25
+ if carbon or (state == self.__last_chat_state and not forced):
26
+ return
27
+ self.__last_chat_state = state
28
+ msg = self._make_message(state=state, hints={"no-store"})
29
+ self._send(msg, **kwargs)
30
+
31
+ def active(self, **kwargs):
32
+ """
33
+ Send an "active" chat state (:xep:`0085`) from this
34
+ :term:`XMPP Entity`.
35
+ """
36
+ self._chat_state("active", **kwargs)
37
+
38
+ def composing(self, **kwargs):
39
+ """
40
+ Send a "composing" (ie "typing notification") chat state (:xep:`0085`)
41
+ from this :term:`XMPP Entity`.
42
+ """
43
+ self._chat_state("composing", forced=True, **kwargs)
44
+
45
+ def paused(self, **kwargs):
46
+ """
47
+ Send a "paused" (ie "typing paused notification") chat state
48
+ (:xep:`0085`) from this :term:`XMPP Entity`.
49
+ """
50
+ self._chat_state("paused", **kwargs)
51
+
52
+ def inactive(self, **kwargs):
53
+ """
54
+ Send an "inactive" (ie "contact has not interacted with the chat session
55
+ interface for an intermediate period of time") chat state (:xep:`0085`)
56
+ from this :term:`XMPP Entity`.
57
+ """
58
+ self._chat_state("inactive", **kwargs)
59
+
60
+ def gone(self, **kwargs):
61
+ """
62
+ Send a "gone" (ie "contact has not interacted with the chat session interface,
63
+ system, or device for a relatively long period of time") chat state
64
+ (:xep:`0085`) from this :term:`XMPP Entity`.
65
+ """
66
+ self._chat_state("gone", **kwargs)
67
+
68
+
69
+ class MarkerMixin(MessageMaker):
70
+ is_group: bool = NotImplemented
71
+
72
+ def _make_marker(
73
+ self, legacy_msg_id: LegacyMessageType, marker: Marker, carbon=False
74
+ ):
75
+ msg = self._make_message(carbon=carbon)
76
+ msg[marker]["id"] = self._legacy_to_xmpp(legacy_msg_id)
77
+ return msg
78
+
79
+ def ack(self, legacy_msg_id: LegacyMessageType, **kwargs):
80
+ """
81
+ Send an "acknowledged" message marker (:xep:`0333`) from this :term:`XMPP Entity`.
82
+
83
+ :param legacy_msg_id: The message this marker refers to
84
+ """
85
+ self._send(
86
+ self._make_marker(
87
+ legacy_msg_id, "acknowledged", carbon=kwargs.get("carbon")
88
+ ),
89
+ **kwargs,
90
+ )
91
+
92
+ def received(self, legacy_msg_id: LegacyMessageType, **kwargs):
93
+ """
94
+ Send a "received" message marker (:xep:`0333`) from this :term:`XMPP Entity`.
95
+ If called on a :class:`LegacyContact`, also send a delivery receipt
96
+ marker (:xep:`0184`).
97
+
98
+ :param legacy_msg_id: The message this marker refers to
99
+ """
100
+ carbon = kwargs.get("carbon")
101
+ if self.mtype == "chat":
102
+ self._send(
103
+ self.xmpp.delivery_receipt.make_ack(
104
+ self._legacy_to_xmpp(legacy_msg_id),
105
+ mfrom=self.jid,
106
+ mto=self.user_jid,
107
+ )
108
+ )
109
+ self._send(
110
+ self._make_marker(legacy_msg_id, "received", carbon=carbon), **kwargs
111
+ )
112
+
113
+ def displayed(self, legacy_msg_id: LegacyMessageType, **kwargs):
114
+ """
115
+ Send a "displayed" message marker (:xep:`0333`) from this :term:`XMPP Entity`.
116
+
117
+ :param legacy_msg_id: The message this marker refers to
118
+ """
119
+ self._send(
120
+ self._make_marker(legacy_msg_id, "displayed", carbon=kwargs.get("carbon")),
121
+ **kwargs,
122
+ )
123
+ if getattr(self, "is_user", False):
124
+ self.session.create_task(self.__send_mds(legacy_msg_id))
125
+
126
+ async def __send_mds(self, legacy_msg_id: LegacyMessageType):
127
+ # Send a MDS displayed marker on behalf of the user for a group chat
128
+ if muc := getattr(self, "muc", None):
129
+ muc_jid = muc.jid.bare
130
+ else:
131
+ # This is not implemented for 1:1 chat because it would rely on
132
+ # storing the XMPP-server injected stanza-id, which we don't track
133
+ # ATM.
134
+ # In practice, MDS should mostly be useful for public group chats,
135
+ # so it should not be an issue.
136
+ # We'll see if we need to implement that later
137
+ return
138
+ xmpp_msg_id = self._legacy_to_xmpp(legacy_msg_id)
139
+ iq = Iq(sto=self.user_jid.bare, sfrom=self.user_jid.bare, stype="set")
140
+ iq["pubsub"]["publish"]["node"] = self.xmpp["xep_0490"].stanza.NS
141
+ iq["pubsub"]["publish"]["item"]["id"] = muc_jid
142
+ displayed = self.xmpp["xep_0490"].stanza.Displayed()
143
+ displayed["stanza_id"]["id"] = xmpp_msg_id
144
+ displayed["stanza_id"]["by"] = muc_jid
145
+ iq["pubsub"]["publish"]["item"]["payload"] = displayed
146
+ iq["pubsub"]["publish_options"] = PUBLISH_OPTIONS
147
+ try:
148
+ await self.xmpp["xep_0356"].send_privileged_iq(iq)
149
+ except Exception as e:
150
+ self.session.log.debug("Could not MDS mark", exc_info=e)
151
+
152
+
153
+ class ContentMessageMixin(AttachmentMixin, TextMessageMixin):
154
+ pass
155
+
156
+
157
+ class CarbonMessageMixin(ContentMessageMixin, MarkerMixin):
158
+ def _privileged_send(self, msg: Message):
159
+ i = msg.get_id()
160
+ if i:
161
+ self.session.ignore_messages.add(i)
162
+ else:
163
+ i = "slidge-carbon-" + str(uuid.uuid4())
164
+ msg.set_id(i)
165
+ msg.del_origin_id()
166
+ try:
167
+ self.xmpp["xep_0356"].send_privileged_message(msg)
168
+ except PermissionError:
169
+ try:
170
+ self.xmpp["xep_0356_old"].send_privileged_message(msg)
171
+ except PermissionError:
172
+ warnings.warn(
173
+ "Slidge does not have privileges to send message on behalf of"
174
+ " user.Refer to"
175
+ " https://slidge.readthedocs.io/en/latest/admin/xmpp_server.html"
176
+ " for more info."
177
+ )
178
+
179
+
180
+ class InviteMixin(MessageMaker):
181
+ def invite_to(
182
+ self,
183
+ muc: "LegacyMUC",
184
+ reason: Optional[str] = None,
185
+ password: Optional[str] = None,
186
+ **send_kwargs,
187
+ ):
188
+ """
189
+ Send an invitation to join a group (:xep:`0249`) from this :term:`XMPP Entity`.
190
+
191
+ :param muc: the muc the user is invited to
192
+ :param reason: a text explaining why the user should join this muc
193
+ :param password: maybe this will make sense later? not sure
194
+ :param send_kwargs: additional kwargs to be passed to _send()
195
+ (internal use by slidge)
196
+ """
197
+ msg = self._make_message(mtype="normal")
198
+ msg["groupchat_invite"]["jid"] = muc.jid
199
+ if reason:
200
+ msg["groupchat_invite"]["reason"] = reason
201
+ if password:
202
+ msg["groupchat_invite"]["password"] = password
203
+ self._send(msg, **send_kwargs)
204
+
205
+
206
+ class MessageMixin(InviteMixin, ChatStateMixin, MarkerMixin, ContentMessageMixin):
207
+ pass
208
+
209
+
210
+ class MessageCarbonMixin(InviteMixin, ChatStateMixin, CarbonMessageMixin):
211
+ pass
212
+
213
+
214
+ log = logging.getLogger(__name__)