diff --git a/client/client.go b/client/client.go index 9a0127ec..c7533f39 100644 --- a/client/client.go +++ b/client/client.go @@ -3,7 +3,6 @@ package client import ( "crypto/md5" "fmt" - "math" "math/rand" "net" "sort" @@ -19,7 +18,6 @@ import ( "github.com/Mrs4s/MiraiGo/client/pb/msg" "github.com/Mrs4s/MiraiGo/internal/crypto" "github.com/Mrs4s/MiraiGo/internal/packets" - "github.com/Mrs4s/MiraiGo/message" "github.com/Mrs4s/MiraiGo/utils" ) @@ -546,68 +544,6 @@ func (c *QQClient) GetFriendList() (*FriendListResponse, error) { return r, nil } -func (c *QQClient) GetForwardMessage(resID string) *message.ForwardMessage { - m := c.DownloadForwardMessage(resID) - if m == nil { - return nil - } - var item *msg.PbMultiMsgItem - ret := &message.ForwardMessage{Nodes: []*message.ForwardNode{}} - for _, iter := range m.Items { - if iter.GetFileName() == m.FileName { - item = iter - } - } - if item == nil { - return nil - } - for _, m := range item.GetBuffer().GetMsg() { - name := m.Head.GetFromNick() - if m.Head.GetMsgType() == 82 && m.Head.GroupInfo != nil { - name = m.Head.GroupInfo.GetGroupCard() - } - ret.Nodes = append(ret.Nodes, &message.ForwardNode{ - SenderId: m.Head.GetFromUin(), - SenderName: name, - Time: m.Head.GetMsgTime(), - Message: message.ParseMessageElems(m.Body.RichText.Elems), - }) - } - return ret -} - -func (c *QQClient) DownloadForwardMessage(resId string) *message.ForwardElement { - i, err := c.sendAndWait(c.buildMultiApplyDownPacket(resId)) - if err != nil { - return nil - } - multiMsg := i.(*msg.PbMultiMsgTransmit) - if multiMsg.GetPbItemList() == nil { - return nil - } - var pv string - for i := 0; i < int(math.Min(4, float64(len(multiMsg.GetMsg())))); i++ { - m := multiMsg.Msg[i] - pv += fmt.Sprintf(`%s: %s`, - func() string { - if m.Head.GetMsgType() == 82 && m.Head.GroupInfo != nil { - return m.Head.GroupInfo.GetGroupCard() - } - return m.Head.GetFromNick() - }(), - message.ToReadableString( - message.ParseMessageElems(multiMsg.Msg[i].GetBody().GetRichText().Elems), - ), - ) - } - return genForwardTemplate( - resId, pv, "群聊的聊天记录", "[聊天记录]", "聊天记录", - fmt.Sprintf("查看 %d 条转发消息", len(multiMsg.GetMsg())), - time.Now().UnixNano(), - multiMsg.GetPbItemList(), - ) -} - func (c *QQClient) SendGroupPoke(groupCode, target int64) { _, _ = c.sendAndWait(c.buildGroupPokePacket(groupCode, target)) } diff --git a/client/multimsg.go b/client/multimsg.go index b5e7696c..6be8a606 100644 --- a/client/multimsg.go +++ b/client/multimsg.go @@ -2,6 +2,8 @@ package client import ( "fmt" + "math" + "time" "github.com/pkg/errors" @@ -11,6 +13,7 @@ import ( "github.com/Mrs4s/MiraiGo/client/pb/multimsg" "github.com/Mrs4s/MiraiGo/internal/packets" "github.com/Mrs4s/MiraiGo/internal/proto" + "github.com/Mrs4s/MiraiGo/message" "github.com/Mrs4s/MiraiGo/utils" ) @@ -132,3 +135,84 @@ func decodeMultiApplyDownResponse(_ *QQClient, _ *incomingPacketInfo, payload [] } return &mt, nil } + +type forwardMsgLinker struct { + items map[string]*msg.PbMultiMsgItem +} + +func (l *forwardMsgLinker) link(name string) *message.ForwardMessage { + item := l.items[name] + if item == nil { + return nil + } + nodes := make([]*message.ForwardNode, 0, len(item.GetBuffer().GetMsg())) + for _, m := range item.GetBuffer().GetMsg() { + name := m.Head.GetFromNick() + if m.Head.GetMsgType() == 82 && m.Head.GroupInfo != nil { + name = m.Head.GroupInfo.GetGroupCard() + } + + msgElems := message.ParseMessageElems(m.Body.RichText.Elems) + for i, elem := range msgElems { + if forward, ok := elem.(*message.ForwardElement); ok { + if forward.FileName != "" { + msgElems[i] = l.link(forward.FileName) // 递归处理嵌套转发 + } + } + } + + nodes = append(nodes, &message.ForwardNode{ + SenderId: m.Head.GetFromUin(), + SenderName: name, + Time: m.Head.GetMsgTime(), + Message: msgElems, + }) + } + return &message.ForwardMessage{Nodes: nodes} +} + +func (c *QQClient) GetForwardMessage(resID string) *message.ForwardMessage { + m := c.DownloadForwardMessage(resID) + if m == nil { + return nil + } + linker := forwardMsgLinker{ + items: make(map[string]*msg.PbMultiMsgItem), + } + for _, item := range m.Items { + linker.items[item.GetFileName()] = item + } + return linker.link(m.FileName) +} + +func (c *QQClient) DownloadForwardMessage(resId string) *message.ForwardElement { + i, err := c.sendAndWait(c.buildMultiApplyDownPacket(resId)) + if err != nil { + return nil + } + multiMsg := i.(*msg.PbMultiMsgTransmit) + if multiMsg.GetPbItemList() == nil { + return nil + } + var pv string + for i := 0; i < int(math.Min(4, float64(len(multiMsg.GetMsg())))); i++ { + m := multiMsg.Msg[i] + pv += fmt.Sprintf(`%s: %s`, + func() string { + if m.Head.GetMsgType() == 82 && m.Head.GroupInfo != nil { + return m.Head.GroupInfo.GetGroupCard() + } + return m.Head.GetFromNick() + }(), + message.ToReadableString( + message.ParseMessageElems(multiMsg.Msg[i].GetBody().GetRichText().Elems), + ), + ) + } + return genForwardTemplate( + resId, pv, "群聊的聊天记录", "[聊天记录]", "聊天记录", + fmt.Sprintf("查看 %d 条转发消息", len(multiMsg.GetMsg())), + time.Now().UnixNano(), + multiMsg.GetPbItemList(), + ) +} diff --git a/message/forward.go b/message/forward.go index 62cc8e45..9062f11d 100644 --- a/message/forward.go +++ b/message/forward.go @@ -3,6 +3,8 @@ package message import ( "bytes" "crypto/md5" + "regexp" + "sync" "github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/client/pb/msg" @@ -34,6 +36,10 @@ type ForwardElement struct { // *----- Implementations -----* // +func (f *ForwardMessage) Type() ElementType { + return Forward +} + // Type impl IMessageElement func (e *ForwardElement) Type() ElementType { return Forward @@ -161,3 +167,36 @@ func (f *ForwardMessage) packForwardMsg(seq int32, random int32, groupCode int64 } return ml } + +type lazyRegex struct { + once sync.Once + reg *regexp.Regexp + Pattern string +} + +func (l *lazyRegex) init() { + l.reg = regexp.MustCompile(l.Pattern) +} + +func (l *lazyRegex) findMatch1(content string) string { + l.once.Do(l.init) + matches := l.reg.FindStringSubmatch(content) + if matches == nil { + return "" + } + return matches[1] +} + +var ( + mResID = lazyRegex{Pattern: `m_resid="(.*?)"`} + mFileName = lazyRegex{Pattern: `m_fileName="(.*?)"`} +) + +func forwardMsgFromXML(xml string) *ForwardElement { + resid := mResID.findMatch1(xml) + fileName := mFileName.findMatch1(xml) + if resid == "" && fileName == "" { + return nil + } + return &ForwardElement{FileName: fileName, ResId: resid} +} diff --git a/message/message.go b/message/message.go index 887e96b2..d3501273 100644 --- a/message/message.go +++ b/message/message.go @@ -3,7 +3,6 @@ package message import ( "encoding/json" "reflect" - "regexp" "strconv" "strings" @@ -415,10 +414,9 @@ func ParseMessageElems(elems []*msg.Elem) []IMessageElement { } if content != "" { if elem.RichMsg.GetServiceId() == 35 { - reg := regexp.MustCompile(`m_resid="(.*?)"`) - sub := reg.FindAllStringSubmatch(content, -1) - if len(sub) > 0 && len(sub[0]) > 1 { - res = append(res, &ForwardElement{ResId: reg.FindAllStringSubmatch(content, -1)[0][1]}) + elem := forwardMsgFromXML(content) + if elem != nil { + res = append(res, elem) continue } }