11using System . Diagnostics . CodeAnalysis ;
2+ using System . Formats . Asn1 ;
3+ using System . Text ;
24using Lagrange . Core . Common . Entity ;
3- using Lagrange . Core . Exceptions ;
45using Lagrange . Core . Internal . Events . System ;
56using Lagrange . Core . Internal . Packets . Message ;
67using Lagrange . Core . Message . Entities ;
78using Lagrange . Core . Utility ;
9+ using Lagrange . Core . Utility . Binary ;
810using Lagrange . Core . Utility . Extension ;
911
1012
@@ -41,7 +43,7 @@ public async Task<BotMessage> Parse(CommonMessage msg)
4143
4244 var contact = await ResolveContact ( contentHead . Type , routingHead ) ;
4345 var receiver = await ResolveReceiver ( contentHead . Type , routingHead ) ;
44- var message = new BotMessage ( contact , receiver )
46+ var message = new BotMessage ( contact , receiver , DateTime . Now )
4547 {
4648 MessageId = contentHead . MsgUid , // MsgUid & 0xFFFFFFFF are the same to random
4749 Time = DateTimeOffset . FromUnixTimeSeconds ( contentHead . Time ) . DateTime ,
@@ -50,14 +52,21 @@ public async Task<BotMessage> Parse(CommonMessage msg)
5052 Random = contentHead . Random
5153 } ;
5254
53- foreach ( var elem in elems )
55+ if ( ParsePttRichText ( msg . MessageBody . RichText ) is { } record )
5456 {
55- foreach ( var factory in _factory )
57+ message . Entities . Add ( record ) ;
58+ }
59+ else
60+ {
61+ foreach ( var elem in elems )
5662 {
57- if ( factory . Parse ( elems , elem ) is not { } entity ) continue ;
63+ foreach ( var factory in _factory )
64+ {
65+ if ( factory . Parse ( elems , elem ) is not { } entity ) continue ;
5866
59- message . Entities . Add ( entity ) ;
60- break ;
67+ message . Entities . Add ( entity ) ;
68+ break ;
69+ }
6170 }
6271 }
6372
@@ -266,4 +275,46 @@ public Task<CommonMessage> BuildFake(BotMessage msg)
266275
267276 return Task . FromResult ( proto ) ;
268277 }
278+
279+ private RecordEntity ? ParsePttRichText ( RichText richText )
280+ {
281+ if ( richText . Ptt is not { } ptt ) return null ;
282+
283+ var kv = new BinaryPacket ( stackalloc byte [ 100 ] ) ;
284+ kv . Write ( "filetype" , Prefix . Int32 | Prefix . LengthOnly ) ;
285+ kv . Write ( "0" , Prefix . Int32 | Prefix . LengthOnly ) ;
286+ kv . Write ( "codec" , Prefix . Int32 | Prefix . LengthOnly ) ;
287+ kv . Write ( "1" , Prefix . Int32 | Prefix . LengthOnly ) ;
288+
289+ Span < byte > innerSpan = stackalloc byte [ 200 ] ;
290+ Span < byte > outerSpan = stackalloc byte [ 300 ] ;
291+
292+ var inner = new AsnWriter ( AsnEncodingRules . DER ) ;
293+ inner . PushSequence ( ) ;
294+ inner . WriteInteger ( 1 ) ;
295+ inner . WriteInteger ( 0 ) ;
296+ inner . WriteInteger ( ( int ) ( _context . BotUin < 0x8000_0000 ? _context . BotUin : _context . BotUin - 0x1_0000_0000 ) ) ;
297+ inner . WriteOctetString ( ptt . GroupFileKey ?? ptt . FileUuid ?? ReadOnlySpan < byte > . Empty ) ;
298+ inner . WriteInteger ( DateTimeOffset . UtcNow . ToUnixTimeSeconds ( ) ) ;
299+ inner . WriteOctetString ( kv . CreateReadOnlySpan ( ) ) ;
300+ inner . PopSequence ( ) ;
301+ inner . TryEncode ( innerSpan , out int length ) ;
302+
303+ var outer = new AsnWriter ( AsnEncodingRules . DER ) ;
304+ outer . PushSequence ( ) ;
305+ outer . WriteInteger ( 1 ) ; // version
306+ outer . WriteOctetString ( innerSpan [ ..length ] ) ; // inner
307+ outer . WriteOctetString ( ReadOnlySpan < byte > . Empty ) ; // “empty”
308+ outer . PopSequence ( ) ;
309+
310+ outer . TryEncode ( outerSpan , out length ) ;
311+
312+ return new RecordEntity
313+ {
314+ FileUrl = $ "https://grouptalk.c2c.qq.com/?ver=2&rkey={ Convert . ToHexString ( outerSpan [ ..length ] ) } &voice_codec=1&filetype=0",
315+ FileName = ptt . FileName ,
316+ FileSize = ptt . FileSize ,
317+ FileMd5 = Convert . ToHexString ( ptt . FileMd5 ?? [ ] )
318+ } ;
319+ }
269320}
0 commit comments