slidge 0.2.9__py3-none-any.whl → 0.2.10__py3-none-any.whl

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.
slidge/__init__.py CHANGED
@@ -29,7 +29,7 @@ def entrypoint(module_name: str) -> None:
29
29
  :param module_name: An importable :term:`Legacy Module`.
30
30
  """
31
31
  sys.argv.extend(["--legacy", module_name])
32
- main_func()
32
+ main_func(module_name)
33
33
 
34
34
 
35
35
  def formatwarning(message, category, filename, lineno, line=""):
slidge/core/gateway.py CHANGED
@@ -31,6 +31,7 @@ from slidge.core.pubsub import PubSubComponent
31
31
  from slidge.core.session import BaseSession
32
32
  from slidge.db import GatewayUser, SlidgeStore
33
33
  from slidge.db.avatar import avatar_cache
34
+ from slidge.slixfix import PrivilegedIqError
34
35
  from slidge.slixfix.delivery_receipt import DeliveryReceipt
35
36
  from slidge.slixfix.roster import RosterBackend
36
37
  from slidge.util import ABCSubclassableOnceAtMost
@@ -474,11 +475,12 @@ class BaseGateway(
474
475
  "create the MDS node of %s",
475
476
  user_jid,
476
477
  )
477
- except (IqError, IqTimeout) as e:
478
+ except PrivilegedIqError as exc:
479
+ nested = exc.nested_error()
478
480
  # conflict this means the node already exists, we can ignore that
479
- if e.condition != "conflict":
481
+ if nested is not None and nested.condition != "conflict":
480
482
  log.exception(
481
- "Could not create the MDS node of %s", user_jid, exc_info=e
483
+ "Could not create the MDS node of %s", user_jid, exc_info=exc
482
484
  )
483
485
  except Exception as e:
484
486
  log.exception(
@@ -46,7 +46,7 @@ class AttachmentMixin(TextMessageMixin):
46
46
  file_path: Path,
47
47
  file_name: Optional[str] = None,
48
48
  content_type: Optional[str] = None,
49
- ):
49
+ ) -> str | None:
50
50
  if file_name and file_path.name != file_name:
51
51
  d = Path(tempfile.mkdtemp())
52
52
  temp = d / file_name
@@ -215,7 +215,7 @@ class AttachmentMixin(TextMessageMixin):
215
215
  else:
216
216
  local_path = file_path
217
217
  new_url = await self.__upload(file_path, file_name, content_type)
218
- if legacy_file_id:
218
+ if legacy_file_id and new_url is not None:
219
219
  self.__store.set_url(self.session.user_pk, str(legacy_file_id), new_url)
220
220
 
221
221
  return is_temp, local_path, new_url
slidge/core/pubsub.py CHANGED
@@ -11,7 +11,7 @@ from slixmpp import (
11
11
  StanzaPath,
12
12
  register_stanza_plugin,
13
13
  )
14
- from slixmpp.exceptions import XMPPError
14
+ from slixmpp.exceptions import IqError, IqTimeout, XMPPError
15
15
  from slixmpp.plugins.base import BasePlugin, register_plugin
16
16
  from slixmpp.plugins.xep_0060.stanza import Event, EventItem, EventItems, Item
17
17
  from slixmpp.plugins.xep_0084 import Data as AvatarData
@@ -134,7 +134,11 @@ class PubSubComponent(NamedLockMixin, BasePlugin):
134
134
  info = None
135
135
  if info is None:
136
136
  async with self.lock(from_):
137
- iq = await self.xmpp.plugin["xep_0030"].get_info(from_)
137
+ try:
138
+ iq = await self.xmpp.plugin["xep_0030"].get_info(from_)
139
+ except (IqError, IqTimeout):
140
+ log.debug("Could get disco#info of %s, ignoring", from_)
141
+ return []
138
142
  info = iq["disco_info"]
139
143
  return info["features"]
140
144
 
slidge/db/store.py CHANGED
@@ -1076,6 +1076,7 @@ class ParticipantStore(EngineMixin):
1076
1076
  update(Participant)
1077
1077
  .where(Participant.id == participant.pk)
1078
1078
  .values(
1079
+ nickname=participant.nickname,
1079
1080
  resource=participant.jid.resource,
1080
1081
  nickname_no_illegal=participant._nickname_no_illegal,
1081
1082
  affiliation=participant.affiliation,
@@ -229,6 +229,8 @@ class LegacyParticipant(
229
229
  p = self._make_presence(ptype="available", last_seen=last_seen, **kwargs)
230
230
  self._send(p)
231
231
 
232
+ self.__part_store.update(self)
233
+
232
234
  def _make_presence(
233
235
  self,
234
236
  *,
slidge/group/room.py CHANGED
@@ -648,7 +648,7 @@ class LegacyMUC(
648
648
  since = self.xmpp.plugin["xep_0082"].parse(history_params["since"])
649
649
  except ValueError:
650
650
  since = None
651
- if seconds:
651
+ if seconds is not None:
652
652
  since = datetime.now() - timedelta(seconds=seconds)
653
653
  if equals_zero(maxchars) or equals_zero(maxstanzas):
654
654
  log.debug("Joining client does not want any old-school MUC history-on-join")
slidge/main.py CHANGED
@@ -60,7 +60,7 @@ class SigTermInterrupt(Exception):
60
60
  pass
61
61
 
62
62
 
63
- def get_configurator():
63
+ def get_configurator(from_entrypoint: bool = False):
64
64
  p = configargparse.ArgumentParser(
65
65
  default_config_files=os.getenv(
66
66
  "SLIDGE_CONF_DIR", "/etc/slidge/conf.d/*.conf"
@@ -98,7 +98,9 @@ def get_configurator():
98
98
  action="version",
99
99
  version=f"%(prog)s {slidge.__version__}",
100
100
  )
101
- configurator = MainConfig(config, p)
101
+ configurator = MainConfig(
102
+ config, p, skip_options=("legacy_module",) if from_entrypoint else ()
103
+ )
102
104
  return configurator
103
105
 
104
106
 
@@ -106,8 +108,8 @@ def get_parser():
106
108
  return get_configurator().parser
107
109
 
108
110
 
109
- def configure():
110
- configurator = get_configurator()
111
+ def configure(from_entrypoint: bool):
112
+ configurator = get_configurator(from_entrypoint)
111
113
  args, unknown_argv = configurator.set_conf()
112
114
 
113
115
  if not (h := config.HOME_DIR).exists():
@@ -124,12 +126,16 @@ def handle_sigterm(_signum, _frame):
124
126
  raise SigTermInterrupt
125
127
 
126
128
 
127
- def main():
129
+ def main(module_name: str | None = None) -> None:
130
+ from_entrypoint = module_name is None
128
131
  signal.signal(signal.SIGTERM, handle_sigterm)
129
132
 
130
- unknown_argv = configure()
133
+ unknown_argv = configure(from_entrypoint)
131
134
  logging.info("Starting slidge version %s", slidge.__version__)
132
135
 
136
+ if module_name is not None:
137
+ config.LEGACY_MODULE = module_name
138
+
133
139
  legacy_module = importlib.import_module(config.LEGACY_MODULE)
134
140
  logging.debug("Legacy module: %s", dir(legacy_module))
135
141
  logging.info(
@@ -3,12 +3,15 @@
3
3
 
4
4
  # ruff: noqa: F401
5
5
 
6
- import logging
6
+ import uuid
7
7
 
8
8
  import slixmpp.plugins
9
9
  import slixmpp.stanza.roster
10
- from slixmpp import InvalidJID, Message
10
+ from slixmpp import Message
11
+ from slixmpp.exceptions import IqError
11
12
  from slixmpp.plugins.xep_0050 import XEP_0050, Command
13
+ from slixmpp.plugins.xep_0356.permissions import IqPermission
14
+ from slixmpp.plugins.xep_0356.privilege import XEP_0356
12
15
  from slixmpp.plugins.xep_0469.stanza import NS as PINNED_NS
13
16
  from slixmpp.plugins.xep_0469.stanza import Pinned
14
17
  from slixmpp.xmlstream import StanzaBase
@@ -22,24 +25,6 @@ from . import (
22
25
  )
23
26
 
24
27
 
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
28
  def set_pinned(self, val: bool):
44
29
  extensions = self.parent()
45
30
  if val:
@@ -83,6 +68,70 @@ def reply(self, body=None, clear=True):
83
68
 
84
69
  Message.reply = reply # type: ignore
85
70
 
71
+ # TODO: remove me when https://codeberg.org/poezio/slixmpp/pulls/3622 is merged
72
+
73
+
74
+ class PrivilegedIqError(IqError):
75
+ """
76
+ Exception raised when sending a privileged IQ stanza fails.
77
+ """
78
+
79
+ def nested_error(self) -> IqError | None:
80
+ """
81
+ Return the IQError generated from the inner IQ stanza, if present.
82
+ """
83
+ if "privilege" in self.iq:
84
+ if "forwarded" in self.iq["privilege"]:
85
+ if "iq" in self.iq["privilege"]["forwarded"]:
86
+ return IqError(self.iq["privilege"]["forwarded"]["iq"])
87
+ return None
88
+
89
+
90
+ async def send_privileged_iq(self, encapsulated_iq, iq_id=None):
91
+ """
92
+ Send an IQ on behalf of a user
93
+
94
+ Caution: the IQ *must* have the jabber:client namespace
95
+
96
+ Raises :class:`PrivilegedIqError` on failure.
97
+ """
98
+ iq_id = iq_id or str(uuid.uuid4())
99
+ encapsulated_iq["id"] = iq_id
100
+ server = encapsulated_iq.get_to().domain
101
+ perms = self.granted_privileges.get(server)
102
+ if not perms:
103
+ raise PermissionError(f"{server} has not granted us any privilege")
104
+ itype = encapsulated_iq["type"]
105
+ for ns in encapsulated_iq.plugins.values():
106
+ type_ = perms.iq[ns.namespace]
107
+ if type_ == IqPermission.NONE:
108
+ raise PermissionError(
109
+ f"{server} has not granted any IQ privilege for namespace {ns.namespace}"
110
+ )
111
+ elif type_ == IqPermission.BOTH:
112
+ pass
113
+ elif type_ != itype:
114
+ raise PermissionError(
115
+ f"{server} has not granted IQ {itype} privilege for namespace {ns.namespace}"
116
+ )
117
+ iq = self.xmpp.make_iq(
118
+ itype=itype,
119
+ ifrom=self.xmpp.boundjid.bare,
120
+ ito=encapsulated_iq.get_from(),
121
+ id=iq_id,
122
+ )
123
+ iq["privileged_iq"].append(encapsulated_iq)
124
+
125
+ try:
126
+ resp = await iq.send()
127
+ except IqError as exc:
128
+ raise PrivilegedIqError(exc.iq)
129
+
130
+ return resp["privilege"]["forwarded"]["iq"]
131
+
132
+
133
+ XEP_0356.send_privileged_iq = send_privileged_iq
134
+
86
135
 
87
136
  slixmpp.plugins.PLUGINS.extend(
88
137
  [
slidge/util/conf.py CHANGED
@@ -95,20 +95,27 @@ class ConfigModule:
95
95
  ENV_VAR_PREFIX = "SLIDGE_"
96
96
 
97
97
  def __init__(
98
- self, config_obj, parser: Optional[configargparse.ArgumentParser] = None
98
+ self,
99
+ config_obj,
100
+ parser: Optional[configargparse.ArgumentParser] = None,
101
+ skip_options: tuple[str, ...] = (),
99
102
  ):
100
103
  self.config_obj = config_obj
101
104
  if parser is None:
102
105
  parser = configargparse.ArgumentParser()
103
106
  self.parser = parser
104
107
 
105
- self.add_options_to_parser()
108
+ self.skip_options = skip_options
109
+ self.add_options_to_parser(skip_options)
106
110
 
107
111
  def _list_options(self):
108
112
  return {
109
113
  o
110
114
  for o in (set(dir(self.config_obj)) | set(get_type_hints(self.config_obj)))
111
- if o.upper() == o and not o.startswith("_") and "__" not in o
115
+ if o.upper() == o
116
+ and not o.startswith("_")
117
+ and "__" not in o
118
+ and o.lower() not in self.skip_options
112
119
  }
113
120
 
114
121
  def set_conf(self, argv: Optional[list[str]] = None):
@@ -179,9 +186,12 @@ class ConfigModule:
179
186
  res.append(Option(self, opt))
180
187
  return res
181
188
 
182
- def add_options_to_parser(self):
189
+ def add_options_to_parser(self, skip_options: tuple[str, ...]):
190
+ skip_options = tuple(o.lower() for o in skip_options)
183
191
  p = self.parser
184
192
  for o in sorted(self.options, key=lambda x: (not x.required, x.name)):
193
+ if o.name.lower() in skip_options:
194
+ continue
185
195
  p.add_argument(*o.names, **o.kwargs)
186
196
 
187
197
  def update_dynamic_defaults(self, args):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: slidge
3
- Version: 0.2.9
3
+ Version: 0.2.10
4
4
  Summary: XMPP bridging framework
5
5
  Author-email: Nicolas Cedilnik <nicoco@nicoco.fr>
6
6
  License-Expression: AGPL-3.0-or-later
@@ -23,21 +23,16 @@ Requires-Dist: defusedxml>=0.7.1
23
23
  Requires-Dist: pillow<12,>=11.0.0
24
24
  Requires-Dist: python-magic<0.5,>=0.4.27
25
25
  Requires-Dist: qrcode<9,>=8.0
26
- Requires-Dist: slixmpp<2,>=1.9.0
26
+ Requires-Dist: slixmpp<2,>=1.10.0
27
27
  Requires-Dist: sqlalchemy<3,>=2
28
28
  Requires-Dist: thumbhash>=0.1.2
29
29
  Dynamic: license-file
30
30
 
31
31
  ![Slidge logo](https://codeberg.org/slidge/slidge/raw/branch/main/dev/assets/slidge-color-small.png)
32
32
 
33
- [![Chat](https://conference.nicoco.fr:5281/muc_badge/slidge@conference.nicoco.fr)](https://conference.nicoco.fr:5281/muc_log/slidge/)
34
-
35
-
36
33
  [![woodpecker CI status](https://ci.codeberg.org/api/badges/14027/status.svg)](https://ci.codeberg.org/repos/14027)
37
- [![coverage](https://slidge.im/coverage/main/coverage.svg)](https://slidge.im/coverage/main)
38
-
39
- [![pypi version](https://badge.fury.io/py/slidge.svg)](https://pypi.org/project/slidge/)
40
- [![debian unstable version](https://badges.debian.net/badges/debian/unstable/python3-slidge/version.svg)](https://packages.debian.org/unstable/python3-slidge)
34
+ [![coverage](https://slidge.im/coverage/slidge/main/coverage.svg)](https://slidge.im/coverage/slidge/main)
35
+ [![Chat](https://conference.nicoco.fr:5281/muc_badge/slidge@conference.nicoco.fr)](https://conference.nicoco.fr:5281/muc_log/slidge/)
41
36
 
42
37
  Slidge is an XMPP (puppeteer) gateway library in python.
43
38
  It makes
@@ -104,8 +99,12 @@ or the
104
99
  [slidge-debian](https://git.sr.ht/~nicoco/slidge-debian)
105
100
  bundle.
106
101
 
102
+ [![pypi version](https://badge.fury.io/py/slidge.svg)](https://pypi.org/project/slidge/)
103
+
104
+ [![Packaging status](https://repology.org/badge/vertical-allrepos/slidge.svg)](https://repology.org/project/slidge/versions)
105
+
107
106
  Slidge is available on
108
- [codeberg](https://codeberg.org/slidge/-/packages) (python packages and containers)
107
+ [codeberg](https://codeberg.org/slidge/slidge/releases)
109
108
  and [pypi](https://pypi.org/project/slidge/).
110
109
  Refer to [the docs](https://slidge.im/docs/slidge/main/admin/install.html) for details.
111
110
 
@@ -1,6 +1,6 @@
1
- slidge/__init__.py,sha256=36BNw5mWk_MWxlPMzNCJpspoou05hFaL-eQp-JwE3JU,1793
1
+ slidge/__init__.py,sha256=OKdIR1pz7HNSokVRB4cEyistagdPM9TDmaARJdnk0kc,1804
2
2
  slidge/__main__.py,sha256=ydjUklOoavS4YlGfjRX_8BQN2DaSbaXPMi47RkOgcFI,37
3
- slidge/main.py,sha256=kusTX-W9cYo1I1TLqHEag20-TPsjFeF5BO2jC8y2Mt4,6223
3
+ slidge/main.py,sha256=NpDKks_6Ib7thhTQu8gI_g3XifX1RNV19p6-Rtz2phY,6533
4
4
  slidge/migration.py,sha256=4BJmPIRB56_WIhRTqBFIIBXuvnhhBjjOMl4CE7jY6oc,1541
5
5
  slidge/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  slidge/command/__init__.py,sha256=UYf1mjCYbZ5G7PIgaFTWSQRAzEJkQ6dTH8Fu_e_XnO0,613
@@ -16,8 +16,8 @@ slidge/contact/contact.py,sha256=CLWuNLvWuODi1mlT6MFGx9s3y8yGPM8ZEsH-Ih6QEn8,229
16
16
  slidge/contact/roster.py,sha256=19EYyX-usuevMob9AgnQmSt6APdE5MxMroHOYmVYt-w,10205
17
17
  slidge/core/__init__.py,sha256=RG7Jj5JCJERjhqJ31lOLYV-7bH_oblClQD1KF9LsTXo,68
18
18
  slidge/core/config.py,sha256=OjJfpXJaDhMxRB-vYA0cqkSf0fwMt-HMThM8GS1htCg,7964
19
- slidge/core/gateway.py,sha256=tBaI8ZTGEOeojgSny1rfec9w8MF24Buce8KL5oes984,37492
20
- slidge/core/pubsub.py,sha256=BoeYE__ptmRAn4x55Hn_6JWRA4nM-XJgDemG5Cy5kN4,11959
19
+ slidge/core/gateway.py,sha256=Ghe2-bZ2XSeWC34uXO0D31yn04WbcwKH5pnDpPL4cVA,37606
20
+ slidge/core/pubsub.py,sha256=IAu-MV_ncrUk3SiVVWyzmKtv9I9yXBNAOE78GaowyYE,12156
21
21
  slidge/core/session.py,sha256=Ie1a6bpUCC_HFvm98S-t03WG5JlOFG0SwbmGB2l9ZTc,28439
22
22
  slidge/core/dispatcher/__init__.py,sha256=1EXcjXietUKlxEqdrCWCV3xZ3q_DSsjHoqWrPMbtYao,84
23
23
  slidge/core/dispatcher/caps.py,sha256=vzCAXo_bhALuLEpJWtyJTzVfWx96g1AsWD8_wkoDl0Y,2028
@@ -39,7 +39,7 @@ slidge/core/dispatcher/muc/misc.py,sha256=bHBjMC-Pu3jR5hAPGMzXf-C05UbACIwg38YbJU
39
39
  slidge/core/dispatcher/muc/owner.py,sha256=1a6YV7b_mmi1jC6q1ko8weeL8imQA-s-hYGPLIHd10I,3308
40
40
  slidge/core/dispatcher/muc/ping.py,sha256=lb1VQPhiUPZ19KhbofRXMVCcY6wwQ2w-asnqtANaAwA,1660
41
41
  slidge/core/mixins/__init__.py,sha256=muReAzgvENgMvlfm0Fpe6BQFfm2EMjoDe9ZhGgo6Vig,627
42
- slidge/core/mixins/attachment.py,sha256=rZcipXiGgo-8klumBvfgrSsU_rmS6cl1zx-zev_FZRg,20174
42
+ slidge/core/mixins/attachment.py,sha256=diEmZAkc_fv9UEHzDXVHtRbE9-vhK8yN9ZtI9gL0JAY,20212
43
43
  slidge/core/mixins/avatar.py,sha256=BVOeH5j5tsPJ0IHUcB5ozpyh02TBPKiZMd9MYizDokA,8136
44
44
  slidge/core/mixins/base.py,sha256=MOd-pas38_52VawQVlxWtBtmTKC6My9G0ZaCeQxOJbs,748
45
45
  slidge/core/mixins/db.py,sha256=5Qpegd7D8e5TLXLLINYcf_DuVdN-7wNmsfztUuFYPcU,442
@@ -54,7 +54,7 @@ slidge/db/__init__.py,sha256=EBDH1JSEhgqYcli2Bw11CRC749wJk8AOucgBzmhDSvU,105
54
54
  slidge/db/avatar.py,sha256=z5e72STv8PdN6zkNyKlLqF7NFxHwCa6IjwgFpzu5ghE,8033
55
55
  slidge/db/meta.py,sha256=v1Jf-npZ28QwdGpsLQWLBHEbEP3-jnPrygRg05tJ_Iw,1831
56
56
  slidge/db/models.py,sha256=MSVNW04x05qfxahvjCYRDFjfFP-XXp-lOHnK5IqFCXw,14046
57
- slidge/db/store.py,sha256=AjbeYAbhd_7KHS094vTEPiuecu_ntIAlpyzsrCIjHHE,47155
57
+ slidge/db/store.py,sha256=P9gprCsRsbJjdzvyG2UKV5IHL6R0tWu-Q7t6mivqJVI,47206
58
58
  slidge/db/alembic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
59
  slidge/db/alembic/env.py,sha256=hsBlRNs0zF5diSHGRSa8Fi3qRVQDA2rJdR41AEIdvxc,1642
60
60
  slidge/db/alembic/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1uy6HUS9NFvDgl93dMj8,635
@@ -79,9 +79,9 @@ slidge/db/alembic/versions/e91195719c2c_store_users_avatars_persistently.py,sha2
79
79
  slidge/group/__init__.py,sha256=yFt7cHqeaKIMN6f9ZyhhspOcJJvBtLedGv-iICG7lto,258
80
80
  slidge/group/archive.py,sha256=AUzVtXlHiCreyY3jp1XMt0G7LDNm-qOU-4CEPQ89ics,5445
81
81
  slidge/group/bookmarks.py,sha256=uGw_XtF0nloZ7rhNLdKM0nNZZb5C6SBfTsLyZryxjxY,6592
82
- slidge/group/participant.py,sha256=h9Cz4liCWzCaysvDk4wr8-zHvLOyIoM3vvQWzHCdpFE,17690
83
- slidge/group/room.py,sha256=C0CYhn3EuqjQnGLia9A3_mmkGfc_gDmd-PMESggupFo,49164
84
- slidge/slixfix/__init__.py,sha256=opamnCRI89KtCY2jfUrzij423hROgMF_Jw8Rrv1i0pw,2515
82
+ slidge/group/participant.py,sha256=YExXhm7FWK_G-_H6VJKFhJhA07l1KB7pZvD1xAYibj8,17730
83
+ slidge/group/room.py,sha256=c1SVpdrI7-xTr0UsF2n539R3iV8C4P5KZw6HhK5cPuU,49176
84
+ slidge/slixfix/__init__.py,sha256=su7mDAHgP3uU7bSxjK8dwW79k7KBLevJHdMQV8_33WA,4130
85
85
  slidge/slixfix/delivery_receipt.py,sha256=3bWdZH3-X3CZJXmnI_TpjkTUUK-EY4Ktm78lW0-40fc,1366
86
86
  slidge/slixfix/roster.py,sha256=KvDjh9q7pqaZf69H93okfib13cc95uVZUJ6rzpqmDaU,1704
87
87
  slidge/slixfix/link_preview/__init__.py,sha256=TDPTSEH5FQxgGpQpQIde-D72AHg-6YVWG-tOj4KpKmU,290
@@ -99,14 +99,14 @@ slidge/slixfix/xep_0292/__init__.py,sha256=_MvS9wGra6ig3P_dPAVlCPDJkiOFvUWGjaRsH
99
99
  slidge/slixfix/xep_0292/vcard4.py,sha256=jL-TOW3eG2QXLduSLNq03L8HoUNmvy8kTZI5ojvo6GE,358
100
100
  slidge/util/__init__.py,sha256=BELovoTMPcPPGz3D48esBr8A4BRRHXTvavfgnArBgEc,301
101
101
  slidge/util/archive_msg.py,sha256=xXAR0BI5r3d6KKWjae9594izCOv6iI03z2WLuTecNw8,1724
102
- slidge/util/conf.py,sha256=1j2OnOsCBar1tOObErhXR5RC3Vl3faliOZ1U8J3My58,6613
102
+ slidge/util/conf.py,sha256=yT_9Wino0xfhTvOjmmokt2PIQBTwBKVuVPWp7_7aoKU,6967
103
103
  slidge/util/jid_escaping.py,sha256=pWJTrB6-M923a_rEE-nxPmiDTOx9UCMa8UgE7JbLC0c,1066
104
104
  slidge/util/test.py,sha256=l1VHBsw5Uzk2t7wtkfb9kWvtehcYhw1t_d567JAJFKA,14135
105
105
  slidge/util/types.py,sha256=5j0G22hhsh3PNhtpJaz2DVt5XINJznZjz0hqewPZoFo,5407
106
106
  slidge/util/util.py,sha256=ZkQltO6JmfqZc9T-86XI6gAsZx9BLdF0CCurnxPRNRc,9329
107
- slidge-0.2.9.dist-info/licenses/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
108
- slidge-0.2.9.dist-info/METADATA,sha256=tmqEtywN5eD_3DDDeh4nPQIvp51Uc7d8wRgKibuh-QE,5102
109
- slidge-0.2.9.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
110
- slidge-0.2.9.dist-info/entry_points.txt,sha256=py3_x834fFJ2TEzPd18Wt2DnysdAfuVqJ5zzBrXbAZs,44
111
- slidge-0.2.9.dist-info/top_level.txt,sha256=2LRjDYHaGZ5ieCMF8xy58JIiabRMzX-MGMbCZwfE17c,7
112
- slidge-0.2.9.dist-info/RECORD,,
107
+ slidge-0.2.10.dist-info/licenses/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
108
+ slidge-0.2.10.dist-info/METADATA,sha256=OFlStm_YVTPwHPhpu8z60NtKdi00uMU2Tp8crY5-6F8,5055
109
+ slidge-0.2.10.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
110
+ slidge-0.2.10.dist-info/entry_points.txt,sha256=py3_x834fFJ2TEzPd18Wt2DnysdAfuVqJ5zzBrXbAZs,44
111
+ slidge-0.2.10.dist-info/top_level.txt,sha256=2LRjDYHaGZ5ieCMF8xy58JIiabRMzX-MGMbCZwfE17c,7
112
+ slidge-0.2.10.dist-info/RECORD,,