From 36783ed669b5c33c67b60a6133f04044c66c51df Mon Sep 17 00:00:00 2001 From: takayama Date: Tue, 8 Sep 2020 18:19:37 +0900 Subject: [PATCH 1/4] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=8F=91=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client.js | 6 +- lib/message.js | 67 +++++++++------ lib/outgoing.js | 219 +++++++++++++++++------------------------------- 3 files changed, 123 insertions(+), 169 deletions(-) diff --git a/client.js b/client.js index 14235422..84389f9f 100644 --- a/client.js +++ b/client.js @@ -661,8 +661,9 @@ class AndroidClient extends Client { return buildApiRet(100); try { try { - var packet = await outgoing.buildPrivateMessageRequestPacket(user_id, message, auto_escape, this); + var packet = await outgoing.commonMessage(user_id, message, auto_escape, false, false, this); } catch (e) { + this.logger.debug(e); return buildApiRet(100); } let message_id = this.curr_msg_id; @@ -695,8 +696,9 @@ class AndroidClient extends Client { return buildApiRet(100); try { try { - var packet = await outgoing.buildSendGroupMessageRequestPacket(group_id, message, auto_escape, as_long, this); + var packet = await outgoing.commonMessage(group_id, message, auto_escape, true, as_long, this); } catch (e) { + this.logger.debug(e); return buildApiRet(100); } diff --git a/lib/message.js b/lib/message.js index a46e52e1..e331b251 100644 --- a/lib/message.js +++ b/lib/message.js @@ -139,7 +139,7 @@ function parseImage(o) { if (o.origUrl) data.url = "http://c2cpicdw.qpic.cn" + o.origUrl; } else { - data.file = o.md5.toString("hex") + o.size; + data.file = o.md5.toString("hex"); if (o.size) data.file += o.size; if (o.origUrl) @@ -303,10 +303,9 @@ async function buildImageMessage(chain, cq, is_group, is_flash = false) { return false; } } - chain[0] = [], chain[0].push({ - buf, md5, size, index: 0, type: "flash" - }); - return true; + return { + buf, md5, size + }; } let elem, index = chain.length - 1; @@ -449,10 +448,9 @@ async function buildRecordMessage(chain, data, is_group) { return false; } md5 = common.md5(buf), size = buf.length; - chain[0].unshift({ - buf, md5, size, ext, type: "ptt" - }); - return true; + return { + buf, md5, size, ext + }; } /** @@ -469,6 +467,7 @@ async function buildRecordMessage(chain, data, is_group) { * @param {Promise[]} tasks */ async function buildMessageFromString(chain, message, escape, is_group, stat, tasks) { + let elem; if (escape) { stat.length += buildTextMessage(chain, message); return; @@ -480,18 +479,18 @@ async function buildMessageFromString(chain, message, escape, is_group, stat, ta if (text) stat.length += buildTextMessage(chain, text); - const elem = v[0]; - let cq = elem.replace("[CQ:", "cqtype="); + const element = v[0]; + let cq = element.replace("[CQ:", "cqtype="); cq = cq.substr(0, cq.length - 1); cq = querystring.parse(cq, ","); for (let k of Object.keys(cq)) cq[k] = cq[k].replace(/,|[|]|&/g, s__s); - await buildElement(chain, cq.cqtype.trim(), cq, is_group, stat, tasks) - if (stat.has_ptt || stat.has_flash) - break; + elem = await buildElement(chain, cq.cqtype.trim(), cq, is_group, stat, tasks) + if (stat.is_ptt || stat.is_flash) + return elem; - prev_index = v.index + elem.length; + prev_index = v.index + element.length; } if (prev_index < message.length) stat.length += buildTextMessage(chain, message.slice(prev_index).replace(/[|]|&/g, _ss_)); @@ -507,21 +506,31 @@ async function buildMessageFromString(chain, message, escape, is_group, stat, ta async function buildMessage(message, escape, is_group) { const chain = [[]], tasks = []; const stat = { - length: 0, at_cnt: 0, face_cnt: 0, bface_cnt: 0, img_cnt: 0, has_ptt: false, has_flash: false + length: 0, at_cnt: 0, face_cnt: 0, bface_cnt: 0, img_cnt: 0, + is_ptt: false, is_flash: false, is_forward: false }; + let elem; if (typeof message === "string") - await buildMessageFromString(chain, message, escape, is_group, stat, tasks); + elem = await buildMessageFromString(chain, message, escape, is_group, stat, tasks); else { for (let v of message) { if (!v.data) continue; - await buildElement(chain, v.type, v.data, is_group, stat, tasks); - if (stat.has_ptt || stat.has_flash) + elem = await buildElement(chain, v.type, v.data, is_group, stat, tasks); + if (stat.is_ptt || stat.is_flash) break; } } - if (stat.has_ptt) { - return [chain[0][0]]; + if (stat.is_ptt) { + return { + type: "ptt", elem + } + } + + if (stat.is_flash) { + return { + type: "flash", elem + } } if (tasks.length) @@ -590,13 +599,19 @@ async function buildElement(chain, type, data, is_group, stat, tasks) { tasks.push(task); break; case "flash": - var task = await buildImageMessage(chain, data, is_group, true); - if (task instanceof Promise) - stat.has_flash = true; - tasks.push(task); + const flash = await buildImageMessage(chain, data, is_group, true); + if (flash) { + stat.is_flash = true; + return flash; + } break; case "record": - stat.has_ptt = await buildRecordMessage(chain, data, is_group); + const ptt = await buildRecordMessage(chain, data, is_group); + if (ptt) { + stat.is_ptt = true; + return ptt; + } + break; default: break; } diff --git a/lib/outgoing.js b/lib/outgoing.js index d2eaabb4..89150709 100644 --- a/lib/outgoing.js +++ b/lib/outgoing.js @@ -411,62 +411,23 @@ function buildGroupMemberListRequestPacket(group_id, next_uin, c) { //发消息---------------------------------------------------------------------------------------------------- -async function buildPrivateMessageRequestPacket(user_id, message, escape, c) { - let elems = await buildMessage(message, escape, false); - const images = elems.shift().slice(0, 20), is_long = elems.pop(); - let flash; - if (images.length > 0) { - try { - const resp = await c.send(buildOffPicUpRequestPacket(user_id, images, c)); - for (let i = 0; i < resp.msgTryUpImgRsp.length; ++i) { - const v = resp.msgTryUpImgRsp[i]; - if (v.result > 0) - throw new Error(v.failMsg); - images[i].key = v.upUkey; - images[i].exists = v.boolFileExit; - if (images[i].type === "flash") { - flash = images[i]; - flash.resId = v.upResid; - } else { - elems[images[i].index].notOnlineImage.resId = v.upResid; - elems[images[i].index].notOnlineImage.downloadPath = v.upResid; - } - } - uploadImages(c.uin, resp.msgTryUpImgRsp[0].uint32UpIp, resp.msgTryUpImgRsp[0].uint32UpPort, images); - } catch (e) { - c.logger.debug(e.stack); - } - } - - if (flash) { - elems = [ - { - commonElem: { - serviceType: 3, - pbElem: pb.encode("MsgElemInfoServtype3", { - flashC2cPic: { - fileLen: flash.size, - filePath: flash.resId, - resId: flash.resId, - picMd5: flash.md5, - oldPicMd5: false - } - }), - businessType: 0, - } - }, - { - text: {str: "[闪照]请使用新版手机QQ查看闪照。"} - } - ] +async function commonMessage(target, message, escape, is_group, as_long, c) { + let elems = await buildMessage(message, escape, is_group); + if (!Array.isArray(elems)) { + if (elems.type === "ptt") + return await buildPttMessageRequestPacket(target, elems.elem, is_group, c); + if (elems.type === "flash") + return await buildFlashMessageRequestPacket(target, elems.elem, is_group, c); } - + const images = elems.shift(), is_long = elems.pop(); + await commonImageMessage(target, images, is_group, elems, c); if (!elems.length) throw new Error("消息内容为空"); - - if (is_long) - elems = await toLongMessageElems(user_id, elems, c); - + if (is_long || as_long) + elems = await toLongMessageElems(is_group?common.code2uin(target):target, elems, c); + return (is_group?commonGroupMessage:commonPrivateMessage).call(null, target, {elems}, c); +} +function commonPrivateMessage(user_id, rich, c) { const target = c.findStranger(user_id); if (target && target.group_id) { var routing = {grpTmp: { @@ -476,7 +437,6 @@ async function buildPrivateMessageRequestPacket(user_id, message, escape, c) { } else { var routing = {c2c: {toUin: user_id}}; } - c.nextSeq(); const random = common.rand(4); c.curr_msg_id = common.genSelfMessageId(user_id, c.seq_id, random); @@ -488,7 +448,7 @@ async function buildPrivateMessageRequestPacket(user_id, message, escape, c) { divSeq: 0 }, msgBody: { - richText: {elems} + richText: rich }, msgSeq: c.seq_id, msgRand: random, @@ -503,71 +463,14 @@ async function buildPrivateMessageRequestPacket(user_id, message, escape, c) { }); return commonUNI(c, CMD.SEND_MSG, body); } -async function buildSendGroupMessageRequestPacket(group_id, message, escape, as_long, c) { - let elems = await buildMessage(message, escape, true); - - if (elems.length === 1) { - return await buildGroupPttMessageRequestPacket(group_id, elems[0], c); - } - - const images = elems.shift().slice(0, 20), is_long = elems.pop(); - let flash; - if (images.length > 0) { - try { - const resp = await c.send(buildImageStoreRequestPacket(group_id, images, c)); - for (let i = 0; i < resp.msgTryUpImgRsp.length; ++i) { - const v = resp.msgTryUpImgRsp[i]; - if (v.result > 0) - throw new Error(v.failMsg); - images[i].key = v.upUkey; - images[i].exists = v.boolFileExit; - if (images[i].type === "flash") { - flash = images[i]; - flash.fid = v.fid.low; - } else - elems[images[i].index].customFace.fileId = v.fid.low; - } - uploadImages(c.uin, resp.msgTryUpImgRsp[0].uint32UpIp, resp.msgTryUpImgRsp[0].uint32UpPort, images); - } catch (e) { - c.logger.debug(e.stack); - } - } - - if (flash) { - elems = [ - { - commonElem: { - serviceType: 3, - pbElem: pb.encode("MsgElemInfoServtype3", { - flashTroopPic: { - size: flash.size, - filePath: flash.md5.toString("hex"), - md5: flash.md5, - fileId: flash.fid, - } - }), - businessType: 0, - } - }, - { - text: {str: "[闪照]请使用新版手机QQ查看闪照。"} - } - ] - } - - if (!elems.length) - throw new Error("消息内容为空"); - - if (is_long || as_long) - elems = await toLongMessageElems(common.code2uin(group_id), elems, c); - +function commonGroupMessage(group_id, rich, c) { c.nextSeq(); c.curr_msg_rand = common.rand(); const body = pb.encode("SendMessageRequest", { routingHead: {grp: {groupCode: group_id}}, contentHead: {pkgNum: 1}, msgBody: { - richText: {elems} + richText: rich }, msgSeq: c.seq_id, msgRand: c.curr_msg_rand, @@ -576,6 +479,31 @@ async function buildSendGroupMessageRequestPacket(group_id, message, escape, as_ }); return commonUNI(c, CMD.SEND_MSG, body); } +async function commonImageMessage(target, images, is_group, elems, c) { + if (!images.length) return; + images = images.slice(0, 20); + try { + if (is_group) + var resp = await c.send(buildImageStoreRequestPacket(target, images, c)); + else + var resp = await c.send(buildOffPicUpRequestPacket(target, images, c)); + for (let i = 0; i < resp.msgTryUpImgRsp.length; ++i) { + var v = resp.msgTryUpImgRsp[i]; + images[i].key = v.upUkey; + images[i].exists = v.boolFileExit; + images[i].fid = is_group ? v.fid.low : v.upResid; + if (elems) { + if (is_group) + elems[images[i].index].customFace.fileId = images[i].fid; + else { + elems[images[i].index].notOnlineImage.resId = images[i].fid; + elems[images[i].index].notOnlineImage.downloadPath = images[i].fid; + } + } + } + uploadImages(c.uin, v.uint32UpIp, v.uint32UpPort, images); + } catch (e) {} +} async function toLongMessageElems(uin, elems, c) { const msg = [{ head: { @@ -660,35 +588,45 @@ async function toLongMessageElems(uin, elems, c) { }, ]; } -async function buildGroupPttMessageRequestPacket(group_id, ptt, c) { +async function buildPttMessageRequestPacket(group_id, ptt, is_group, c) { const resp = await c.send(buildPttUpRequestPacket(group_id, ptt, c)); const v = resp.msgTryUpPttRsp[0]; if (!v.boolFileExit) await uploadPtt(ptt, v); - c.nextSeq(); - c.curr_msg_rand = common.rand(); - const body = pb.encode("SendMessageRequest", { - routingHead: {grp: {groupCode: group_id}}, - contentHead: {pkgNum: 1}, - msgBody: { - richText: { - ptt: { - fileType: 4, - fileMd5: ptt.md5, - fileName: ptt.md5.toString("hex") + ".amr", - fileSize: ptt.length, - boolValid: true, - groupFileKey: v.fileKey, - pbReserve: Buffer.from([8, 0, 40, 0, 56, 0]), - } - } - }, - msgSeq: c.seq_id, - msgRand: c.curr_msg_rand, - syncCookie: BUF0, - msgVia: 1, - }); - return commonUNI(c, CMD.SEND_MSG, body); + ptt = { + fileType: 4, + fileMd5: ptt.md5, + fileName: ptt.md5.toString("hex") + ".amr", + fileSize: ptt.length, + boolValid: true, + groupFileKey: v.fileKey, + pbReserve: Buffer.from([8, 0, 40, 0, 56, 0]), + }; + return commonGroupMessage(group_id, {ptt}, c); +} +async function buildFlashMessageRequestPacket(target, flash, is_group, c) { + await commonImageMessage(target, [flash], is_group, null, c); + const elem = is_group ? {flashTroopPic: { + size: flash.size, + filePath: flash.md5.toString("hex"), + md5: flash.md5, + fileId: flash.fid, + }} : {flashC2cPic: { + fileLen: flash.size, + filePath: flash.fid, + resId: flash.fid, + picMd5: flash.md5.toString("hex"), + oldPicMd5: false + }}; + const elems = [ + {commonElem: { + serviceType: 3, + pbElem: pb.encode("MsgElemInfoServtype3", elem), + businessType: 0, + }}, + {text: {str: "[闪照]请使用新版手机QQ查看闪照。"}} + ]; + return (is_group?commonGroupMessage:commonPrivateMessage).call(null, target, {elems}, c); } //好友申请群申请---------------------------------------------------------------------------------------------------- @@ -1052,8 +990,7 @@ module.exports = { buildHeartbeatRequestPacket, buildClientRegisterRequestPacket, buildConfPushResponsePacket, // send&recv message - buildGetMessageRequestPacket, buildDeleteMessageRequestPacket, - buildPrivateMessageRequestPacket, buildSendGroupMessageRequestPacket, + buildGetMessageRequestPacket, buildDeleteMessageRequestPacket, commonMessage, // get list&info buildFriendListRequestPacket, buildGroupListRequestPacket, buildGroupMemberListRequestPacket, From 0281f7bdd8070ed4005df831acb4854992f3cc73 Mon Sep 17 00:00:00 2001 From: takayama Date: Tue, 8 Sep 2020 22:27:43 +0900 Subject: [PATCH 2/4] =?UTF-8?q?=E6=B6=88=E6=81=AF=E8=BD=AC=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/message.js | 28 ++++++++++++++++ lib/outgoing.js | 83 +++++++++++++++++++++++++++++++++++++++++++++-- package-lock.json | 2 +- package.json | 2 +- 4 files changed, 110 insertions(+), 5 deletions(-) diff --git a/lib/message.js b/lib/message.js index e331b251..95611e0a 100644 --- a/lib/message.js +++ b/lib/message.js @@ -453,6 +453,19 @@ async function buildRecordMessage(chain, data, is_group) { }; } +function buildForwardNode(chain, data) { + let {name, uin, content, time} = data; + uin = parseInt(uin); + if (!common.checkUin(uin) || !content) return false; + content = content.toString(); + time = time ? parseInt(time) : common.timestamp(); + name = name ? name : "无名氏"; + chain.push({ + uin, content, time, name + }); + return true; +} + /** * @async * @param {Array} chain @@ -533,6 +546,13 @@ async function buildMessage(message, escape, is_group) { } } + if (stat.is_forward) { + chain.shift(); + return { + type: "forward", elem: chain + } + } + if (tasks.length) await Promise.all(tasks); @@ -571,6 +591,10 @@ async function buildMessage(message, escape, is_group) { * @param {Promise[]} tasks 异步任务列表 */ async function buildElement(chain, type, data, is_group, stat, tasks) { + if (stat.is_forward && type !== "node") + return; + if (chain.length > 1 && !stat.is_forward && type === "node") + return; switch (type) { // case "reply": // buildReplyMessage(chain, data); @@ -612,6 +636,10 @@ async function buildElement(chain, type, data, is_group, stat, tasks) { return ptt; } break; + case "node": + if (buildForwardNode(chain, data)) + stat.is_forward = true; + break; default: break; } diff --git a/lib/outgoing.js b/lib/outgoing.js index 89150709..441f439a 100644 --- a/lib/outgoing.js +++ b/lib/outgoing.js @@ -418,6 +418,8 @@ async function commonMessage(target, message, escape, is_group, as_long, c) { return await buildPttMessageRequestPacket(target, elems.elem, is_group, c); if (elems.type === "flash") return await buildFlashMessageRequestPacket(target, elems.elem, is_group, c); + if (elems.type === "forward") + return await buildForwardMessageRequestPacket(is_group?common.code2uin(target):target, elems.elem, is_group, c); } const images = elems.shift(), is_long = elems.pop(); await commonImageMessage(target, images, is_group, elems, c); @@ -505,12 +507,13 @@ async function commonImageMessage(target, images, is_group, elems, c) { } catch (e) {} } async function toLongMessageElems(uin, elems, c) { + const seq = common.rand(); const msg = [{ head: { fromUin: c.uin, - msgSeq: c.nextSeq(), + msgSeq: seq, msgTime: common.timestamp(), - msgUid: 0x01000000000000000n | BigInt(common.rand()), + msgUid: 0x01000000000000000n | BigInt(seq), mutiltransHead: { msgId: 1, }, @@ -574,7 +577,7 @@ async function toLongMessageElems(uin, elems, c) { return [ { richMsg: { - template1: Buffer.concat([BUF1, zlib.gzipSync(templete)]), + template1: Buffer.concat([BUF1, zlib.deflateSync(templete)]), serviceId: 35, msgResId: BUF0, } @@ -628,6 +631,80 @@ async function buildFlashMessageRequestPacket(target, flash, is_group, c) { ]; return (is_group?commonGroupMessage:commonPrivateMessage).call(null, target, {elems}, c); } +async function buildForwardMessageRequestPacket(uin, nodes, is_group, c) { + const seq = common.rand(), msg = []; + for (let v of nodes) { + msg.push({ + head: { + fromUin: v.uin, + msgSeq: seq, + msgTime: v.time, + msgUid: 0x01000000000000000n | BigInt(seq), + mutiltransHead: { + msgId: 1, + }, + msgType: 82, + groupInfo: { + groupCode: common.uin2code(uin), + groupRank: BUF0, + groupName: BUF0, + groupCard: v.name, + }, + }, + body: { + richText: { + elems: [{text: {str: v.content}}] + }, + }, + }) + } + const compressed = zlib.gzipSync(pb.encode("PbMultiMsgTransmit", { + msg, pbItemList: [{ + fileName: "MultiMsg", + buffer: pb.encode("PbMultiMsgNew", {msg}), + }] + })); + let resp; + try { + resp = await c.send(buildMultiApplyUpRequestPacket(uin, compressed, 2, c)); + resp = resp.multimsgApplyupRsp[0]; + if (resp.result > 0) + throw new Error(); + const body = pb.encode("LongReqBody", { + subcmd: 1, + termType: 5, + platformType: 9, + msgUpReq: [{ + msgType: 3, + dstUin: uin, + msgContent: compressed, + storeType: 2, + msgUkey: resp.msgUkey, + }], + }); + uploadMultiMessage(c.uin, resp.uint32UpIp, resp.uint32UpPort, { + buf: body, + md5: common.md5(body), + key: resp.msgSig + }); + } catch (e) { + throw new Error(); + } + let preview = ""; + for (let v of nodes) + preview += ` ${v.name}:${v.content} ` + const template = ` + 群聊的聊天记录 ${preview}
查看转发消息
`; + const elems = [ + { + richMsg: { + template1: Buffer.concat([BUF1, zlib.deflateSync(template)]), + serviceId: 35, + } + }, + ]; + return (is_group?commonGroupMessage:commonPrivateMessage).call(null, is_group?common.uin2code(uin):uin, {elems}, c); +} //好友申请群申请---------------------------------------------------------------------------------------------------- diff --git a/package-lock.json b/package-lock.json index 59acf026..ffde7635 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "oicq", - "version": "1.2.4", + "version": "1.2.5", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index bd8ed37b..c0f15468 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "oicq", - "version": "1.2.4", + "version": "1.2.5", "description": "QQ protocol!", "main": "client.js", "scripts": { From 49192a0bb04b63cc4a19bb822d00510bc9a6dee2 Mon Sep 17 00:00:00 2001 From: takayama Date: Wed, 9 Sep 2020 01:08:07 +0900 Subject: [PATCH 3/4] =?UTF-8?q?=E5=90=88=E5=B9=B6=E8=BD=AC=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/outgoing.js | 4 ++-- package-lock.json | 2 +- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/outgoing.js b/lib/outgoing.js index 441f439a..8a31e926 100644 --- a/lib/outgoing.js +++ b/lib/outgoing.js @@ -692,8 +692,8 @@ async function buildForwardMessageRequestPacket(uin, nodes, is_group, c) { } let preview = ""; for (let v of nodes) - preview += ` ${v.name}:${v.content} ` - const template = ` + preview += ` ${v.name}:${v.content} ` + const template = ` 群聊的聊天记录 ${preview}
查看转发消息
`; const elems = [ { diff --git a/package-lock.json b/package-lock.json index ffde7635..c37b45e0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "oicq", - "version": "1.2.5", + "version": "1.2.7", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index c0f15468..cadaea16 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "oicq", - "version": "1.2.5", + "version": "1.2.7", "description": "QQ protocol!", "main": "client.js", "scripts": { From e8e4e511569301bcc0df1d7b995797f5d74aa124 Mon Sep 17 00:00:00 2001 From: takayama Date: Wed, 9 Sep 2020 11:03:45 +0900 Subject: [PATCH 4/4] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=8F=91=E9=80=81?= =?UTF-8?q?=E5=9C=B0=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/project.md | 26 ++++++------------------ lib/message.js | 51 +++++++++++++++++++++++++++++++++++++++++++---- package-lock.json | 2 +- package.json | 2 +- 4 files changed, 55 insertions(+), 26 deletions(-) diff --git a/docs/project.md b/docs/project.md index 7178b1c8..c1a7b58b 100644 --- a/docs/project.md +++ b/docs/project.md @@ -5,11 +5,11 @@ ---- -|[消息]|文字和表情|长消息|图片|语音|合并转发|其他富文本| +|[消息]|文字和表情|长消息|图片|语音|合并转发|xml/json| |-|-|-|-|-|-|-| -|好友|◯|◯|◯|✕|✕|✕| -|群聊|◯|◯|◯|◯|✕|✕| -|临时会话|◯|◯|◯|✕|✕|✕| +|好友|◯|◯|◯|✕|◯|✕| +|群聊|◯|◯|◯|◯|◯|✕| +|临时会话|◯|◯|◯|✕|◯|✕| ---- @@ -59,21 +59,7 @@ |file|◯|✕|群文件,[CQ:file,url=xxxxxx,size=123456,md5=xxxxxx,duration=0,name=xxxxxx]| |music|✕|✕| |video|✕|✕| -|location|✕|✕| +|location|◯|◯|[CQ:location,address=江西省九江市修水县,lat=29.063940,lng=114.339610]| |reply|✕|✕| |share|✕|✕| - ----- - -## 不会支持的功能 - -* 点赞 -* 抢红包等金钱相关 -* 搜索添加群、搜索添加好友 -* 自定义(伪造)消息转发 -* 自定义卡片消息 - -## 考虑支持的功能 - -* 添加群员为好友 -* 邀请好友入群 +|node|✕|◯|[CQ:node,uin=123456789,name=昵称,content=消息内容,time=时间戳]
time可省略,暂时只支持纯文本| diff --git a/lib/message.js b/lib/message.js index 95611e0a..bf32c0d2 100644 --- a/lib/message.js +++ b/lib/message.js @@ -43,7 +43,7 @@ function s__s(s) { function parseMessage(elems) { const chain = []; let raw_message = ""; - let bface_tmp = null; + let bface_tmp = null, light_app = false; for (let v of elems) { const type = Object.keys(v)[0]; const msg = {type:"",data:{}}; @@ -62,12 +62,20 @@ function parseMessage(elems) { // console.log(a.toString()); break; case "lightApp": + const data = JSON.parse(zlib.unzipSync(o.data.slice(1)).toString()); + if (data.app === "com.tencent.map") { + msg.type = "location"; + msg.data = data.meta["Location.Search"]; + delete msg.data.from; + light_app = true; + } break; case "transElemInfo": msg.type = "file"; msg.data = pb.decode("ObjMsg", o.elemValue.slice(3)).msgContentInfo[0].msgFile; break; case "text": + if (light_app) break; if (bface_tmp && o.str && o.str.startsWith("[")) { msg.data.file = bface_tmp, msg.type = "bface"; msg.data.text = o.str.replace("[","").replace("]","").trim(); @@ -151,6 +159,7 @@ function parseImage(o) { //---------------------------------------------------------------------------------------------------- const AT_BUF = Buffer.from([0,1,0,0,0]); +const BUF1 = Buffer.from([1]); const BUF2 = Buffer.alloc(2); const BUF4 = Buffer.alloc(4); const FACE_OLD_BUF = Buffer.from([0x00, 0x01, 0x00, 0x04, 0x52, 0xCC, 0xF5, 0xD0]); @@ -466,6 +475,35 @@ function buildForwardNode(chain, data) { return true; } +function buildLocationNode(chain, data) { + let {address, lat, lng, name, id} = data; + if (!address || !lat || !lng) return; + name = name ? name : "位置分享"; + let build = { + config: { forward: true, type: 'card', autosize: true }, + prompt: '[应用]地图', + from: 1, + app: 'com.tencent.map', + ver: '1.0.3.5', + view: 'LocationShare', + meta: { + 'Location.Search': { + from: 'plusPanel', + id: id?id:"", + lat, lng, name, address + } + }, + desc: '地图' + }; + build = Buffer.concat([BUF1, zlib.deflateSync(JSON.stringify(build))]); + chain.push({ + lightApp: {data: build} + }); + chain.push({ + text: {str: "收到[[应用]地图]消息,请升级QQ版本查看"} + }); +} + /** * @async * @param {Array} chain @@ -490,7 +528,7 @@ async function buildMessageFromString(chain, message, escape, is_group, stat, ta for (let v of res) { const text = message.slice(prev_index, v.index).replace(/[|]|&/g, _ss_); if (text) - stat.length += buildTextMessage(chain, text); + await buildElement(chain, "text", {text}, is_group, stat, tasks) const element = v[0]; let cq = element.replace("[CQ:", "cqtype="); @@ -505,8 +543,10 @@ async function buildMessageFromString(chain, message, escape, is_group, stat, ta prev_index = v.index + element.length; } - if (prev_index < message.length) - stat.length += buildTextMessage(chain, message.slice(prev_index).replace(/[|]|&/g, _ss_)); + if (prev_index < message.length) { + const text = message.slice(prev_index).replace(/[|]|&/g, _ss_); + await buildElement(chain, "text", {text}, is_group, stat, tasks) + } } /** @@ -640,6 +680,9 @@ async function buildElement(chain, type, data, is_group, stat, tasks) { if (buildForwardNode(chain, data)) stat.is_forward = true; break; + case "location": + buildLocationNode(chain, data); + break; default: break; } diff --git a/package-lock.json b/package-lock.json index c37b45e0..04612054 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "oicq", - "version": "1.2.7", + "version": "1.3.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index cadaea16..ea3737a0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "oicq", - "version": "1.2.7", + "version": "1.3.0", "description": "QQ protocol!", "main": "client.js", "scripts": {