slidge 0.1.0rc1__py3-none-any.whl → 0.1.2__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- slidge/__init__.py +54 -31
- slidge/__main__.py +51 -5
- 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 +121 -39
- slidge/core/config.py +116 -11
- 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 +795 -0
- slidge/core/gateway/vcard_temp.py +130 -0
- slidge/core/mixins/__init__.py +9 -1
- slidge/core/mixins/attachment.py +506 -0
- slidge/core/mixins/avatar.py +167 -0
- slidge/core/mixins/base.py +6 -19
- slidge/core/mixins/disco.py +66 -15
- slidge/core/mixins/lock.py +31 -0
- slidge/core/mixins/message.py +254 -252
- slidge/core/mixins/message_maker.py +154 -0
- slidge/core/mixins/presence.py +128 -31
- slidge/core/mixins/recipient.py +43 -0
- slidge/core/pubsub.py +275 -116
- slidge/core/session.py +586 -518
- 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_0050 → slixfix/link_preview}/__init__.py +4 -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 +1 -2
- slidge/slixfix/xep_0077/stanza.py +104 -0
- slidge/{util → slixfix}/xep_0100/gateway.py +17 -12
- 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 +25 -4
- slidge/util/db.py +23 -69
- slidge/util/schema.sql +126 -0
- slidge/util/sql.py +508 -0
- slidge/util/test.py +136 -86
- slidge/util/types.py +155 -14
- slidge/util/util.py +225 -51
- slidge-0.1.2.dist-info/METADATA +111 -0
- slidge-0.1.2.dist-info/RECORD +96 -0
- {slidge-0.1.0rc1.dist-info → slidge-0.1.2.dist-info}/WHEEL +1 -1
- slidge/core/adhoc.py +0 -492
- slidge/core/chat_command.py +0 -197
- slidge/core/contact.py +0 -441
- slidge/core/disco.py +0 -59
- slidge/core/gateway.py +0 -899
- slidge/core/muc/__init__.py +0 -3
- slidge/core/muc/bookmarks.py +0 -74
- slidge/core/muc/participant.py +0 -152
- slidge/core/muc/room.py +0 -348
- slidge/plugins/discord/__init__.py +0 -121
- slidge/plugins/discord/client.py +0 -121
- slidge/plugins/discord/session.py +0 -172
- slidge/plugins/dummy.py +0 -334
- slidge/plugins/facebook.py +0 -591
- slidge/plugins/hackernews.py +0 -209
- slidge/plugins/mattermost/__init__.py +0 -1
- slidge/plugins/mattermost/api.py +0 -288
- slidge/plugins/mattermost/gateway.py +0 -417
- slidge/plugins/mattermost/websocket.py +0 -248
- slidge/plugins/signal/__init__.py +0 -4
- slidge/plugins/signal/config.py +0 -4
- slidge/plugins/signal/contact.py +0 -104
- slidge/plugins/signal/gateway.py +0 -379
- slidge/plugins/signal/group.py +0 -76
- slidge/plugins/signal/session.py +0 -515
- slidge/plugins/signal/txt.py +0 -13
- slidge/plugins/signal/util.py +0 -32
- slidge/plugins/skype.py +0 -310
- slidge/plugins/steam.py +0 -400
- slidge/plugins/telegram/__init__.py +0 -6
- slidge/plugins/telegram/client.py +0 -325
- slidge/plugins/telegram/config.py +0 -21
- slidge/plugins/telegram/contact.py +0 -154
- slidge/plugins/telegram/gateway.py +0 -182
- slidge/plugins/telegram/group.py +0 -184
- slidge/plugins/telegram/session.py +0 -275
- slidge/plugins/telegram/util.py +0 -153
- slidge/plugins/whatsapp/__init__.py +0 -6
- slidge/plugins/whatsapp/config.py +0 -17
- slidge/plugins/whatsapp/contact.py +0 -33
- slidge/plugins/whatsapp/event.go +0 -455
- slidge/plugins/whatsapp/gateway.go +0 -156
- slidge/plugins/whatsapp/gateway.py +0 -69
- slidge/plugins/whatsapp/go.mod +0 -17
- slidge/plugins/whatsapp/go.sum +0 -22
- slidge/plugins/whatsapp/session.go +0 -371
- slidge/plugins/whatsapp/session.py +0 -370
- 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_0050/adhoc.py +0 -631
- slidge/util/xep_0050/stanza.py +0 -180
- slidge/util/xep_0077/stanza.py +0 -71
- slidge/util/xep_0292/__init__.py +0 -1
- slidge/util/xep_0292/stanza.py +0 -167
- slidge/util/xep_0292/vcard4.py +0 -74
- 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_0461/__init__.py +0 -6
- slidge/util/xep_0461/reply.py +0 -48
- slidge/util/xep_0461/stanza.py +0 -80
- slidge-0.1.0rc1.dist-info/METADATA +0 -171
- slidge-0.1.0rc1.dist-info/RECORD +0 -99
- /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_0100/stanza.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.0rc1.dist-info → slidge-0.1.2.dist-info}/LICENSE +0 -0
- {slidge-0.1.0rc1.dist-info → slidge-0.1.2.dist-info}/entry_points.txt +0 -0
slidge/plugins/discord/client.py
DELETED
@@ -1,121 +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
|
-
(
|
31
|
-
await self.session.contacts.by_discord_user(channel.recipient)
|
32
|
-
).send_text(message.content, carbon=True)
|
33
|
-
else:
|
34
|
-
fut.set_result(True)
|
35
|
-
else:
|
36
|
-
contact = await self.session.contacts.by_discord_user(author)
|
37
|
-
reply_to = message.reference.message_id if message.reference else None
|
38
|
-
|
39
|
-
text = message.content
|
40
|
-
attachments = message.attachments
|
41
|
-
msg_id = message.id
|
42
|
-
|
43
|
-
if not attachments:
|
44
|
-
contact.send_text(
|
45
|
-
text,
|
46
|
-
legacy_msg_id=msg_id,
|
47
|
-
reply_to_msg_id=reply_to,
|
48
|
-
)
|
49
|
-
return
|
50
|
-
|
51
|
-
last_attachment_i = len(attachments := message.attachments) - 1
|
52
|
-
for i, attachment in enumerate(attachments):
|
53
|
-
last = i == last_attachment_i
|
54
|
-
await contact.send_file(
|
55
|
-
url=attachment.url,
|
56
|
-
filename=attachment.filename,
|
57
|
-
content_type=attachment.content_type,
|
58
|
-
reply_to_msg_id=reply_to if last else None,
|
59
|
-
legacy_msg_id=msg_id if last else None,
|
60
|
-
caption=text if last else None,
|
61
|
-
)
|
62
|
-
|
63
|
-
async def on_typing(self, channel, user, _when):
|
64
|
-
if user != self.user and isinstance(channel, di.DMChannel):
|
65
|
-
(await self.session.contacts.by_discord_user(user)).composing()
|
66
|
-
|
67
|
-
async def on_message_edit(self, before: di.Message, after: di.Message):
|
68
|
-
if not isinstance(after.channel, di.DMChannel):
|
69
|
-
return
|
70
|
-
if before.content == after.content:
|
71
|
-
return
|
72
|
-
if (author := after.author) == self.user:
|
73
|
-
fut = self.session.edit_futures.get(after.id)
|
74
|
-
if fut is None:
|
75
|
-
(
|
76
|
-
await self.session.contacts.by_discord_user(after.channel.recipient)
|
77
|
-
).correct(after.id, after.content, carbon=True)
|
78
|
-
else:
|
79
|
-
fut.set_result(True)
|
80
|
-
else:
|
81
|
-
(await self.session.contacts.by_discord_user(author)).correct(
|
82
|
-
after.id, after.content
|
83
|
-
)
|
84
|
-
|
85
|
-
async def on_message_delete(self, m: di.Message):
|
86
|
-
if not isinstance(m.channel, di.DMChannel):
|
87
|
-
return
|
88
|
-
if (author := m.author) == self.user:
|
89
|
-
fut = self.session.delete_futures.get(m.id)
|
90
|
-
if fut is None:
|
91
|
-
(
|
92
|
-
await self.session.contacts.by_discord_user(m.channel.recipient)
|
93
|
-
).retract(m.id, carbon=True)
|
94
|
-
else:
|
95
|
-
fut.set_result(True)
|
96
|
-
else:
|
97
|
-
(await self.session.contacts.by_discord_user(author)).retract(m.id)
|
98
|
-
|
99
|
-
async def on_reaction_add(
|
100
|
-
self, reaction: di.Reaction, user: Union[di.User, di.ClientUser]
|
101
|
-
):
|
102
|
-
await self.update_reactions(reaction, user)
|
103
|
-
|
104
|
-
async def on_reaction_remove(
|
105
|
-
self, reaction: di.Reaction, user: Union[di.User, di.ClientUser]
|
106
|
-
):
|
107
|
-
await self.update_reactions(reaction, user)
|
108
|
-
|
109
|
-
async def update_reactions(
|
110
|
-
self, reaction: di.Reaction, user: Union[di.User, di.ClientUser]
|
111
|
-
):
|
112
|
-
message: di.Message = reaction.message
|
113
|
-
if not isinstance(message.channel, di.DMChannel):
|
114
|
-
return
|
115
|
-
|
116
|
-
if user == self.user:
|
117
|
-
await self.session.update_reactions(message)
|
118
|
-
else:
|
119
|
-
await (await self.session.contacts.by_discord_user(user)).update_reactions(
|
120
|
-
message
|
121
|
-
)
|
@@ -1,172 +0,0 @@
|
|
1
|
-
import asyncio
|
2
|
-
from typing import TYPE_CHECKING, Any, Optional, Union
|
3
|
-
|
4
|
-
import discord as di
|
5
|
-
|
6
|
-
from slidge import *
|
7
|
-
|
8
|
-
from ...util.types import Chat
|
9
|
-
|
10
|
-
if TYPE_CHECKING:
|
11
|
-
from . import Contact, Gateway, Roster
|
12
|
-
from .client import Discord
|
13
|
-
|
14
|
-
|
15
|
-
class Session(
|
16
|
-
BaseSession[
|
17
|
-
"Gateway",
|
18
|
-
int,
|
19
|
-
"Roster",
|
20
|
-
"Contact",
|
21
|
-
LegacyBookmarks,
|
22
|
-
LegacyMUC,
|
23
|
-
LegacyParticipant,
|
24
|
-
]
|
25
|
-
):
|
26
|
-
def __init__(self, user):
|
27
|
-
super().__init__(user)
|
28
|
-
from .client import Discord
|
29
|
-
|
30
|
-
self.discord = Discord(self)
|
31
|
-
self.ready_future: asyncio.Future[bool] = self.xmpp.loop.create_future()
|
32
|
-
self.delete_futures = dict[int, asyncio.Future[bool]]()
|
33
|
-
self.edit_futures = dict[int, asyncio.Future[bool]]()
|
34
|
-
self.send_futures = dict[int, asyncio.Future[bool]]()
|
35
|
-
self.send_lock = asyncio.Lock()
|
36
|
-
|
37
|
-
@staticmethod
|
38
|
-
def xmpp_msg_id_to_legacy_msg_id(i: str):
|
39
|
-
return int(i)
|
40
|
-
|
41
|
-
async def login(self):
|
42
|
-
await self.discord.login(self.user.registration_form["token"])
|
43
|
-
self.xmpp.loop.create_task(self.discord.connect())
|
44
|
-
|
45
|
-
await self.ready_future
|
46
|
-
for u in self.discord.users:
|
47
|
-
if not isinstance(u, di.User):
|
48
|
-
self.log.debug(f"Skipping %s", u)
|
49
|
-
continue
|
50
|
-
if not u.is_friend():
|
51
|
-
self.log.debug(f"%s is not a friend", u)
|
52
|
-
continue
|
53
|
-
c = await self.contacts.by_legacy_id(u.id)
|
54
|
-
await c.update_info()
|
55
|
-
await c.add_to_roster()
|
56
|
-
# TODO: contribute to discord.py-self so that the presence information
|
57
|
-
# of relationships is parsed. logs show:
|
58
|
-
# 'PRESENCE_UPDATE referencing an unknown guild ID: %s. Discarding.'
|
59
|
-
# https://github.com/dolfies/discord.py-self/blob/master/discord/state.py#L1044
|
60
|
-
c.online()
|
61
|
-
return f"Logged on as {self.discord.user}"
|
62
|
-
|
63
|
-
async def send_text(
|
64
|
-
self,
|
65
|
-
text: str,
|
66
|
-
chat,
|
67
|
-
reply_to_msg_id=None,
|
68
|
-
reply_to_fallback_text: Optional[str] = None,
|
69
|
-
**kwargs,
|
70
|
-
):
|
71
|
-
async with self.send_lock:
|
72
|
-
mid = (
|
73
|
-
await chat.discord_user.send(
|
74
|
-
text,
|
75
|
-
reference=None
|
76
|
-
if reply_to_msg_id is None
|
77
|
-
else di.MessageReference(
|
78
|
-
message_id=reply_to_msg_id,
|
79
|
-
channel_id=chat.direct_channel_id,
|
80
|
-
),
|
81
|
-
)
|
82
|
-
).id
|
83
|
-
f = self.send_futures[mid] = self.xmpp.loop.create_future()
|
84
|
-
await f
|
85
|
-
return mid
|
86
|
-
|
87
|
-
async def logout(self):
|
88
|
-
await self.discord.close()
|
89
|
-
|
90
|
-
async def send_file(self, url: str, chat: Chat, **kwargs):
|
91
|
-
# discord clients inline previews of external URLs, so no need to actually send on discord servers
|
92
|
-
await chat.discord_user.send(url)
|
93
|
-
|
94
|
-
async def active(self, c: "Contact"):
|
95
|
-
pass
|
96
|
-
|
97
|
-
async def inactive(self, c: "Contact"):
|
98
|
-
pass
|
99
|
-
|
100
|
-
async def composing(self, c: "Contact"):
|
101
|
-
await c.discord_user.trigger_typing()
|
102
|
-
|
103
|
-
async def paused(self, c: "Contact"):
|
104
|
-
pass
|
105
|
-
|
106
|
-
async def displayed(self, legacy_msg_id: int, c: "Contact"):
|
107
|
-
if not isinstance(legacy_msg_id, int):
|
108
|
-
self.log.debug("This is not a valid discord msg id: %s", legacy_msg_id)
|
109
|
-
return
|
110
|
-
u = c.discord_user
|
111
|
-
channel: di.DMChannel = u.dm_channel
|
112
|
-
if channel is None:
|
113
|
-
return
|
114
|
-
m = await channel.fetch_message(legacy_msg_id)
|
115
|
-
self.log.debug("Message %s should be marked as read", m)
|
116
|
-
# try:
|
117
|
-
# await m.ack() # triggers 404, maybe does not work for DM?
|
118
|
-
# except Exception as e:
|
119
|
-
# self.log.exception("Message %s should have been marked as read but this raised %s", m, e)
|
120
|
-
|
121
|
-
async def correct(self, text: str, legacy_msg_id: Any, 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
|
-
self.edit_futures[legacy_msg_id] = self.xmpp.loop.create_future()
|
128
|
-
await m.edit(content=text)
|
129
|
-
await self.edit_futures[legacy_msg_id]
|
130
|
-
|
131
|
-
async def react(self, legacy_msg_id: int, emojis: list[str], c: "Contact"):
|
132
|
-
u = c.discord_user
|
133
|
-
channel: di.DMChannel = u.dm_channel
|
134
|
-
if channel is None:
|
135
|
-
return
|
136
|
-
m = await channel.fetch_message(legacy_msg_id)
|
137
|
-
|
138
|
-
legacy_reactions = set(self.get_my_legacy_reactions(m))
|
139
|
-
xmpp_reactions = set(emojis)
|
140
|
-
|
141
|
-
self.log.debug("%s vs %s", legacy_reactions, xmpp_reactions)
|
142
|
-
for e in xmpp_reactions - legacy_reactions:
|
143
|
-
await m.add_reaction(e)
|
144
|
-
for e in legacy_reactions - xmpp_reactions:
|
145
|
-
await m.remove_reaction(e, self.discord.user)
|
146
|
-
|
147
|
-
async def retract(self, legacy_msg_id: Any, c: "Contact"):
|
148
|
-
u = c.discord_user
|
149
|
-
channel: di.DMChannel = u.dm_channel
|
150
|
-
if channel is None:
|
151
|
-
return
|
152
|
-
m = await channel.fetch_message(legacy_msg_id)
|
153
|
-
self.delete_futures[legacy_msg_id] = self.xmpp.loop.create_future()
|
154
|
-
await m.delete()
|
155
|
-
await self.delete_futures[legacy_msg_id]
|
156
|
-
|
157
|
-
async def update_reactions(self, message: di.Message):
|
158
|
-
(await self.contacts.by_discord_user(message.channel.recipient)).react(
|
159
|
-
message.id, self.get_my_legacy_reactions(message), carbon=True
|
160
|
-
)
|
161
|
-
|
162
|
-
@staticmethod
|
163
|
-
def get_my_legacy_reactions(message: di.Message) -> list[str]:
|
164
|
-
reactions = []
|
165
|
-
for r in message.reactions:
|
166
|
-
if r.me and not r.custom_emoji:
|
167
|
-
reactions.append(r.emoji)
|
168
|
-
|
169
|
-
return reactions
|
170
|
-
|
171
|
-
async def search(self, form_values: dict[str, str]):
|
172
|
-
pass
|
slidge/plugins/dummy.py
DELETED
@@ -1,334 +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 collections import defaultdict
|
9
|
-
from datetime import datetime, timedelta
|
10
|
-
from pathlib import Path
|
11
|
-
from typing import Any, Optional, Union
|
12
|
-
|
13
|
-
from slixmpp import JID
|
14
|
-
from slixmpp.exceptions import XMPPError
|
15
|
-
|
16
|
-
from slidge import *
|
17
|
-
from slidge.core.adhoc import RegistrationType
|
18
|
-
|
19
|
-
ASSETS_DIR = Path(__file__).parent.parent.parent / "assets"
|
20
|
-
|
21
|
-
|
22
|
-
class Bookmarks(LegacyBookmarks):
|
23
|
-
@staticmethod
|
24
|
-
async def jid_local_part_to_legacy_id(local_part):
|
25
|
-
if local_part not in {"prout-1", "prout2"}:
|
26
|
-
raise XMPPError("not-found")
|
27
|
-
return local_part
|
28
|
-
|
29
|
-
|
30
|
-
class MUC(LegacyMUC["Session", str, "Participant", str]):
|
31
|
-
REACTIONS_SINGLE_EMOJI = True
|
32
|
-
|
33
|
-
session: "Session"
|
34
|
-
msg_ids = defaultdict(int) # type: ignore
|
35
|
-
|
36
|
-
async def join(self, p):
|
37
|
-
self.user_nick = "SomeNick"
|
38
|
-
await super().join(p)
|
39
|
-
|
40
|
-
async def fill_history(
|
41
|
-
self,
|
42
|
-
full_jid: JID,
|
43
|
-
maxchars: Optional[int] = None,
|
44
|
-
maxstanzas: Optional[int] = None,
|
45
|
-
seconds: Optional[int] = None,
|
46
|
-
since: Optional[int] = None,
|
47
|
-
):
|
48
|
-
if maxchars is not None and maxchars == 0:
|
49
|
-
return
|
50
|
-
part = await self.get_participant("someone")
|
51
|
-
log.debug("PART")
|
52
|
-
for i in range(10, 0, -1):
|
53
|
-
log.debug("HISTORY")
|
54
|
-
part.send_text(
|
55
|
-
"history",
|
56
|
-
f"-{i}",
|
57
|
-
when=datetime.now() - timedelta(hours=i),
|
58
|
-
full_jid=full_jid,
|
59
|
-
)
|
60
|
-
|
61
|
-
async def get_participants(self):
|
62
|
-
if self.legacy_id == "prout-1":
|
63
|
-
for nick in "anon1", "anon2":
|
64
|
-
yield Participant(self, nick)
|
65
|
-
break
|
66
|
-
elif self.legacy_id == "prout2":
|
67
|
-
for nick in "anon1", "anon2", "anon3", "anon4":
|
68
|
-
yield Participant(self, nick)
|
69
|
-
|
70
|
-
async def send_text(self, text: str) -> str:
|
71
|
-
self.msg_ids[self.legacy_id] += 1
|
72
|
-
i = self.msg_ids[self.legacy_id]
|
73
|
-
self.xmpp.loop.create_task(self.session.muc_later(self, text, i))
|
74
|
-
return str(self.msg_ids[self.legacy_id])
|
75
|
-
|
76
|
-
|
77
|
-
class Participant(LegacyParticipant[MUC]):
|
78
|
-
pass
|
79
|
-
|
80
|
-
|
81
|
-
class Contact(LegacyContact):
|
82
|
-
REACTIONS_SINGLE_EMOJI = True
|
83
|
-
|
84
|
-
async def available_emojis(self, legacy_msg_id):
|
85
|
-
return {"🦅", "🧺"}
|
86
|
-
|
87
|
-
|
88
|
-
class Gateway(BaseGateway):
|
89
|
-
COMPONENT_NAME = "The great legacy network (slidge)"
|
90
|
-
COMPONENT_AVATAR = ASSETS_DIR / "gateway.png"
|
91
|
-
COMPONENT_TYPE = "aim"
|
92
|
-
GROUPS = True
|
93
|
-
REGISTRATION_INSTRUCTIONS = (
|
94
|
-
"Only username 'n' is accepted and only 'baba' and 'bibi' contacts exist.\n"
|
95
|
-
"You can use any password you want."
|
96
|
-
)
|
97
|
-
REGISTRATION_TYPE = RegistrationType.QRCODE
|
98
|
-
MARK_ALL_MESSAGES = True
|
99
|
-
|
100
|
-
async def validate(
|
101
|
-
self, user_jid: JID, registration_form: dict[str, Optional[str]]
|
102
|
-
):
|
103
|
-
if registration_form["username"] != "n":
|
104
|
-
raise XMPPError("bad-request", "Y a que N!")
|
105
|
-
|
106
|
-
async def validate_two_factor_code(self, user, code):
|
107
|
-
if code != "8":
|
108
|
-
raise XMPPError("not-authorized", text="Wrong code! It's 8.")
|
109
|
-
|
110
|
-
async def get_qr_text(self, user: GatewayUser) -> str:
|
111
|
-
self.loop.create_task(self.later_confirm_qr(user))
|
112
|
-
return "dummy:///SLIDGE-IS-GREAT-AGAIN/prout"
|
113
|
-
|
114
|
-
async def later_confirm_qr(self, user: GatewayUser):
|
115
|
-
await asyncio.sleep(1)
|
116
|
-
exc = (
|
117
|
-
XMPPError("bad-request", "Ben non")
|
118
|
-
if user.registration_form["password"] == "n"
|
119
|
-
else None
|
120
|
-
)
|
121
|
-
await self.confirm_qr(user.bare_jid, exc)
|
122
|
-
|
123
|
-
|
124
|
-
class Roster(LegacyRoster):
|
125
|
-
@staticmethod
|
126
|
-
async def jid_username_to_legacy_id(jid_username: str):
|
127
|
-
if jid_username not in BUDDIES + ["bubu"]:
|
128
|
-
raise XMPPError("not-found")
|
129
|
-
return jid_username
|
130
|
-
|
131
|
-
|
132
|
-
class Session(
|
133
|
-
BaseSession[
|
134
|
-
Gateway, int, LegacyRoster, LegacyContact, LegacyBookmarks, MUC, Participant
|
135
|
-
]
|
136
|
-
):
|
137
|
-
def __init__(self, user):
|
138
|
-
super(Session, self).__init__(user)
|
139
|
-
self.counter = 0
|
140
|
-
self.xmpp.loop.create_task(self.backfill())
|
141
|
-
self.xmpp.loop.create_task(
|
142
|
-
self.contacts.by_legacy_id("bibi")
|
143
|
-
).add_done_callback(
|
144
|
-
lambda c: c.result().set_vcard(
|
145
|
-
given="FirstBi",
|
146
|
-
surname="LastBi",
|
147
|
-
phone="+555",
|
148
|
-
full_name="Bi bi",
|
149
|
-
note="A fake friend, always there for you",
|
150
|
-
url="https://example.org",
|
151
|
-
email="bibi@prout.com",
|
152
|
-
country="Westeros",
|
153
|
-
locality="The place with the thing",
|
154
|
-
)
|
155
|
-
)
|
156
|
-
self.xmpp.loop.create_task(self.add_groups())
|
157
|
-
|
158
|
-
async def add_groups(self):
|
159
|
-
muc = await self.bookmarks.by_legacy_id("prout-1")
|
160
|
-
muc.n_participants = 45
|
161
|
-
await self.bookmarks.by_legacy_id("prout2")
|
162
|
-
muc.n_participants = 885
|
163
|
-
|
164
|
-
async def muc_later(self, muc: MUC, text: str, trigger_msg_id: int):
|
165
|
-
replier = await muc.get_participant("anon1")
|
166
|
-
log.debug("REPLIER: %s", replier)
|
167
|
-
await asyncio.sleep(0.5)
|
168
|
-
replier.composing()
|
169
|
-
await asyncio.sleep(0.5)
|
170
|
-
replier.send_text("prout", trigger_msg_id * 1000)
|
171
|
-
# next(muc.participants).send_text("I agree. Ain't that great?")
|
172
|
-
|
173
|
-
async def backfill(self):
|
174
|
-
self.log.debug("CARBON")
|
175
|
-
i = uuid.uuid1()
|
176
|
-
|
177
|
-
baba = await self.contacts.by_legacy_id("baba")
|
178
|
-
|
179
|
-
baba.send_text(
|
180
|
-
f"You're bad!",
|
181
|
-
legacy_msg_id=i,
|
182
|
-
when=datetime.now() - timedelta(hours=5),
|
183
|
-
carbon=True,
|
184
|
-
)
|
185
|
-
baba.send_text(
|
186
|
-
f"You're worse",
|
187
|
-
legacy_msg_id=i,
|
188
|
-
when=datetime.now() - timedelta(hours=4),
|
189
|
-
)
|
190
|
-
|
191
|
-
async def paused(self, c: LegacyContact):
|
192
|
-
pass
|
193
|
-
|
194
|
-
async def correct(self, text: str, legacy_msg_id: Any, c: LegacyContact):
|
195
|
-
pass
|
196
|
-
|
197
|
-
async def login(self):
|
198
|
-
log.debug("Logging in user: %s", self.user)
|
199
|
-
self.send_gateway_status("Connecting...", show="dnd")
|
200
|
-
await asyncio.sleep(1)
|
201
|
-
self.send_gateway_status("Connected")
|
202
|
-
for b, a in zip(BUDDIES, AVATARS):
|
203
|
-
c = await self.contacts.by_legacy_id(b.lower())
|
204
|
-
c.name = b.title()
|
205
|
-
c.avatar = a
|
206
|
-
await c.add_to_roster()
|
207
|
-
c.online("I am not a real person, so what?")
|
208
|
-
return "You can talk to your fake friends now"
|
209
|
-
|
210
|
-
async def logout(self):
|
211
|
-
log.debug("User has disconnected")
|
212
|
-
|
213
|
-
async def send_text(
|
214
|
-
self,
|
215
|
-
text: str,
|
216
|
-
chat: Union[LegacyContact, MUC],
|
217
|
-
*,
|
218
|
-
reply_to_msg_id=None,
|
219
|
-
reply_to_fallback_text=None,
|
220
|
-
reply_to=None,
|
221
|
-
):
|
222
|
-
if isinstance(chat, MUC):
|
223
|
-
await chat.send_text(text)
|
224
|
-
return
|
225
|
-
|
226
|
-
log.debug("REPLY FALLBACK: %r", reply_to_fallback_text)
|
227
|
-
i = self.counter
|
228
|
-
self.counter = i + 1
|
229
|
-
|
230
|
-
if text == "crash":
|
231
|
-
raise RuntimeError("PANIC!!!")
|
232
|
-
if text == "crash2":
|
233
|
-
self.xmpp.loop.create_task(self.crash())
|
234
|
-
elif text == "delete":
|
235
|
-
self.xmpp.loop.create_task(self.later_carbon_delete(chat, i))
|
236
|
-
elif text == "nick":
|
237
|
-
chat.name = "NEWNAME"
|
238
|
-
elif text == "avatar":
|
239
|
-
chat.avatar = ASSETS_DIR / "5x5.png"
|
240
|
-
elif text == "nonick":
|
241
|
-
chat.name = None
|
242
|
-
else:
|
243
|
-
self.xmpp.loop.create_task(self.later(chat, i, body=text))
|
244
|
-
|
245
|
-
return i
|
246
|
-
|
247
|
-
async def crash(self):
|
248
|
-
raise RuntimeError("PANIC222!!!")
|
249
|
-
|
250
|
-
async def send_file(self, url: str, chat: Union[LegacyContact, MUC], **k) -> int:
|
251
|
-
i = self.counter
|
252
|
-
self.counter = i + 1
|
253
|
-
if isinstance(chat, MUC):
|
254
|
-
replier = await chat.get_participant("uploader")
|
255
|
-
else:
|
256
|
-
replier = chat # type: ignore
|
257
|
-
replier.send_text(url)
|
258
|
-
await replier.send_file(ASSETS_DIR / "buddy1.png", caption="This is a caption")
|
259
|
-
return i
|
260
|
-
|
261
|
-
async def later(self, c: LegacyContact, trigger_msg_id: int, body: str):
|
262
|
-
i = self.counter - 1
|
263
|
-
await asyncio.sleep(1)
|
264
|
-
c.received(i)
|
265
|
-
await asyncio.sleep(1)
|
266
|
-
c.active()
|
267
|
-
await asyncio.sleep(1)
|
268
|
-
c.displayed(i)
|
269
|
-
await asyncio.sleep(1)
|
270
|
-
c.ack(i)
|
271
|
-
await asyncio.sleep(1)
|
272
|
-
c.composing()
|
273
|
-
await asyncio.sleep(1)
|
274
|
-
c.paused()
|
275
|
-
await asyncio.sleep(1)
|
276
|
-
c.composing()
|
277
|
-
await asyncio.sleep(1)
|
278
|
-
c.send_text(
|
279
|
-
"OK",
|
280
|
-
legacy_msg_id=i,
|
281
|
-
reply_to_msg_id=trigger_msg_id,
|
282
|
-
reply_to_fallback_text=body,
|
283
|
-
)
|
284
|
-
await asyncio.sleep(1)
|
285
|
-
i = uuid.uuid1().int
|
286
|
-
c.send_text("I will retract this", legacy_msg_id=i)
|
287
|
-
c.retract(i)
|
288
|
-
c.inactive()
|
289
|
-
|
290
|
-
async def later_carbon_delete(self, c: LegacyContact, trigger_msg_id: int):
|
291
|
-
await asyncio.sleep(1)
|
292
|
-
c.retract(trigger_msg_id, carbon=True)
|
293
|
-
|
294
|
-
async def active(self, c: LegacyContact):
|
295
|
-
log.debug("User is active for contact %s", c)
|
296
|
-
|
297
|
-
async def inactive(self, c: LegacyContact):
|
298
|
-
log.debug("User is inactive for contact %s", c)
|
299
|
-
|
300
|
-
async def composing(self, c: LegacyContact):
|
301
|
-
log.debug("User is composing for contact %s", c)
|
302
|
-
|
303
|
-
async def displayed(self, legacy_msg_id: int, c: LegacyContact):
|
304
|
-
log.debug("Message #%s was read by the user", legacy_msg_id)
|
305
|
-
|
306
|
-
async def search(self, form_values: dict[str, str]):
|
307
|
-
if form_values["first"] == "bubu":
|
308
|
-
return SearchResult(
|
309
|
-
fields=[
|
310
|
-
FormField("name", label="Name"),
|
311
|
-
FormField("jid", type="jid-single"),
|
312
|
-
],
|
313
|
-
items=[{"name": "bubu", "jid": f"bubu@{self.xmpp.boundjid.bare}"}],
|
314
|
-
)
|
315
|
-
|
316
|
-
async def react(self, legacy_msg_id, emojis, c):
|
317
|
-
if "😈" in emojis:
|
318
|
-
c.send_text("That's forbidden")
|
319
|
-
c.react(legacy_msg_id, "", carbon=True)
|
320
|
-
raise XMPPError("not-acceptable")
|
321
|
-
else:
|
322
|
-
c.react(legacy_msg_id, "♥")
|
323
|
-
|
324
|
-
async def retract(self, legacy_msg_id, c):
|
325
|
-
log.debug("User has retracted their msg: '%s' (sent to '%s')", legacy_msg_id, c)
|
326
|
-
|
327
|
-
|
328
|
-
BUDDIES = ["baba", "bibi"]
|
329
|
-
AVATARS = ["https://wallpapercave.com/wp/PSksftM.jpg"]
|
330
|
-
|
331
|
-
with (ASSETS_DIR / "buddy2.png").open("rb") as fp:
|
332
|
-
AVATARS.append(fp.read()) # type:ignore
|
333
|
-
|
334
|
-
log = logging.getLogger(__name__)
|