Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
M
Mirai
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
Mirai
Commits
28859056
Commit
28859056
authored
Oct 26, 2019
by
Him188
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve image uploading
parent
a2f35f5d
Changes
20
Show whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
404 additions
and
220 deletions
+404
-220
README.md
README.md
+1
-1
mirai-console/src/main/java/net/mamoe/mirai/MiraiServer.kt
mirai-console/src/main/java/net/mamoe/mirai/MiraiServer.kt
+1
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotHelper.kt
...i-core/src/commonMain/kotlin/net.mamoe.mirai/BotHelper.kt
+4
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/Message.kt
.../src/commonMain/kotlin/net.mamoe.mirai/message/Message.kt
+1
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt
....mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt
+1
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMProtocol.kt
...otlin/net.mamoe.mirai/network/protocol/tim/TIMProtocol.kt
+1
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/UploadFriendImage.kt
...i/network/protocol/tim/packet/action/UploadFriendImage.kt
+109
-94
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/UploadGroupImage.kt
...ai/network/protocol/tim/packet/action/UploadGroupImage.kt
+94
-54
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/event/ServerEventPackets.kt
...i/network/protocol/tim/packet/event/ServerEventPackets.kt
+1
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt
.../commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt
+11
-2
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/PlatformUtils.kt
.../commonMain/kotlin/net.mamoe.mirai/utils/PlatformUtils.kt
+64
-21
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/ByteArrayUtil.kt
...mmonMain/kotlin/net.mamoe.mirai/utils/io/ByteArrayUtil.kt
+2
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/InputUtils.kt
.../commonMain/kotlin/net.mamoe.mirai/utils/io/InputUtils.kt
+1
-3
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/network/protocol/tim/packet/PacketInternalJvm.kt
...oe/mirai/network/protocol/tim/packet/PacketInternalJvm.kt
+21
-4
mirai-core/src/jvmTest/kotlin/TestGroupImage.kt
mirai-core/src/jvmTest/kotlin/TestGroupImage.kt
+3
-3
mirai-core/src/jvmTest/kotlin/TestImageFile.kt
mirai-core/src/jvmTest/kotlin/TestImageFile.kt
+9
-0
mirai-debug/build.gradle
mirai-debug/build.gradle
+21
-1
mirai-debug/src/main/java/HexComparator.kt
mirai-debug/src/main/java/HexComparator.kt
+2
-4
mirai-debug/src/main/java/PacketDebuger.kt
mirai-debug/src/main/java/PacketDebuger.kt
+46
-18
mirai-demos/mirai-demo-1/src/main/java/demo1/Main.kt
mirai-demos/mirai-demo-1/src/main/java/demo1/Main.kt
+11
-9
No files found.
README.md
View file @
28859056
...
...
@@ -50,7 +50,7 @@ subscribeAlways<FriendMessageEvent>{
-
成员权限, 昵称(10/18)
-
好友在线状态改变(10/14)
-
Android客户端上线/下线(10/18)
-
上传并发送
图片(10/21
)
-
上传并发送
好友/群图片(10/26
)
## 使用方法
### 要求
...
...
mirai-console/src/main/java/net/mamoe/mirai/MiraiServer.kt
View file @
28859056
...
...
@@ -147,7 +147,7 @@ object MiraiServer {
Bot bot = new Bot(section);
var state = bot.network.login$mirai_core().of();
//bot.network.login$mirai_core().whenComplete((state, e) -> {
if (state == LoginState.
SUCCESS
) {
if (state == LoginState.
REQUIRE_UPLOAD
) {
Bot.instances.add(bot);
getLogger().logGreen(" Login Succeed");
} else {
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotHelper.kt
View file @
28859056
...
...
@@ -3,8 +3,10 @@
package
net.mamoe.mirai
import
net.mamoe.mirai.contact.*
import
net.mamoe.mirai.network.BotSession
import
net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
import
net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult
import
net.mamoe.mirai.network.session
import
net.mamoe.mirai.utils.BotNetworkConfiguration
/*
...
...
@@ -22,6 +24,8 @@ suspend fun Bot.getGroup(internalId: GroupInternalId): Group = this.contacts.get
val
Bot
.
groups
:
ContactList
<
Group
>
get
()
=
this
.
contacts
.
groups
val
Bot
.
qqs
:
ContactList
<
QQ
>
get
()
=
this
.
contacts
.
qqs
inline
fun
<
T
>
Bot
.
withSession
(
block
:
BotSession
.()
->
T
):
T
=
with
(
this
.
network
.
session
)
{
block
()
}
//NetworkHandler
suspend
fun
Bot
.
sendPacket
(
packet
:
OutgoingPacket
)
=
this
.
network
.
sendPacket
(
packet
)
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/Message.kt
View file @
28859056
...
...
@@ -4,7 +4,7 @@ package net.mamoe.mirai.message
import
net.mamoe.mirai.contact.Contact
import
net.mamoe.mirai.contact.QQ
import
net.mamoe.mirai.network.protocol.tim.packet.FriendImageIdRequestPacket
import
net.mamoe.mirai.network.protocol.tim.packet.
action.
FriendImageIdRequestPacket
import
net.mamoe.mirai.utils.ExternalImage
/**
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt
View file @
28859056
...
...
@@ -97,7 +97,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
override
suspend
fun
close
(
cause
:
Throwable
?)
{
super
.
close
(
cause
)
this
.
heartbeatJob
?.
cancel
(
CancellationException
(
"handler closed"
))
this
.
heartbeatJob
?.
cancel
Children
(
CancellationException
(
"handler closed"
))
this
.
heartbeatJob
?.
join
()
//等待 cancel 完成
this
.
heartbeatJob
=
null
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMProtocol.kt
View file @
28859056
...
...
@@ -20,7 +20,7 @@ object TIMProtocol {
).
forEach
{
list
.
add
(
solveIpAddress
(
it
))
}
list
.
toList
()
}()
//不使用lazy
是为了在启动
时就加载.
}()
//不使用lazy
, 在初始化
时就加载.
const
val
head
=
"02"
const
val
ver
=
"37 13"
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/UploadFriendImage.kt
→
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/
action/
UploadFriendImage.kt
View file @
28859056
@
file
:
Suppress
(
"EXPERIMENTAL_API_USAGE"
,
"EXPERIMENTAL_UNSIGNED_LITERALS"
,
"unused"
)
package
net.mamoe.mirai.network.protocol.tim.packet
package
net.mamoe.mirai.network.protocol.tim.packet
.action
import
kotlinx.io.core.*
import
net.mamoe.mirai.contact.QQ
import
net.mamoe.mirai.message.ImageId
import
net.mamoe.mirai.network.protocol.tim.TIMProtocol
import
net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
import
net.mamoe.mirai.network.protocol.tim.packet.PacketId
import
net.mamoe.mirai.network.protocol.tim.packet.PacketVersion
import
net.mamoe.mirai.network.protocol.tim.packet.ResponsePacket
import
net.mamoe.mirai.network.qqAccount
import
net.mamoe.mirai.network.session
import
net.mamoe.mirai.qqAccount
import
net.mamoe.mirai.utils.*
import
net.mamoe.mirai.utils.ExternalImage
import
net.mamoe.mirai.utils.httpPostFriendImage
import
net.mamoe.mirai.utils.io.*
import
net.mamoe.mirai.utils.readUnsignedVarInt
import
net.mamoe.mirai.utils.writeUVarInt
/**
* 上传图片
...
...
@@ -18,14 +25,16 @@ import net.mamoe.mirai.utils.io.*
suspend
fun
QQ
.
uploadImage
(
image
:
ExternalImage
):
ImageId
=
with
(
bot
.
network
.
session
)
{
//SubmitImageFilenamePacket(account, account, "sdiovaoidsa.png", sessionKey).sendAndExpect<ServerSubmitImageFilenameResponsePacket>().join()
DebugLogger
.
logPurple
(
"正在上传好友图片, md5=${image.md5.toUHexString()}"
)
return
FriendImageIdRequestPacket
(
this
.
qqAccount
,
sessionKey
,
this
.
qqAccount
,
image
).
sendAndExpect
<
FriendImageIdRequestPacket
.
Response
,
ImageId
>
{
return
FriendImageIdRequestPacket
(
this
.
qqAccount
,
sessionKey
,
id
,
image
).
sendAndExpect
<
FriendImageIdRequestPacket
.
Response
,
ImageId
>
{
if
(
it
.
uKey
!=
null
)
require
(
httpPostFriendImage
(
require
(
httpPostFriendImage
(
botAccount
=
bot
.
qqAccount
,
uKeyHex
=
it
.
uKey
!!
.
toUHexString
(
""
),
imageInput
=
image
.
input
,
inputSize
=
image
.
inputSize
))
)
)
it
.
imageId
!!
}.
await
()
}
...
...
@@ -43,7 +52,7 @@ suspend fun QQ.uploadImage(image: ExternalImage): ImageId = with(bot.network.ses
* 似乎没有必要. 服务器的返回永远都是 01 00 00 00 02 00 00
*/
@PacketId
(
0
X01_BDu
)
@PacketVersion
(
date
=
"2019.10.
19
"
,
timVersion
=
"2.3.2.21173"
)
@PacketVersion
(
date
=
"2019.10.
26
"
,
timVersion
=
"2.3.2.21173"
)
class
SubmitImageFilenamePacket
(
private
val
bot
:
UInt
,
private
val
target
:
UInt
,
...
...
@@ -99,7 +108,7 @@ class SubmitImageFilenamePacket(
* - 服务器未存有, 返回一个 key 用于客户端上传
*/
@PacketId
(
0
x03_52u
)
@PacketVersion
(
date
=
"2019.10.2
0
"
,
timVersion
=
"2.3.2.21173"
)
@PacketVersion
(
date
=
"2019.10.2
6
"
,
timVersion
=
"2.3.2.21173"
)
class
FriendImageIdRequestPacket
(
private
val
botNumber
:
UInt
,
private
val
sessionKey
:
ByteArray
,
...
...
@@ -187,13 +196,10 @@ class FriendImageIdRequestPacket(
* 70 [80 14]
* 78 [A0 0B]//84
*/
writeZero
(
3
)
writeUShort
(
0
x07_00u
)
writeZero
(
1
)
writeHex
(
"00 00 00 07 00 00 00"
)
//proto
val
packet
=
buildPacket
{
writeUVarintLVPacket
(
lengthOffset
=
{
it
-
7
})
{
writeUByte
(
0
x08u
)
writeUShort
(
0
x01_12u
)
writeUShort
(
0
x03_98u
)
...
...
@@ -201,8 +207,7 @@ class FriendImageIdRequestPacket(
writeUShort
(
0
x08_01u
)
writeUShort
(
0
x12_47u
)
//?似乎会变
writeUVarintLVPacket
(
tag
=
0
x12u
,
lengthOffset
=
{
it
+
1
})
{
writeUByte
(
0
x08u
)
writeUVarInt
(
botNumber
)
...
...
@@ -245,18 +250,42 @@ class FriendImageIdRequestPacket(
writeUByte
(
0
x78u
)
writeUVarInt
(
image
.
height
.
toUInt
())
}
writeShort
((
packet
.
remaining
-
7
).
toShort
())
//why?
writePacket
(
packet
)
}
//println(this.build().readBytes().toUHexString())
}
}
@PacketId
(
0
x0352u
)
@PacketVersion
(
date
=
"2019.10.2
0
"
,
timVersion
=
"2.3.2.21173"
)
@PacketVersion
(
date
=
"2019.10.2
6
"
,
timVersion
=
"2.3.2.21173"
)
class
Response
(
input
:
ByteReadPacket
)
:
ResponsePacket
(
input
)
{
var
uKey
:
ByteArray
?
=
null
//最终可能为null
var
imageId
:
ImageId
?
=
null
//最终不会为null
/**
* 访问 HTTP API 时需要使用的一个 key. 128 位
*/
var
uKey
:
ByteArray
?
=
null
/**
* 发送消息时使用的 id
*/
var
imageId
:
ImageId
?
=
null
lateinit
var
state
:
State
enum
class
State
{
/**
* 需要上传. 此时 [uKey], [imageId] 均不为 `null`
*/
REQUIRE_UPLOAD
,
/**
* 服务器已有这个图片. 此时 [uKey] 为 `null`, [imageId] 不为 `null`
*/
ALREADY_EXISTS
,
/**
* 图片过大. 此时 [uKey], [imageId] 均为 `null`
*/
OVER_FILE_SIZE_MAX
,
}
override
fun
decode
()
=
with
(
input
)
{
//00 00 00 08 00 00
...
...
@@ -278,41 +307,27 @@ class FriendImageIdRequestPacket(
discardExact
(
1
)
//52, id
imageId
=
ImageId
(
readString
(
readUnsignedVarInt
().
toInt
()))
//37
state
=
State
.
REQUIRE_UPLOAD
//DebugLogger.logPurple("获得 uKey(${uKey!!.size})=${uKey!!.toUHexString()}")
//DebugLogger.logPurple("获得 imageId(${imageId!!.value.length})=${imageId}")
}
else
{
//服务器已经有这个图片了
//DebugLogger.logPurple("服务器已有好友图片 ")
//89 12 06 98 01 01 A0 01 00 08 01 12 82 01 08 00 10 AB A7 89 D8 02 18 00 28 01 32 20 0A 10 5A 39 37 10 EA D5 B5 57 A8 04 14 70 CE 90 67 14 10 67 18 8A 94 17 20 ED 03 28 97 04 30 0A 52 25 2F 39 38 31 65 61 31 64 65 2D 62 32 31 33 2D 34 31 61 39 2D 38 38 37 65 2D 32 38 37 39 39 66 31 39 36 37 35 65 5A 25 2F 39 38 31 65 61 31 64 65 2D 62 32 31 33 2D 34 31 61 39 2D 38 38 37 65 2D 32 38 37 39 39 66 31 39 36 37 35 65 60 00 68 80 80 08 20 01
// 89
// 12 06 98 01 01 A0 01 00 08 01 12 82 01 08 00 10 AB A7 89 D8 02 18 00 28 01 32 20 0A 10 5A 39 37 10 EA D5 B5 57 A8 04 14 70 CE 90 67 14 10 67 18 8A 94 17 20 ED 03 28 97 04 30 0A 52 25 2F 39 38 31 65 61 31 64 65 2D 62 32 31 33 2D 34 31 61 39 2D 38 38 37 65 2D 32 38 37 39 39 66 31 39 36 37 35 65 5A 25 2F 39 38 31 65 61 31 64 65 2D 62 32 31 33 2D 34 31 61 39 2D 38 38 37 65 2D 32 38 37 39 39 66 31 39 36 37 35 65 60 00 68 80 80 08 20 01
discardExact
(
60
)
discardExact
(
1
)
//52, id
imageId
=
ImageId
(
readString
(
readUnsignedVarInt
().
toInt
()))
//37
//83 12 06 98 01 01 A0 01 00 08 01 12 7D 08 00 10 9B A4 DC 92 06 18 00 28 01 32 1B 0A 10 8E C4 9D 72 26 AE 20 C0 5D A2 B6 78 4D 12 B7 3A 10 00 18 86 1F 20 30 28 30 52 25 2F 30 31 62
val
toDiscard
=
readUByte
().
toInt
()
-
37
if
(
toDiscard
<
0
)
{
state
=
State
.
OVER_FILE_SIZE_MAX
}
else
{
discardExact
(
toDiscard
)
imageId
=
ImageId
(
readString
(
37
))
state
=
State
.
ALREADY_EXISTS
}
}
}
}
fun
main
()
{
//GlobalSysTemp:II%E]PA}OVFK]61EGGF$356.jpg
//实际文件名为 II%E]PA}OVFK]61EGGF$356.jpg
println
(
SubmitImageFilenamePacket
(
1994701021
u
,
1040400290
u
,
"testfilename.png"
,
"99 82 67 D4 62 20 CA 5D 81 F8 6F 83 EE 8A F7 68"
.
hexToBytes
()
).
packet
.
readBytes
().
toUHexString
())
println
(
"01ee6426-5ff1-4cf0-8278-e8634d2909e"
.
toByteArray
().
toUHexString
())
"5A 25 2F 36 61 38 35 32 66 64 65 2D 38 32 38 35 2D 34 33 35 31 2D 61 65 65 38 2D 35 34 65 37 35 65 65 32 65 61 37 63 60 00 68 80 80 08 20 01"
.
printStringFromHex
()
"25 2F "
.
hexToBytes
().
read
{
println
(
readUnsignedVarInt
())
}
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/UploadGroupImage.kt
→
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/
action/
UploadGroupImage.kt
View file @
28859056
@
file
:
Suppress
(
"EXPERIMENTAL_API_USAGE"
,
"EXPERIMENTAL_UNSIGNED_LITERALS"
)
package
net.mamoe.mirai.network.protocol.tim.packet
package
net.mamoe.mirai.network.protocol.tim.packet
.action
import
kotlinx.io.core.*
import
net.mamoe.mirai.contact.Group
import
net.mamoe.mirai.contact.GroupId
import
net.mamoe.mirai.contact.GroupInternalId
import
net.mamoe.mirai.network.session
import
net.mamoe.mirai.contact.withSession
import
net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
import
net.mamoe.mirai.network.protocol.tim.packet.PacketId
import
net.mamoe.mirai.network.protocol.tim.packet.PacketVersion
import
net.mamoe.mirai.network.protocol.tim.packet.ResponsePacket
import
net.mamoe.mirai.qqAccount
import
net.mamoe.mirai.utils.ExternalImage
import
net.mamoe.mirai.utils.hexToBytes
import
net.mamoe.mirai.utils.httpPostGroupImage
import
net.mamoe.mirai.utils.io.*
import
net.mamoe.mirai.utils.readUnsignedVarInt
/**
* 图片文件过大
*/
class
OverFileSizeMaxException
:
IllegalStateException
()
/**
* 上传群图片
* 挂起直到上传完成或失败
* 失败后抛出 [OverFileSizeMaxException]
*/
suspend
fun
Group
.
uploadImage
(
image
:
ExternalImage
)
=
with
(
bot
.
network
.
session
)
{
)
=
with
Session
{
GroupImageIdRequestPacket
(
bot
.
qqAccount
,
internalId
,
image
,
sessionKey
)
.
sendAndExpect
<
GroupImageIdRequestPacket
.
Response
,
Unit
>
{
if
(
it
.
uKey
!=
null
)
{
when
(
it
.
state
)
{
GroupImageIdRequestPacket
.
Response
.
State
.
REQUIRE_UPLOAD
->
{
httpPostGroupImage
(
botAccount
=
bot
.
qqAccount
,
groupInternalId
=
internalId
,
groupId
=
GroupId
(
id
)
,
imageInput
=
image
.
input
,
inputSize
=
image
.
inputSize
,
uKeyHex
=
it
.
uKey
!!
.
toUHexString
(
""
)
)
}
}.
await
()
GroupImageIdRequestPacket
.
Response
.
State
.
ALREADY_EXISTS
->
{
}
GroupImageIdRequestPacket
.
Response
.
State
.
OVER_FILE_SIZE_MAX
->
throw
OverFileSizeMaxException
()
}
}.
join
()
}
/**
* 获取 Image Id 和上传用的一个 uKey
*/
@PacketId
(
0
x0388u
)
@PacketVersion
(
date
=
"2019.10.2
0
"
,
timVersion
=
"2.3.2.21173"
)
@PacketVersion
(
date
=
"2019.10.2
6
"
,
timVersion
=
"2.3.2.21173"
)
class
GroupImageIdRequestPacket
(
private
val
bot
:
UInt
,
private
val
groupInternalId
:
GroupInternalId
,
...
...
@@ -51,8 +72,8 @@ class GroupImageIdRequestPacket(
//小图B
// 00 00 00 07 00 00 00
// 5B
08 =后文长度-6
// 01 12 03 98 01 01 10 01 1A
// 5B
=后文长度-7
// 0
8 0
1 12 03 98 01 01 10 01 1A
// 57长度
// 08 FB D2 D8 94 02
// 10 A2 FF 8C F0 03
...
...
@@ -83,6 +104,28 @@ class GroupImageIdRequestPacket(
// 78 03
// 80 01 00
//450*298
//00 00 00 07 00 00 00
// 5D=后文-7 varint
// 08 01 12 03 98 01 01 10 01 1A
// 59 =后文长度 varint
// 08 A0 89 F7 B6 03
// 10 A2 FF 8C F0 03
// 18 00
// 22 10 01 FC 9D 6B E9 B2 D9 CD AC 25 66 73 F9 AF 6A 67
// 28 [C9 10] varint size
// 32 1A
// 58 00 51 00 56 00 51 00 58 00 47 00 55 00 47 00 38 00 57 00 5F 00 4A 00 43 00
// 38 01 48 01
// 50 [C2 03]
// 58 [AA 02]
// 60 02
// 6A 05 32 36 39 33 33
// 70 00
// 78 03
// 80 01
// 00
//大图C
// 00 00 00 07 00 00 00
// 5E 08 =后文长度-6
...
...
@@ -144,11 +187,11 @@ class GroupImageIdRequestPacket(
encryptAndWrite
(
sessionKey
)
{
writeHex
(
"00 00 00 07 00 00 00"
)
writeUVarintLVPacket
(
lengthOffset
=
{
it
-
6
})
{
writeUVarintLVPacket
(
lengthOffset
=
{
it
-
7
})
{
writeByte
(
0
x08
)
writeHex
(
"01 12 03 98 01 01 10 01 1A"
)
writeUVarintLVPacket
(
lengthOffset
=
{
it
+
1
})
{
writeUVarintLVPacket
(
lengthOffset
=
{
it
})
{
writeTUVarint
(
0
x08u
,
groupInternalId
.
value
)
writeTUVarint
(
0
x10u
,
bot
)
writeTV
(
0
x1800u
)
...
...
@@ -207,31 +250,6 @@ class GroupImageIdRequestPacket(
}.readBytes().toUHexString())
*/
}
//以下仅支持中等大小图片
/*
writeQQ(bot)
writeHex("04 00 00 00 01 01 01 00 00 68 20 00 00 00 00 00 00 00 00")
encryptAndWrite(sessionKey) {
writeHex("00 00 00 07 00 00 00 5E 08 01 12 03 98 01 01 10 01 1A")
writeHex("5A 08")
writeUVarInt(groupId)
writeUByte(0x10u)
writeUVarInt(bot)
writeHex("18 00 22 10")
writeFully(image.md5)
writeUByte(0x28u)
writeUVarInt(image.fileSize.toUInt())
writeHex("32 1A 37 00 4D 00 32 00 25 00 4C 00 31 00 56 00 32 00 7B 00 39 00 30 00 29 00 52 00")
writeHex("38 01 48 01 50")
writeUVarInt(image.width.toUInt())
writeUByte(0x58u)
writeUVarInt(image.height.toUInt())
writeHex("60 04 6A 05 32 36 36 35 36 70 00 78 03 80 01 00")
}
*/
}
companion
object
{
...
...
@@ -239,21 +257,51 @@ class GroupImageIdRequestPacket(
}
@PacketId
(
0
x0388u
)
@PacketVersion
(
date
=
"2019.10.2
0
"
,
timVersion
=
"2.3.2.21173"
)
@PacketVersion
(
date
=
"2019.10.2
6
"
,
timVersion
=
"2.3.2.21173"
)
class
Response
(
input
:
ByteReadPacket
)
:
ResponsePacket
(
input
)
{
lateinit
var
state
:
State
/**
* 访问 HTTP API 时需要使用的一个 key. 128 位
*/
var
uKey
:
ByteArray
?
=
null
enum
class
State
{
/**
* 需要上传. 此时 [uKey] 不为 `null`
*/
REQUIRE_UPLOAD
,
/**
* 服务器已有这个图片. 此时 [uKey] 为 `null`
*/
ALREADY_EXISTS
,
/**
* 图片过大. 此时 [uKey] 为 `null`
*/
OVER_FILE_SIZE_MAX
,
}
override
fun
decode
():
Unit
=
with
(
input
)
{
discardExact
(
6
)
//00 00 00 05 00 00
val
length
=
remaining
-
128
-
14
if
(
length
<
0
)
{
//服务器已经有这个图片了
state
=
if
(
readUShort
().
toUInt
()
==
0
x0025u
)
{
State
.
OVER_FILE_SIZE_MAX
}
else
{
State
.
ALREADY_EXISTS
}
//图片过大 00 25 12 03 98 01 01 08 9B A4 DC 92 06 10 01 1A 1B 08 00 10 C5 01 1A 12 6F 76 65 72 20 66 69 6C 65 20 73 69 7A 65 20 6D 61 78 20 00
//图片过大 00 25 12 03 98 01 01 08 9B A4 DC 92 06 10 01 1A 1B 08 00 10 C5 01 1A 12 6F 76 65 72 20 66 69 6C 65 20 73 69 7A 65 20 6D 61 78 20 00
//图片已有 00 3F 12 03 98 01 01 08 9B A4 DC 92 06 10 01 1A 35 08 00 10 00 20 01 2A 1F 0A 10 24 66 B9 6B E8 58 FE C0 12 BD 1E EC CB 74 A8 8E 10 04 18 83 E2 AF 01 20 80 3C 28 E0 21 30 EF 9A 88 B9 0B 38 50 48 90 D7 DA B0 08
//debugPrint("后文")
return
@
with
}
discardExact
(
length
)
uKey
=
readBytes
(
128
)
state
=
State
.
REQUIRE_UPLOAD
//} else {
// println("服务器已经有了这个图片")
//println("后文 = ${readRemainingBytes().toUHexString()}")
...
...
@@ -273,11 +321,3 @@ class GroupImageIdRequestPacket(
}
}
}
\ No newline at end of file
fun
main
()
{
(
"A2 FF 8C F0 03"
).
hexToBytes
().
read
{
println
(
readUnsignedVarInt
())
}
println
(
0
x40
)
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/event/ServerEventPackets.kt
View file @
28859056
...
...
@@ -20,7 +20,7 @@ data class EventPacketIdentity(
val
to
:
UInt
,
//对于好友消息, 这个是bot
internal
val
uniqueId
:
IoBuffer
//8
)
{
override
fun
toString
():
String
=
"(
from=$from, to=
$to)"
override
fun
toString
():
String
=
"(
$from->
$to)"
}
fun
BytePacketBuilder
.
writeEventPacketIdentity
(
identity
:
EventPacketIdentity
)
=
with
(
identity
)
{
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt
View file @
28859056
...
...
@@ -18,17 +18,26 @@ class ExternalImage(
val
width
:
Int
,
val
height
:
Int
,
val
md5
:
ByteArray
,
val
f
ormat
:
String
,
imageF
ormat
:
String
,
val
input
:
Input
,
val
inputSize
:
Long
)
{
private
val
format
:
String
init
{
if
(
imageFormat
==
"JPEG"
||
imageFormat
==
"jpeg"
)
{
//必须转换
this
.
format
=
"jpg"
}
else
{
this
.
format
=
imageFormat
}
}
/**
* 用于发送消息的 [ImageId]
*/
val
groupImageId
:
ImageId
by
lazy
{
ImageId
(
"{${md5[0..3]}-${md5[4..5]}-${md5[6..7]}-${md5[8..9]}-${md5[10..15]}}.$format"
)
}
override
fun
toString
():
String
=
"[ExternalImage(${width}x$
{height}
$format)]"
override
fun
toString
():
String
=
"[ExternalImage(${width}x$
height
$format)]"
}
private
operator
fun
ByteArray
.
get
(
range
:
IntRange
):
String
=
buildString
{
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/PlatformUtils.kt
View file @
28859056
...
...
@@ -10,7 +10,7 @@ import io.ktor.http.HttpStatusCode
import
io.ktor.http.URLProtocol
import
io.ktor.http.userAgent
import
kotlinx.io.core.Input
import
net.mamoe.mirai.contact.GroupI
nternalI
d
import
net.mamoe.mirai.contact.GroupId
/**
* 时间戳
...
...
@@ -59,52 +59,95 @@ suspend fun httpPostFriendImage(
uKeyHex
:
String
,
imageInput
:
Input
,
inputSize
:
Long
):
Boolean
=
(
httpClient
.
postImage
(
imageInput
,
inputSize
,
uKeyHex
)
{
url
{
parameters
[
"htcmd"
]
=
"0x6ff0070"
parameters
[
"uin"
]
=
botAccount
.
toLong
().
toString
()
}
}
as
HttpStatusCode
).
value
.
also
{
println
(
it
)
}
==
200
):
Boolean
=
(
httpClient
.
postImage
(
htcmd
=
"0x6ff0070"
,
uin
=
botAccount
,
groupcode
=
null
,
imageInput
=
imageInput
,
inputSize
=
inputSize
,
uKeyHex
=
uKeyHex
)
as
HttpStatusCode
).
value
.
also
{
println
(
it
)
}
==
200
/*
httpPostFriendImageOld(uKeyHex, botAccount, imageInput.readBytes().toReadPacket())
expect suspend fun httpPostFriendImageOld(
uKeyHex: String,
botNumber: UInt,
imageData: ByteReadPacket
): Boolean
*/
/**
* 上传群图片
*/
@Suppress
(
"DuplicatedCode"
)
suspend
fun
httpPostGroupImage
(
botAccount
:
UInt
,
groupI
nternalId
:
GroupInternal
Id
,
groupI
d
:
Group
Id
,
uKeyHex
:
String
,
imageInput
:
Input
,
inputSize
:
Long
):
Boolean
=
(
httpClient
.
postImage
(
imageInput
,
inputSize
,
uKeyHex
)
{
url
{
):
Boolean
=
(
httpClient
.
postImage
(
htcmd
=
"0x6ff0071"
,
uin
=
botAccount
,
groupcode
=
groupId
,
imageInput
=
imageInput
,
inputSize
=
inputSize
,
uKeyHex
=
uKeyHex
)
as
HttpStatusCode
).
value
.
also
{
println
(
it
)
}
==
200
/* = (httpClient.post {
url {
protocol = URLProtocol.HTTP
host = "htdata2.qq.com"
path("cgi-bin/httpconn")
parameters["htcmd"] = "0x6ff0071"
parameters["ver"] = "5603"
parameters["term"] = "pc"
parameters["ukey"] = uKeyHex
parameters["filesize"] = inputSize.toString()
parameters["range"] = 0.toString()
parameters["uin"] = botAccount.toLong().toString()
parameters
[
"groupcode"
]
=
groupInternal
Id
.
value
.
toLong
().
toString
()
}
}
as
HttpStatusCode
).
value
.
also
{
println
(
it
)
}
==
200
parameters["groupcode"] = group
Id.value.toLong().toString()
// userAgent("QQClient")
}
println(url.buildString())
body = ByteArrayContent(imageInput.readBytes())
//configureBody(inputSize, imageInput)
} as HttpStatusCode).value.also { println(it) } == 200*/
@Suppress
(
"SpellCheckingInspection"
)
private
suspend
inline
fun
<
reified
T
>
HttpClient
.
postImage
(
htcmd
:
String
,
uin
:
UInt
,
groupcode
:
GroupId
?,
imageInput
:
Input
,
inputSize
:
Long
,
uKeyHex
:
String
,
block
:
HttpRequestBuilder
.()
->
Unit
=
{}
uKeyHex
:
String
):
T
=
post
{
url
{
protocol
=
URLProtocol
.
HTTP
host
=
"htdata2.qq.com"
path
(
"cgi-bin/httpconn"
)
parameters
[
"htcmd"
]
=
htcmd
parameters
[
"uin"
]
=
uin
.
toLong
().
toString
()
if
(
groupcode
!=
null
)
{
parameters
[
"groupcode"
]
=
groupcode
.
value
.
toLong
().
toString
()
}
parameters
[
"term"
]
=
"pc"
parameters
[
"ver"
]
=
"5603"
parameters
[
"file
zis
e"
]
=
inputSize
.
toString
()
parameters
[
"file
siz
e"
]
=
inputSize
.
toString
()
parameters
[
"range"
]
=
0
.
toString
()
parameters
[
"ukey"
]
=
uKeyHex
userAgent
(
"QQClient"
)
}
block
()
println
(
url
.
buildString
())
configureBody
(
inputSize
,
imageInput
)
}
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/ByteArrayUtil.kt
View file @
28859056
...
...
@@ -6,6 +6,7 @@ import kotlinx.io.charsets.Charset
import
kotlinx.io.charsets.Charsets
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.String
import
kotlinx.io.core.use
import
kotlin.jvm.JvmOverloads
@JvmOverloads
...
...
@@ -34,6 +35,6 @@ fun UByteArray.toUHexString(separator: String = " "): String = this.joinToString
fun
ByteArray
.
toReadPacket
()
=
ByteReadPacket
(
this
)
fun
<
R
>
ByteArray
.
read
(
t
:
ByteReadPacket
.()
->
R
):
R
=
this
.
toReadPacket
().
run
(
t
)
fun
<
R
>
ByteArray
.
read
(
t
:
ByteReadPacket
.()
->
R
):
R
=
this
.
toReadPacket
().
use
(
t
)
fun
ByteArray
.
cutTail
(
length
:
Int
):
ByteArray
=
this
.
copyOfRange
(
0
,
this
.
size
-
length
)
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/InputUtils.kt
View file @
28859056
...
...
@@ -5,9 +5,7 @@ package net.mamoe.mirai.utils.io
import
kotlinx.io.core.*
import
net.mamoe.mirai.network.protocol.tim.TIMProtocol
import
net.mamoe.mirai.network.protocol.tim.packet.*
import
net.mamoe.mirai.network.protocol.tim.packet.action.CanAddFriendPacket
import
net.mamoe.mirai.network.protocol.tim.packet.action.SendFriendMessagePacket
import
net.mamoe.mirai.network.protocol.tim.packet.action.SendGroupMessagePacket
import
net.mamoe.mirai.network.protocol.tim.packet.action.*
import
net.mamoe.mirai.network.protocol.tim.packet.event.ServerEventPacket
import
net.mamoe.mirai.network.protocol.tim.packet.login.*
import
net.mamoe.mirai.utils.MiraiLogger
...
...
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/network/protocol/tim/packet/PacketInternalJvm.kt
View file @
28859056
...
...
@@ -6,6 +6,8 @@ import kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.IoBuffer
import
net.mamoe.mirai.utils.io.toUHexString
import
java.lang.reflect.Field
import
kotlin.properties.ReadWriteProperty
import
kotlin.reflect.jvm.kotlinProperty
internal
object
PacketNameFormatter
{
@JvmStatic
...
...
@@ -22,7 +24,7 @@ internal object PacketNameFormatter {
}
}
private
object
IgnoreIdList
:
List
<
String
>
by
listOf
(
private
object
IgnoreIdList
Equals
:
List
<
String
>
by
listOf
(
"idHex"
,
"id"
,
"packetId"
,
...
...
@@ -32,18 +34,32 @@ private object IgnoreIdList : List<String> by listOf(
"idByteArray"
,
"encoded"
,
"packet"
,
"EMPTY_ID_HEX"
,
"input"
,
"sequenceId"
,
"output"
,
"bot"
,
"UninitializedByteReadPacket"
,
"sessionKey"
)
private
object
IgnoreIdListInclude
:
List
<
String
>
by
listOf
(
"Companion"
,
"EMPTY_ID_HEX"
,
"input"
,
"output"
,
"this\$
0
"
,
"this\$"
,
"\$\$delegatedProperties"
,
"UninitializedByteReadPacket"
,
"sessionKey"
"\$FU"
,
"RefVolatile"
)
@Suppress
(
"UNCHECKED_CAST"
)
internal
actual
fun
Packet
.
packetToString
():
String
=
PacketNameFormatter
.
adjustName
(
this
::
class
.
simpleName
+
"(${this.idHexString})"
)
+
this
::
class
.
java
.
allDeclaredFields
.
filterNot
{
it
.
name
in
IgnoreIdList
/*|| "delegate" in it.name|| "$" in it.name */
}
.
filterNot
{
field
->
IgnoreIdListEquals
.
any
{
field
.
name
.
replace
(
"\$delegate"
,
""
)
==
it
}
||
IgnoreIdListInclude
.
any
{
it
in
field
.
name
}
}
.
joinToString
(
", "
,
"{"
,
"}"
)
{
it
.
isAccessible
=
true
it
.
name
.
replace
(
"\$delegate"
,
""
)
+
"="
+
it
.
get
(
this
).
let
{
value
->
...
...
@@ -55,6 +71,7 @@ internal actual fun Packet.packetToString(): String = PacketNameFormatter.adjust
//is ByteReadPacket -> value.copy().readBytes().toUHexString()
is
IoBuffer
->
"[IoBuffer(${value.readRemaining})]"
is
Lazy
<
*
>
->
"[Lazy]"
is
ReadWriteProperty
<
*
,
*
>
->
(
value
as
ReadWriteProperty
<
Packet
,
*
>).
getValue
(
this
,
it
.
kotlinProperty
!!
)
else
->
value
.
toString
()
}
}
...
...
mirai-core/src/jvmTest/kotlin/TestGroupImage.kt
View file @
28859056
...
...
@@ -2,18 +2,18 @@
import
net.mamoe.mirai.contact.groupId
import
net.mamoe.mirai.contact.toInternalId
import
net.mamoe.mirai.network.protocol.tim.packet.GroupImageIdRequestPacket
import
net.mamoe.mirai.network.protocol.tim.packet.
action.
GroupImageIdRequestPacket
import
net.mamoe.mirai.utils.hexToBytes
import
net.mamoe.mirai.utils.io.readRemainingBytes
import
net.mamoe.mirai.utils.io.toUHexString
import
net.mamoe.mirai.utils.to
Mirai
Image
import
net.mamoe.mirai.utils.to
External
Image
import
java.io.File
import
javax.imageio.ImageIO
val
sessionKey
:
ByteArray
=
"F1 ED F2 BC 55 17 7B FE CC CC F3 08 D1 8D A7 0E"
.
hexToBytes
()
fun
main
()
=
println
({
val
image
=
ImageIO
.
read
(
File
(
"C:\\Users\\Him18\\Desktop\\test2.gif"
).
readBytes
().
inputStream
()).
to
Mirai
Image
(
"png"
)
val
image
=
ImageIO
.
read
(
File
(
"C:\\Users\\Him18\\Desktop\\test2.gif"
).
readBytes
().
inputStream
()).
to
External
Image
(
"png"
)
// File("C:\\Users\\Him18\\Desktop\\test2.jpg").writeBytes(image.fileData.readBytes())
GroupImageIdRequestPacket
(
...
...
mirai-core/src/jvmTest/kotlin/TestImageFile.kt
0 → 100644
View file @
28859056
import
java.io.File
fun
main
()
{
val
file
=
File
(
"C:\\Users\\Him18\\Desktop\\lemon.png"
)
println
(
file
.
inputStream
().
readAllBytes
().
size
)
println
(
file
.
length
())
}
\ No newline at end of file
mirai-debug/build.gradle
View file @
28859056
plugins
{
id
'application'
id
'org.openjfx.javafxplugin'
version
'0.0.8'
}
apply
plugin:
"kotlin"
apply
plugin:
"java"
javafx
{
version
=
"11"
modules
=
[
'javafx.controls'
]
}
dependencies
{
implementation
project
(
':mirai-core'
)
compile
files
(
'./lib/jpcap.jar'
)
implementation
files
(
'./lib/jpcap.jar'
)
api
group:
'org.jetbrains.kotlin'
,
name:
'kotlin-stdlib-jdk8'
,
version:
kotlin_version
api
group:
'org.jetbrains.kotlinx'
,
name:
'kotlinx-io'
,
version:
kotlinxio_version
api
group:
'org.jetbrains.kotlin'
,
name:
'kotlin-reflect'
,
version:
kotlin_version
// https://mvnrepository.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-javafx
compile
group:
'org.jetbrains.kotlinx'
,
name:
'kotlinx-coroutines-javafx'
,
version:
'1.3.2'
implementation
'org.pcap4j:pcap4j-distribution:1.8.2'
implementation
'no.tornado:tornadofx:1.7.17'
}
mainClassName
=
'Application'
tasks
.
withType
(
JavaCompile
)
{
options
.
encoding
=
"UTF-8"
}
mirai-debug/src/main/java/HexComparator.kt
View file @
28859056
@
file
:
Suppress
(
"ObjectPropertyName"
,
"unused"
,
"NonAsciiCharacters"
,
"MayBeConstant"
)
import
net.mamoe.mirai.utils.io.printCompareHex
import
java.util.*
fun
main
()
{
// println(HexComparator.printColorize("00 00 00 25 00 08 00 02 00 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 76 E4 B8 DD E7 86 74 F2 64 55 AD 9A EB 2F B9 DF F1 7F 8C 28 00 0B 78 14 5D A2 F5 CB 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D A2 F5 CA 9D 26 CB 5E 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E4 BD A0 E5 A5 BD 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00"))
val
scanner
=
Scanner
(
System
.
`in`
)
while
(
true
)
{
println
(
"Hex1: "
)
val
hex1
=
scanner
.
nextLine
()
val
hex1
=
readLine
()
!!
println
(
"Hex2: "
)
val
hex2
=
scanner
.
nextLine
()
val
hex2
=
readLine
()
!!
println
(
"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
)
println
(
printCompareHex
(
hex1
,
hex2
))
println
()
...
...
mirai-debug/src/main/java/PacketDebuger.kt
View file @
28859056
...
...
@@ -3,9 +3,7 @@
import
Main.localIp
import
Main.qq
import
Main.sessionKey
import
jpcap.JpcapCaptor
import
jpcap.packet.IPPacket
import
jpcap.packet.UDPPacket
import
com.sun.jna.Platform
import
kotlinx.io.core.discardExact
import
kotlinx.io.core.readBytes
import
kotlinx.io.core.readUInt
...
...
@@ -20,6 +18,12 @@ import net.mamoe.mirai.utils.decryptBy
import
net.mamoe.mirai.utils.hexToBytes
import
net.mamoe.mirai.utils.io.*
import
net.mamoe.mirai.utils.toUHexString
import
org.pcap4j.core.BpfProgram.BpfCompileMode
import
org.pcap4j.core.PacketListener
import
org.pcap4j.core.PcapNetworkInterface
import
org.pcap4j.core.PcapNetworkInterface.PromiscuousMode
import
org.pcap4j.core.Pcaps
/**
* 抓包分析器.
...
...
@@ -30,11 +34,31 @@ import net.mamoe.mirai.utils.toUHexString
object
Main
{
@JvmStatic
fun
main
(
args
:
Array
<
String
>)
{
val
devices
=
JpcapCaptor
.
getDeviceList
()
val
jpcap
:
JpcapCaptor
?
val
caplen
=
4096
val
promiscCheck
=
true
jpcap
=
JpcapCaptor
.
openDevice
(
devices
[
0
],
caplen
,
promiscCheck
,
50
)
val
nif
:
PcapNetworkInterface
=
Pcaps
.
findAllDevs
()[
0
]
println
(
nif
.
name
+
"("
+
nif
.
description
+
")"
)
val
handle
=
nif
.
openLive
(
65536
,
PromiscuousMode
.
PROMISCUOUS
,
3000
)
handle
.
setFilter
(
"src $localIp && udp port 8000"
,
BpfCompileMode
.
OPTIMIZE
)
val
listener
=
PacketListener
{
println
(
it
.
rawData
.
toUHexString
())
println
()
}
handle
.
loop
(
Int
.
MAX_VALUE
,
listener
)
val
ps
=
handle
.
stats
println
(
"ps_recv: "
+
ps
.
numPacketsReceived
)
println
(
"ps_drop: "
+
ps
.
numPacketsDropped
)
println
(
"ps_ifdrop: "
+
ps
.
numPacketsDroppedByIf
)
if
(
Platform
.
isWindows
())
{
println
(
"bs_capt: "
+
ps
.
numPacketsCaptured
)
}
handle
.
close
()
/*
while (true) {
assert(jpcap != null)
val pk = jpcap!!.packet ?: continue
...
...
@@ -65,6 +89,8 @@ object Main {
//pk.dst_ip
}
}
*/
}
/**
...
...
@@ -79,9 +105,9 @@ object Main {
* 6. 运行到 `mov eax,dword ptr ss:[ebp+10]`
* 7. 查看内存, 从 `eax` 开始的 16 bytes 便是 `sessionKey`
*/
val
sessionKey
:
ByteArray
=
"
1D 1E 71 68 B9 41 FD 5B F3 5A 3F 71 87 B5 86 CB
"
.
hexToBytes
()
val
sessionKey
:
ByteArray
=
"
0D D7 C8 06 C6 C1 40 FE A8 3B CF 81 EE DF 69 83
"
.
hexToBytes
()
const
val
qq
:
UInt
=
1040400290
u
const
val
localIp
=
"192.168.3."
const
val
localIp
=
"192.168.3.
10
"
fun
dataReceived
(
data
:
ByteArray
)
{
//println("raw = " + data.toUHexString())
...
...
@@ -159,12 +185,14 @@ object Main {
return
@
read
}
println
(
"fixVer2="
+
when
(
val
flag
=
readByte
().
toInt
())
{
println
(
"fixVer2="
+
when
(
val
flag
=
readByte
().
toInt
())
{
2
->
byteArrayOf
(
2
)
+
readBytes
(
TIMProtocol
.
fixVer2
.
hexToBytes
().
size
-
1
)
4
->
byteArrayOf
(
4
)
+
readBytes
(
TIMProtocol
.
fixVer2
.
hexToBytes
().
size
-
1
+
8
)
//8个0
0
->
byteArrayOf
(
0
)
+
readBytes
(
2
)
else
->
error
(
"unknown fixVer2 flag=$flag. Remaining =${readBytes().toUHexString()}"
)
}.
toUHexString
())
}.
toUHexString
()
)
//39 27 DC E2 04 00 00 00 00 00 00 00 1E 0E 89 00 00 01 05 0F 05 0F 00 00 00 00 00 00 00 00 00 00 00 00 00 3E 03 3F A2 00 00 00 00 00 00 00 00 00 00 00
...
...
mirai-demos/mirai-demo-1/src/main/java/demo1/Main.kt
View file @
28859056
...
...
@@ -17,8 +17,8 @@ import net.mamoe.mirai.message.ImageId
import
net.mamoe.mirai.message.PlainText
import
net.mamoe.mirai.message.firstOrNull
import
net.mamoe.mirai.network.protocol.tim.packet.OutgoingRawPacket
import
net.mamoe.mirai.network.protocol.tim.packet.action.uploadImage
import
net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult
import
net.mamoe.mirai.network.protocol.tim.packet.uploadImage
import
net.mamoe.mirai.network.session
import
net.mamoe.mirai.qqAccount
import
net.mamoe.mirai.utils.*
...
...
@@ -99,25 +99,27 @@ suspend fun main() {
}
"上传好友图片"
in
it
.
message
->
withTimeoutOrNull
(
5000
)
{
val
filename
=
it
.
message
.
toString
().
substringAfter
(
"上传好友图片"
)
val
id
=
1040400290
u
.
qq
()
.
uploadImage
(
File
(
"C:\\Users\\Him18\\Desktop\\$
{it.message.toString().substringAfter("
上传好友图片
")}"
).
toMirai
Image
())
.
uploadImage
(
File
(
"C:\\Users\\Him18\\Desktop\\$
filename"
).
toExternal
Image
())
it
.
reply
(
id
.
value
)
delay
(
100
0
)
delay
(
100
)
it
.
reply
(
Image
(
id
))
}
"上传群图片"
in
it
.
message
->
withTimeoutOrNull
(
5000
)
{
val
filename
=
it
.
message
.
toString
().
substringAfter
(
"上传群图片"
)
val
image
=
File
(
"C:\\Users\\Him18\\Desktop\\$
{it.message.toString().substringAfter("
上传群图片
")}
"
).
to
Mirai
Image
()
580266363
u
.
group
().
uploadImage
(
image
)
"C:\\Users\\Him18\\Desktop\\$
filename
"
).
to
External
Image
()
920503456
u
.
group
().
uploadImage
(
image
)
it
.
reply
(
image
.
groupImageId
.
value
)
delay
(
100
0
)
580266363
u
.
group
().
sendMessage
(
Image
(
image
.
groupImageId
))
delay
(
100
)
920503456
u
.
group
().
sendMessage
(
Image
(
image
.
groupImageId
))
}
"发群图片"
in
it
.
message
->
{
580266363
u
.
group
().
sendMessage
(
Image
(
ImageId
(
it
.
message
.
toString
().
substringAfter
(
"发群图片"
))))
920503456
u
.
group
().
sendMessage
(
Image
(
ImageId
(
it
.
message
.
toString
().
substringAfter
(
"发群图片"
))))
}
"发好友图片"
in
it
.
message
->
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment