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{