slidge 0.1.0b2__py3-none-any.whl → 0.1.1__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- slidge/__init__.py +55 -31
- slidge/__main__.py +118 -116
- slidge/command/__init__.py +28 -0
- slidge/command/adhoc.py +258 -0
- slidge/command/admin.py +193 -0
- slidge/command/base.py +441 -0
- slidge/command/categories.py +3 -0
- slidge/command/chat_command.py +288 -0
- slidge/command/register.py +179 -0
- slidge/command/user.py +250 -0
- slidge/contact/__init__.py +8 -0
- slidge/contact/contact.py +452 -0
- slidge/contact/roster.py +192 -0
- slidge/core/__init__.py +2 -0
- slidge/core/cache.py +183 -0
- slidge/core/config.py +216 -0
- slidge/core/gateway/__init__.py +3 -0
- slidge/core/gateway/base.py +895 -0
- slidge/core/gateway/caps.py +63 -0
- slidge/core/gateway/delivery_receipt.py +52 -0
- slidge/core/gateway/disco.py +80 -0
- slidge/core/gateway/mam.py +75 -0
- slidge/core/gateway/muc_admin.py +35 -0
- slidge/core/gateway/ping.py +66 -0
- slidge/core/gateway/presence.py +95 -0
- slidge/core/gateway/registration.py +53 -0
- slidge/core/gateway/search.py +102 -0
- slidge/core/gateway/session_dispatcher.py +789 -0
- slidge/core/gateway/vcard_temp.py +130 -0
- slidge/core/mixins/__init__.py +19 -0
- slidge/core/mixins/attachment.py +506 -0
- slidge/core/mixins/avatar.py +167 -0
- slidge/core/mixins/base.py +31 -0
- slidge/core/mixins/disco.py +130 -0
- slidge/core/mixins/lock.py +31 -0
- slidge/core/mixins/message.py +398 -0
- slidge/core/mixins/message_maker.py +154 -0
- slidge/core/mixins/presence.py +217 -0
- slidge/core/mixins/recipient.py +43 -0
- slidge/core/pubsub.py +282 -116
- slidge/core/session.py +595 -372
- slidge/group/__init__.py +10 -0
- slidge/group/archive.py +125 -0
- slidge/group/bookmarks.py +163 -0
- slidge/group/participant.py +458 -0
- slidge/group/room.py +1103 -0
- slidge/migration.py +18 -0
- slidge/slixfix/__init__.py +68 -0
- slidge/{util/xep_0084 → slixfix/link_preview}/__init__.py +3 -5
- slidge/slixfix/link_preview/link_preview.py +17 -0
- slidge/slixfix/link_preview/stanza.py +99 -0
- slidge/slixfix/roster.py +60 -0
- slidge/{util → slixfix}/xep_0077/register.py +14 -2
- slidge/slixfix/xep_0077/stanza.py +104 -0
- slidge/{util → slixfix}/xep_0100/gateway.py +25 -15
- slidge/slixfix/xep_0100/stanza.py +9 -0
- slidge/slixfix/xep_0153/__init__.py +10 -0
- slidge/slixfix/xep_0153/stanza.py +25 -0
- slidge/slixfix/xep_0153/vcard_avatar.py +23 -0
- slidge/slixfix/xep_0264/__init__.py +5 -0
- slidge/slixfix/xep_0264/stanza.py +36 -0
- slidge/slixfix/xep_0264/thumbnail.py +23 -0
- slidge/slixfix/xep_0292/__init__.py +5 -0
- slidge/slixfix/xep_0292/vcard4.py +100 -0
- slidge/slixfix/xep_0313/__init__.py +12 -0
- slidge/slixfix/xep_0313/mam.py +262 -0
- slidge/slixfix/xep_0313/stanza.py +359 -0
- slidge/slixfix/xep_0317/__init__.py +5 -0
- slidge/slixfix/xep_0317/hats.py +17 -0
- slidge/slixfix/xep_0317/stanza.py +28 -0
- slidge/{util → slixfix}/xep_0356_old/privilege.py +9 -7
- slidge/slixfix/xep_0424/__init__.py +9 -0
- slidge/slixfix/xep_0424/retraction.py +77 -0
- slidge/slixfix/xep_0424/stanza.py +28 -0
- slidge/slixfix/xep_0490/__init__.py +8 -0
- slidge/slixfix/xep_0490/mds.py +47 -0
- slidge/slixfix/xep_0490/stanza.py +17 -0
- slidge/util/__init__.py +4 -6
- slidge/util/archive_msg.py +61 -0
- slidge/util/conf.py +206 -0
- slidge/util/db.py +57 -76
- slidge/util/schema.sql +126 -0
- slidge/util/sql.py +508 -0
- slidge/util/test.py +215 -25
- slidge/util/types.py +177 -4
- slidge/util/util.py +225 -59
- slidge-0.1.1.dist-info/METADATA +110 -0
- slidge-0.1.1.dist-info/RECORD +96 -0
- {slidge-0.1.0b2.dist-info → slidge-0.1.1.dist-info}/WHEEL +1 -1
- slidge/core/contact.py +0 -891
- slidge/core/gateway.py +0 -916
- slidge/plugins/discord/__init__.py +0 -90
- slidge/plugins/discord/client.py +0 -108
- slidge/plugins/discord/session.py +0 -162
- slidge/plugins/dummy.py +0 -203
- slidge/plugins/facebook.py +0 -493
- slidge/plugins/hackernews.py +0 -213
- slidge/plugins/mattermost/__init__.py +0 -1
- slidge/plugins/mattermost/api.py +0 -280
- slidge/plugins/mattermost/gateway.py +0 -365
- slidge/plugins/mattermost/websocket.py +0 -252
- slidge/plugins/signal/__init__.py +0 -3
- slidge/plugins/signal/contact.py +0 -106
- slidge/plugins/signal/gateway.py +0 -282
- slidge/plugins/signal/session.py +0 -448
- slidge/plugins/signal/txt.py +0 -53
- slidge/plugins/skype.py +0 -325
- slidge/plugins/steam.py +0 -310
- slidge/plugins/telegram/__init__.py +0 -5
- slidge/plugins/telegram/client.py +0 -228
- slidge/plugins/telegram/config.py +0 -12
- slidge/plugins/telegram/contact.py +0 -176
- slidge/plugins/telegram/gateway.py +0 -150
- slidge/plugins/telegram/session.py +0 -256
- slidge/util/xep_0030/__init__.py +0 -13
- slidge/util/xep_0030/disco.py +0 -811
- slidge/util/xep_0030/stanza/__init__.py +0 -7
- slidge/util/xep_0030/stanza/info.py +0 -270
- slidge/util/xep_0030/stanza/items.py +0 -147
- slidge/util/xep_0030/static.py +0 -467
- slidge/util/xep_0055/__init__.py +0 -5
- slidge/util/xep_0055/search.py +0 -75
- slidge/util/xep_0055/stanza.py +0 -10
- slidge/util/xep_0077/stanza.py +0 -71
- slidge/util/xep_0084/avatar.py +0 -137
- slidge/util/xep_0084/stanza.py +0 -104
- slidge/util/xep_0115/__init__.py +0 -12
- slidge/util/xep_0115/caps.py +0 -379
- slidge/util/xep_0115/stanza.py +0 -16
- slidge/util/xep_0115/static.py +0 -137
- slidge/util/xep_0292/__init__.py +0 -1
- slidge/util/xep_0292/stanza.py +0 -167
- slidge/util/xep_0292/vcard4.py +0 -75
- slidge/util/xep_0333/__init__.py +0 -10
- slidge/util/xep_0333/markers.py +0 -96
- slidge/util/xep_0333/stanza.py +0 -34
- slidge/util/xep_0356/__init__.py +0 -7
- slidge/util/xep_0356/permissions.py +0 -35
- slidge/util/xep_0356/privilege.py +0 -160
- slidge/util/xep_0356/stanza.py +0 -44
- slidge/util/xep_0363/__init__.py +0 -16
- slidge/util/xep_0363/http_upload.py +0 -215
- slidge/util/xep_0363/stanza.py +0 -46
- slidge/util/xep_0461/__init__.py +0 -6
- slidge/util/xep_0461/reply.py +0 -48
- slidge/util/xep_0461/stanza.py +0 -47
- slidge-0.1.0b2.dist-info/METADATA +0 -171
- slidge-0.1.0b2.dist-info/RECORD +0 -81
- /slidge/{plugins/__init__.py → py.typed} +0 -0
- /slidge/{util → slixfix}/xep_0077/__init__.py +0 -0
- /slidge/{util → slixfix}/xep_0100/__init__.py +0 -0
- /slidge/{util → slixfix}/xep_0356_old/__init__.py +0 -0
- /slidge/{util → slixfix}/xep_0356_old/stanza.py +0 -0
- {slidge-0.1.0b2.dist-info → slidge-0.1.1.dist-info}/LICENSE +0 -0
- {slidge-0.1.0b2.dist-info → slidge-0.1.1.dist-info}/entry_points.txt +0 -0
@@ -1,90 +0,0 @@
|
|
1
|
-
import functools
|
2
|
-
import logging
|
3
|
-
from argparse import ArgumentParser
|
4
|
-
|
5
|
-
import discord as di
|
6
|
-
from slixmpp.exceptions import XMPPError
|
7
|
-
|
8
|
-
from slidge import *
|
9
|
-
|
10
|
-
from .session import Session
|
11
|
-
|
12
|
-
|
13
|
-
class Gateway(BaseGateway[Session]):
|
14
|
-
COMPONENT_NAME = "Discord (slidge)"
|
15
|
-
COMPONENT_TYPE = "discord"
|
16
|
-
REGISTRATION_INSTRUCTIONS = (
|
17
|
-
"Have a look at https://discordpy-self.readthedocs.io/en/latest/token.html"
|
18
|
-
)
|
19
|
-
REGISTRATION_FIELDS = [FormField("token", required=True)]
|
20
|
-
|
21
|
-
ROSTER_GROUP = "Discord"
|
22
|
-
|
23
|
-
def config(self, argv: list[str]):
|
24
|
-
parser = ArgumentParser()
|
25
|
-
parser.add_argument("--discord-verbose", action="store_true")
|
26
|
-
args = parser.parse_args(argv)
|
27
|
-
if not args.discord_verbose:
|
28
|
-
log.debug("Disabling discord info logs")
|
29
|
-
logging.getLogger("discord.gateway").setLevel(logging.WARNING)
|
30
|
-
logging.getLogger("discord.client").setLevel(logging.WARNING)
|
31
|
-
|
32
|
-
|
33
|
-
class Contact(LegacyContact[Session]):
|
34
|
-
MARKS = False
|
35
|
-
|
36
|
-
@functools.cached_property
|
37
|
-
def discord_user(self) -> di.User:
|
38
|
-
logging.debug("Searching for user: %s", self.legacy_id)
|
39
|
-
if (u := self.session.discord.get_user(self.legacy_id)) is None:
|
40
|
-
raise XMPPError(
|
41
|
-
"not-found", text=f"Cannot find the discord user {self.legacy_id}"
|
42
|
-
)
|
43
|
-
return u
|
44
|
-
|
45
|
-
@functools.cached_property
|
46
|
-
def direct_channel_id(self):
|
47
|
-
return self.discord_user.dm_channel.id
|
48
|
-
|
49
|
-
async def update_reactions(self, m: di.Message):
|
50
|
-
legacy_reactions = []
|
51
|
-
user = self.discord_user
|
52
|
-
for r in m.reactions:
|
53
|
-
async for u in r.users():
|
54
|
-
if u == user:
|
55
|
-
legacy_reactions.append(r.emoji)
|
56
|
-
self.react(m.id, legacy_reactions)
|
57
|
-
|
58
|
-
async def update_info(self):
|
59
|
-
u = self.discord_user
|
60
|
-
self.name = name = u.display_name
|
61
|
-
self.avatar = str(u.avatar_url)
|
62
|
-
|
63
|
-
try:
|
64
|
-
profile = await u.profile()
|
65
|
-
except di.Forbidden:
|
66
|
-
log.debug("Forbidden to fetch the profile of %s", u)
|
67
|
-
except di.HTTPException as e:
|
68
|
-
log.debug("HTTP exception %s when fetch the profile of %s", e, u)
|
69
|
-
else:
|
70
|
-
self.set_vcard(full_name=name, note=profile.bio)
|
71
|
-
|
72
|
-
# TODO: use the relationship here
|
73
|
-
# relationship = u.relationship
|
74
|
-
|
75
|
-
|
76
|
-
class Roster(LegacyRoster[Contact, "Session"]):
|
77
|
-
def by_discord_user(self, u: di.User):
|
78
|
-
return self.by_legacy_id(u.id)
|
79
|
-
|
80
|
-
@staticmethod
|
81
|
-
def jid_username_to_legacy_id(discord_id: str):
|
82
|
-
try:
|
83
|
-
return int(discord_id)
|
84
|
-
except ValueError:
|
85
|
-
raise XMPPError(
|
86
|
-
"not-found", text=f"Not a valid discord user ID: {discord_id}"
|
87
|
-
)
|
88
|
-
|
89
|
-
|
90
|
-
log = logging.getLogger(__name__)
|
slidge/plugins/discord/client.py
DELETED
@@ -1,108 +0,0 @@
|
|
1
|
-
from typing import TYPE_CHECKING, Union
|
2
|
-
|
3
|
-
import discord as di
|
4
|
-
|
5
|
-
if TYPE_CHECKING:
|
6
|
-
from .session import Session
|
7
|
-
|
8
|
-
|
9
|
-
class Discord(di.Client):
|
10
|
-
def __init__(self, session: "Session"):
|
11
|
-
super().__init__()
|
12
|
-
self.session = session
|
13
|
-
self.log = session.log
|
14
|
-
|
15
|
-
async def on_ready(self):
|
16
|
-
if (f := self.session.ready_future).done():
|
17
|
-
return
|
18
|
-
f.set_result(True)
|
19
|
-
self.log.debug(f"Logged on as {self.user}")
|
20
|
-
|
21
|
-
async def on_message(self, message: di.Message):
|
22
|
-
channel = message.channel
|
23
|
-
if not isinstance(channel, di.DMChannel):
|
24
|
-
return
|
25
|
-
|
26
|
-
if (author := message.author) == self.user:
|
27
|
-
async with self.session.send_lock:
|
28
|
-
fut = self.session.send_futures.get(message.id)
|
29
|
-
if fut is None:
|
30
|
-
self.session.contacts.by_discord_user(channel.recipient).carbon(
|
31
|
-
message.content
|
32
|
-
)
|
33
|
-
else:
|
34
|
-
fut.set_result(True)
|
35
|
-
else:
|
36
|
-
contact = self.session.contacts.by_discord_user(author)
|
37
|
-
reply_to = message.reference.message_id if message.reference else None
|
38
|
-
if content := message.content:
|
39
|
-
contact.send_text(
|
40
|
-
content,
|
41
|
-
legacy_msg_id=message.id,
|
42
|
-
reply_to_msg_id=reply_to,
|
43
|
-
)
|
44
|
-
for attachment in message.attachments:
|
45
|
-
await contact.send_file(
|
46
|
-
url=attachment.url,
|
47
|
-
filename=attachment.filename,
|
48
|
-
content_type=attachment.content_type,
|
49
|
-
reply_to_msg_id=reply_to,
|
50
|
-
)
|
51
|
-
|
52
|
-
async def on_typing(self, channel, user, _when):
|
53
|
-
if user != self.user and isinstance(channel, di.DMChannel):
|
54
|
-
self.session.contacts.by_discord_user(user).composing()
|
55
|
-
|
56
|
-
async def on_message_edit(self, before: di.Message, after: di.Message):
|
57
|
-
if not isinstance(after.channel, di.DMChannel):
|
58
|
-
return
|
59
|
-
if before.content == after.content:
|
60
|
-
return
|
61
|
-
if (author := after.author) == self.user:
|
62
|
-
fut = self.session.edit_futures.get(after.id)
|
63
|
-
if fut is None:
|
64
|
-
self.session.contacts.by_discord_user(
|
65
|
-
after.channel.recipient
|
66
|
-
).carbon_correct(after.id, after.content)
|
67
|
-
else:
|
68
|
-
fut.set_result(True)
|
69
|
-
else:
|
70
|
-
self.session.contacts.by_discord_user(author).correct(
|
71
|
-
after.id, after.content
|
72
|
-
)
|
73
|
-
|
74
|
-
async def on_message_delete(self, m: di.Message):
|
75
|
-
if not isinstance(m.channel, di.DMChannel):
|
76
|
-
return
|
77
|
-
if (author := m.author) == self.user:
|
78
|
-
fut = self.session.delete_futures.get(m.id)
|
79
|
-
if fut is None:
|
80
|
-
self.session.contacts.by_discord_user(
|
81
|
-
m.channel.recipient
|
82
|
-
).carbon_retract(m.id)
|
83
|
-
else:
|
84
|
-
fut.set_result(True)
|
85
|
-
else:
|
86
|
-
self.session.contacts.by_discord_user(author).retract(m.id)
|
87
|
-
|
88
|
-
async def on_reaction_add(
|
89
|
-
self, reaction: di.Reaction, user: Union[di.User, di.ClientUser]
|
90
|
-
):
|
91
|
-
await self.update_reactions(reaction, user)
|
92
|
-
|
93
|
-
async def on_reaction_remove(
|
94
|
-
self, reaction: di.Reaction, user: Union[di.User, di.ClientUser]
|
95
|
-
):
|
96
|
-
await self.update_reactions(reaction, user)
|
97
|
-
|
98
|
-
async def update_reactions(
|
99
|
-
self, reaction: di.Reaction, user: Union[di.User, di.ClientUser]
|
100
|
-
):
|
101
|
-
message: di.Message = reaction.message
|
102
|
-
if not isinstance(message.channel, di.DMChannel):
|
103
|
-
return
|
104
|
-
|
105
|
-
if user == self.user:
|
106
|
-
self.session.update_reactions(message)
|
107
|
-
else:
|
108
|
-
await self.session.contacts.by_discord_user(user).update_reactions(message)
|
@@ -1,162 +0,0 @@
|
|
1
|
-
import asyncio
|
2
|
-
from typing import TYPE_CHECKING, Any, Union
|
3
|
-
|
4
|
-
import discord as di
|
5
|
-
|
6
|
-
from slidge import *
|
7
|
-
|
8
|
-
if TYPE_CHECKING:
|
9
|
-
from . import Contact, Gateway, Roster
|
10
|
-
from .client import Discord
|
11
|
-
|
12
|
-
|
13
|
-
class Session(BaseSession["Contact", "Roster", "Gateway"]):
|
14
|
-
discord: "Discord"
|
15
|
-
ready_future: asyncio.Future[bool]
|
16
|
-
delete_futures: dict[int, asyncio.Future[bool]]
|
17
|
-
edit_futures: dict[int, asyncio.Future[bool]]
|
18
|
-
send_futures: dict[int, asyncio.Future[bool]]
|
19
|
-
send_lock: asyncio.Lock
|
20
|
-
|
21
|
-
def post_init(self):
|
22
|
-
from .client import Discord
|
23
|
-
|
24
|
-
self.discord = Discord(self)
|
25
|
-
self.ready_future = self.xmpp.loop.create_future()
|
26
|
-
self.delete_futures = {}
|
27
|
-
self.edit_futures = {}
|
28
|
-
self.send_futures = {}
|
29
|
-
self.send_lock = asyncio.Lock()
|
30
|
-
|
31
|
-
@staticmethod
|
32
|
-
def xmpp_msg_id_to_legacy_msg_id(i: str) -> Union[int, str]:
|
33
|
-
try:
|
34
|
-
return int(i)
|
35
|
-
except ValueError:
|
36
|
-
return i
|
37
|
-
|
38
|
-
async def login(self):
|
39
|
-
self.xmpp.loop.create_task(
|
40
|
-
self.discord.start(self.user.registration_form["token"])
|
41
|
-
)
|
42
|
-
await self.ready_future
|
43
|
-
for u in self.discord.users:
|
44
|
-
if not isinstance(u, di.User):
|
45
|
-
self.log.debug(f"Skipping %s", u)
|
46
|
-
continue
|
47
|
-
if not u.is_friend():
|
48
|
-
self.log.debug(f"%s is not a friend", u)
|
49
|
-
continue
|
50
|
-
c = self.contacts.by_legacy_id(u.id)
|
51
|
-
await c.update_info()
|
52
|
-
await c.add_to_roster()
|
53
|
-
# TODO: contribute to discord.py-self so that the presence information
|
54
|
-
# of relationships is parsed. logs show:
|
55
|
-
# 'PRESENCE_UPDATE referencing an unknown guild ID: %s. Discarding.'
|
56
|
-
# https://github.com/dolfies/discord.py-self/blob/master/discord/state.py#L1044
|
57
|
-
c.online()
|
58
|
-
return f"Logged on as {self.discord.user}"
|
59
|
-
|
60
|
-
async def send_text(self, t: str, c: "Contact", *, reply_to_msg_id=None):
|
61
|
-
async with self.send_lock:
|
62
|
-
mid = (
|
63
|
-
await c.discord_user.send(
|
64
|
-
t,
|
65
|
-
reference=None
|
66
|
-
if reply_to_msg_id is None
|
67
|
-
else di.MessageReference(
|
68
|
-
message_id=reply_to_msg_id,
|
69
|
-
channel_id=c.direct_channel_id,
|
70
|
-
),
|
71
|
-
)
|
72
|
-
).id
|
73
|
-
f = self.send_futures[mid] = self.xmpp.loop.create_future()
|
74
|
-
await f
|
75
|
-
return mid
|
76
|
-
|
77
|
-
async def logout(self):
|
78
|
-
await self.discord.close()
|
79
|
-
|
80
|
-
async def send_file(self, u: str, c: "Contact", *, reply_to_msg_id=None):
|
81
|
-
# discord clients inline previews of external URLs, so no need to actually send on discord servers
|
82
|
-
await c.discord_user.send(u)
|
83
|
-
|
84
|
-
async def active(self, c: "Contact"):
|
85
|
-
pass
|
86
|
-
|
87
|
-
async def inactive(self, c: "Contact"):
|
88
|
-
pass
|
89
|
-
|
90
|
-
async def composing(self, c: "Contact"):
|
91
|
-
await c.discord_user.trigger_typing()
|
92
|
-
|
93
|
-
async def paused(self, c: "Contact"):
|
94
|
-
pass
|
95
|
-
|
96
|
-
async def displayed(self, legacy_msg_id: str, c: "Contact"):
|
97
|
-
if not isinstance(legacy_msg_id, int):
|
98
|
-
self.log.debug("This is not a valid discord msg id: %s", legacy_msg_id)
|
99
|
-
return
|
100
|
-
u = c.discord_user
|
101
|
-
channel: di.DMChannel = u.dm_channel
|
102
|
-
if channel is None:
|
103
|
-
return
|
104
|
-
m = await channel.fetch_message(legacy_msg_id)
|
105
|
-
self.log.debug("Message %s should be marked as read", m)
|
106
|
-
# try:
|
107
|
-
# await m.ack() # triggers 404, maybe does not work for DM?
|
108
|
-
# except Exception as e:
|
109
|
-
# self.log.exception("Message %s should have been marked as read but this raised %s", m, e)
|
110
|
-
|
111
|
-
async def correct(self, text: str, legacy_msg_id: Any, c: "Contact"):
|
112
|
-
u = c.discord_user
|
113
|
-
channel: di.DMChannel = u.dm_channel
|
114
|
-
if channel is None:
|
115
|
-
return
|
116
|
-
m = await channel.fetch_message(legacy_msg_id)
|
117
|
-
self.edit_futures[legacy_msg_id] = self.xmpp.loop.create_future()
|
118
|
-
await m.edit(content=text)
|
119
|
-
await self.edit_futures[legacy_msg_id]
|
120
|
-
|
121
|
-
async def react(self, legacy_msg_id: int, emojis: list[str], c: "Contact"):
|
122
|
-
u = c.discord_user
|
123
|
-
channel: di.DMChannel = u.dm_channel
|
124
|
-
if channel is None:
|
125
|
-
return
|
126
|
-
m = await channel.fetch_message(legacy_msg_id)
|
127
|
-
|
128
|
-
legacy_reactions = set(self.get_my_legacy_reactions(m))
|
129
|
-
xmpp_reactions = set(emojis)
|
130
|
-
|
131
|
-
self.log.debug("%s vs %s", legacy_reactions, xmpp_reactions)
|
132
|
-
for e in xmpp_reactions - legacy_reactions:
|
133
|
-
await m.add_reaction(e)
|
134
|
-
for e in legacy_reactions - xmpp_reactions:
|
135
|
-
await m.remove_reaction(e, self.discord.user)
|
136
|
-
|
137
|
-
async def retract(self, legacy_msg_id: Any, c: "Contact"):
|
138
|
-
u = c.discord_user
|
139
|
-
channel: di.DMChannel = u.dm_channel
|
140
|
-
if channel is None:
|
141
|
-
return
|
142
|
-
m = await channel.fetch_message(legacy_msg_id)
|
143
|
-
self.delete_futures[legacy_msg_id] = self.xmpp.loop.create_future()
|
144
|
-
await m.delete()
|
145
|
-
await self.delete_futures[legacy_msg_id]
|
146
|
-
|
147
|
-
def update_reactions(self, message: di.Message):
|
148
|
-
self.contacts.by_discord_user(message.channel.recipient).carbon_react(
|
149
|
-
message.id, self.get_my_legacy_reactions(message)
|
150
|
-
)
|
151
|
-
|
152
|
-
@staticmethod
|
153
|
-
def get_my_legacy_reactions(message: di.Message) -> list[str]:
|
154
|
-
reactions = []
|
155
|
-
for r in message.reactions:
|
156
|
-
if r.me and not r.custom_emoji:
|
157
|
-
reactions.append(r.emoji)
|
158
|
-
|
159
|
-
return reactions
|
160
|
-
|
161
|
-
async def search(self, form_values: dict[str, str]) -> SearchResult:
|
162
|
-
pass
|
slidge/plugins/dummy.py
DELETED
@@ -1,203 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
A pseudo legacy network, to easily test things
|
3
|
-
"""
|
4
|
-
|
5
|
-
import asyncio
|
6
|
-
import logging
|
7
|
-
import uuid
|
8
|
-
from pathlib import Path
|
9
|
-
from typing import Any, Optional
|
10
|
-
|
11
|
-
from slixmpp import JID
|
12
|
-
from slixmpp.exceptions import XMPPError
|
13
|
-
|
14
|
-
from slidge import *
|
15
|
-
|
16
|
-
ASSETS_DIR = Path(__file__).parent.parent.parent / "assets"
|
17
|
-
|
18
|
-
|
19
|
-
class Gateway(BaseGateway):
|
20
|
-
COMPONENT_NAME = "The great legacy network (slidge)"
|
21
|
-
COMPONENT_AVATAR = ASSETS_DIR / "gateway.png"
|
22
|
-
COMPONENT_TYPE = "aim"
|
23
|
-
REGISTRATION_INSTRUCTIONS = (
|
24
|
-
"Only username 'n' is accepted and only 'baba' and 'bibi' contacts exist.\n"
|
25
|
-
"You can use any password you want."
|
26
|
-
)
|
27
|
-
REGISTRATION_FIELDS = list(BaseGateway.REGISTRATION_FIELDS) + [
|
28
|
-
FormField(
|
29
|
-
var="something_else",
|
30
|
-
label="Some optional stuff not covered by jabber:iq:register",
|
31
|
-
required=False,
|
32
|
-
private=False,
|
33
|
-
),
|
34
|
-
FormField(
|
35
|
-
var="device",
|
36
|
-
type="list-single",
|
37
|
-
label="What do you want to do?",
|
38
|
-
options=[
|
39
|
-
{"label": "Choice #1", "value": "choice1"},
|
40
|
-
{"label": "Choice #2", "value": "choice2"},
|
41
|
-
],
|
42
|
-
required=True,
|
43
|
-
),
|
44
|
-
]
|
45
|
-
|
46
|
-
async def validate(
|
47
|
-
self, user_jid: JID, registration_form: dict[str, Optional[str]]
|
48
|
-
):
|
49
|
-
if registration_form["username"] != "n":
|
50
|
-
raise ValueError("Y a que N!")
|
51
|
-
|
52
|
-
|
53
|
-
class Session(BaseSession[LegacyContact, LegacyRoster, Gateway]):
|
54
|
-
def __init__(self, user):
|
55
|
-
super(Session, self).__init__(user)
|
56
|
-
self.counter = 0
|
57
|
-
self.xmpp.loop.create_task(self.backfill())
|
58
|
-
self.contacts.by_legacy_id("bibi").set_vcard(
|
59
|
-
given="FirstBi",
|
60
|
-
surname="LastBi",
|
61
|
-
phone="+555",
|
62
|
-
full_name="Bi bi",
|
63
|
-
note="A fake friend, always there for you",
|
64
|
-
url="https://example.org",
|
65
|
-
email="bibi@prout.com",
|
66
|
-
country="Westeros",
|
67
|
-
locality="The place with the thing",
|
68
|
-
)
|
69
|
-
|
70
|
-
async def backfill(self):
|
71
|
-
self.log.debug("CARBON")
|
72
|
-
i = uuid.uuid1()
|
73
|
-
|
74
|
-
self.contacts.by_legacy_id("bibi").carbon(
|
75
|
-
f"Sent by the component on behalf of the user, and this should reach MAM. Msg ID: {i}",
|
76
|
-
legacy_id=i,
|
77
|
-
)
|
78
|
-
|
79
|
-
async def paused(self, c: LegacyContact):
|
80
|
-
pass
|
81
|
-
|
82
|
-
async def correct(self, text: str, legacy_msg_id: Any, c: LegacyContact):
|
83
|
-
pass
|
84
|
-
|
85
|
-
async def login(self):
|
86
|
-
log.debug("Logging in user: %s", self.user)
|
87
|
-
self.send_gateway_status("Connecting...", show="dnd")
|
88
|
-
await asyncio.sleep(1)
|
89
|
-
self.send_gateway_status("Connected")
|
90
|
-
for b, a in zip(BUDDIES, AVATARS):
|
91
|
-
c = self.contacts.by_legacy_id(b.lower())
|
92
|
-
c.name = b.title()
|
93
|
-
c.avatar = a
|
94
|
-
await c.add_to_roster()
|
95
|
-
c.online("I am not a real person, so what?")
|
96
|
-
return "You can talk to your fake friends now"
|
97
|
-
|
98
|
-
async def logout(self):
|
99
|
-
log.debug("User has disconnected")
|
100
|
-
|
101
|
-
async def send_text(self, t: str, c: LegacyContact, *, reply_to_msg_id=None):
|
102
|
-
i = self.counter
|
103
|
-
self.counter = i + 1
|
104
|
-
|
105
|
-
if t == "crash":
|
106
|
-
raise RuntimeError("PANIC!!!")
|
107
|
-
if t == "crash2":
|
108
|
-
self.xmpp.loop.create_task(self.crash())
|
109
|
-
elif t == "delete":
|
110
|
-
self.xmpp.loop.create_task(self.later_carbon_delete(c, i))
|
111
|
-
elif t == "nick":
|
112
|
-
c.name = "NEWNAME"
|
113
|
-
elif t == "avatar":
|
114
|
-
c.avatar = ASSETS_DIR / "5x5.png"
|
115
|
-
elif t == "nonick":
|
116
|
-
c.name = None
|
117
|
-
else:
|
118
|
-
self.xmpp.loop.create_task(self.later(c, i))
|
119
|
-
|
120
|
-
return i
|
121
|
-
|
122
|
-
async def crash(self):
|
123
|
-
raise RuntimeError("PANIC222!!!")
|
124
|
-
|
125
|
-
async def send_file(self, u: str, c: LegacyContact, *, reply_to_msg_id=None) -> int:
|
126
|
-
i = self.counter
|
127
|
-
self.counter = i + 1
|
128
|
-
c.send_text(u)
|
129
|
-
await c.send_file(ASSETS_DIR / "buddy1.png")
|
130
|
-
return i
|
131
|
-
|
132
|
-
async def later(self, c: LegacyContact, trigger_msg_id: int):
|
133
|
-
i = self.counter - 1
|
134
|
-
await asyncio.sleep(1)
|
135
|
-
c.received(i)
|
136
|
-
await asyncio.sleep(1)
|
137
|
-
c.active()
|
138
|
-
await asyncio.sleep(1)
|
139
|
-
c.displayed(i)
|
140
|
-
await asyncio.sleep(1)
|
141
|
-
c.ack(i)
|
142
|
-
await asyncio.sleep(1)
|
143
|
-
c.composing()
|
144
|
-
await asyncio.sleep(1)
|
145
|
-
c.paused()
|
146
|
-
await asyncio.sleep(1)
|
147
|
-
c.composing()
|
148
|
-
await asyncio.sleep(1)
|
149
|
-
c.send_text("OK", legacy_msg_id=i, reply_to_msg_id=trigger_msg_id)
|
150
|
-
await asyncio.sleep(1)
|
151
|
-
i = uuid.uuid1().int
|
152
|
-
c.send_text("I will retract this", legacy_msg_id=i)
|
153
|
-
c.retract(i)
|
154
|
-
c.inactive()
|
155
|
-
|
156
|
-
async def later_carbon_delete(self, c: LegacyContact, trigger_msg_id: int):
|
157
|
-
await asyncio.sleep(1)
|
158
|
-
c.carbon_retract(trigger_msg_id)
|
159
|
-
|
160
|
-
async def active(self, c: LegacyContact):
|
161
|
-
log.debug("User is active for contact %s", c)
|
162
|
-
|
163
|
-
async def inactive(self, c: LegacyContact):
|
164
|
-
log.debug("User is inactive for contact %s", c)
|
165
|
-
|
166
|
-
async def composing(self, c: LegacyContact):
|
167
|
-
log.debug("User is composing for contact %s", c)
|
168
|
-
|
169
|
-
async def displayed(self, legacy_msg_id: int, c: LegacyContact):
|
170
|
-
log.debug("Message #%s was read by the user", legacy_msg_id)
|
171
|
-
|
172
|
-
async def search(self, form_values: dict[str, str]):
|
173
|
-
if form_values["first"] == "bubu":
|
174
|
-
return SearchResult(
|
175
|
-
fields=[
|
176
|
-
FormField("name", label="Name"),
|
177
|
-
FormField("jid", type="jid-single"),
|
178
|
-
],
|
179
|
-
items=[{"name": "bubu", "jid": f"bubu@{self.xmpp.boundjid.bare}"}],
|
180
|
-
)
|
181
|
-
|
182
|
-
async def react(self, legacy_msg_id, emojis, c):
|
183
|
-
if "😈" in emojis:
|
184
|
-
c.send_text("That's forbidden")
|
185
|
-
c.carbon_react(legacy_msg_id, "")
|
186
|
-
raise XMPPError("not-acceptable")
|
187
|
-
else:
|
188
|
-
c.react(legacy_msg_id, "♥")
|
189
|
-
|
190
|
-
async def retract(self, legacy_msg_id, c):
|
191
|
-
log.debug("User has retracted their msg: '%s' (sent to '%s')", legacy_msg_id, c)
|
192
|
-
|
193
|
-
|
194
|
-
BUDDIES = ["baba", "bibi"]
|
195
|
-
AVATARS = []
|
196
|
-
|
197
|
-
with (ASSETS_DIR / "buddy1.png").open("rb") as fp:
|
198
|
-
AVATARS.append(fp.read())
|
199
|
-
|
200
|
-
with (ASSETS_DIR / "buddy2.png").open("rb") as fp:
|
201
|
-
AVATARS.append(fp.read())
|
202
|
-
|
203
|
-
log = logging.getLogger(__name__)
|