Merge remote-tracking branch 'origin/master'

# Conflicts:
#	mirai-core/src/main/java/net/mamoe/mirai/Robot.java
This commit is contained in:
liujiahua123123 2019-09-02 10:55:25 +08:00
commit 1c8e5679a1
22 changed files with 386 additions and 140 deletions

View File

@ -3,9 +3,9 @@
一个以<b>TIM QQ协议</b>驱动的JAVA(+Kotlin) QQ机器人服务端核心
我们坚持免费与开源
项目处于快速开发阶段, 现在已经可以接受和发送群聊/好友消息.
协议来自网络上开源项目
一切开发旨在学习, 请勿用于非法用途
项目处于快速开发阶段, 现在已经可以接受和发送群聊/好友消息.
协议来自网络上开源项目
一切开发旨在学习, 请勿用于非法用途
<br>
@ -14,8 +14,8 @@ It use protocols from <i>TIM QQ</i>, that is, it won't be affected by the close
The project is all for <b>learning proposes</b> and still in <b>developing stage</b><br>
### 代码结构
Network部分使用 Kotlin 完成(因为kt有对 unsigned byte 的支持).
与插件相关性强(或其他在二次开发中容易接触的部分)均使用 Java 完成,
Network部分使用 Kotlin 完成(因为kt有对 unsigned byte 的支持).
与插件相关性强(或其他在二次开发中容易接触的部分)均使用 Java 完成,
同时也会针对kotlin提供优化的方法调用. 例如对'+'操作符的重载: `String+BufferedImage+QQ.At+Face+URL+String+File` 将会被自动处理为String消息.
@ -24,14 +24,14 @@ Network部分使用 Kotlin 完成(因为kt有对 unsigned byte 的支持).
- [ ] 插件(Plugin)模块 **(Working on)**
- [x] Network - Touch
- [X] Network - Login
- [X] Network - Session
- [ ] Network - Verification Code (Low priority)
- [X] Network - Message Receiving
- [X] Network - Message Sending
- [ ] Network - Events **(Working on)**
- [ ] Robot - Friend/group list
- [ ] Message Section **(Working on)**
- [ ] Contact
- [X] Network - Session
- [ ] Network - Verification Code (Low priority)
- [X] Network - Message Receiving
- [X] Network - Message Sending
- [ ] Network - Events **(Working on)**
- [ ] Robot - Friend/group list
- [ ] Message Section **(Working on)**
- [ ] Contact
<br>

View File

@ -53,7 +53,7 @@ public class MiraiServer {
MiraiConfig qqs;
protected MiraiServer(){
protected MiraiServer() {
instance = this;
this.onLoad();
this.onEnable();
@ -61,17 +61,17 @@ public class MiraiServer {
private boolean enabled;
protected void shutdown(){
if(this.enabled) {
getLogger().info(LoggerTextFormat.SKY_BLUE + "About to shutdown Mirai");
protected void shutdown() {
if (this.enabled) {
getLogger().info("About to shutdown Mirai");
this.getEventManager().broadcastEvent(new ServerDisableEvent());
getLogger().info(LoggerTextFormat.SKY_BLUE + "Data have been saved");
getLogger().info("Data have been saved");
}
}
private void onLoad(){
private void onLoad() {
this.parentFolder = new File(System.getProperty("user.dir"));
this.unix = !System.getProperties().getProperty("os.name").toUpperCase().contains("WINDOWS");
@ -79,36 +79,36 @@ public class MiraiServer {
this.eventManager = MiraiEventManager.getInstance();
this.taskManager = MiraiTaskManager.getInstance();
getLogger().info(LoggerTextFormat.SKY_BLUE + "About to run Mirai (" + MiraiServer.MIRAI_VERSION + ") under " + (isUnix() ? "unix" : "windows"));
getLogger().info("About to run Mirai (" + MiraiServer.MIRAI_VERSION + ") under " + (isUnix() ? "unix" : "windows"));
getLogger().info("Loading data under " + LoggerTextFormat.GREEN + this.parentFolder);
File setting = new File(this.parentFolder + "/Mirai.ini");
getLogger().info("Selecting setting from " + LoggerTextFormat.GREEN + setting);
if(!setting.exists()){
if (!setting.exists()) {
this.initSetting(setting);
}else {
} else {
this.setting = new MiraiSetting(setting);
}
File qqs = new File(this.parentFolder + "/QQ.yml");
getLogger().info("Reading QQ accounts from " + LoggerTextFormat.GREEN + qqs);
if(!qqs.exists()){
if (!qqs.exists()) {
this.initQQConfig(qqs);
}else {
} else {
this.qqs = new MiraiConfig(qqs);
}
if(this.qqs.isEmpty()){
if (this.qqs.isEmpty()) {
this.initQQConfig(qqs);
}
/*
MiraiSettingMapSection qqs = this.setting.getMapSection("qq");
qqs.forEach((a,p) -> {
this.getLogger().info(LoggerTextFormat.SKY_BLUE + "Finding available ports between " + "1-65536");
this.getLogger().info("Finding available ports between " + "1-65536");
try {
int port = MiraiNetwork.getAvailablePort();
this.getLogger().info(LoggerTextFormat.SKY_BLUE + "Listening on port " + port);
this.getLogger().info("Listening on port " + port);
} catch (IOException e) {
e.printStackTrace();
@ -178,56 +178,56 @@ public class MiraiServer {
}
private void initSetting(File setting) {
getLogger().info(LoggerTextFormat.SKY_BLUE + "Thanks for using Mirai");
getLogger().info(LoggerTextFormat.SKY_BLUE + "initializing Settings");
getLogger().info("Thanks for using Mirai");
getLogger().info("initializing Settings");
try {
if(setting.createNewFile()){
getLogger().info(LoggerTextFormat.SKY_BLUE + "Mirai Config Created");
if (setting.createNewFile()) {
getLogger().info("Mirai Config Created");
}
} catch (IOException e) {
e.printStackTrace();
}
this.setting = new MiraiSetting(setting);
MiraiSettingMapSection network = this.setting.getMapSection("network");
network.set("enable_proxy","not supporting yet");
MiraiSettingMapSection network = this.setting.getMapSection("network");
network.set("enable_proxy", "not supporting yet");
MiraiSettingListSection proxy = this.setting.getListSection("proxy");
MiraiSettingListSection proxy = this.setting.getListSection("proxy");
proxy.add("1.2.3.4:95");
proxy.add("1.2.3.4:100");
MiraiSettingMapSection worker = this.setting.getMapSection("worker");
worker.set("core_task_pool_worker_amount",5);
MiraiSettingMapSection worker = this.setting.getMapSection("worker");
worker.set("core_task_pool_worker_amount", 5);
MiraiSettingMapSection plugin = this.setting.getMapSection("plugin");
plugin.set("debug", false);
this.setting.save();
getLogger().info(LoggerTextFormat.SKY_BLUE + "initialized; changing can be made in setting file: " + setting.toString());
getLogger().info("initialized; changing can be made in setting file: " + setting.toString());
}
private void initQQConfig(File qqConfig){
private void initQQConfig(File qqConfig) {
this.qqs = new MiraiConfig(qqConfig);
MiraiConfigSection<Object> section = new MiraiConfigSection<>();
System.out.println("/");
Scanner scanner = new Scanner(System.in);
getLogger().info(LoggerTextFormat.SKY_BLUE + "input one " + LoggerTextFormat.RED + " QQ number " + LoggerTextFormat.SKY_BLUE + "for default robotNetworkHandler");
getLogger().info(LoggerTextFormat.SKY_BLUE + "输入用于默认机器人的QQ号");
getLogger().info("Input a " + LoggerTextFormat.RED + " QQ number " + LoggerTextFormat.GREEN + "for default robotNetworkHandler");
getLogger().info("输入用于默认机器人的QQ号");
long qqNumber = scanner.nextLong();
getLogger().info(LoggerTextFormat.SKY_BLUE + "input the password for that QQ account");
getLogger().info(LoggerTextFormat.SKY_BLUE + "输入该QQ号对应密码");
getLogger().info("Input the password for that QQ account");
getLogger().info("输入该QQ号的密码");
String qqPassword = scanner.next();
section.put("password",qqPassword);
section.put("owner","default");
section.put("password", qqPassword);
section.put("owner", "default");
this.qqs.put(String.valueOf(qqNumber),section);
this.qqs.put(String.valueOf(qqNumber), section);
this.qqs.save();
getLogger().info(LoggerTextFormat.SKY_BLUE + "QQ account initialized; changing can be made in Config file: " + qqConfig.toString());
getLogger().info("QQ account initialized; changing can be made in Config file: " + qqConfig.toString());
}
private void onEnable(){
private void onEnable() {
this.eventManager.broadcastEvent(new ServerEnableEvent());
this.enabled = true;
getLogger().info(LoggerTextFormat.GREEN + "Server enabled; Welcome to Mirai");

View File

@ -1,7 +1,10 @@
package net.mamoe.mirai;
import lombok.Getter;
import net.mamoe.mirai.contact.Group;
import net.mamoe.mirai.contact.QQ;
import net.mamoe.mirai.network.RobotNetworkHandler;
import net.mamoe.mirai.utils.ContactList;
import net.mamoe.mirai.utils.config.MiraiConfigSection;
import java.util.ArrayList;
@ -10,10 +13,8 @@ import java.util.List;
public class Robot {
private final int qq;
private final int qqNumber;
private final String password;
@Getter
private final RobotNetworkHandler handler;
@ -23,6 +24,9 @@ public class Robot {
@Getter
private final List<String> owners;
private final ContactList<Group> groups = new ContactList<>();
private final ContactList<QQ> qqs = new ContactList<>();
public boolean isOwnBy(String ownerName) {
return owners.contains(ownerName);
}
@ -30,20 +34,36 @@ public class Robot {
public Robot(MiraiConfigSection<Object> data) throws Throwable {
this(
data.getIntOrThrow("account", () -> new Exception("can not parse QQ account")),
data.getStringOrThrow("password", () -> new Exception("can not parse QQ password")),
data.getIntOrThrow("account", () -> new IllegalArgumentException("account")),
data.getStringOrThrow("password", () -> new IllegalArgumentException("password")),
data.getAsOrDefault("owners", ArrayList::new)
);
}
public Robot(int qq, String password, List<String> owners) {
this.qq = qq;
public Robot(int qqNumber, String password, List<String> owners) {
this.qqNumber = qqNumber;
this.password = password;
this.owners = Collections.unmodifiableList(owners);
this.handler = new RobotNetworkHandler(this, this.qq, this.password);
this.handler = new RobotNetworkHandler(this, this.qqNumber, this.password);
}
public QQ getQQ(int qqNumber) {
if (!this.qqs.containsKey(qqNumber)) {
this.qqs.put(qqNumber, new QQ(qqNumber));
}
return this.qqs.get(qqNumber);
}
public Group getGroup(int groupNumber) {
if (!this.groups.containsKey(groupNumber)) {
this.groups.put(groupNumber, new Group(groupNumber));
}
return groups.get(groupNumber);
}
public Group getGroupByGroupId(int groupId) {
return getGroup(Group.Companion.groupIdToNumber(groupId));
}
}

View File

@ -1,9 +1,11 @@
package net.mamoe.mirai.contact
import net.mamoe.mirai.message.Message
import net.mamoe.mirai.utils.ContactList
class Group(number: Int) : Contact(number) {
val groupId = groupNumberToId(number)
val members = ContactList<QQ>()
init {
Instances.groups.add(this)
@ -55,6 +57,11 @@ class Group(number: Int) : Contact(number) {
}
}
@JvmStatic
fun main(args: Array<String>) {
groupNumberToId(580266363)
}
fun groupIdToNumber(id: Int): Int {
var left: Int = id.toString().let {
if (it.length < 6) {

View File

@ -0,0 +1,23 @@
package net.mamoe.mirai.event.events.group;
import net.mamoe.mirai.Robot;
import net.mamoe.mirai.contact.Group;
import net.mamoe.mirai.event.events.robot.RobotEvent;
import org.jetbrains.annotations.NotNull;
/**
* @author Him188moe
*/
public abstract class GroupEvent extends RobotEvent {
private final Group group;
public GroupEvent(Robot robot, Group group) {
super(robot);
this.group = group;
}
@NotNull
public Group getGroup() {
return group;
}
}

View File

@ -0,0 +1,38 @@
package net.mamoe.mirai.event.events.group;
import net.mamoe.mirai.Robot;
import net.mamoe.mirai.contact.Group;
import net.mamoe.mirai.contact.QQ;
import net.mamoe.mirai.message.defaults.MessageChain;
import org.jetbrains.annotations.NotNull;
/**
* @author Him188moe
*/
public final class GroupMessageEvent extends GroupEvent {
private final QQ sender;
private final MessageChain messageChain;
private final String messageString;
public GroupMessageEvent(@NotNull Robot robot, @NotNull Group group, @NotNull QQ sender, @NotNull MessageChain messageChain) {
super(robot, group);
this.sender = sender;
this.messageChain = messageChain;
this.messageString = messageChain.toString();
}
@NotNull
public MessageChain getMessageChain() {
return messageChain;
}
@NotNull
public String getMessageString() {
return messageString;
}
@NotNull
public QQ getSender() {
return sender;
}
}

View File

@ -0,0 +1,25 @@
package net.mamoe.mirai.event.events.qq;
import net.mamoe.mirai.Robot;
import net.mamoe.mirai.contact.QQ;
import net.mamoe.mirai.event.events.robot.RobotEvent;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
/**
* @author Him188moe
*/
public abstract class FriendEvent extends RobotEvent {
private final QQ qq;
public FriendEvent(@NotNull Robot robot, @NotNull QQ qq) {
super(robot);
this.qq = Objects.requireNonNull(qq);
}
@NotNull
public QQ getQQ() {
return qq;
}
}

View File

@ -0,0 +1,30 @@
package net.mamoe.mirai.event.events.qq;
import net.mamoe.mirai.Robot;
import net.mamoe.mirai.contact.QQ;
import net.mamoe.mirai.message.defaults.MessageChain;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
/**
* @author Him188moe
*/
public final class FriendMessageEvent extends FriendEvent {
private final MessageChain messageChain;
private final String messageString;
public FriendMessageEvent(@NotNull Robot robot, @NotNull QQ sender, @NotNull MessageChain messageChain) {
super(robot, sender);
this.messageChain = Objects.requireNonNull(messageChain);
this.messageString = messageChain.toString();
}
public String getMessageString() {
return messageString;
}
public MessageChain getMessageChain() {
return messageChain;
}
}

View File

@ -2,15 +2,20 @@ package net.mamoe.mirai.event.events.robot;
import net.mamoe.mirai.Robot;
import net.mamoe.mirai.event.events.MiraiEvent;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
public abstract class RobotEvent extends MiraiEvent {
private final Robot robot;
public RobotEvent(@NotNull Robot robot) {
this.robot = Objects.requireNonNull(robot);
}
@NotNull
public Robot getRobot() {
return robot;
}
public RobotEvent(Robot robot){
this.robot = robot;
}
}

View File

@ -2,6 +2,6 @@ package net.mamoe.mirai.event.events.server;
import net.mamoe.mirai.event.events.MiraiEvent;
public class ServerDisableEvent extends MiraiEvent {
public final class ServerDisableEvent extends MiraiEvent {
}

View File

@ -2,7 +2,7 @@ package net.mamoe.mirai.event.events.server;
import net.mamoe.mirai.event.events.MiraiEvent;
public class ServerEnableEvent extends MiraiEvent {
public final class ServerEnableEvent extends MiraiEvent {
}

View File

@ -3,9 +3,12 @@ package net.mamoe.mirai.message.defaults;
import net.mamoe.mirai.message.Message;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author Him188moe
@ -21,6 +24,19 @@ public final class MessageChain extends Message {
list.add(tail);
}
public MessageChain(@NotNull Message message) {
Objects.requireNonNull(message);
list.add(message);
}
public List<Message> toList() {
return List.copyOf(list);
}
public Stream<Message> stream() {
return new ArrayList<>(list).stream();
}
@Override
public synchronized String toString() {
return this.list.stream().map(Message::toString).collect(Collectors.joining(""));

View File

@ -2,11 +2,14 @@ package net.mamoe.mirai.network
import net.mamoe.mirai.MiraiServer
import net.mamoe.mirai.Robot
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.event.events.qq.FriendMessageEvent
import net.mamoe.mirai.event.events.robot.RobotLoginSucceedEvent
import net.mamoe.mirai.network.packet.*
import net.mamoe.mirai.network.packet.login.*
import net.mamoe.mirai.network.packet.message.ClientSendFriendMessagePacket
import net.mamoe.mirai.network.packet.message.ClientSendGroupMessagePacket
import net.mamoe.mirai.network.packet.message.ServerSendFriendMessageResponsePacket
import net.mamoe.mirai.network.packet.message.ServerSendGroupMessageResponsePacket
import net.mamoe.mirai.network.packet.verification.ServerVerificationCodePacket
import net.mamoe.mirai.network.packet.verification.ServerVerificationCodePacketEncrypted
import net.mamoe.mirai.task.MiraiThreadPool
@ -84,6 +87,7 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor
*/
private lateinit var cookies: String
private var gtk: Int = 0
private var ignoreMessage: Boolean = false
init {
tlv0105 = lazyEncode {
@ -197,6 +201,11 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor
sendPacket(ClientHeartbeatPacket(this.number, this.sessionKey))
}, 90000, 90000, TimeUnit.MILLISECONDS)
RobotLoginSucceedEvent(robot).broadcast()
MiraiThreadPool.getInstance().schedule({
ignoreMessage = false
}, 2, TimeUnit.SECONDS)
this.tlv0105 = packet.tlv0105
sendPacket(ClientLoginStatusPacket(this.number, this.sessionKey, ClientLoginStatus.ONLINE))
}
@ -225,23 +234,23 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor
}
is ServerMessageEventPacketRaw -> onPacketReceived(packet.analyze())
is ServerFriendMessageEventPacket -> {
println(packet.toString())
if (packet.message == "牛逼") {
sendPacket(ClientSendFriendMessagePacket(this.number, packet.qq, this.sessionKey, "牛逼!!"))
if (ignoreMessage) {
return
}
//friend message
FriendMessageEvent(this.robot, this.robot.getQQ(packet.qq), packet.message)
}
is ServerGroupMessageEventPacket -> {
//group message
if (packet.message == "牛逼") {
sendPacket(ClientSendGroupMessagePacket(packet.group, this.number, this.sessionKey, "牛逼!"))
sendPacket(ClientSendGroupMessagePacket(Group.groupNumberToId(packet.groupNumber), this.number, this.sessionKey, "牛逼!"))
}
//todo
//GroupMessageEvent(this.robot, this.robot.getGroup(packet.groupNumber), this.robot.getQQ(packet.qq), packet.message)
}
is UnknownServerEventPacket -> {
@ -256,6 +265,8 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor
}
is ServerMessageEventPacketRaw -> onPacketReceived(packet.analyze())
is ServerVerificationCodePacketEncrypted -> onPacketReceived(packet.decrypt(this.token00BA))
is ServerLoginResponseVerificationCodePacketEncrypted -> onPacketReceived(packet.decrypt())
is ServerLoginResponseResendPacketEncrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!))
@ -267,6 +278,11 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor
is ServerMessageEventPacketRawEncoded -> onPacketReceived(packet.decrypt(this.sessionKey))
is ServerSendFriendMessageResponsePacket,
is ServerSendGroupMessageResponsePacket -> {
}
else -> throw IllegalArgumentException(packet.toString())
}

View File

@ -1,5 +1,7 @@
package net.mamoe.mirai.network.packet
import net.mamoe.mirai.message.defaults.MessageChain
import net.mamoe.mirai.message.defaults.PlainText
import net.mamoe.mirai.utils.toUHexString
import java.io.ByteArrayOutputStream
import java.io.DataInputStream
@ -29,15 +31,15 @@ class ServerAndroidOfflineEventPacket(input: DataInputStream, packetId: ByteArra
* 群文件上传
*/
class ServerGroupUploadFileEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) {
lateinit var message: String
lateinit var xmlMessage: String
override fun decode() {
message = String(this.input.goto(65).readNBytes(this.input.goto(60).readShort().toInt()))
xmlMessage = String(this.input.goto(65).readNBytes(this.input.goto(60).readShort().toInt()))
}//todo test
}
class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) {
var group: Int = 0
var groupNumber: Int = 0
var qq: Int = 0
lateinit var message: String
lateinit var messageType: MessageType
@ -57,10 +59,10 @@ class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray,
}
override fun decode() {
group = this.input.goto(51).readInt()
groupNumber = this.input.goto(51).readInt()
qq = this.input.goto(56).readInt()
val fontLength = this.input.goto(108).readShort()
//println(this.input.goto(110 + fontLength).readNBytes(2).toUHexString())//always 00 00
//println(this.input.goto(110 + fontLength).readNBytesAt(2).toUHexString())//always 00 00
messageType = when (val id = this.input.goto(110 + fontLength + 2).readByte().toInt()) {
19 -> MessageType.NORMAL
@ -102,7 +104,7 @@ class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray,
message = "[face${faceId}.gif]"
}
MessageType.AT, MessageType.OTHER -> {
MessageType.AT, MessageType.OTHER, MessageType.PLAIN_TEXT, MessageType.IMAGE, MessageType.ANONYMOUS -> {
var messageLength: Int = this.input.goto(110 + fontLength + 6).readShort().toInt()
message = String(this.input.goto(110 + fontLength + 8).readNBytes(messageLength))
@ -120,7 +122,7 @@ class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray,
//读取 nick, ignore.
/*
when (this.input.goto(110 + fontLength + 3 + oeLength).readByte().toInt()) {
when (this.input.goto(110 + fontLength + 3 + oeLength).readByteAt().toInt()) {
12 -> {
this.input.skip(4)//maybe 5?
@ -139,6 +141,35 @@ class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray,
}
}
class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) {
var qq: Int = 0
lateinit var message: MessageChain
@ExperimentalUnsignedTypes
override fun decode() {
//start at Sep1.0:27
input.goto(0)
println(input.readAllBytes().toUHexString())
input.goto(0)
qq = input.readIntAt(0)
val msgLength = input.readShortAt(22)
val fontLength = input.readShortAt(93 + msgLength)
val offset = msgLength + fontLength
message = MessageChain(PlainText(let {
val offset2 = input.readShortAt(101 + offset)
input.goto(103 + offset).readVarString(offset2.toInt())
}))
}
}
/*
backup
class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) {
var qq: Int = 0
lateinit var message: String
@ -147,17 +178,17 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray
@ExperimentalUnsignedTypes
override fun decode() {
//start at Sep1.0:27
qq = input.readInt(0)
val msgLength = input.readShort(22)
val fontLength = input.readShort(93+msgLength)
qq = input.readIntAt(0)
val msgLength = input.readShortAt(22)
val fontLength = input.readShortAt(93+msgLength)
val offset = msgLength+fontLength
message = if(input.readByte(97+offset).toUHexString() == "02"){
"[face" + input.goto(103+offset).readByte(1).toInt().toString() + ".gif]"
message = if(input.readByteAt(97+offset).toUHexString() == "02"){
"[face" + input.goto(103+offset).readByteAt(1).toInt().toString() + ".gif]"
//.gif
}else {
val offset2 = input.readShort(101 + offset)
val offset2 = input.readShortAt(101 + offset)
input.goto(103 + offset).readVarString(offset2.toInt())
}
// TODO("FRIEND 解析")d
}
}
}
*/

View File

@ -145,22 +145,22 @@ infix fun <N : Number> DataInputStream.goto(position: N): DataInputStream {
return this
}
fun <N : Number> DataInputStream.readNBytes(position: N, length: Int): ByteArray {
fun <N : Number> DataInputStream.readNBytesAt(position: N, length: Int): ByteArray {
this.goto(position)
return this.readNBytes(length)
}
fun <N : Number> DataInputStream.readInt(position: N): Int {
fun <N : Number> DataInputStream.readIntAt(position: N): Int {
this.goto(position)
return this.readInt();
}
fun <N : Number> DataInputStream.readByte(position: N): Byte {
fun <N : Number> DataInputStream.readByteAt(position: N): Byte {
this.goto(position)
return this.readByte();
}
fun <N : Number> DataInputStream.readShort(position: N): Short {
fun <N : Number> DataInputStream.readShortAt(position: N): Short {
this.goto(position)
return this.readShort();
}

View File

@ -3,7 +3,7 @@ package net.mamoe.mirai.network.packet.login
import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.network.packet.ServerPacket
import net.mamoe.mirai.network.packet.goto
import net.mamoe.mirai.network.packet.readNBytes
import net.mamoe.mirai.network.packet.readNBytesAt
import net.mamoe.mirai.network.packet.readVarString
import net.mamoe.mirai.util.TestedSuccessfully
import net.mamoe.mirai.utils.TEACryptor
@ -31,16 +31,16 @@ class ServerLoginResponseSuccessPacket(input: DataInputStream) : ServerPacket(in
* Version 1 @Deprecated
this.input.skip(7)//8
encryptionKey = this.input.readNBytes(16)//24
encryptionKey = this.input.readNBytesAt(16)//24
this.input.skip(2)//25->26
token38 = this.input.readNBytes(56)//81->82
token38 = this.input.readNBytesAt(56)//81->82
this.input.skip(60L)//142
//??
var b = this.input.readNBytes(2)
var b = this.input.readNBytesAt(2)
val msgLength = when (b.toUByteArray().toUHexString()) {
"01 07" -> 0
"00 33" -> 28
@ -55,17 +55,17 @@ class ServerLoginResponseSuccessPacket(input: DataInputStream) : ServerPacket(in
this.input.skip(10)//171+msgLength
_0828_rec_decr_key = this.input.readNBytes(16)//187+msgLength
_0828_rec_decr_key = this.input.readNBytesAt(16)//187+msgLength
this.input.skip(2)
token88 = this.input.readNBytes(136)//325+ // msgLength
token88 = this.input.readNBytesAt(136)//325+ // msgLength
this.input.skip(299L)//624+msgLength
//varString (nickLength bytes)
val nickLength = this.input.readByte().toInt()//625+msgLength
val nickLength = this.input.readByteAt().toInt()//625+msgLength
System.out.println(nickLength)
@ -76,11 +76,11 @@ class ServerLoginResponseSuccessPacket(input: DataInputStream) : ServerPacket(in
/*
this.input.skip((dataIndex - (625 + msgLength + nickLength)) + 0L)//-31
gender = this.input.readByte().toUByte().toInt()//-30
gender = this.input.readByteAt().toUByte().toInt()//-30
this.input.skip(9)//-27
age = this.input.readShort()//-25
age = this.input.readShortAt()//-25
*/
age = 0
gender = 0
@ -106,16 +106,16 @@ class ServerLoginResponseSuccessPacket(input: DataInputStream) : ServerPacket(in
else -> throw IllegalStateException(id)
}
this._0828_rec_decr_key = this.input.readNBytes(171 + msgLength, 16)
this._0828_rec_decr_key = this.input.readNBytesAt(171 + msgLength, 16)
this.token88 = this.input.readNBytes(189 + msgLength, 136)
this.token88 = this.input.readNBytesAt(189 + msgLength, 136)
val nickLength = this.input.goto(624 + msgLength).readByte().toInt()
this.nick = this.input.readVarString(nickLength)
//this.age = this.input.goto(packetDataLength - 28).readShort()
//this.age = this.input.goto(packetDataLength - 28).readShortAt()
//this.gender = this.input.goto(packetDataLength - 32).readByte().toInt()
//this.gender = this.input.goto(packetDataLength - 32).readByteAt().toInt()
}
}

View File

@ -2,6 +2,8 @@ package net.mamoe.mirai.network.packet.message
import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.network.packet.*
import net.mamoe.mirai.utils.lazyEncode
import net.mamoe.mirai.utils.toUHexString
import java.io.DataInputStream
/**
@ -21,6 +23,11 @@ class ClientSendGroupMessagePacket(
this.writeHex(Protocol._fixVer)
this.encryptAndWrite(sessionKey) {
val bytes = message.toByteArray()
it.writeByte(0x2A)
it.writeInt(groupId)
it.writeShort(56 + bytes.size)
it.writeHex("00 01 01 00 00 00 00 00 00 00 4D 53 47 00 00 00 00 00")
it.writeTime()
it.writeRandom(4)
@ -28,21 +35,33 @@ class ClientSendGroupMessagePacket(
it.writeZero(2)
//messages
val bytes = message.toByteArray()
it.writeByte(0x2A)
it.writeInt(groupId)
it.writeShort(19 + bytes.size)
it.writeByte(0x01)
it.writeByte(0x01)
it.writeShort(bytes.size + 3)
it.writeByte(0x01)
it.writeShort(bytes.size)
it.write(bytes)
println(it.toByteArray().toUHexString())
}
}
}
fun main() {
println(lazyEncode {
val bytes = "message".toByteArray()
it.writeByte(0x2A)
it.writeInt(580266363)
it.writeShort(19 + bytes.size)
it.writeByte(0x01)
it.writeByte(0x01)
it.writeShort(bytes.size + 3)
it.writeByte(0x01)
it.writeShort(bytes.size)
it.write(bytes)
}.toUHexString())
}
@PacketId("00 02")
class ServerSendGroupMessageResponsePacket(input: DataInputStream) : ServerPacket(input) {
override fun decode() {

View File

@ -27,7 +27,7 @@ class ServerVerificationCodePacket(input: DataInputStream) : ServerPacket(input)
this.unknownBoolean = this.input.readByte().toInt() == 1
//this.token00BA = this.input.goto(packetLength - 60).readNBytes(40)
//this.token00BA = this.input.goto(packetLength - 60).readNBytesAt(40)
}
}

View File

@ -0,0 +1,10 @@
package net.mamoe.mirai.utils;
import net.mamoe.mirai.contact.Contact;
import net.mamoe.mirai.utils.config.MiraiSynchronizedLinkedListMap;
/**
* @author Him188moe
*/
public class ContactList<C extends Contact> extends MiraiSynchronizedLinkedListMap<Integer, C> {
}

View File

@ -1,14 +1,25 @@
package net.mamoe.mirai.utils;
import net.mamoe.mirai.MiraiServer;
public enum LoggerTextFormat {
RED("\033[31m"),
GREEN("\033[32m"),
YELLOW("\033[33m"),
BLUE("\033[34m"),
SKY_BLUE("\033[36m"),
RESET("\33[0m");
RESET("\33[0m"),
BLUE("\033[0;34m"),
BLACK("\033[0;30m"),
DARK_GREY("\033[1;30m"),
LIGHT_BLUE("\033[1;34m"),
GREEN("\033[0;32m"),
LIGHT_GTEEN("\033[1;32m"),
CYAN("\033[0;36m"),
LIGHT_CYAN("\033[1;36m"),
RED("\033[0;31m"),
LIGHT_RED("\033[1;31m"),
PURPLE("\033[0;35m"),
LIGHT_PURPLE("\033[1;35m"),
BROWN("\033[0;33m"),
YELLOW("\033[1;33m"),
LIGHT_GRAY("\033[0;37m"),
WHITE("\033[1;37m");
private String format;
LoggerTextFormat(String format) {
@ -17,9 +28,9 @@ public enum LoggerTextFormat {
@Override
public String toString() {
if(MiraiServer.getInstance().isUnix()){
return format;
}
return "";
//if(MiraiServer.getInstance().isUnix()){
return format;
// }
// return "";
}
}

View File

@ -7,21 +7,16 @@ import java.util.*
* used to replace old logger
*/
object MiraiLogger {
infix fun info(o: Any?) {
this.print(o.toString())
}
infix fun error(o: Any?) {
this.print(o.toString(), LoggerTextFormat.RED)
}
infix fun log(o: Any?) = info(o)
infix fun println(o: Any?) = info(o)
infix fun info(o: Any?) = this.print(o.toString(), LoggerTextFormat.RESET)
infix fun debug(o: Any?) {
this.print(o.toString())
}
infix fun error(o: Any?) = this.print(o.toString(), LoggerTextFormat.RED)
infix fun notice(o: Any?) = this.print(o.toString(), LoggerTextFormat.LIGHT_BLUE)
infix fun debug(o: Any?) = this.print(o.toString(), LoggerTextFormat.YELLOW)
infix fun catching(e: Throwable) {
e.printStackTrace()
@ -31,7 +26,7 @@ object MiraiLogger {
this.print(e.cause.toString())*/
}
private fun print(value: String?, color: LoggerTextFormat = LoggerTextFormat.BLUE) {
private fun print(value: String?, color: LoggerTextFormat = LoggerTextFormat.WHITE) {
val s = SimpleDateFormat("MM-dd HH:mm:ss").format(Date())
kotlin.io.println("$color[Mirai] $s : $value")
}
@ -42,4 +37,6 @@ fun Any.logInfo() = MiraiLogger.info(this)
fun Any.logDebug() = MiraiLogger.debug(this)
fun Any.logError() = MiraiLogger.error(this)
fun Any.logError() = MiraiLogger.error(this)
fun Any.logNotice() = MiraiLogger.notice(this)

View File

@ -6,12 +6,10 @@ import net.mamoe.mirai.network.Protocol;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.BiConsumer;
/**
@ -213,16 +211,16 @@ public class HexComparator {
}
public static void main(String[] args) {
/*
System.out.println(HexComparator.compare(
//mirai
"01 12 00 38 56 3A E4 8B B4 64 D2 72 60 FE 01 54 FC B1 5F 88 E0 BA 64 1A 55 F2 84 FC 97 D0 BF 5F 47 A8 D9 76 BB FB 4A 7A F3 5E 0E A4 8E CA 8F 27 C2 02 6E 5D E7 68 9F 7C CF 91 83 F4 03 0F 00 11 00 0F 44 45 53 4B 54 4F 50 2D 4D 31 37 4A 52 45 55 00 05 00 06 00 02 76 E4 B8 DD 00 06 00 78 0D DF 92 9C 5A 08 D1 67 FD 7D D6 DE CE D0 92 39 79 17 53 57 41 9B D6 D3 F9 F8 9A 3B E1 C2 3A E7 CF 02 6E 5E 36 B7 6D CF 33 66 77 FE AC 58 93 A3 85 E7 AF 6F 2D A2 74 E2 60 28 4B 29 17 04 79 95 39 D4 BF 4D C1 ED 61 49 13 23 9D 71 62 29 AF 87 D7 E3 42 49 88 3F D8 5C DB 9F 9E 5A 2A EA 02 F6 4F 2B D3 5B AF BE 0C B2 54 46 AE 99 1B 07 0B BE 6A C2 29 18 25 6A 95 0A 00 15 00 30 00 01 01 27 9B C7 F5 00 10 65 03 FD 8B 00 00 00 00 00 00 00 00 00 00 00 00 02 90 49 55 33 00 10 15 74 C4 89 85 7A 19 F5 5E A9 C9 A3 5E 8A 5A 9B 00 1A 00 40 E2 9A D0 B3 7D CD 3D F4 55 DB 04 A4 68 2A AF 4E 38 46 8B E0 1F 2D 2A B8 F6 C6 AB 4F DF D1 5F 8C D4 CA 2A 91 25 14 33 A3 C5 08 F8 01 4C E6 3D 89 5F 23 38 3A EC 01 58 F6 B1 F6 7F 2E 6A 02 17 4A 00 18 00 16 00 01 00 00 04 53 00 00 00 01 00 00 15 85 76 E4 B8 DD 00 00 00 00 01 03 00 14 00 01 00 10 60 C9 5D A7 45 70 04 7F 21 7D 84 50 5C 66 A5 C6 01 10 00 3C 00 01 00 38 57 3A 37 C3 FB A0 C3 E5 AE F3 0E B6 03 DE BF 9E E2 B5 C5 FE A0 F0 03 4F F7 8A 5C 29 5C E0 5A A2 89 D5 3F 60 E2 B2 81 FE D4 16 04 D4 E3 C6 4A D7 A9 D9 E6 FC 2E 7E 0C F3 03 12 00 05 01 00 00 00 01 05 08 00 05 10 00 00 00 00 03 13 00 19 01 01 02 00 10 04 EA 78 D1 A4 FF CD CC 7C B8 D4 12 7D BB 03 AA 00 00 00 00 01 02 00 62 00 01 04 EB B7 C1 86 F9 08 96 ED 56 84 AB 50 85 2E 48 00 38 E9 AA 2B 4D 26 4C 76 18 FE 59 D5 A9 82 6A 0C 04 B4 49 50 D7 9B B1 FE 5D 97 54 8D 82 F3 22 C2 48 B9 C9 22 69 CA 78 AD 3E 2D E9 C9 DF A8 9E 7D 8C 8D 6B DF 4C D7 34 D0 D3 00 14 10 21 DF C4 F3 DD 42 09 6F A0 93 8C 7E 0E 78 EF 22 8D 88 35"
"2A 22 96 29 7B 00 40 00 01 01 00 00 00 00 00 00 00 4D 53 47 00 00 00 00 00 EC 21 40 06 18 89 54 BC 00 00 00 00 09 00 86 00 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 0A 01 00 07 E7 89 9B E9 80 BC 21\n"
,
//e
"01 12 00 38 56 3A E4 8B B4 64 D2 72 60 FE 01 54 FC B1 5F 88 E0 BA 64 1A 55 F2 84 FC 97 D0 BF 5F 47 A8 D9 76 BB FB 4A 7A F3 5E 0E A4 8E CA 8F 27 C2 02 6E 5D E7 68 9F 7C CF 91 83 F4 03 0F 00 11 00 0F 44 45 53 4B 54 4F 50 2D 4D 31 37 4A 52 45 55 00 05 00 06 00 02 76 E4 B8 DD 00 06 00 78 0D DF 92 9C 5A 08 D1 67 FD 7D D6 DE CE D0 92 39 79 17 53 57 41 9B D6 D3 F9 F8 9A 3B E1 C2 3A E7 CF 02 6E 5E 36 B7 6D CF 33 66 77 FE AC 58 93 A3 85 E7 AF 6F 2D A2 74 E2 60 28 4B 29 17 04 79 95 39 D4 BF 4D C1 ED 61 49 13 23 9D 71 62 29 AF 87 D7 E3 42 49 88 3F D8 5C DB 9F 9E 5A 2A EA 02 F6 4F 2B D3 5B AF BE 0C B2 54 46 AE 99 1B 07 0B BE 6A C2 29 18 25 6A 95 0A 00 15 00 30 00 01 01 27 9B C7 F5 00 10 65 03 FD 8B 00 00 00 00 00 00 00 00 00 00 00 00 02 90 49 55 33 00 10 15 74 C4 89 85 7A 19 F5 5E A9 C9 A3 5E 8A 5A 9B 00 1A 00 40 26 2B FE EB 21 8E 08 16 BA 42 B3 A3 C5 6A 5B 31 33 A9 B3 F0 EB 16 80 BE F0 58 D3 51 98 2F A7 23 27 7C 06 97 F4 85 01 77 5C 5B D6 A2 82 54 06 A0 07 53 39 E2 E7 62 E5 09 1A 25 79 6F D9 E0 ED B6 00 18 00 16 00 01 00 00 04 53 00 00 00 01 00 00 15 85 76 E4 B8 DD 00 00 00 00 01 03 00 14 00 01 00 10 60 C9 5D A7 45 70 04 7F 21 7D 84 50 5C 66 A5 C6 01 10 00 3C 00 01 00 38 57 3A 37 C3 FB A0 C3 E5 AE F3 0E B6 03 DE BF 9E E2 B5 C5 FE A0 F0 03 4F F7 8A 5C 29 5C E0 5A A2 89 D5 3F 60 E2 B2 81 FE D4 16 04 D4 E3 C6 4A D7 A9 D9 E6 FC 2E 7E 0C F3 03 12 00 05 01 00 00 00 01 05 08 00 05 01 00 00 00 00 03 13 00 19 01 01 02 00 10 04 EA 78 D1 A4 FF CD CC 7C B8 D4 12 7D BB 03 AA 00 00 00 00 01 02 00 62 00 01 04 EB B7 C1 86 F9 08 96 ED 56 84 AB 50 85 2E 48 00 38 E9 AA 2B 4D 26 4C 76 18 FE 59 D5 A9 82 6A 0C 04 B4 49 50 D7 9B B1 FE 5D 97 54 8D 82 F3 22 C2 48 B9 C9 22 69 CA 78 AD 3E 2D E9 C9 DF A8 9E 7D 8C 8D 6B DF 4C D7 34 D0 D3 00 14 4C 97 73 32 83 1A 6F C4 94 91 0A 7A D8 21 81 58 73 3D 24 F6"
"2A 22 96 29 7B 00 3F 00 01 01 00 00 00 00 00 00 00 4D 53 47 00 00 00 00 00 5D 6B 8E 1A FE 39 0B FC 00 00 00 00 09 00 86 00 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 0A 01 00 07 6D 65 73 73 61 67 65"
));
*/
/*
System.out.println(HexComparator.compare(