diff --git a/client/global.go b/client/global.go
index 10faba5c..493c8e6b 100644
--- a/client/global.go
+++ b/client/global.go
@@ -1,10 +1,8 @@
package client
import (
- "bytes"
"crypto/md5"
"encoding/hex"
- "encoding/xml"
"fmt"
"math/rand"
"net"
@@ -13,6 +11,9 @@ import (
"strings"
"time"
+ "github.com/pkg/errors"
+ "google.golang.org/protobuf/proto"
+
"github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/binary/jce"
devinfo "github.com/Mrs4s/MiraiGo/client/pb"
@@ -20,8 +21,6 @@ import (
"github.com/Mrs4s/MiraiGo/client/pb/oidb"
"github.com/Mrs4s/MiraiGo/message"
"github.com/Mrs4s/MiraiGo/utils"
- "github.com/pkg/errors"
- "google.golang.org/protobuf/proto"
)
type (
@@ -586,12 +585,6 @@ func packUniRequestData(data []byte) (r []byte) {
return
}
-func XmlEscape(c string) string {
- buf := new(bytes.Buffer)
- _ = xml.EscapeText(buf, []byte(c))
- return buf.String()
-}
-
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,
@@ -617,7 +610,7 @@ func genLongTemplate(resID, brief string, ts int64) *message.ServiceElement {
return brief
}()
template := fmt.Sprintf(` - %s
点击查看完整消息 `,
- XmlEscape(limited), resID, ts, XmlEscape(limited),
+ utils.XmlEscape(limited), resID, ts, utils.XmlEscape(limited),
)
return &message.ServiceElement{
Id: 35,
diff --git a/client/group_msg.go b/client/group_msg.go
index 0003d036..d57a47c7 100644
--- a/client/group_msg.go
+++ b/client/group_msg.go
@@ -7,6 +7,7 @@ import (
"math"
"math/rand"
"strconv"
+ "strings"
"time"
"github.com/Mrs4s/MiraiGo/client/pb/longmsg"
@@ -53,14 +54,12 @@ func (c *QQClient) SendGroupMessage(groupCode int64, m *message.SendingMessage,
ret := c.sendGroupMessage(groupCode, false,
&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,
- },
- }},
+ message.NewForwardMessage().AddNode(&message.ForwardNode{
+ SenderId: c.Uin,
+ SenderName: c.Nickname,
+ Time: int32(time.Now().Unix()),
+ Message: m.Elements,
+ }),
),
}},
)
@@ -71,9 +70,9 @@ func (c *QQClient) SendGroupMessage(groupCode int64, m *message.SendingMessage,
}
// SendGroupForwardMessage 发送群合并转发消息
-func (c *QQClient) SendGroupForwardMessage(groupCode int64, m *message.ForwardMessage) *message.GroupMessage {
+func (c *QQClient) SendGroupForwardMessage(groupCode int64, m *message.ForwardElement) *message.GroupMessage {
return c.sendGroupMessage(groupCode, true,
- &message.SendingMessage{Elements: []message.IMessageElement{c.UploadGroupForwardMessage(groupCode, m)}},
+ &message.SendingMessage{Elements: []message.IMessageElement{m}},
)
}
@@ -161,7 +160,7 @@ func (c *QQClient) sendGroupMessage(groupCode int64, forward bool, m *message.Se
}
func (c *QQClient) uploadGroupLongMessage(groupCode int64, m *message.ForwardMessage) *message.ServiceElement {
- if len(m.Nodes) >= 200 {
+ if m.Length() >= 200 {
return nil
}
ts := time.Now().UnixNano()
@@ -173,25 +172,16 @@ func (c *QQClient) uploadGroupLongMessage(groupCode int64, m *message.ForwardMes
}
for i, ip := range rsp.Uint32UpIp {
err := c.highwayUpload(uint32(ip), int(rsp.Uint32UpPort[i]), rsp.MsgSig, body, 27)
- if err == nil {
- bri := func() string {
- var r string
- for _, n := range m.Nodes {
- r += message.ToReadableString(n.Message)
- if len(r) >= 27 {
- break
- }
- }
- return r
- }()
- return genLongTemplate(rsp.MsgResid, bri, ts)
+ if err != nil {
+ continue
}
+ return genLongTemplate(rsp.MsgResid, m.Brief(), ts)
}
return nil
}
func (c *QQClient) UploadGroupForwardMessage(groupCode int64, m *message.ForwardMessage) *message.ForwardElement {
- if len(m.Nodes) > 200 {
+ if m.Length() > 200 {
return nil
}
ts := time.Now().UnixNano()
@@ -203,13 +193,10 @@ func (c *QQClient) UploadGroupForwardMessage(groupCode int64, m *message.Forward
}
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`, XmlEscape(m.Nodes[i].SenderName), XmlEscape(message.ToReadableString(m.Nodes[i].Message)))
- }
- return genForwardTemplate(rsp.MsgResid, pv, "群聊的聊天记录", "[聊天记录]", "聊天记录", fmt.Sprintf("查看 %d 条转发消息", len(m.Nodes)), ts, items)
+ if err != nil {
+ continue
}
+ return genForwardTemplate(rsp.MsgResid, m.Preview(), "群聊的聊天记录", "[聊天记录]", "聊天记录", fmt.Sprintf("查看 %d 条转发消息", m.Length()), ts, items)
}
return nil
}
@@ -529,10 +516,11 @@ func (c *QQClient) parseGroupMessage(m *msg.Message) *message.GroupMessage {
if extInfo != nil && len(extInfo.GroupCard) > 0 && extInfo.GroupCard[0] == 0x0A {
buf := oidb.D8FCCommCardNameBuf{}
if err := proto.Unmarshal(extInfo.GroupCard, &buf); err == nil && len(buf.RichCardName) > 0 {
- groupCard = ""
+ var gcard strings.Builder
for _, e := range buf.RichCardName {
- groupCard += string(e.Text)
+ gcard.Write(e.Text)
}
+ groupCard = gcard.String()
}
}
if m.Head.GroupInfo != nil && groupCard != "" && mem.CardName != groupCard {
diff --git a/message/elements.go b/message/elements.go
index 0910d47b..bf630c85 100644
--- a/message/elements.go
+++ b/message/elements.go
@@ -178,8 +178,7 @@ func NewPrivateReply(m *PrivateMessage) *ReplyElement {
func NewUrlShare(url, title, content, image string) *ServiceElement {
template := fmt.Sprintf(`- %v%v
`,
- title, url, image, title, content,
- )
+ title, url, image, title, content)
/*
template := fmt.Sprintf(`- %s%s
`,
url, url, image, title, content,
diff --git a/message/forward.go b/message/forward.go
index 21c923f0..1b144d6e 100644
--- a/message/forward.go
+++ b/message/forward.go
@@ -1,18 +1,22 @@
package message
import (
+ "bytes"
"crypto/md5"
"google.golang.org/protobuf/proto"
"github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/client/pb/msg"
+ "github.com/Mrs4s/MiraiGo/utils"
)
// *----- Definitions -----* //
+// ForwardMessage 添加 Node 请用 AddNode 方法
type ForwardMessage struct {
Nodes []*ForwardNode
+ items []*msg.PbMultiMsgItem
}
type ForwardNode struct {
@@ -36,26 +40,67 @@ func (e *ForwardElement) Type() ElementType {
return Forward
}
-func (e *ForwardElement) Pack() (r []*msg.Elem) {
- r = []*msg.Elem{}
- r = append(r, &msg.Elem{
+func (e *ForwardElement) Pack() []*msg.Elem {
+ rich := &msg.Elem{
RichMsg: &msg.RichMsg{
- Template1: append([]byte{1}, binary.ZlibCompress([]byte(e.Content))...),
+ Template1: append([]byte{1}, binary.ZlibCompress(utils.S2B(e.Content))...),
ServiceId: proto.Int32(35),
MsgResId: []byte{},
},
- })
- r = append(r, &msg.Elem{
+ }
+ txt := &msg.Elem{
Text: &msg.Text{
Str: proto.String("你的QQ暂不支持查看[转发多条消息],请期待后续版本。"),
},
- })
- return
+ }
+ return []*msg.Elem{rich, txt}
}
-// Type impl IMessageElement
-func (f *ForwardMessage) Type() ElementType {
- return Forward
+func NewForwardMessage() *ForwardMessage {
+ return &ForwardMessage{}
+}
+
+// AddNode adds a node to the forward message. return for method chaining.
+func (f *ForwardMessage) AddNode(node *ForwardNode) *ForwardMessage {
+ f.Nodes = append(f.Nodes, node)
+ for _, item := range node.Message {
+ if item.Type() != Forward { // quick path
+ continue
+ }
+ if forward, ok := item.(*ForwardElement); ok {
+ f.items = append(f.items, forward.Items...)
+ }
+ }
+ return f
+}
+
+// Length return the length of Nodes.
+func (f *ForwardMessage) Length() int { return len(f.Nodes) }
+
+func (f *ForwardMessage) Brief() string {
+ var brief bytes.Buffer
+ for _, n := range f.Nodes {
+ brief.WriteString(ToReadableString(n.Message))
+ if brief.Len() >= 27 {
+ break
+ }
+ }
+ return brief.String()
+}
+
+func (f *ForwardMessage) Preview() string {
+ var pv bytes.Buffer
+ for i, node := range f.Nodes {
+ if i >= 4 {
+ break
+ }
+ pv.WriteString(``)
+ pv.WriteString(utils.XmlEscape(node.SenderName))
+ pv.WriteString(": ")
+ pv.WriteString(utils.XmlEscape(ToReadableString(node.Message)))
+ pv.WriteString("")
+ }
+ return pv.String()
}
func (f *ForwardMessage) CalculateValidationData(seq, random int32, groupCode int64) ([]byte, []byte) {
@@ -81,13 +126,7 @@ func (f *ForwardMessage) CalculateValidationDataForward(seq, random int32, group
Buffer: &msg.PbMultiMsgNew{Msg: msgs},
},
}}
- for _, node := range f.Nodes {
- for _, message := range node.Message {
- if forwardElement, ok := message.(*ForwardElement); ok {
- trans.PbItemList = append(trans.PbItemList, forwardElement.Items...)
- }
- }
- }
+ trans.PbItemList = append(trans.PbItemList, f.items...)
b, _ := proto.Marshal(trans)
data := binary.GZipCompress(b)
hash := md5.Sum(data)
@@ -95,9 +134,9 @@ func (f *ForwardMessage) CalculateValidationDataForward(seq, random int32, group
}
func (f *ForwardMessage) packForwardMsg(seq int32, random int32, groupCode int64) []*msg.Message {
- msgs := make([]*msg.Message, 0, len(f.Nodes))
+ ml := make([]*msg.Message, 0, len(f.Nodes))
for _, node := range f.Nodes {
- msgs = append(msgs, &msg.Message{
+ ml = append(ml, &msg.Message{
Head: &msg.MessageHead{
FromUin: &node.SenderId,
MsgSeq: &seq,
@@ -121,5 +160,5 @@ func (f *ForwardMessage) packForwardMsg(seq int32, random int32, groupCode int64
},
})
}
- return msgs
+ return ml
}
diff --git a/message/message.go b/message/message.go
index 95f807c6..ccc38bb9 100644
--- a/message/message.go
+++ b/message/message.go
@@ -418,7 +418,7 @@ func ParseMessageElems(elems []*msg.Elem) []IMessageElement {
}
if content != "" {
if elem.RichMsg.GetServiceId() == 35 {
- reg := regexp.MustCompile(`m_resid="(.+)"`)
+ 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]})
diff --git a/utils/string.go b/utils/string.go
index 0078e82b..41f69ab4 100644
--- a/utils/string.go
+++ b/utils/string.go
@@ -1,6 +1,7 @@
package utils
import (
+ "encoding/xml"
"math/rand"
"reflect"
"strconv"
@@ -66,3 +67,10 @@ func S2B(s string) (b []byte) {
bh.Len = sh.Len
return
}
+
+// XmlEscape xml escape string
+func XmlEscape(c string) string {
+ buf := new(strings.Builder)
+ _ = xml.EscapeText(buf, []byte(c))
+ return buf.String()
+}