diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt index 17e2711c4..842c889ef 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt @@ -17,9 +17,7 @@ import net.mamoe.mirai.message.Message import net.mamoe.mirai.message.defaults.MessageChain import net.mamoe.mirai.network.RobotNetworkHandler.* import net.mamoe.mirai.network.packet.* -import net.mamoe.mirai.network.packet.action.ClientSendFriendMessagePacket -import net.mamoe.mirai.network.packet.action.ServerSendFriendMessageResponsePacket -import net.mamoe.mirai.network.packet.action.ServerSendGroupMessageResponsePacket +import net.mamoe.mirai.network.packet.action.* import net.mamoe.mirai.network.packet.login.* import net.mamoe.mirai.task.MiraiThreadPool import net.mamoe.mirai.utils.* @@ -31,6 +29,7 @@ import java.util.* import java.util.concurrent.CompletableFuture import java.util.concurrent.ScheduledFuture import java.util.concurrent.TimeUnit +import java.util.function.Supplier import javax.imageio.ImageIO import kotlin.reflect.KClass @@ -545,16 +544,87 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable { } internal var gtk: Int = 0 - override fun onPacketReceived(packet: ServerPacket) { + private val addFriendSessions = Collections.synchronizedCollection(mutableListOf()) + override fun onPacketReceived(packet: ServerPacket) { + when (packet) { + is ServerCanAddFriendResponsePacket -> { + this.addFriendSessions.forEach { + it.onPacketReceived(packet) + } + } + else -> { + } + } } - fun addFriend(qqNumber: Long): Unit { + fun addFriend(qqNumber: Long, message: Supplier) { + addFriend(qqNumber, lazy { message.get() }) + } + @JvmSynthetic + fun addFriend(qqNumber: Long, message: Lazy = lazyOf("")): CompletableFuture { + val future = CompletableFuture() + val session = AddFriendSession(qqNumber, future, message) + addFriendSessions.add(session) + session.sendAddRequest(); + return future } override fun close() { } + + private inner class AddFriendSession( + private val qq: Long, + private val future: CompletableFuture, + private val message: Lazy + ) : Closeable { + lateinit var id: ByteArray + + fun onPacketReceived(packet: ServerPacket) { + if (!::id.isInitialized) { + return + } + + when (packet) { + is ServerCanAddFriendResponsePacket -> { + if (!(packet.idByteArray[2] == id[0] && packet.idByteArray[3] == id[1])) { + return + } + + when (packet.state) { + ServerCanAddFriendResponsePacket.State.FAILED -> { + future.complete(AddFriendResult.FAILED) + close() + } + + ServerCanAddFriendResponsePacket.State.ALREADY_ADDED -> { + future.complete(AddFriendResult.ALREADY_ADDED) + close() + } + + ServerCanAddFriendResponsePacket.State.REQUIRE_VERIFICATION -> { + sendPacket(ClientAddFriendPacket(robot.account.qqNumber, qq, sessionKey)) + } + + ServerCanAddFriendResponsePacket.State.NOT_REQUIRE_VERIFICATION -> { + + } + } + } + + + } + } + + fun sendAddRequest() { + sendPacket(ClientCanAddFriendPacket(robot.account.qqNumber, qq, sessionKey).also { this.id = it.packetIdLast }) + } + + override fun close() { + addFriendSessions.remove(this) + } + } } } \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt index bea51f94c..3427bdc5d 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt @@ -30,7 +30,6 @@ abstract class ClientPacket : ByteArrayDataOutputStream(), Packet { } catch (e: IOException) { throw RuntimeException(e) } - } @Throws(IOException::class) diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/GradeInfo.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/GradeInfo.kt index 6288a255c..c208c07f0 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/GradeInfo.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/GradeInfo.kt @@ -26,10 +26,6 @@ class ClientAccountInfoRequestPacket( it.writeByte(0x00) } } - - override fun getFixedId(): String { - return this.idHex + " ?? ??" - } } @PacketId("00 5C") diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Heartbeat.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Heartbeat.kt index b9d6c41a8..9fcd36304 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Heartbeat.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Heartbeat.kt @@ -22,10 +22,6 @@ class ClientHeartbeatPacket( it.writeHex("00 01 00 01") } } - - override fun getFixedId(): String { - return this.idHex + " ?? ??" - } } class ServerHeartbeatResponsePacket(input: DataInputStream) : ServerPacket(input) \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/SKey.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/SKey.kt index 8a42d9394..30f8c16b3 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/SKey.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/SKey.kt @@ -23,10 +23,6 @@ class ClientSKeyRequestPacket( it.writeHex("33 00 05 00 08 74 2E 71 71 2E 63 6F 6D 00 0A 71 75 6E 2E 71 71 2E 63 6F 6D 00 0C 71 7A 6F 6E 65 2E 71 71 2E 63 6F 6D 00 0C 6A 75 62 61 6F 2E 71 71 2E 63 6F 6D 00 09 6B 65 2E 71 71 2E 63 6F 6D") } } - - override fun getFixedId(): String { - return this.idHex + " ?? ??" - } } /** diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt index d21b3fc72..eaed7769f 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt @@ -1,7 +1,7 @@ package net.mamoe.mirai.network.packet -import lombok.Getter import net.mamoe.mirai.network.packet.PacketNameFormatter.adjustName +import net.mamoe.mirai.network.packet.action.ServerCanAddFriendResponsePacket import net.mamoe.mirai.network.packet.action.ServerSendFriendMessageResponsePacket import net.mamoe.mirai.network.packet.action.ServerSendGroupMessageResponsePacket import net.mamoe.mirai.network.packet.login.* @@ -12,9 +12,11 @@ import java.io.DataInputStream * @author Him188moe */ abstract class ServerPacket(val input: DataInputStream) : Packet { - @Getter var idHex: String + var idByteArray: ByteArray//fixed 4 size + + var encoded: Boolean = false init { @@ -24,6 +26,12 @@ abstract class ServerPacket(val input: DataInputStream) : Packet { } catch (e: NullPointerException) { "" } + + idByteArray = if (idHex.isEmpty()) { + byteArrayOf(0, 0, 0, 0) + } else { + idHex.hexToBytes() + } } fun

P.setId(idHex: String): P { @@ -101,6 +109,8 @@ abstract class ServerPacket(val input: DataInputStream) : Packet { "00 CD" -> ServerSendFriendMessageResponsePacket(stream) "00 02" -> ServerSendGroupMessageResponsePacket(stream) + "00 A7" -> ServerCanAddFriendResponsePacket(stream) + else -> throw IllegalArgumentException(idHex) } }.apply { this.idHex = idHex } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/action/AddContact.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/action/AddContact.kt new file mode 100644 index 000000000..d784c4f0b --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/action/AddContact.kt @@ -0,0 +1,133 @@ +package net.mamoe.mirai.network.packet.action + +import net.mamoe.mirai.network.Protocol +import net.mamoe.mirai.network.packet.* +import net.mamoe.mirai.utils.getRandomByteArray +import net.mamoe.mirai.utils.toUHexString +import java.io.DataInputStream +import java.util.* + +/** + * 向服务器检查是否可添加某人为好友 + * + * @author Him188moe + */ +@PacketId("00 A7") +@ExperimentalUnsignedTypes +class ClientCanAddFriendPacket( + val robot: Long, + val qq: Long, + val sessionKey: ByteArray +) : ClientPacket() { + val packetIdLast = getRandomByteArray(2) + + override fun getFixedId(): String { + return idHex + " " + packetIdLast.toUHexString() + } + + override fun encode() { + this.write(packetIdLast)//id, 2bytes + + this.writeQQ(robot) + this.writeHex(Protocol.fixVer2) + this.encryptAndWrite(sessionKey) { + it.writeQQ(qq) + } + } +} + +@PacketId("00 A7") +class ServerCanAddFriendResponsePacket(input: DataInputStream) : ServerPacket(input) { + lateinit var state: State + + enum class State { + ALREADY_ADDED, + REQUIRE_VERIFICATION, + NOT_REQUIRE_VERIFICATION, + FAILED, + } + + @ExperimentalUnsignedTypes + override fun decode() { + val data = input.goto(0).readAllBytes() + if (data.size == 99) { + state = State.ALREADY_ADDED + return + } + state = when (data[data.size - 1].toUInt()) { + 0u -> State.NOT_REQUIRE_VERIFICATION + 1u -> State.REQUIRE_VERIFICATION + 99u -> State.ALREADY_ADDED + 3u, 4u -> State.FAILED + else -> throw IllegalArgumentException(Arrays.toString(data)) + } + } + + + @PacketId("00 A7") + class Encrypted(inputStream: DataInputStream) : ServerPacket(inputStream) { + fun decrypt(sessionKey: ByteArray): ServerCanAddFriendResponsePacket { + return ServerCanAddFriendResponsePacket(this.decryptBy(sessionKey)).setId(this.idHex) + } + } +} + + +/** + * 请求添加好友 + */ +@PacketId("00 AE") +@ExperimentalUnsignedTypes +class ClientAddFriendPacket( + val robot: Long, + val qq: Long, + val sessionKey: ByteArray +) : ClientPacket() { + val packetIdLast = getRandomByteArray(2) + + override fun getFixedId(): String { + return idHex + " " + packetIdLast.toUHexString() + } + + override fun encode() { + this.write(packetIdLast)//id, 2bytes + + this.writeQQ(robot) + this.writeHex(Protocol.fixVer2) + this.encryptAndWrite(sessionKey) { + it.writeHex("01 00 01") + it.writeQQ(qq) + } + } + +} + + +class ServerAddFriendResponsePacket(input: DataInputStream) : ServerAddContactResponsePacket(input) + +class ServerAddGroupResponsePacket(input: DataInputStream) : ServerAddContactResponsePacket(input) + +/** + * 添加好友/群的回复 + */ +open class ServerAddContactResponsePacket(input: DataInputStream) : ServerPacket(input) { + + + class Raw(input: DataInputStream) : ServerPacket(input) { + + override fun decode() { + + } + + fun distribute(): ServerAddContactResponsePacket { + + TODO() + } + + class Encrypted(input: DataInputStream) : ServerPacket(input) { + fun decrypt(sessionKey: ByteArray): Raw = Raw(this.decryptBy(sessionKey)) + } + } + + +} \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/action/AddFriendResult.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/action/AddFriendResult.kt new file mode 100644 index 000000000..b76ff64f5 --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/action/AddFriendResult.kt @@ -0,0 +1,21 @@ +package net.mamoe.mirai.network.packet.action + +/** + * 添加好友结果 + */ +enum class AddFriendResult { + /** + * 等待对方处理 + */ + WAITING_FOR_AGREEMENT, + + /** + * 和对方已经是好友了 + */ + ALREADY_ADDED, + + /** + * 对方设置为不添加好友等 + */ + FAILED, +} \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientChangeOnlineStatusPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientChangeOnlineStatusPacket.kt index d7b63cbc9..d817bce50 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientChangeOnlineStatusPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientChangeOnlineStatusPacket.kt @@ -17,9 +17,6 @@ class ClientChangeOnlineStatusPacket( private val loginStatus: ClientLoginStatus ) : ClientPacket() { - override fun getFixedId(): String { - return this.idHex + " ?? ??"; - } override fun encode() { this.writeRandom(2)//part of packet id