oicq
Version:
QQ protocol!
432 lines (431 loc) • 15.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.discussMsgListener = exports.groupMsgListener = exports.dmMsgSyncListener = exports.onlinePushTransListener = exports.onlinePushListener = exports.emitGroupNoticeEvent = void 0;
const core_1 = require("../core");
const common_1 = require("../common");
const message_1 = require("../message");
/** OnlinePush回执 */
function handleOnlinePush(svrip, seq, items = []) {
const resp = core_1.jce.encodeStruct([
this.uin, items, svrip & 0xffffffff, null, 0
]);
const body = core_1.jce.encodeWrapper({ resp }, "OnlinePush", "SvcRespPushMsg", seq);
this.writeUni("OnlinePush.RespPush", body);
}
const statuslist = [
null,
common_1.OnlineStatus.Online,
null,
common_1.OnlineStatus.Absent,
common_1.OnlineStatus.Invisible,
common_1.OnlineStatus.Busy,
common_1.OnlineStatus.Qme,
common_1.OnlineStatus.DontDisturb,
];
const sub0x27 = {
0: function (data) {
this.classes.set(data[3][1], String(data[3][3]));
},
1: function (data) {
this.classes.delete(data[4][1]);
},
2: function (data) {
this.classes.set(data[5][1], String(data[5][2]));
},
4: function (data) {
const arr = Array.isArray(data[7][1]) ? data[7][1] : [data[7][1]];
for (let v of arr)
this.fl.get(v[1]).class_id = v[3];
},
80: function (data) {
const o = data[12];
const gid = o[3];
if (!o[4])
return;
this.gl.get(gid).group_name = String(o[2][2]);
},
5: function (data) {
const user_id = data[14][1];
const nickname = this.fl.get(user_id)?.nickname || "";
this.fl.delete(user_id);
this.logger.info(`更新了好友列表,删除了好友 ${user_id}(${nickname})`);
return {
sub_type: "decrease",
user_id, nickname
};
},
20: function (data) {
// 20002昵称 20009性别 20031生日 23109农历生日 20019说明 20032地区 24002故乡 27372在线状态
const uid = data[8][1];
let o = data[8][2];
if (Array.isArray(o))
o = o[0];
let key, value;
if (o[1] === 20002) {
key = "nickname";
value = String(o[2]);
this.fl.get(uid).nickname = value;
}
else if (o[1] === 20009) {
key = "sex";
value = ["unknown", "male", "female"][o[2].toBuffer()[0]];
}
else if (o[1] === 20031) {
key = "age";
value = new Date().getFullYear() - o[2].toBuffer().readUInt16BE();
}
else if (o[1] === 27372 && uid === this.uin) {
const status = o[2].toBuffer()[o[2].toBuffer().length - 1];
this.status = statuslist[status] || 11;
return;
}
else {
return;
}
if (uid === this.uin)
this[key] = value;
},
40: function (data) {
const o = data[9][1], uid = o[2];
if (o[1] > 0)
return; //0好友备注 1群备注
this.fl.get(uid).remark = String(o[3]);
},
};
// 好友事件解析
const push528 = {
0x8A: function (buf) {
let data = core_1.pb.decode(buf)[1];
if (Array.isArray(data))
data = data[0];
let user_id = data[1], operator_id = data[1], flag = 0;
if (user_id === this.uin) {
user_id = data[2];
flag = 1;
}
return {
sub_type: "recall",
message_id: (0, message_1.genDmMessageId)(user_id, data[3], data[6], data[5], flag),
operator_id,
user_id,
seq: data[3],
rand: data[6],
time: data[5],
};
},
0x8B: function (buf) {
return push528[0x8A].call(this, buf);
},
0xB3: function (buf) {
const data = core_1.pb.decode(buf)[2];
const user_id = data[1], nickname = String(data[5]);
this.fl.set(user_id, {
user_id: user_id,
nickname,
sex: "unknown",
remark: nickname,
class_id: data[7]
});
this.sl.delete(user_id);
this.logger.info(`更新了好友列表,新增了好友 ${user_id}(${nickname})`);
return {
sub_type: "increase",
user_id, nickname
};
},
0xD4: function (buf) {
const gid = core_1.pb.decode(buf)[1];
this.pickGroup(gid).renew().catch(common_1.NOOP);
},
0x27: function (buf) {
let data = core_1.pb.decode(buf)[1];
if (Array.isArray(data))
data = data[0];
return sub0x27[data[2]]?.call(this, data);
},
0x122: function (buf) {
const data = core_1.pb.decode(buf);
const e = parsePoke(data);
if (e.action) {
e.operator_id = e.operator_id || this.uin;
e.target_id = e.target_id || this.uin;
return Object.assign(e, { sub_type: "poke" });
}
},
0x115: function (buf) {
const data = core_1.pb.decode(buf);
const user_id = data[1];
const end = data[3][4] === 2;
this.emit("internal.input", { user_id, end });
},
};
function parsePoke(data) {
let target_id = 0, operator_id = 0, action = "", suffix = "";
for (let o of data[7]) {
const name = String(o[1]), val = String(o[2]);
switch (name) {
case "action_str":
case "alt_str1":
action = action || val;
break;
case "uin_str1":
operator_id = parseInt(val);
break;
case "uin_str2":
target_id = parseInt(val);
break;
case "suffix_str":
suffix = val;
break;
}
}
return { target_id, operator_id, action, suffix };
}
// 群事件解析
const push732 = {
0x0C: function (gid, buf) {
const operator_id = buf.readUInt32BE(6);
const user_id = buf.readUInt32BE(16);
let duration = buf.readUInt32BE(20);
try {
if (user_id === 0) {
duration = duration ? 0xffffffff : 0;
this.gl.get(gid).shutup_time_whole = duration;
}
else if (user_id === this.uin)
this.gl.get(gid).shutup_time_me = duration ? ((0, common_1.timestamp)() + duration) : 0;
this.gml.get(gid).get(user_id).shutup_time = duration ? ((0, common_1.timestamp)() + duration) : 0;
}
catch { }
this.logger.info(`用户${user_id}在群${gid}被禁言${duration}秒`);
return {
sub_type: "ban",
operator_id, user_id, duration
};
},
0x11: function (gid, buf) {
const data = core_1.pb.decode(buf.slice(7))[11];
const operator_id = data[1];
const msg = Array.isArray(data[3]) ? data[3][0] : data[3];
const user_id = msg[6];
const message_id = (0, message_1.genGroupMessageId)(gid, user_id, msg[1], msg[3], msg[2], Array.isArray(data[3]) ? data[3].length : 1);
return {
sub_type: "recall",
user_id, operator_id, message_id,
seq: msg[1],
rand: msg[3],
time: msg[2]
};
},
0x14: function (gid, buf) {
const data = core_1.pb.decode(buf.slice(7))[26];
let e = parsePoke(data);
if (e.action) {
e.operator_id = e.operator_id || this.uin;
e.target_id = e.target_id || this.uin;
return Object.assign(e, {
sub_type: "poke",
/** @deprecated */
user_id: e.target_id
});
}
},
0x0E: function (gid, buf) {
if (buf[5] !== 1)
return;
const duration = buf.readInt32BE(10);
if (buf[14] !== 0) {
const nickname = String(buf.slice(15, 15 + buf[14]));
const operator_id = buf.readUInt32BE(6);
this.logger.info(`匿名用户${nickname}在群${gid}被禁言${duration}秒`);
return {
sub_type: "ban",
operator_id,
user_id: 80000000, nickname,
duration
};
}
},
};
function emitFriendNoticeEvent(c, uid, e) {
if (!e)
return;
const name = "notice.friend." + e.sub_type;
c.em(name, Object.assign({
post_type: "notice",
notice_type: "friend",
user_id: uid,
friend: c.pickFriend(uid)
}, e));
}
function emitGroupNoticeEvent(c, gid, e) {
if (!e)
return;
const name = "notice.group." + e.sub_type;
c.em(name, Object.assign({
post_type: "notice",
notice_type: "group",
group_id: gid,
group: c.pickGroup(gid)
}, e));
}
exports.emitGroupNoticeEvent = emitGroupNoticeEvent;
function onlinePushListener(payload, seq) {
const nested = core_1.jce.decodeWrapper(payload);
const list = nested[2], v = list[0];
const rubbish = core_1.jce.encodeNested([
this.uin, v[1], v[3], v[8], 0, 0, 0, 0, 0, 0, 0
]);
handleOnlinePush.call(this, nested[3], seq, [rubbish]);
if (!this._sync_cookie)
return;
if (v[2] === 528) {
const uid = v[0];
const nested = core_1.jce.decode(v[6]);
const type = nested[0], buf = nested[10];
emitFriendNoticeEvent(this, uid, push528[type]?.call(this, buf));
}
else if (v[2] === 732) {
const gid = v[6].readUInt32BE();
const type = v[6][4];
emitGroupNoticeEvent(this, gid, push732[type]?.call(this, gid, v[6]));
}
}
exports.onlinePushListener = onlinePushListener;
function onlinePushTransListener(payload, seq) {
const proto = core_1.pb.decode(payload);
handleOnlinePush.call(this, proto[11], seq);
if (!this._sync_cookie)
return;
const buf = proto[10].toBuffer();
const gid = buf.readUInt32BE();
if (proto[3] === 44) {
if (buf[5] === 0 || buf[5] === 1) {
const user_id = buf.readUInt32BE(6);
const set = buf[10] > 0;
this.logger.info(`群${gid}设置管理员${user_id}: ` + set);
emitGroupNoticeEvent(this, gid, {
sub_type: "admin",
user_id, set
});
if (user_id === this.uin)
this.gl.get(gid).admin_flag = set;
this.gml.get(gid).get(user_id).role = set ? "admin" : "member";
}
else if (buf[5] === 0xFF) {
const operator_id = buf.readUInt32BE(6);
const user_id = buf.readUInt32BE(10);
this.logger.info(`群${gid}被转让给` + user_id);
emitGroupNoticeEvent(this, gid, {
sub_type: "transfer",
operator_id, user_id
});
this.gl.get(gid).owner_id = user_id;
this.gml.get(gid).get(user_id).role = "owner";
this.gml.get(gid).get(operator_id).role = "member";
}
}
else if (proto[3] === 34) {
const user_id = buf.readUInt32BE(5);
let operator_id, dismiss = false;
let member = this.gml.get(gid)?.get(user_id);
if (buf[9] === 0x82 || buf[9] === 0x2) {
operator_id = user_id;
this.gml.get(gid)?.delete(user_id);
this.logger.info(`${user_id}离开了群${gid}`);
}
else {
operator_id = buf.readUInt32BE(10);
if (buf[9] === 0x01 || buf[9] === 0x81)
dismiss = true;
if (user_id === this.uin) {
this.gl.delete(gid);
this.gml.delete(gid);
this.logger.info(`更新了群列表,删除了群:${gid}`);
}
else {
this.gml.get(gid)?.delete(user_id);
this.logger.info(`${user_id}离开了群${gid}`);
}
}
emitGroupNoticeEvent(this, gid, {
sub_type: "decrease",
user_id, operator_id, dismiss, member
});
this.gl.get(gid).member_count--;
}
}
exports.onlinePushTransListener = onlinePushTransListener;
function dmMsgSyncListener(payload, seq) {
const proto = core_1.pb.decode(payload);
handleOnlinePush.call(this, proto[2], seq);
const msg = new message_1.PrivateMessage(proto[1], this.uin);
msg.sender.nickname = this.nickname;
this.em("sync.message", msg);
}
exports.dmMsgSyncListener = dmMsgSyncListener;
const fragmap = new Map();
function groupMsgListener(payload) {
this.stat.recv_msg_cnt++;
if (!this._sync_cookie)
return;
let msg = new message_1.GroupMessage(core_1.pb.decode(payload)[1]);
this.emit(`internal.${msg.group_id}.${msg.rand}`, msg.message_id);
if (msg.user_id === this.uin && this.config.ignore_self)
return;
//分片专属屎山
if (msg.pktnum > 1) {
const k = [this.uin, msg.group_id, msg.user_id, msg.div].join();
if (!fragmap.has(k))
fragmap.set(k, []);
const arr = fragmap.get(k);
arr.push(msg);
setTimeout(() => fragmap.delete(k), 5000);
if (arr.length !== msg.pktnum)
return;
msg = message_1.GroupMessage.combine(arr);
}
if (msg.raw_message) {
msg.group = this.pickGroup(msg.group_id);
msg.member = msg.group.pickMember(msg.user_id);
msg.reply = function (content, quote = false) {
return this.group.sendMsg(content, quote ? this : undefined);
};
msg.recall = function () {
return this.group.recallMsg(this);
};
const sender = msg.sender;
if (msg.member.info) {
const info = msg.member.info;
sender.nickname = info.nickname;
sender.sex = info.sex;
sender.age = info.age;
sender.area = info.area || "";
info.card = sender.card;
info.title = sender.title;
info.level = sender.level;
info.last_sent_time = (0, common_1.timestamp)();
}
this.logger.info(`recv from: [Group: ${msg.group_name}(${msg.group_id}), Member: ${sender.card || sender.nickname}(${sender.user_id})] ` + msg);
this.em("message.group." + msg.sub_type, msg);
msg.group.info.last_sent_time = (0, common_1.timestamp)();
}
}
exports.groupMsgListener = groupMsgListener;
function discussMsgListener(payload, seq) {
this.statistics.recv_msg_cnt++;
const proto = core_1.pb.decode(payload);
handleOnlinePush.call(this, proto[2], seq);
if (!this._sync_cookie)
return;
const msg = new message_1.DiscussMessage(proto[1]);
if (msg.user_id === this.uin && this.config.ignore_self)
return;
if (msg.raw_message) {
msg.discuss = this.pickDiscuss(msg.discuss_id);
msg.reply = msg.discuss.sendMsg.bind(msg.discuss);
this.logger.info(`recv from: [Discuss: ${msg.discuss_name}(${msg.discuss_id}), Member: ${msg.sender.card}(${msg.sender.user_id})] ` + msg);
this.em("message.discuss", msg);
}
}
exports.discussMsgListener = discussMsgListener;