From 6ce32da5a1b640d4808cb29a0d4727a76578e021 Mon Sep 17 00:00:00 2001 From: wdvxdr Date: Fri, 25 Dec 2020 20:08:55 +0800 Subject: [PATCH] =?UTF-8?q?send=20forward=20msg=E5=A5=97=E5=A8=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit :poop: --- client/global.go | 31 +++++++++------- client/group_msg.go | 89 ++++++++++++++++++++++++++++++++------------- message/elements.go | 3 +- message/message.go | 57 ++++++++++++++++++++++++++++- message/pack.go | 17 +++++++++ 5 files changed, 156 insertions(+), 41 deletions(-) diff --git a/client/global.go b/client/global.go index 01141b7e..d2e31fe4 100644 --- a/client/global.go +++ b/client/global.go @@ -9,6 +9,7 @@ import ( "math/rand" "net" "sort" + "strconv" "strings" "time" @@ -575,21 +576,27 @@ func packUniRequestData(data []byte) (r []byte) { return } -func genForwardTemplate(resId, preview, title, brief, source, summary string, ts int64) *message.SendingMessage { +func genForwardTemplate(resId, preview, title, brief, source, summary string, ts int64, items []*msg.PbMultiMsgItem) *message.ForwardElement { template := fmt.Sprintf(`%s %s
%s
`, brief, resId, ts, title, preview, summary, source, ) - return &message.SendingMessage{Elements: []message.IMessageElement{ - &message.ServiceElement{ + for index, item := range items { + if item.GetFileName() == "MultiMsg" { + items[index].FileName = proto.String(strconv.FormatInt(ts, 10)) + } + } + return &message.ForwardElement{ + ServiceElement: message.ServiceElement{ Id: 35, Content: template, ResId: resId, SubType: "Forward", }, - }} + Items: items, + } } -func genLongTemplate(resId, brief string, ts int64) *message.SendingMessage { +func genLongTemplate(resId, brief string, ts int64) *message.ServiceElement { limited := func() string { if len(brief) > 30 { return brief[:30] + "…" @@ -599,14 +606,12 @@ func genLongTemplate(resId, brief string, ts int64) *message.SendingMessage { template := fmt.Sprintf(` %s 点击查看完整消息 `, limited, resId, ts, limited, ) - return &message.SendingMessage{Elements: []message.IMessageElement{ - &message.ServiceElement{ - Id: 35, - Content: template, - ResId: resId, - SubType: "Long", - }, - }} + return &message.ServiceElement{ + Id: 35, + Content: template, + ResId: resId, + SubType: "Long", + } } func (c *QQClient) Error(msg string, args ...interface{}) { diff --git a/client/group_msg.go b/client/group_msg.go index 6c60a8dd..b3997224 100644 --- a/client/group_msg.go +++ b/client/group_msg.go @@ -40,14 +40,20 @@ func (c *QQClient) SendGroupMessage(groupCode int64, m *message.SendingMessage, return nil } if (msgLen > 200 || imgCount > 1) && !useFram { - ret := c.sendGroupLongOrForwardMessage(groupCode, true, &message.ForwardMessage{Nodes: []*message.ForwardNode{ - { - SenderId: c.Uin, - SenderName: c.Nickname, - Time: int32(time.Now().Unix()), - Message: m.Elements, - }, - }}) + ret := c.sendGroupMessage(groupCode, true, + &message.SendingMessage{Elements: []message.IMessageElement{ + c.uploadGroupLongMessage(groupCode, + &message.ForwardMessage{Nodes: []*message.ForwardNode{ + { + SenderId: c.Uin, + SenderName: c.Nickname, + Time: int32(time.Now().Unix()), + Message: m.Elements, + }, + }}, + ), + }}, + ) return ret } return c.sendGroupMessage(groupCode, false, m) @@ -55,7 +61,12 @@ func (c *QQClient) SendGroupMessage(groupCode int64, m *message.SendingMessage, // SendGroupForwardMessage 发送群合并转发消息 func (c *QQClient) SendGroupForwardMessage(groupCode int64, m *message.ForwardMessage) *message.GroupMessage { - return c.sendGroupLongOrForwardMessage(groupCode, false, m) + mg := c.UploadGroupForwardMessage(groupCode, m) + return c.sendGroupMessage(groupCode, true, + &message.SendingMessage{Elements: []message.IMessageElement{ + &mg.ServiceElement, + }}, + ) } // GetGroupMessages 从服务器获取历史信息 @@ -134,20 +145,14 @@ func (c *QQClient) sendGroupMessage(groupCode int64, forward bool, m *message.Se } } -func (c *QQClient) sendGroupLongOrForwardMessage(groupCode int64, isLong bool, m *message.ForwardMessage) *message.GroupMessage { +func (c *QQClient) uploadGroupLongMessage(groupCode int64, m *message.ForwardMessage) *message.ServiceElement { if len(m.Nodes) >= 200 { return nil } - ts := time.Now().Unix() + ts := time.Now().UnixNano() seq := c.nextGroupSeq() data, hash := m.CalculateValidationData(seq, rand.Int31(), groupCode) - i, err := c.sendAndWait(c.buildMultiApplyUpPacket(data, hash, func() int32 { - if isLong { - return 1 - } else { - return 2 - } - }(), utils.ToGroupUin(groupCode))) + i, err := c.sendAndWait(c.buildMultiApplyUpPacket(data, hash, 1, utils.ToGroupUin(groupCode))) if err != nil { return nil } @@ -169,13 +174,6 @@ func (c *QQClient) sendGroupLongOrForwardMessage(groupCode int64, isLong bool, m for i, ip := range rsp.Uint32UpIp { err := c.highwayUpload(uint32(ip), int(rsp.Uint32UpPort[i]), rsp.MsgSig, body, 27) if err == nil { - if !isLong { - var pv string - for i := 0; i < int(math.Min(4, float64(len(m.Nodes)))); i++ { - pv += fmt.Sprintf(`%s: %s`, m.Nodes[i].SenderName, message.ToReadableString(m.Nodes[i].Message)) - } - return c.sendGroupMessage(groupCode, true, genForwardTemplate(rsp.MsgResid, pv, "群聊的聊天记录", "[聊天记录]", "聊天记录", fmt.Sprintf("查看 %d 条转发消息", len(m.Nodes)), ts)) - } bri := func() string { var r string for _, n := range m.Nodes { @@ -186,7 +184,46 @@ func (c *QQClient) sendGroupLongOrForwardMessage(groupCode int64, isLong bool, m } return r }() - return c.sendGroupMessage(groupCode, false, genLongTemplate(rsp.MsgResid, bri, ts)) + return genLongTemplate(rsp.MsgResid, bri, ts) + } + } + return nil +} + +func (c *QQClient) UploadGroupForwardMessage(groupCode int64, m *message.ForwardMessage) *message.ForwardElement { + if len(m.Nodes) >= 200 { + return nil + } + ts := time.Now().UnixNano() + seq := c.nextGroupSeq() + data, hash, items := m.CalculateValidationDataForward(seq, rand.Int31(), groupCode) + i, err := c.sendAndWait(c.buildMultiApplyUpPacket(data, hash, 2, utils.ToGroupUin(groupCode))) + if err != nil { + return nil + } + rsp := i.(*multimsg.MultiMsgApplyUpRsp) + body, _ := proto.Marshal(&longmsg.LongReqBody{ + Subcmd: 1, + TermType: 5, + PlatformType: 9, + MsgUpReq: []*longmsg.LongMsgUpReq{ + { + MsgType: 3, + DstUin: utils.ToGroupUin(groupCode), + MsgContent: data, + StoreType: 2, + MsgUkey: rsp.MsgUkey, + }, + }, + }) + for i, ip := range rsp.Uint32UpIp { + err := c.highwayUpload(uint32(ip), int(rsp.Uint32UpPort[i]), rsp.MsgSig, body, 27) + if err == nil { + var pv string + for i := 0; i < int(math.Min(4, float64(len(m.Nodes)))); i++ { + pv += fmt.Sprintf(`%s: %s`, m.Nodes[i].SenderName, message.ToReadableString(m.Nodes[i].Message)) + } + return genForwardTemplate(rsp.MsgResid, pv, "群聊的聊天记录", "[聊天记录]", "聊天记录", fmt.Sprintf("查看 %d 条转发消息", len(m.Nodes)), ts, items) } } return nil diff --git a/message/elements.go b/message/elements.go index 23756f83..b2b27129 100644 --- a/message/elements.go +++ b/message/elements.go @@ -103,7 +103,8 @@ type ServiceElement struct { } type ForwardElement struct { - ResId string + ServiceElement + Items []*msg.PbMultiMsgItem } type LightAppElement struct { diff --git a/message/message.go b/message/message.go index a1e76b8b..80bc3b4c 100644 --- a/message/message.go +++ b/message/message.go @@ -434,7 +434,7 @@ func ParseMessageElems(elems []*msg.Elem) []IMessageElement { reg := regexp.MustCompile(`m_resid="(\w+?.*?)"`) sub := reg.FindAllStringSubmatch(content, -1) if len(sub) > 0 && len(sub[0]) > 1 { - res = append(res, &ForwardElement{ResId: reg.FindAllStringSubmatch(content, -1)[0][1]}) + res = append(res, &ForwardElement{ServiceElement: ServiceElement{ResId: reg.FindAllStringSubmatch(content, -1)[0][1]}}) continue } } @@ -575,6 +575,55 @@ func (forMsg *ForwardMessage) CalculateValidationData(seq, random int32, groupCo return data, hash[:] } +// CalculateValidationDataForward 屎代码 +func (forMsg *ForwardMessage) CalculateValidationDataForward(seq, random int32, groupCode int64) ([]byte, []byte, []*msg.PbMultiMsgItem) { + var msgs []*msg.Message + for _, node := range forMsg.Nodes { + msgs = append(msgs, &msg.Message{ + Head: &msg.MessageHead{ + FromUin: &node.SenderId, + MsgSeq: &seq, + MsgTime: &node.Time, + MsgUid: proto.Int64(0x01000000000000000 | (int64(random) & 0xFFFFFFFF)), + MutiltransHead: &msg.MutilTransHead{ + MsgId: proto.Int32(1), + }, + MsgType: proto.Int32(82), + GroupInfo: &msg.GroupInfo{ + GroupCode: &groupCode, + GroupRank: []byte{}, + GroupName: []byte{}, + GroupCard: &node.SenderName, + }, + }, + Body: &msg.MessageBody{ + RichText: &msg.RichText{ + Elems: func() []*msg.Elem { + return ToProtoElems(node.Message, false) + }(), + }, + }, + }) + } + trans := &msg.PbMultiMsgTransmit{Msg: msgs, PbItemList: []*msg.PbMultiMsgItem{ + { + FileName: proto.String("MultiMsg"), + Buffer: &msg.PbMultiMsgNew{Msg: msgs}, + }, + }} + for _, item1 := range forMsg.Nodes { + for _, item2 := range item1.Message { + if item3, ok := item2.(*ForwardElement); ok { + trans.PbItemList = append(trans.PbItemList, item3.Items...) + } + } + } + b, _ := proto.Marshal(trans) + data := binary.GZipCompress(b) + hash := md5.Sum(data) + return data, hash[:], trans.PbItemList +} + func ToReadableString(m []IMessageElement) (r string) { for _, elem := range m { switch e := elem.(type) { @@ -586,6 +635,12 @@ func ToReadableString(m []IMessageElement) (r string) { r += "/" + e.Name case *GroupImageElement: r += "[图片]" + case *ServiceElement: + if e.SubType == "Forward" { + r += "[聊天记录]" + } + case *ForwardElement: + r += "[聊天记录]" // NOTE: flash pic is singular // To be clarified // case *GroupFlashImgElement: diff --git a/message/pack.go b/message/pack.go index 2b5ec7f5..f62e6344 100644 --- a/message/pack.go +++ b/message/pack.go @@ -162,6 +162,23 @@ func (e *ServiceElement) Pack() (r []*msg.Elem) { return } +func (e *ForwardElement) Pack() (r []*msg.Elem) { + r = []*msg.Elem{} + r = append(r, &msg.Elem{ + RichMsg: &msg.RichMsg{ + Template1: append([]byte{1}, binary.ZlibCompress([]byte(e.Content))...), + ServiceId: &e.Id, + MsgResId: []byte{}, + }, + }) + r = append(r, &msg.Elem{ + Text: &msg.Text{ + Str: proto.String("你的QQ暂不支持查看[转发多条消息],请期待后续版本。"), + }, + }) + return +} + func (e *LightAppElement) Pack() (r []*msg.Elem) { r = []*msg.Elem{} r = append(r, &msg.Elem{