slidge 0.2.7.post1__tar.gz → 0.2.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. {slidge-0.2.7.post1 → slidge-0.2.8}/.woodpecker/test.yaml +1 -1
  2. {slidge-0.2.7.post1 → slidge-0.2.8}/Dockerfile +1 -1
  3. {slidge-0.2.7.post1 → slidge-0.2.8}/PKG-INFO +2 -2
  4. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/admin/daemon.rst +6 -2
  5. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/admin/install.rst +2 -8
  6. {slidge-0.2.7.post1 → slidge-0.2.8}/pyproject.toml +26 -18
  7. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/__version__.py +1 -1
  8. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/contact/contact.py +2 -2
  9. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/contact/roster.py +2 -3
  10. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/dispatcher/session_dispatcher.py +6 -1
  11. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/gateway.py +12 -2
  12. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/mixins/message_maker.py +3 -3
  13. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/db/store.py +3 -0
  14. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/group/archive.py +11 -3
  15. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/group/bookmarks.py +4 -5
  16. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/group/participant.py +33 -35
  17. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/group/room.py +10 -12
  18. slidge-0.2.8/slidge/slixfix/__init__.py +92 -0
  19. slidge-0.2.8/slidge/util/jid_escaping.py +52 -0
  20. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge.egg-info/PKG-INFO +2 -2
  21. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge.egg-info/SOURCES.txt +2 -3
  22. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge.egg-info/requires.txt +1 -1
  23. {slidge-0.2.7.post1 → slidge-0.2.8}/tests/test_adhoc/test_access.py +2 -2
  24. {slidge-0.2.7.post1 → slidge-0.2.8}/tests/test_adhoc/test_confirmation.py +2 -2
  25. {slidge-0.2.7.post1 → slidge-0.2.8}/tests/test_adhoc/test_form.py +1 -1
  26. {slidge-0.2.7.post1 → slidge-0.2.8}/tests/test_adhoc/test_reported.py +1 -1
  27. {slidge-0.2.7.post1 → slidge-0.2.8}/tests/test_chat_commands.py +1 -1
  28. slidge-0.2.8/tests/test_mam_archivable.py +49 -0
  29. {slidge-0.2.7.post1 → slidge-0.2.8}/tests/test_mds.py +1 -1
  30. {slidge-0.2.7.post1 → slidge-0.2.8}/tests/test_muc.py +13 -8
  31. {slidge-0.2.7.post1 → slidge-0.2.8}/tests/test_session.py +6 -5
  32. {slidge-0.2.7.post1 → slidge-0.2.8}/uv.lock +18 -4
  33. slidge-0.2.7.post1/slidge/slixfix/__init__.py +0 -152
  34. slidge-0.2.7.post1/slidge/slixfix/xep_0492/__init__.py +0 -8
  35. slidge-0.2.7.post1/slidge/slixfix/xep_0492/notify.py +0 -16
  36. slidge-0.2.7.post1/slidge/slixfix/xep_0492/stanza.py +0 -107
  37. {slidge-0.2.7.post1 → slidge-0.2.8}/.gitignore +0 -0
  38. {slidge-0.2.7.post1 → slidge-0.2.8}/.pre-commit-config.yaml +0 -0
  39. {slidge-0.2.7.post1 → slidge-0.2.8}/.woodpecker/container-cache.yml +0 -0
  40. {slidge-0.2.7.post1 → slidge-0.2.8}/.woodpecker/container-ci.yaml +0 -0
  41. {slidge-0.2.7.post1 → slidge-0.2.8}/.woodpecker/container.yml +0 -0
  42. {slidge-0.2.7.post1 → slidge-0.2.8}/.woodpecker/docs.yaml +0 -0
  43. {slidge-0.2.7.post1 → slidge-0.2.8}/.woodpecker/package.yaml +0 -0
  44. {slidge-0.2.7.post1 → slidge-0.2.8}/LICENSE +0 -0
  45. {slidge-0.2.7.post1 → slidge-0.2.8}/README.md +0 -0
  46. {slidge-0.2.7.post1 → slidge-0.2.8}/commitlint.config.js +0 -0
  47. {slidge-0.2.7.post1 → slidge-0.2.8}/dev/assets/5x5.png +0 -0
  48. {slidge-0.2.7.post1 → slidge-0.2.8}/dev/assets/slidge-color-small.png +0 -0
  49. {slidge-0.2.7.post1 → slidge-0.2.8}/dev/assets/slidge-color.png +0 -0
  50. {slidge-0.2.7.post1 → slidge-0.2.8}/dev/assets/slidge-mono-black.png +0 -0
  51. {slidge-0.2.7.post1 → slidge-0.2.8}/dev/assets/slidge-mono-white.png +0 -0
  52. {slidge-0.2.7.post1 → slidge-0.2.8}/dev/assets/slidge.svg +0 -0
  53. {slidge-0.2.7.post1 → slidge-0.2.8}/dev/confs/movim.env +0 -0
  54. {slidge-0.2.7.post1 → slidge-0.2.8}/dev/confs/nginx.conf +0 -0
  55. {slidge-0.2.7.post1 → slidge-0.2.8}/dev/confs/slidge-example.ini +0 -0
  56. {slidge-0.2.7.post1 → slidge-0.2.8}/dev/prettify_tests.py +0 -0
  57. {slidge-0.2.7.post1 → slidge-0.2.8}/doap.xml +0 -0
  58. {slidge-0.2.7.post1 → slidge-0.2.8}/docker-compose.yml +0 -0
  59. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/Makefile +0 -0
  60. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/admin/attachments.rst +0 -0
  61. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/admin/component.rst +0 -0
  62. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/admin/config/index.rst +0 -0
  63. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/admin/examples/ejabberd.yaml +0 -0
  64. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/admin/examples/index.rst +0 -0
  65. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/admin/examples/prosody.cfg.lua +0 -0
  66. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/admin/index.rst +0 -0
  67. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/admin/note.rst +0 -0
  68. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/admin/privilege.rst +0 -0
  69. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/codeberg.svg +0 -0
  70. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/conf.py +0 -0
  71. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/dev/contributing.rst +0 -0
  72. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/dev/design.rst +0 -0
  73. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/dev/howto.rst +0 -0
  74. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/dev/index.rst +0 -0
  75. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/dev/tutorial.rst +0 -0
  76. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/glossary.rst +0 -0
  77. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/index.rst +0 -0
  78. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/user/commands.rst +0 -0
  79. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/user/contacts.rst +0 -0
  80. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/user/foxyproxy.png +0 -0
  81. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/user/gajim.png +0 -0
  82. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/user/index.rst +0 -0
  83. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/user/low_profile.rst +0 -0
  84. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/user/movim1.png +0 -0
  85. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/user/movim2.png +0 -0
  86. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/user/note.rst +0 -0
  87. {slidge-0.2.7.post1 → slidge-0.2.8}/docs/source/user/register.rst +0 -0
  88. {slidge-0.2.7.post1 → slidge-0.2.8}/setup.cfg +0 -0
  89. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/__init__.py +0 -0
  90. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/__main__.py +0 -0
  91. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/command/__init__.py +0 -0
  92. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/command/adhoc.py +0 -0
  93. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/command/admin.py +0 -0
  94. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/command/base.py +0 -0
  95. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/command/categories.py +0 -0
  96. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/command/chat_command.py +0 -0
  97. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/command/register.py +0 -0
  98. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/command/user.py +0 -0
  99. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/contact/__init__.py +0 -0
  100. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/__init__.py +0 -0
  101. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/config.py +0 -0
  102. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/dispatcher/__init__.py +0 -0
  103. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/dispatcher/caps.py +0 -0
  104. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/dispatcher/disco.py +0 -0
  105. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/dispatcher/message/__init__.py +0 -0
  106. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/dispatcher/message/chat_state.py +0 -0
  107. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/dispatcher/message/marker.py +0 -0
  108. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/dispatcher/message/message.py +0 -0
  109. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/dispatcher/muc/__init__.py +0 -0
  110. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/dispatcher/muc/admin.py +0 -0
  111. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/dispatcher/muc/mam.py +0 -0
  112. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/dispatcher/muc/misc.py +0 -0
  113. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/dispatcher/muc/owner.py +0 -0
  114. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/dispatcher/muc/ping.py +0 -0
  115. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/dispatcher/presence.py +0 -0
  116. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/dispatcher/registration.py +0 -0
  117. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/dispatcher/search.py +0 -0
  118. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/dispatcher/util.py +0 -0
  119. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/dispatcher/vcard.py +0 -0
  120. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/mixins/__init__.py +0 -0
  121. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/mixins/attachment.py +0 -0
  122. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/mixins/avatar.py +0 -0
  123. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/mixins/base.py +0 -0
  124. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/mixins/db.py +0 -0
  125. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/mixins/disco.py +0 -0
  126. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/mixins/lock.py +0 -0
  127. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/mixins/message.py +0 -0
  128. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/mixins/message_text.py +0 -0
  129. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/mixins/presence.py +0 -0
  130. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/mixins/recipient.py +0 -0
  131. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/pubsub.py +0 -0
  132. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/core/session.py +0 -0
  133. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/db/__init__.py +0 -0
  134. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/db/alembic/__init__.py +0 -0
  135. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/db/alembic/env.py +0 -0
  136. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/db/alembic/script.py.mako +0 -0
  137. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/db/alembic/versions/04cf35e3cf85_add_participant_nickname_no_illegal.py +0 -0
  138. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/db/alembic/versions/09f27f098baa_add_missing_attributes_in_room.py +0 -0
  139. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/db/alembic/versions/15b0bd83407a_remove_bogus_unique_constraints_on_room_.py +0 -0
  140. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/db/alembic/versions/2461390c0af2_store_contacts_caps_verstring_in_db.py +0 -0
  141. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/db/alembic/versions/29f5280c61aa_store_subject_setter_in_room.py +0 -0
  142. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/db/alembic/versions/2b1f45ab7379_store_room_subject_setter_by_nickname.py +0 -0
  143. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/db/alembic/versions/3071e0fa69d4_add_contact_client_type.py +0 -0
  144. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/db/alembic/versions/45c24cc73c91_add_bob.py +0 -0
  145. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/db/alembic/versions/5bd48bfdffa2_lift_room_legacy_id_constraint.py +0 -0
  146. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/db/alembic/versions/82a4af84b679_add_muc_history_filled.py +0 -0
  147. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/db/alembic/versions/8b993243a536_add_vcard_content_to_contact_table.py +0 -0
  148. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/db/alembic/versions/8d2ced764698_rely_on_db_to_store_contacts_rooms_and_.py +0 -0
  149. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/db/alembic/versions/aa9d82a7f6ef_db_creation.py +0 -0
  150. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/db/alembic/versions/abba1ae0edb3_store_avatar_legacy_id_in_the_contact_.py +0 -0
  151. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/db/alembic/versions/b33993e87db3_move_everything_to_persistent_db.py +0 -0
  152. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/db/alembic/versions/b64b1a793483_add_source_and_legacy_id_for_archived_.py +0 -0
  153. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/db/alembic/versions/c4a8ec35a0e8_per_room_user_nick.py +0 -0
  154. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/db/alembic/versions/e91195719c2c_store_users_avatars_persistently.py +0 -0
  155. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/db/avatar.py +0 -0
  156. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/db/meta.py +0 -0
  157. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/db/models.py +0 -0
  158. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/group/__init__.py +0 -0
  159. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/main.py +0 -0
  160. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/migration.py +0 -0
  161. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/py.typed +0 -0
  162. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/slixfix/delivery_receipt.py +0 -0
  163. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/slixfix/link_preview/__init__.py +0 -0
  164. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/slixfix/link_preview/link_preview.py +0 -0
  165. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/slixfix/link_preview/stanza.py +0 -0
  166. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/slixfix/roster.py +0 -0
  167. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/slixfix/xep_0077/__init__.py +0 -0
  168. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/slixfix/xep_0077/register.py +0 -0
  169. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/slixfix/xep_0077/stanza.py +0 -0
  170. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/slixfix/xep_0100/__init__.py +0 -0
  171. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/slixfix/xep_0100/gateway.py +0 -0
  172. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/slixfix/xep_0100/stanza.py +0 -0
  173. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/slixfix/xep_0153/__init__.py +0 -0
  174. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/slixfix/xep_0153/vcard_avatar.py +0 -0
  175. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/slixfix/xep_0292/__init__.py +0 -0
  176. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/slixfix/xep_0292/vcard4.py +0 -0
  177. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/util/__init__.py +0 -0
  178. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/util/archive_msg.py +0 -0
  179. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/util/conf.py +0 -0
  180. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/util/test.py +0 -0
  181. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/util/types.py +0 -0
  182. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge/util/util.py +0 -0
  183. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge.egg-info/dependency_links.txt +0 -0
  184. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge.egg-info/entry_points.txt +0 -0
  185. {slidge-0.2.7.post1 → slidge-0.2.8}/slidge.egg-info/top_level.txt +0 -0
  186. {slidge-0.2.7.post1 → slidge-0.2.8}/superduper/__init__.py +0 -0
  187. {slidge-0.2.7.post1 → slidge-0.2.8}/superduper/contact.py +0 -0
  188. {slidge-0.2.7.post1 → slidge-0.2.8}/superduper/gateway.py +0 -0
  189. {slidge-0.2.7.post1 → slidge-0.2.8}/superduper/group.py +0 -0
  190. {slidge-0.2.7.post1 → slidge-0.2.8}/superduper/legacy_client.py +0 -0
  191. {slidge-0.2.7.post1 → slidge-0.2.8}/superduper/session.py +0 -0
  192. {slidge-0.2.7.post1 → slidge-0.2.8}/superduper/util.py +0 -0
  193. {slidge-0.2.7.post1 → slidge-0.2.8}/tests/conftest.py +0 -0
  194. {slidge-0.2.7.post1 → slidge-0.2.8}/tests/test_attachment.py +0 -0
  195. {slidge-0.2.7.post1 → slidge-0.2.8}/tests/test_avatar.py +0 -0
  196. {slidge-0.2.7.post1 → slidge-0.2.8}/tests/test_backfill.py +0 -0
  197. {slidge-0.2.7.post1 → slidge-0.2.8}/tests/test_config.py +0 -0
  198. {slidge-0.2.7.post1 → slidge-0.2.8}/tests/test_db/test_store.py +0 -0
  199. {slidge-0.2.7.post1 → slidge-0.2.8}/tests/test_db/test_user.py +0 -0
  200. {slidge-0.2.7.post1 → slidge-0.2.8}/tests/test_feature_restriction.py +0 -0
  201. {slidge-0.2.7.post1 → slidge-0.2.8}/tests/test_name_in_constructor.py +0 -0
  202. {slidge-0.2.7.post1 → slidge-0.2.8}/tests/test_resourceprep.py +0 -0
  203. {slidge-0.2.7.post1 → slidge-0.2.8}/tests/test_session_2.py +0 -0
  204. {slidge-0.2.7.post1 → slidge-0.2.8}/tests/test_set_name_before_fill.py +0 -0
  205. {slidge-0.2.7.post1 → slidge-0.2.8}/tests/test_shakespeare.py +0 -0
  206. {slidge-0.2.7.post1 → slidge-0.2.8}/tests/test_stanza_link_preview.py +0 -0
  207. {slidge-0.2.7.post1 → slidge-0.2.8}/tests/test_util.py +0 -0
  208. {slidge-0.2.7.post1 → slidge-0.2.8}/tests/test_vcard.py +0 -0
@@ -31,7 +31,7 @@ steps:
31
31
  image: codeberg.org/slidge/woodpecker-${CI_REPO_NAME}:${PYTHON_VERSION}
32
32
  commands:
33
33
  - ruff check
34
- - ruff format
34
+ - ruff format --check
35
35
 
36
36
  mypy:
37
37
  image: codeberg.org/slidge/woodpecker-${CI_REPO_NAME}:${PYTHON_VERSION}
@@ -20,7 +20,7 @@ RUN apt-get update -y && apt-get install -y --no-install-recommends \
20
20
  python3-dev \
21
21
  rustc
22
22
 
23
- RUN uv venv /venv
23
+ RUN uv venv /venv --relocatable
24
24
  WORKDIR /build
25
25
  # Only copy files used to define dependencies, so this step can be in cache
26
26
  # as long as we don't touch the deps.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: slidge
3
- Version: 0.2.7.post1
3
+ Version: 0.2.8
4
4
  Summary: XMPP bridging framework
5
5
  Author-email: Nicolas Cedilnik <nicoco@nicoco.fr>
6
6
  License: GNU AFFERO GENERAL PUBLIC LICENSE
@@ -683,7 +683,7 @@ Requires-Dist: defusedxml>=0.7.1
683
683
  Requires-Dist: pillow<12,>=11.0.0
684
684
  Requires-Dist: python-magic<0.5,>=0.4.27
685
685
  Requires-Dist: qrcode<9,>=8.0
686
- Requires-Dist: slixmpp<1.9.0,>=1.8.6
686
+ Requires-Dist: slixmpp<2,>=1.9.0
687
687
  Requires-Dist: sqlalchemy<3,>=2
688
688
  Requires-Dist: thumbhash>=0.1.2
689
689
 
@@ -15,8 +15,12 @@ contributions are welcome).
15
15
 
16
16
  In this page we assume that you have fulfilled the basic :ref:`XMPP server config`.
17
17
 
18
- Debian packages (systemd)
19
- =========================
18
+ Debian packages (unofficial)
19
+ ============================
20
+
21
+ These instructions are for the slidge bundle unofficial package hosted on
22
+ `codeberg <https://codeberg.org/slidge/debian>`_. They do not apply to the official
23
+ debian slidge package, which is incompatible with this bundle.
20
24
 
21
25
  Edit and remove the ``.example`` extension for ``/etc/slidge/conf.d/common.conf``
22
26
  and ``/etc/slidge/superduper.conf.example``.
@@ -13,14 +13,8 @@ debian
13
13
  ------
14
14
 
15
15
  A debian package containing slidge and a bunch of legacy modules is available at
16
- `<https://git.sr.ht/~nicoco/slidge-debian>`_.
17
-
18
- Debian packages for *bookworm* (amd64 and arm64)
19
- are built on each push to master as artifacts of
20
- this `build job <https://builds.sr.ht/~nicoco/slidge/commits/master/debian.yml?>`_.
21
-
22
- A repo is maintained by IGImonster. Refer to the README of
23
- `<https://git.sr.ht/~nicoco/slidge-debian>`_ for setup instructions.
16
+ `<https://codeberg.org/slidge/debian>`_. See the README there for details and
17
+ instructions.
24
18
 
25
19
  See :ref:`Debian packages` for information about how to launch slidge as a daemon via systemd.
26
20
 
@@ -10,7 +10,7 @@ dependencies = [
10
10
  "pillow>=11.0.0,<12",
11
11
  "python-magic>=0.4.27,<0.5",
12
12
  "qrcode>=8.0,<9",
13
- "slixmpp>=1.8.6,<1.9.0",
13
+ "slixmpp>=1.9.0,<2",
14
14
  "sqlalchemy>=2,<3",
15
15
  "thumbhash>=0.1.2",
16
16
  ]
@@ -23,7 +23,7 @@ classifiers = [
23
23
  "Topic :: Software Development :: Libraries :: Python Modules",
24
24
  ]
25
25
  keywords = ["xmpp", "gateway", "bridge", "instant messaging"]
26
- version = "v0.2.7.post1"
26
+ version = "v0.2.8"
27
27
  readme = "README.md"
28
28
 
29
29
  [build-system]
@@ -128,14 +128,20 @@ header = """
128
128
  # Changes
129
129
  """
130
130
  body = """
131
- {% for group, commits in commits | group_by(attribute="group") %}
131
+ {% for group, all_commits in commits | group_by(attribute="group") %}
132
+ {%- if group == "cfix" %}{% continue %}{%- endif %}
132
133
  ## {{ group | striptags | trim | upper_first }}
133
- {% for commit in commits %}
134
+ {% for commit in all_commits %}
134
135
  - {% if commit.scope %}*({{ commit.scope }})* {% endif %}\
135
136
  {% if commit.breaking %}[**breaking**] {% endif %}\
136
- {{ commit.message | split(pat="\n") | first | upper_first | trim }}\
137
- {% if commit.remote.username %} by @{{ commit.remote.username }}{%- endif %} \
138
- [`{{ commit.id | truncate(length=7, end="") }}`](./commit/{{ commit.id }})\
137
+ {{ commit.message | split(pat="\n") | first | upper_first | trim }} \
138
+ ([`{{ commit.id | truncate(length=7, end="") }}`](./commit/{{ commit.id -}})\
139
+ {% if commit.remote.username %} by @{{ commit.remote.username }}{%- endif -%}
140
+ {%- for cfix_commit in commits | filter(attribute="group", value="cfix") -%}
141
+ {%- if cfix_commit.scope and commit.id is starting_with(cfix_commit.scope) -%}
142
+ , [`{{ cfix_commit.id | truncate(length=7, end="") }}`](./commit/{{ cfix_commit.id }}){% if cfix_commit.remote.username %} by @{{ cfix_commit.remote.username }}{%- endif -%}
143
+ {%- endif -%}
144
+ {%- endfor -%})\
139
145
  {% endfor %}
140
146
  {% endfor %}\n
141
147
  """
@@ -148,21 +154,23 @@ conventional_commits = true
148
154
  filter_unconventional = false
149
155
  commit_parsers = [
150
156
  { message = "^feat", group = "<!-- 0 -->🚀 Features" },
151
- { message = "^imprv", group = "<!-- 1 -->✨ Improvements" },
152
- { message = "^fix", group = "<!-- 2 -->🐛 Bug Fixes" },
153
- { message = "^compat", group = "<!-- 3 -->💑 Compatibility" },
154
- { message = "^refactor", group = "<!-- 4 -->🚜 Refactor" },
155
- { message = "^doc", group = "<!-- 5 -->📚 Documentation" },
156
- { message = "^perf", group = "<!-- 6 -->⚡ Performance" },
157
- { message = "^style", group = "<!-- 7 -->🎨 Styling" },
158
- { message = "^test", group = "<!-- 8 -->🧪 Testing" },
157
+ { message = "^imprv", group = "<!-- 01 -->✨ Improvements" },
158
+ { message = "^fix", group = "<!-- 02 -->🐛 Bug Fixes" },
159
+ { message = "^compat", group = "<!-- 03 -->💑 Compatibility" },
160
+ { message = "^refactor", group = "<!-- 04 -->🚜 Refactor" },
161
+ { message = "^doc", group = "<!-- 05 -->📚 Documentation" },
162
+ { message = "^perf", group = "<!-- 06 -->⚡ Performance" },
163
+ { message = "^style", group = "<!-- 07 -->🎨 Styling" },
164
+ { message = "^test", group = "<!-- 08 -->🧪 Testing" },
159
165
  { message = "^chore\\(release\\): prepare for", skip = true },
160
166
  { message = "^chore\\(deps.*\\)", skip = true },
161
167
  { message = "^chore\\(pr\\)", skip = true },
162
168
  { message = "^chore\\(pull\\)", skip = true },
163
- { message = "^cfix", skip = true },
164
- { message = "^chore|^ci", group = "<!-- 9 -->⚙️ Miscellaneous Tasks" },
169
+ { message = "^build\\(lockfile\\)", skip = true },
170
+ { message = "^chore\\(lockfile\\)", skip = true },
171
+ { message = "^chore|^ci", group = "<!-- 09 -->⚙️ Miscellaneous Tasks" },
165
172
  { body = ".*security", group = "<!-- 10 -->🛡️ Security" },
166
173
  { message = "^revert", group = "<!-- 11 -->◀️ Revert" },
167
- { message = ".*", group = "<!-- 12 -->💼 Other" },
174
+ { message = "^cfix", group = "cfix" },
175
+ { message = ".*", group = "<!-- 13 -->💼 Other" },
168
176
  ]
@@ -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__ = "v0.2.7.post1"
5
+ __version__ = "v0.2.8"
@@ -218,7 +218,7 @@ class LegacyContact(
218
218
  self.log.name = f"{self.user_jid.bare}:contact:{self}"
219
219
 
220
220
  def __repr__(self):
221
- return f"<Contact #{self.contact_pk} '{self.name}' ({self.legacy_id} - {self.jid.local})'>"
221
+ return f"<Contact #{self.contact_pk} '{self.name}' ({self.legacy_id} - {self.jid.user})'>"
222
222
 
223
223
  def __ensure_pk(self):
224
224
  if self.contact_pk is not None:
@@ -617,7 +617,7 @@ class LegacyContact(
617
617
  contact = cls(
618
618
  session,
619
619
  cls.xmpp.LEGACY_CONTACT_ID_TYPE(stored.legacy_id),
620
- stored.jid.username, # type: ignore
620
+ stored.jid.user, # type: ignore
621
621
  *args, # type: ignore
622
622
  **kwargs, # type: ignore
623
623
  )
@@ -5,12 +5,12 @@ from typing import TYPE_CHECKING, AsyncIterator, Generic, Iterator, Optional, Ty
5
5
 
6
6
  from slixmpp import JID
7
7
  from slixmpp.exceptions import IqError, IqTimeout, XMPPError
8
- from slixmpp.jid import JID_UNESCAPE_TRANSFORMATIONS, _unescape_node
9
8
 
10
9
  from ..core.mixins.lock import NamedLockMixin
11
10
  from ..db.models import Contact
12
11
  from ..db.store import ContactStore
13
12
  from ..util import SubclassableOnce
13
+ from ..util.jid_escaping import ESCAPE_TABLE, unescape_node
14
14
  from ..util.types import LegacyContactType, LegacyUserIdType
15
15
  from .contact import LegacyContact
16
16
 
@@ -198,7 +198,7 @@ class LegacyRoster(
198
198
  :param jid_username: User part of a JID, ie "user" in "user@example.com"
199
199
  :return: An identifier for the user on the legacy network.
200
200
  """
201
- return _unescape_node(jid_username)
201
+ return unescape_node(jid_username)
202
202
 
203
203
  async def _fill(self):
204
204
  try:
@@ -259,5 +259,4 @@ class LegacyRoster(
259
259
  yield
260
260
 
261
261
 
262
- ESCAPE_TABLE = "".maketrans({v: k for k, v in JID_UNESCAPE_TRANSFORMATIONS.items()})
263
262
  log = logging.getLogger(__name__)
@@ -52,7 +52,6 @@ class SessionDispatcher(
52
52
  if session.user.avatar_hash == hash_:
53
53
  session.log.debug("We already know this avatar hash")
54
54
  return
55
- self.xmpp.store.users.set_avatar_hash(session.user_pk, None)
56
55
 
57
56
  if hash_:
58
57
  try:
@@ -67,6 +66,7 @@ class SessionDispatcher(
67
66
  height = info["height"]
68
67
  width = info["width"]
69
68
  else:
69
+ self.xmpp.store.users.set_avatar_hash(session.user_pk, None)
70
70
  bytes_ = type_ = height = width = hash_ = None
71
71
  try:
72
72
  await session.on_avatar(bytes_, hash_, type_, width, height)
@@ -79,6 +79,11 @@ class SessionDispatcher(
79
79
  session.send_gateway_message(
80
80
  f"Something went wrong trying to set your avatar: {e!r}"
81
81
  )
82
+ else:
83
+ self.xmpp.store.users.set_avatar_hash(session.user_pk, hash_)
84
+ for room in session.bookmarks:
85
+ participant = await room.get_user_participant()
86
+ participant.send_last_presence(force=True, no_cache_online=True)
82
87
 
83
88
 
84
89
  log = logging.getLogger(__name__)
@@ -559,8 +559,18 @@ class BaseGateway(
559
559
  self.xmpp.plugin["xep_0084"].stanza.MetaData.namespace,
560
560
  ifrom=self.boundjid.bare,
561
561
  )
562
- except (IqError, IqTimeout):
563
- self.xmpp.store.users.set_avatar_hash(session.user_pk, None)
562
+ except IqTimeout:
563
+ self.log.warning("Iq timeout trying to fetch user avatar")
564
+ return
565
+ except IqError as e:
566
+ self.log.debug("Iq error when trying to fetch user avatar: %s", e)
567
+ if e.condition == "item-not-found":
568
+ try:
569
+ await session.on_avatar(None, None, None, None, None)
570
+ except NotImplementedError:
571
+ pass
572
+ else:
573
+ self.xmpp.store.users.set_avatar_hash(session.user_pk, None)
564
574
  return
565
575
  await self.__dispatcher.on_avatar_metadata_info(
566
576
  session, iq["pubsub"]["items"]["item"]["avatar_metadata"]["info"]
@@ -4,7 +4,7 @@ from datetime import datetime, timezone
4
4
  from typing import TYPE_CHECKING, Iterable, Optional, cast
5
5
  from uuid import uuid4
6
6
 
7
- from slixmpp import Message
7
+ from slixmpp import JID, Message
8
8
  from slixmpp.types import MessageTypes
9
9
 
10
10
  from ...db.models import GatewayUser
@@ -120,14 +120,14 @@ class MessageMaker(BaseSender):
120
120
  DeprecationWarning,
121
121
  )
122
122
  if muc:
123
- jid = copy(muc.jid)
123
+ jid = JID(muc.jid)
124
124
  jid.resource = fallback_nick = muc.user_nick
125
125
  msg["reply"]["to"] = jid
126
126
  else:
127
127
  msg["reply"]["to"] = self.session.user_jid
128
128
  # TODO: here we should use preferably use the PEP nick of the user
129
129
  # (but it doesn't matter much)
130
- fallback_nick = self.session.user_jid.local
130
+ fallback_nick = self.session.user_jid.user
131
131
  else:
132
132
  if muc:
133
133
  if hasattr(entity, "muc"):
@@ -443,6 +443,7 @@ class ContactStore(UpdatedMixin):
443
443
  break
444
444
  for row_id in to_del:
445
445
  session.execute(delete(ContactSent).where(ContactSent.id == row_id))
446
+ session.commit()
446
447
  return result
447
448
 
448
449
  def set_friend(self, contact_pk: int, is_friend: bool) -> None:
@@ -751,6 +752,8 @@ class MultiStore(EngineMixin):
751
752
  ).scalar()
752
753
  if multi is None:
753
754
  return None
755
+ if multi.legacy_ids_multi is None:
756
+ return None
754
757
  return multi.legacy_ids_multi.legacy_id
755
758
 
756
759
 
@@ -150,19 +150,27 @@ def archivable(msg: Message):
150
150
  :return:
151
151
  """
152
152
 
153
- if msg.get_plugin("hint", check=True) and msg["hint"] == "no-store":
153
+ if msg.get_plugin("no-store", check=True):
154
154
  return False
155
155
 
156
+ if msg.get_plugin("no-permanent-store", check=True):
157
+ return False
158
+
159
+ if msg.get_plugin("store", check=True):
160
+ return True
161
+
156
162
  if msg["body"]:
157
163
  return True
158
164
 
159
- if msg.get_plugin("apply_to", check=True):
160
- # retractions
165
+ if msg.get_plugin("retract", check=True):
161
166
  return True
162
167
 
163
168
  if msg.get_plugin("reactions", check=True):
164
169
  return True
165
170
 
171
+ if msg.get_plugin("displayed", check=True):
172
+ return True
173
+
166
174
  return False
167
175
 
168
176
 
@@ -4,12 +4,11 @@ from typing import TYPE_CHECKING, Generic, Iterator, Optional, Type
4
4
 
5
5
  from slixmpp import JID
6
6
  from slixmpp.exceptions import XMPPError
7
- from slixmpp.jid import _unescape_node
8
7
 
9
- from ..contact.roster import ESCAPE_TABLE
10
8
  from ..core.mixins.lock import NamedLockMixin
11
9
  from ..db.models import Room
12
10
  from ..util import SubclassableOnce
11
+ from ..util.jid_escaping import ESCAPE_TABLE, unescape_node
13
12
  from ..util.types import LegacyGroupIdType, LegacyMUCType
14
13
  from .archive import MessageArchive
15
14
  from .room import LegacyMUC
@@ -83,14 +82,14 @@ class LegacyBookmarks(
83
82
  :param username:
84
83
  :return:
85
84
  """
86
- return _unescape_node(username)
85
+ return unescape_node(username)
87
86
 
88
87
  async def by_jid(self, jid: JID) -> LegacyMUCType:
89
88
  if jid.resource:
90
89
  jid = JID(jid.bare)
91
90
  async with self.lock(("bare", jid.bare)):
92
- assert isinstance(jid.local, str)
93
- legacy_id = await self.jid_local_part_to_legacy_id(jid.local)
91
+ assert isinstance(jid.user, str)
92
+ legacy_id = await self.jid_local_part_to_legacy_id(jid.user)
94
93
  if self.get_lock(("legacy_id", legacy_id)):
95
94
  self.log.debug("Not instantiating %s after all", jid)
96
95
  return await self.by_legacy_id(legacy_id)
@@ -1,6 +1,5 @@
1
1
  import logging
2
2
  import string
3
- import stringprep
4
3
  import uuid
5
4
  import warnings
6
5
  from copy import copy
@@ -10,9 +9,7 @@ from typing import TYPE_CHECKING, Optional, Self, Union
10
9
 
11
10
  from slixmpp import JID, InvalidJID, Message, Presence
12
11
  from slixmpp.plugins.xep_0045.stanza import MUCAdminItem
13
- from slixmpp.stringprep import StringprepError, resourceprep
14
12
  from slixmpp.types import MessageTypes, OptJid
15
- from slixmpp.util.stringprep_profiles import StringPrepError, prohibit_output
16
13
 
17
14
  from ..contact import LegacyContact
18
15
  from ..core.mixins import (
@@ -175,39 +172,22 @@ class LegacyParticipant(
175
172
  self.send_last_presence(force=True, no_cache_online=True)
176
173
 
177
174
  def __update_jid(self, unescaped_nickname: Optional[str]):
178
- j: JID = copy(self.muc.jid)
179
-
180
- if self.is_system:
181
- self.jid = j
182
- self._nickname_no_illegal = ""
175
+ if not unescaped_nickname:
176
+ self.jid = JID(self.muc.jid)
177
+ if self.is_system:
178
+ self._nickname_no_illegal = ""
179
+ else:
180
+ warnings.warn(
181
+ "Only the system participant is allowed to not have a nickname"
182
+ )
183
+ nickname = f"unnamed-{uuid.uuid4()}"
184
+ self.jid.resource = self._nickname_no_illegal = nickname
183
185
  return
184
186
 
185
- nickname = unescaped_nickname
186
-
187
- if nickname:
188
- nickname = self._nickname_no_illegal = strip_illegal_chars(nickname)
189
- else:
190
- warnings.warn(
191
- "Only the system participant is allowed to not have a nickname"
192
- )
193
- nickname = f"unnamed-{uuid.uuid4()}"
194
-
195
- assert isinstance(nickname, str)
196
-
197
- try:
198
- # workaround for https://codeberg.org/poezio/slixmpp/issues/3480
199
- prohibit_output(nickname, [stringprep.in_table_a1])
200
- resourceprep(nickname)
201
- except (StringPrepError, StringprepError):
202
- nickname = nickname.encode("punycode").decode()
203
-
204
- # at this point there still might be control chars
205
- try:
206
- j.resource = nickname
207
- except InvalidJID:
208
- j.resource = strip_non_printable(nickname)
209
-
210
- self.jid = j
187
+ self._nickname_no_illegal, self.jid = escape_nickname(
188
+ self.muc.jid,
189
+ unescaped_nickname,
190
+ )
211
191
 
212
192
  def send_configuration_change(self, codes: tuple[int]):
213
193
  if not self.is_system:
@@ -270,7 +250,7 @@ class LegacyParticipant(
270
250
  if user_full_jid:
271
251
  p["muc"]["jid"] = user_full_jid
272
252
  else:
273
- jid = copy(self.user_jid)
253
+ jid = JID(self.user_jid)
274
254
  try:
275
255
  jid.resource = next(
276
256
  iter(self.muc.get_user_resources()) # type:ignore
@@ -539,4 +519,22 @@ class LegacyParticipant(
539
519
  return part
540
520
 
541
521
 
522
+ def escape_nickname(muc_jid: JID, nickname: str) -> tuple[str, JID]:
523
+ nickname = nickname_no_illegal = strip_illegal_chars(nickname)
524
+
525
+ jid = JID(muc_jid)
526
+
527
+ try:
528
+ jid.resource = nickname
529
+ except InvalidJID:
530
+ nickname = nickname.encode("punycode").decode()
531
+ try:
532
+ jid.resource = nickname
533
+ except InvalidJID:
534
+ # at this point there still might be control chars
535
+ jid.resource = strip_non_printable(nickname)
536
+
537
+ return nickname_no_illegal, jid
538
+
539
+
542
540
  log = logging.getLogger(__name__)
@@ -10,11 +10,12 @@ from uuid import uuid4
10
10
 
11
11
  from slixmpp import JID, Iq, Message, Presence
12
12
  from slixmpp.exceptions import IqError, IqTimeout, XMPPError
13
- from slixmpp.jid import _unescape_node
14
13
  from slixmpp.plugins.xep_0004 import Form
15
14
  from slixmpp.plugins.xep_0060.stanza import Item
16
15
  from slixmpp.plugins.xep_0082 import parse as str_to_datetime
17
16
  from slixmpp.plugins.xep_0469.stanza import NS as PINNING_NS
17
+ from slixmpp.plugins.xep_0492.stanza import NS as NOTIFY_NS
18
+ from slixmpp.plugins.xep_0492.stanza import WhenLiteral
18
19
  from slixmpp.xmlstream import ET
19
20
 
20
21
  from ..contact.contact import LegacyContact
@@ -27,9 +28,8 @@ from ..core.mixins.disco import ChatterDiscoMixin
27
28
  from ..core.mixins.lock import NamedLockMixin
28
29
  from ..core.mixins.recipient import ReactionRecipientMixin, ThreadRecipientMixin
29
30
  from ..db.models import Room
30
- from ..slixfix.xep_0492.stanza import NS as NOTIFY_NS
31
- from ..slixfix.xep_0492.stanza import WhenLiteral
32
31
  from ..util import ABCSubclassableOnceAtMost
32
+ from ..util.jid_escaping import unescape_node
33
33
  from ..util.types import (
34
34
  HoleBound,
35
35
  LegacyGroupIdType,
@@ -42,7 +42,7 @@ from ..util.types import (
42
42
  )
43
43
  from ..util.util import deprecated, timeit, with_session
44
44
  from .archive import MessageArchive
45
- from .participant import LegacyParticipant
45
+ from .participant import LegacyParticipant, escape_nickname
46
46
 
47
47
  if TYPE_CHECKING:
48
48
  from ..core.gateway import BaseGateway
@@ -184,7 +184,7 @@ class LegacyMUC(
184
184
  self.log = logging.getLogger(f"{self.user_jid}:muc:{self}")
185
185
 
186
186
  def __repr__(self):
187
- return f"<MUC #{self.pk} '{self.name}' ({self.legacy_id} - {self.jid.local})'>"
187
+ return f"<MUC #{self.pk} '{self.name}' ({self.legacy_id} - {self.jid.user})'>"
188
188
 
189
189
  @property
190
190
  def subject_date(self) -> Optional[datetime]:
@@ -515,8 +515,7 @@ class LegacyMUC(
515
515
  return r
516
516
 
517
517
  def shutdown(self):
518
- user_jid = copy(self.jid)
519
- user_jid.resource = self.user_nick
518
+ _, user_jid = escape_nickname(self.jid, self.user_nick)
520
519
  for user_full_jid in self.user_full_jids():
521
520
  presence = self.xmpp.make_presence(
522
521
  pfrom=user_jid, pto=user_full_jid, ptype="unavailable"
@@ -528,14 +527,13 @@ class LegacyMUC(
528
527
 
529
528
  def user_full_jids(self):
530
529
  for r in self._user_resources:
531
- j = copy(self.user_jid)
530
+ j = JID(self.user_jid)
532
531
  j.resource = r
533
532
  yield j
534
533
 
535
534
  @property
536
535
  def user_muc_jid(self):
537
- user_muc_jid = copy(self.jid)
538
- user_muc_jid.resource = self.user_nick
536
+ _, user_muc_jid = escape_nickname(self.jid, self.user_nick)
539
537
  return user_muc_jid
540
538
 
541
539
  def _legacy_to_xmpp(self, legacy_id: LegacyMessageType):
@@ -782,7 +780,7 @@ class LegacyMUC(
782
780
  self.session, stored, muc=self, contact=c
783
781
  )
784
782
 
785
- nickname = c.name or _unescape_node(c.jid_username)
783
+ nickname = c.name or unescape_node(c.jid_username)
786
784
 
787
785
  if self.pk is None:
788
786
  nick_available = True
@@ -990,7 +988,7 @@ class LegacyMUC(
990
988
 
991
989
  :param r: The resource to kick
992
990
  """
993
- pto = self.user_jid
991
+ pto = JID(self.user_jid)
994
992
  pto.resource = r
995
993
  p = self.xmpp.make_presence(
996
994
  pfrom=(await self.get_user_participant()).jid, pto=pto
@@ -0,0 +1,92 @@
1
+ # This module contains patches for slixmpp; some have pending requests upstream
2
+ # and should be removed on the next slixmpp release.
3
+
4
+ # ruff: noqa: F401
5
+
6
+ import logging
7
+
8
+ import slixmpp.plugins
9
+ import slixmpp.stanza.roster
10
+ from slixmpp import InvalidJID, Message
11
+ from slixmpp.plugins.xep_0050 import XEP_0050, Command
12
+ from slixmpp.plugins.xep_0469.stanza import NS as PINNED_NS
13
+ from slixmpp.plugins.xep_0469.stanza import Pinned
14
+ from slixmpp.xmlstream import StanzaBase
15
+
16
+ from . import (
17
+ link_preview,
18
+ xep_0077,
19
+ xep_0100,
20
+ xep_0153,
21
+ xep_0292,
22
+ )
23
+
24
+
25
+ # TODO: remove this when we pin slixmpp > 1.9.0
26
+ def get_items(self):
27
+ items = {}
28
+ for item in self["substanzas"]:
29
+ if isinstance(item, slixmpp.stanza.roster.RosterItem):
30
+ try:
31
+ items[item["jid"]] = item.values
32
+ except InvalidJID:
33
+ logging.warning("Invalid JID in roster: %s", item)
34
+ continue
35
+ del items[item["jid"]]["jid"]
36
+ del items[item["jid"]]["lang"]
37
+ return items
38
+
39
+
40
+ slixmpp.stanza.roster.Roster.get_items = get_items # type:ignore
41
+
42
+
43
+ def set_pinned(self, val: bool):
44
+ extensions = self.parent()
45
+ if val:
46
+ extensions.enable("pinned")
47
+ else:
48
+ extensions._del_sub(f"{{{PINNED_NS}}}pinned")
49
+
50
+
51
+ Pinned.set_pinned = set_pinned
52
+
53
+
54
+ def session_bind(self, jid):
55
+ self.xmpp["xep_0030"].add_feature(Command.namespace)
56
+ # awful hack to for the disco items: we need to comment this line
57
+ # related issue: https://todo.sr.ht/~nicoco/slidge/131
58
+ # self.xmpp['xep_0030'].set_items(node=Command.namespace, items=tuple())
59
+
60
+
61
+ XEP_0050.session_bind = session_bind # type:ignore
62
+
63
+
64
+ def reply(self, body=None, clear=True):
65
+ """
66
+ Overrides slixmpp's Message.reply(), since it strips to sender's resource
67
+ for mtype=groupchat, and we do not want that, because when we raise an XMPPError,
68
+ we actually want to preserve the resource.
69
+ (this is called in RootStanza.exception() to handle XMPPErrors)
70
+ """
71
+ new_message = StanzaBase.reply(self, clear)
72
+ new_message["thread"] = self["thread"]
73
+ new_message["parent_thread"] = self["parent_thread"]
74
+
75
+ del new_message["id"]
76
+ if self.stream is not None and self.stream.use_message_ids:
77
+ new_message["id"] = self.stream.new_id()
78
+
79
+ if body is not None:
80
+ new_message["body"] = body
81
+ return new_message
82
+
83
+
84
+ Message.reply = reply # type: ignore
85
+
86
+
87
+ slixmpp.plugins.PLUGINS.extend(
88
+ [
89
+ "link_preview",
90
+ "xep_0292_provider",
91
+ ]
92
+ )