From 21befc2052915f3328916f88d4a6267abd4d1e2e Mon Sep 17 00:00:00 2001 From: Mrs4s <1844812067@qq.com> Date: Mon, 27 Jul 2020 03:52:38 +0800 Subject: [PATCH] add func: GetForwardMessage(). --- README.md | 2 +- client/builders.go | 23 +++++++++++++++++++++++ client/client.go | 26 +++++++++++++++++++++++++- client/decoders.go | 37 +++++++++++++++++++++++++++++++++++++ utils/http.go | 32 ++++++++++++++++++++++++++++++++ 5 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 utils/http.go diff --git a/README.md b/README.md index 3314a2fa..f21ba85a 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ qq-android协议的golang实现 移植于Mirai - [x] At - [x] 回复 - [ ] 长消息 -- [x] 合并转发(有待测试) +- [x] 合并转发(只能接收, 发送还有问题) #### 事件 - [x] 好友消息 diff --git a/client/builders.go b/client/builders.go index 6428b632..ffeb6b0b 100644 --- a/client/builders.go +++ b/client/builders.go @@ -856,3 +856,26 @@ func (c *QQClient) buildMultiApplyUpPacket(data, hash []byte, groupUin int64) (u packet := packets.BuildUniPacket(c.Uin, seq, "MultiMsg.ApplyUp", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload) return seq, packet } + +// MultiMsg.ApplyDown +func (c *QQClient) buildMultiApplyDownPacket(resId string) (uint16, []byte) { + seq := c.nextSeq() + req := &multimsg.MultiReqBody{ + Subcmd: 2, + TermType: 5, + PlatformType: 9, + NetType: 3, + BuildVer: "8.2.0.1296", + MultimsgApplydownReq: []*multimsg.MultiMsgApplyDownReq{ + { + MsgResid: []byte(resId), + MsgType: 3, + }, + }, + BuType: 2, + ReqChannelType: 2, + } + payload, _ := proto.Marshal(req) + packet := packets.BuildUniPacket(c.Uin, seq, "MultiMsg.ApplyDown", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload) + return seq, packet +} diff --git a/client/client.go b/client/client.go index cea4dd02..19f6eb7d 100644 --- a/client/client.go +++ b/client/client.go @@ -118,6 +118,7 @@ func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient { "ProfileService.Pb.ReqSystemMsgNew.Group": decodeSystemMsgGroupPacket, "ProfileService.Pb.ReqSystemMsgNew.Friend": decodeSystemMsgFriendPacket, "MultiMsg.ApplyUp": decodeMultiApplyUpResponse, + "MultiMsg.ApplyDown": decodeMultiApplyDownResponse, }, handlers: map[uint16]func(interface{}, error){}, sigInfo: &loginSigInfo{}, @@ -257,7 +258,30 @@ func (c *QQClient) SendPrivateMessage(target int64, m *message.SendingMessage) * } } -// 目前似乎iOS端无法正常打开转发消息,经测试数据上传正常,应该是解析问题。iOS目前没有越狱设备抓不到日志,有空再测试。 +func (c *QQClient) GetForwardMessage(resId string) *message.ForwardMessage { + i, err := c.sendAndWait(c.buildMultiApplyDownPacket(resId)) + if err != nil { + return nil + } + multiMsg := i.(*msg.PbMultiMsgTransmit) + ret := &message.ForwardMessage{} + for _, m := range multiMsg.Msg { + ret.Nodes = append(ret.Nodes, &message.ForwardNode{ + SenderId: m.Head.FromUin, + SenderName: func() string { + if m.Head.MsgType == 82 { + return m.Head.GroupInfo.GroupCard + } + return m.Head.FromNick + }(), + Time: m.Head.MsgTime, + Message: message.ParseMessageElems(m.Body.RichText.Elems), + }) + } + return ret +} + +// 目前手机端无法解析,可能是加密的问题,等待修复 func (c *QQClient) SendForwardMessage(groupCode int64, m *message.ForwardMessage) *message.GroupMessage { if len(m.Nodes) >= 200 { return nil diff --git a/client/decoders.go b/client/decoders.go index 2486ba1d..a442961b 100644 --- a/client/decoders.go +++ b/client/decoders.go @@ -2,13 +2,16 @@ package client import ( "errors" + "fmt" "github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/binary/jce" "github.com/Mrs4s/MiraiGo/client/pb" "github.com/Mrs4s/MiraiGo/client/pb/cmd0x352" + "github.com/Mrs4s/MiraiGo/client/pb/longmsg" "github.com/Mrs4s/MiraiGo/client/pb/msg" "github.com/Mrs4s/MiraiGo/client/pb/multimsg" "github.com/Mrs4s/MiraiGo/client/pb/structmsg" + "github.com/Mrs4s/MiraiGo/utils" "github.com/golang/protobuf/proto" "sync" "sync/atomic" @@ -686,3 +689,37 @@ func decodeMultiApplyUpResponse(c *QQClient, _ uint16, payload []byte) (interfac } return nil, errors.New("failed") } + +func decodeMultiApplyDownResponse(c *QQClient, _ uint16, payload []byte) (interface{}, error) { + body := multimsg.MultiRspBody{} + if err := proto.Unmarshal(payload, &body); err != nil { + return nil, err + } + if len(body.MultimsgApplydownRsp) == 0 { + return nil, errors.New("not found") + } + rsp := body.MultimsgApplydownRsp[0] + i := binary.UInt32ToIPV4Address(uint32(rsp.Uint32DownIp[0])) + b, err := utils.HttpGetBytes(fmt.Sprintf("http://%s:%d%s", i, body.MultimsgApplydownRsp[0].Uint32DownPort[0], string(rsp.ThumbDownPara))) + if err != nil { + return nil, err + } + tea := binary.NewTeaCipher(body.MultimsgApplydownRsp[0].MsgKey) + r := binary.NewReader(b[1:]) + i1 := r.ReadInt32() + i2 := r.ReadInt32() + if i1 > 0 { + r.ReadBytes(int(i1)) // highway head + } + data := tea.Decrypt(r.ReadBytes(int(i2))) + lb := longmsg.LongRspBody{} + if err = proto.Unmarshal(data, &lb); err != nil { + return nil, err + } + uc := binary.GZipUncompress(lb.MsgDownRsp[0].MsgContent) + mt := msg.PbMultiMsgTransmit{} + if err = proto.Unmarshal(uc, &mt); err != nil { + return nil, err + } + return &mt, nil +} diff --git a/utils/http.go b/utils/http.go new file mode 100644 index 00000000..6b271519 --- /dev/null +++ b/utils/http.go @@ -0,0 +1,32 @@ +package utils + +import ( + "bytes" + "compress/gzip" + "io/ioutil" + "net/http" + "strings" +) + +func HttpGetBytes(url string) ([]byte, error) { + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return nil, err + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + if strings.Contains(resp.Header.Get("Content-Encoding"), "gzip") { + buffer := bytes.NewBuffer(body) + r, _ := gzip.NewReader(buffer) + unCom, err := ioutil.ReadAll(r) + return unCom, err + } + return body, nil +}