mirror of
https://git.ugnet.gay/CrossTalk/azul.git
synced 2026-05-27 22:59:49 +00:00
112 lines
4.6 KiB
Python
112 lines
4.6 KiB
Python
import struct
|
|
import time
|
|
|
|
from core.models import Contact
|
|
from util.misc import Logger
|
|
|
|
from ..proto.snac import OSCARClient, OSCARContext, SNACMessage, Foodgroup, Subgroup
|
|
from ..proto.tlv import TLV, unmarshal_tlvs
|
|
|
|
|
|
# should be piped to .ctrl.send_snac()
|
|
def build_presence_notif(contact: Contact) -> SNACMessage:
|
|
# Packet dump from NINA's servers when a contact goes online:
|
|
# ===
|
|
# 0000 04 64 6b 61 79 00 00 00 07 00 30 00 04 67 19 67 .dkay.....0..g.g
|
|
# 0010 4c 00 0d 00 c0 09 46 13 45 4c 7f 11 d1 82 22 44 L.....F.EL...."D
|
|
# 0020 45 53 54 00 00 09 46 01 ff 4c 7f 11 d1 82 22 44 EST...F..L...."D
|
|
# 0030 45 53 54 00 00 74 8f 24 20 62 87 11 d1 82 22 44 EST..t.$ b...."D
|
|
# 0040 45 53 54 00 00 09 46 13 43 4c 7f 11 d1 82 22 44 EST...F.CL...."D
|
|
# 0050 45 53 54 00 00 09 46 13 41 4c 7f 11 d1 82 22 44 EST...F.AL...."D
|
|
# 0060 45 53 54 00 00 09 46 01 04 4c 7f 11 d1 82 22 44 EST...F..L...."D
|
|
# 0070 45 53 54 00 00 09 46 01 05 4c 7f 11 d1 82 22 44 EST...F..L...."D
|
|
# 0080 45 53 54 00 00 09 46 01 02 4c 7f 11 d1 82 22 44 EST...F..L...."D
|
|
# 0090 45 53 54 00 00 09 46 01 03 4c 7f 11 d1 82 22 44 EST...F..L...."D
|
|
# 00a0 45 53 54 00 00 09 46 01 01 4c 7f 11 d1 82 22 44 EST...F..L...."D
|
|
# 00b0 45 53 54 00 00 09 46 13 4a 4c 7f 11 d1 82 22 44 EST...F.JL...."D
|
|
# 00c0 45 53 54 00 00 09 46 13 46 4c 7f 11 d1 82 22 44 EST...F.FL...."D
|
|
# 00d0 45 53 54 00 00 00 1d 00 12 00 01 00 05 02 01 d2 EST.............
|
|
# 00e0 04 72 00 00 00 05 02 01 d2 04 72 00 01 00 02 00 .r........r.....
|
|
# 00f0 08 00 03 00 04 67 19 67 4b 00 0f 00 04 00 00 00 .....g.gK.......
|
|
# 0100 02 00 05 00 04 62 7c 7a cd .....b|z.
|
|
#
|
|
# Buddy length: 0x04
|
|
# Buddy name: dkay
|
|
# TLVs (7):
|
|
# - TLV 0x3000: unknown (data = 67 19 67 4C)
|
|
# - TLV 0x000D: capability list
|
|
# - TLV 0x001D: BART info (data = 00 01 00 05 02 01 D2 04 72 00 00 00 05 02 01 D2 04 72
|
|
# - TLV 0x0001: user class (data = 00 00 00 08)
|
|
# - TLV 0x0003: account signon time (value = 1729718091, in UNIX time)
|
|
# - TLV 0x000F: session length (value = 2)
|
|
# - TLV 0x0005: account creation time (value = 1652325069, in UNIX time)
|
|
#
|
|
|
|
msg = SNACMessage(0x0003, 0x000B if not contact.status.is_offlineish() else 0x000C)
|
|
|
|
msg.write_string_u8(contact.head.username)
|
|
msg.write_u16(0)
|
|
|
|
if contact.status.is_offlineish():
|
|
msg.write_tlv(TLV(0x0001, struct.pack('>L', 0x0008))) # User class (bitfield)
|
|
else:
|
|
capabilities = [
|
|
"{09461345-4C7F-11D1-8222-444553540000}", # Direct ICBM
|
|
"{094601FF-4C7F-11D1-8222-444553540000}", # Smart caps
|
|
"{748F2420-6287-11D1-8222-444553540000}", # Chat
|
|
"{09461343-4C7F-11D1-8222-444553540000}", # File transfer
|
|
"{09461341-4C7F-11D1-8222-444553540000}", # Voice chat
|
|
"{09460104-4C7F-11D1-8222-444553540000}", # RTC audio
|
|
"{09460105-4C7F-11D1-8222-444553540000}", # Unknown
|
|
"{09460102-4C7F-11D1-8222-444553540000}", # Camera
|
|
"{09460103-4C7F-11D1-8222-444553540000}", # Microphone
|
|
"{09460101-4C7F-11D1-8222-444553540000}", # RTC video
|
|
"{0946134A-4C7F-11D1-8222-444553540000}", # Games
|
|
"{09461346-4C7F-11D1-8222-444553540000}" # BART
|
|
]
|
|
capabilities_bytes = b''
|
|
|
|
for capability in capabilities:
|
|
capabilities_bytes += bytes.fromhex(capability
|
|
.lstrip('{')
|
|
.rstrip('}')
|
|
.replace('-', ''))
|
|
|
|
date_created_unix = int(time.mktime(contact.head.date_created.timetuple()))
|
|
date_login_unix = int(time.mktime(contact.head.date_login.timetuple())) if contact.head.date_login else 0
|
|
|
|
# usually would include 0x001D (BART info), but since CrossTalk doesn't support
|
|
# it rn I've decided to omit it
|
|
msg.write_tlv_block([
|
|
TLV(0x3000, struct.pack('>L', 0x6719674C)), # Unknown
|
|
TLV(0x000D, capabilities_bytes), # Capability info
|
|
TLV(0x0001, struct.pack('>H', 0x0008)), # User class (bitfield)
|
|
TLV(0x0003, struct.pack('>L', date_login_unix)), # Account signon time (unix time_t)
|
|
TLV(0x000F, struct.pack('>L', 0)), # Session length
|
|
TLV(0x0005, struct.pack('>L', date_created_unix)), # Account creation time (unix time_t)
|
|
])
|
|
|
|
print('Subgroup:', hex(msg.subgroup))
|
|
print('TLVs:', unmarshal_tlvs(msg.data))
|
|
|
|
return msg
|
|
|
|
|
|
@Foodgroup(0x0003)
|
|
class BuddyFoodgroup:
|
|
logger: Logger
|
|
|
|
@Subgroup(0x0002)
|
|
def rights_query(self, client: OSCARClient, context: OSCARContext, message: SNACMessage) -> None:
|
|
self.logger.info('[Client] BUDDY_RIGHTS_QUERY')
|
|
|
|
response_msg = SNACMessage(0x0003, 0x0003)
|
|
response_msg.write_tlvs([
|
|
TLV(0x0001, struct.pack('>H', 1000)), # max buddies
|
|
TLV(0x0002, struct.pack('>H', 3000)), # max watchers
|
|
TLV(0x0004, struct.pack('>H', 160)) # max temp buddies
|
|
])
|
|
|
|
self.logger.info('[Server] BUDDY_RIGHTS_REPLY')
|
|
client.send_snac(response_msg)
|