diff --git a/binary/jce/structs.go b/binary/jce/structs.go index db98d38d..d0483654 100644 --- a/binary/jce/structs.go +++ b/binary/jce/structs.go @@ -430,6 +430,12 @@ func (pkt *RequestDataVersion3) ReadFrom(r *JceReader) { }) } +func (pkt *RequestDataVersion2) ToBytes() []byte { + w := NewJceWriter() + w.WriteJceStructRaw(pkt) + return w.Bytes() +} + func (pkt *RequestDataVersion2) ReadFrom(r *JceReader) { pkt.Map = make(map[string]map[string][]byte) r.ReadMapF(0, func(k interface{}, v interface{}) { diff --git a/binary/jce/writer.go b/binary/jce/writer.go index 94f9647c..a4ba3350 100644 --- a/binary/jce/writer.go +++ b/binary/jce/writer.go @@ -26,13 +26,14 @@ func (w *JceWriter) writeHead(t byte, tag int) { } } -func (w *JceWriter) WriteByte(b byte, tag int) { +func (w *JceWriter) WriteByte(b byte, tag int) *JceWriter { if b == 0 { w.writeHead(12, tag) } else { w.writeHead(0, tag) w.buf.WriteByte(b) } + return w } func (w *JceWriter) WriteBool(b bool, tag int) { @@ -52,22 +53,23 @@ func (w *JceWriter) WriteInt16(n int16, tag int) { _ = goBinary.Write(w.buf, goBinary.BigEndian, n) } -func (w *JceWriter) WriteInt32(n int32, tag int) { +func (w *JceWriter) WriteInt32(n int32, tag int) *JceWriter { if n >= -32768 && n <= 32767 { // ? if ((n >= 32768) && (n <= 32767)) w.WriteInt16(int16(n), tag) - return + return w } w.writeHead(2, tag) _ = goBinary.Write(w.buf, goBinary.BigEndian, n) + return w } -func (w *JceWriter) WriteInt64(n int64, tag int) { +func (w *JceWriter) WriteInt64(n int64, tag int) *JceWriter { if n >= -2147483648 && n <= 2147483647 { - w.WriteInt32(int32(n), tag) - return + return w.WriteInt32(int32(n), tag) } w.writeHead(3, tag) _ = goBinary.Write(w.buf, goBinary.BigEndian, n) + return w } func (w *JceWriter) WriteFloat32(n float32, tag int) { @@ -80,17 +82,18 @@ func (w *JceWriter) WriteFloat64(n float64, tag int) { _ = goBinary.Write(w.buf, goBinary.BigEndian, n) } -func (w *JceWriter) WriteString(s string, tag int) { +func (w *JceWriter) WriteString(s string, tag int) *JceWriter { by := []byte(s) if len(by) > 255 { w.writeHead(7, tag) _ = goBinary.Write(w.buf, goBinary.BigEndian, len(by)) w.buf.Write(by) - return + return w } w.writeHead(6, tag) w.buf.WriteByte(byte(len(by))) w.buf.Write(by) + return w } func (w *JceWriter) WriteBytes(l []byte, tag int) { @@ -167,6 +170,10 @@ func (w *JceWriter) WriteObject(i interface{}, tag int) { return } if t.Kind() == reflect.Slice { + if b, ok := i.([]byte); ok { + w.WriteBytes(b, tag) + return + } w.WriteSlice(i, tag) return } diff --git a/client/builders.go b/client/builders.go index fd5e19c7..d1a564cf 100644 --- a/client/builders.go +++ b/client/builders.go @@ -274,7 +274,7 @@ func (c *QQClient) buildConfPushRespPacket(t int32, pktSeq int64, jceBuf []byte) req.WriteInt64(pktSeq, 2) req.WriteBytes(jceBuf, 3) buf := &jce.RequestDataVersion3{ - Map: map[string][]byte{"PushResp": packRequestDataV3(req.Bytes())}, + Map: map[string][]byte{"PushResp": packUniRequestData(req.Bytes())}, } pkt := &jce.RequestPacket{ IVersion: 3, @@ -298,7 +298,7 @@ func (c *QQClient) buildDeviceListRequestPacket() (uint16, []byte) { RequireMax: 20, GetDevListType: 2, } - buf := &jce.RequestDataVersion3{Map: map[string][]byte{"SvcReqGetDevLoginInfo": packRequestDataV3(req.ToBytes())}} + buf := &jce.RequestDataVersion3{Map: map[string][]byte{"SvcReqGetDevLoginInfo": packUniRequestData(req.ToBytes())}} pkt := &jce.RequestPacket{ IVersion: 3, SServantName: "StatSvc", @@ -353,7 +353,7 @@ func (c *QQClient) buildFriendGroupListRequestPacket(friendStartIndex, friendLis SnsTypeList: []int64{13580, 13581, 13582}, } buf := &jce.RequestDataVersion3{ - Map: map[string][]byte{"FL": packRequestDataV3(req.ToBytes())}, + Map: map[string][]byte{"FL": packUniRequestData(req.ToBytes())}, } pkt := &jce.RequestPacket{ IVersion: 3, @@ -386,8 +386,8 @@ func (c *QQClient) buildSummaryCardRequestPacket(target int64) (uint16, []byte) head := jce.NewJceWriter() head.WriteInt32(2, 0) buf := &jce.RequestDataVersion3{Map: map[string][]byte{ - "ReqHead": packRequestDataV3(head.Bytes()), - "ReqSummaryCard": packRequestDataV3(req.ToBytes()), + "ReqHead": packUniRequestData(head.Bytes()), + "ReqSummaryCard": packUniRequestData(req.ToBytes()), }} pkt := &jce.RequestPacket{ IVersion: 3, @@ -869,7 +869,7 @@ func (c *QQClient) buildEditGroupTagPacket(groupCode, memberUin int64, newTag st }, }, } - buf := &jce.RequestDataVersion3{Map: map[string][]byte{"MGCREQ": packRequestDataV3(req.ToBytes())}} + buf := &jce.RequestDataVersion3{Map: map[string][]byte{"MGCREQ": packUniRequestData(req.ToBytes())}} pkt := &jce.RequestPacket{ IVersion: 3, IRequestId: c.nextPacketSeq(), @@ -1051,7 +1051,7 @@ func (c *QQClient) buildQuitGroupPacket(groupCode int64) (uint16, []byte) { w.WriteUInt32(uint32(c.Uin)) w.WriteUInt32(uint32(groupCode)) }), 2) - buf := &jce.RequestDataVersion3{Map: map[string][]byte{"GroupMngReq": packRequestDataV3(jw.Bytes())}} + buf := &jce.RequestDataVersion3{Map: map[string][]byte{"GroupMngReq": packUniRequestData(jw.Bytes())}} pkt := &jce.RequestPacket{ IVersion: 3, IRequestId: c.nextPacketSeq(), diff --git a/client/client.go b/client/client.go index 1c4c1674..763fe518 100644 --- a/client/client.go +++ b/client/client.go @@ -151,7 +151,8 @@ func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient { "ProfileService.Pb.ReqSystemMsgNew.Friend": decodeSystemMsgFriendPacket, "MultiMsg.ApplyUp": decodeMultiApplyUpResponse, "MultiMsg.ApplyDown": decodeMultiApplyDownResponse, - "OidbSvc.0x6d6_2": decodeOIDB6d6Response, + "OidbSvc.0x6d6_2": decodeOIDB6d62Response, + "OidbSvc.0x6d6_3": decodeOIDB6d63Response, "OidbSvc.0x6d8_1": decodeOIDB6d81Response, "OidbSvc.0x88d_0": decodeGroupInfoResponse, "OidbSvc.0xe07_0": decodeImageOcrResponse, @@ -187,11 +188,18 @@ func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient { } adds, err := net.LookupIP("msfwifi.3g.qq.com") // host servers if err == nil && len(adds) > 0 { - addr := &net.TCPAddr{ - IP: adds[0], - Port: 8080, + var hostAddrs []*net.TCPAddr + for _, addr := range adds { + hostAddrs = append(hostAddrs, &net.TCPAddr{ + IP: addr, + Port: 8080, + }) } - cli.servers = append([]*net.TCPAddr{addr}, cli.servers...) + cli.servers = append(hostAddrs, cli.servers...) + } + sso, err := getSSOAddress() + if err == nil && len(sso) > 0 { + cli.servers = append(sso, cli.servers...) } rand.Read(cli.RandomKey) return cli @@ -207,8 +215,7 @@ func (c *QQClient) Login() (*LoginResponse, error) { return nil, err } go c.netLoop() - seq, packet := c.buildLoginPacket() - rsp, err := c.sendAndWait(seq, packet) + rsp, err := c.sendAndWait(c.buildLoginPacket()) if err != nil { c.Disconnect() return nil, err @@ -225,6 +232,7 @@ func (c *QQClient) SubmitCaptcha(result string, sign []byte) (*LoginResponse, er seq, packet := c.buildCaptchaPacket(result, sign) rsp, err := c.sendAndWait(seq, packet) if err != nil { + c.Disconnect() return nil, err } l := rsp.(LoginResponse) @@ -237,6 +245,7 @@ func (c *QQClient) SubmitCaptcha(result string, sign []byte) (*LoginResponse, er func (c *QQClient) SubmitSMS(code string) (*LoginResponse, error) { rsp, err := c.sendAndWait(c.buildSMSCodeSubmitPacket(code)) if err != nil { + c.Disconnect() return nil, err } l := rsp.(LoginResponse) @@ -251,7 +260,7 @@ func (c *QQClient) init() { _ = c.registerClient() c.groupSysMsgCache, _ = c.GetGroupSystemMessages() if !c.heartbeatEnabled { - c.startHeartbeat() + go c.doHeartbeat() } } @@ -641,17 +650,19 @@ func (c *QQClient) uploadPrivateImage(target int64, img []byte, count int) (*mes count++ h := md5.Sum(img) e, err := c.QueryFriendImage(target, h[:], int32(len(img))) - if err != nil { + if err == ErrNotExists { // use group highway upload and query again for image id. if _, err = c.UploadGroupImage(target, img); err != nil { return nil, err } - // safe if count >= 5 { - return nil, errors.New("upload failed") + return e, nil } return c.uploadPrivateImage(target, img, count) } + if err != nil { + return nil, err + } return e, nil } @@ -698,7 +709,10 @@ func (c *QQClient) QueryFriendImage(target int64, hash []byte, size int32) (*mes return nil, errors.New(rsp.Message) } if !rsp.IsExists { - return nil, errors.New("image not exists") + return &message.FriendImageElement{ + ImageId: rsp.ResourceId, + Md5: hash, + }, ErrNotExists } return &message.FriendImageElement{ ImageId: rsp.ResourceId, @@ -1021,6 +1035,9 @@ func (c *QQClient) sendAndWait(seq uint16, pkt []byte) (interface{}, error) { } func (c *QQClient) netLoop() { + if c.NetLooping { + return + } c.NetLooping = true reader := binary.NewNetworkReader(c.Conn) retry := 0 @@ -1031,13 +1048,14 @@ func (c *QQClient) netLoop() { c.Error("connection dropped by server: %v", err) err = c.connect() if err != nil { + c.Error("connect server error: %v", err) break } reader = binary.NewNetworkReader(c.Conn) - if c.registerClient() != nil { + if e := c.registerClient(); e != nil { c.Disconnect() - c.lastLostMsg = "register client failed." - c.Error("reconnect failed: register client failed.") + c.lastLostMsg = "register client failed: " + e.Error() + c.Error("reconnect failed: " + e.Error()) break } } @@ -1053,7 +1071,7 @@ func (c *QQClient) netLoop() { pkt, err := packets.ParseIncomingPacket(data, c.sigInfo.d2Key) if err != nil { c.Error("parse incoming packet error: %v", err) - if err == packets.ErrSessionExpired { + if err == packets.ErrSessionExpired || err == packets.ErrPacketDropped { break } errCount++ @@ -1109,21 +1127,19 @@ func (c *QQClient) netLoop() { c.dispatchDisconnectEvent(&ClientDisconnectedEvent{Message: c.lastLostMsg}) } -func (c *QQClient) startHeartbeat() { - c.heartbeatEnabled = true - time.AfterFunc(30*time.Second, c.doHeartbeat) -} - func (c *QQClient) doHeartbeat() { - if c.Online { + c.heartbeatEnabled = true + for c.Online { seq := c.nextSeq() sso := packets.BuildSsoPacket(seq, c.version.AppId, "Heartbeat.Alive", SystemDeviceInfo.IMEI, []byte{}, c.OutGoingPacketSessionId, []byte{}, c.ksid) packet := packets.BuildLoginPacket(c.Uin, 0, []byte{}, sso, []byte{}) _, err := c.sendAndWait(seq, packet) if err != nil { - _ = c.Conn.Close() + c.lastLostMsg = "Heartbeat failed: " + err.Error() + c.Disconnect() + break } - time.AfterFunc(30*time.Second, c.doHeartbeat) + time.Sleep(time.Second * 30) } c.heartbeatEnabled = false } diff --git a/client/decoders.go b/client/decoders.go index 525375c4..1b1e89a2 100644 --- a/client/decoders.go +++ b/client/decoders.go @@ -165,7 +165,7 @@ func decodeLoginResponse(c *QQClient, _ uint16, payload []byte) (interface{}, er } // StatSvc.register -func decodeClientRegisterResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { +func decodeClientRegisterResponse(c *QQClient, _ uint16, payload []byte) (interface{}, error) { request := &jce.RequestPacket{} request.ReadFrom(jce.NewJceReader(payload)) data := &jce.RequestDataVersion2{} @@ -173,6 +173,9 @@ func decodeClientRegisterResponse(_ *QQClient, _ uint16, payload []byte) (interf svcRsp := &jce.SvcRespRegister{} svcRsp.ReadFrom(jce.NewJceReader(data.Map["SvcRespRegister"]["QQService.SvcRespRegister"][1:])) if svcRsp.Result != "" || svcRsp.Status != 11 { + if svcRsp.Result != "" { + c.Error("reg error: %v", svcRsp.Result) + } return nil, errors.New("reg failed") } return nil, nil @@ -221,12 +224,17 @@ func decodePushReqPacket(c *QQClient, _ uint16, payload []byte) (interface{}, er Port: int(s.Port), }) } - c.SetCustomServer(adds) + f := true for _, e := range c.eventHandlers.serverUpdatedHandlers { cover(func() { - e(c, &ServerUpdatedEvent{Servers: servers}) + if !e(c, &ServerUpdatedEvent{Servers: servers}) { + f = false + } }) } + if f { + c.SetCustomServer(adds) + } return nil, nil } } diff --git a/client/entities.go b/client/entities.go index 172c6e83..ce2e6447 100644 --- a/client/entities.go +++ b/client/entities.go @@ -11,6 +11,7 @@ import ( var ( ErrAlreadyOnline = errors.New("already online") ErrMemberNotFound = errors.New("member not found") + ErrNotExists = errors.New("not exists") ) type ( @@ -251,7 +252,7 @@ const ( Member AndroidPhone ClientProtocol = 1 - AndroidPad ClientProtocol = 2 + IPad ClientProtocol = 2 AndroidWatch ClientProtocol = 3 ) diff --git a/client/events.go b/client/events.go index 6f286e51..83a23c0d 100644 --- a/client/events.go +++ b/client/events.go @@ -25,7 +25,7 @@ type eventHandlers struct { newFriendHandlers []func(*QQClient, *NewFriendEvent) disconnectHandlers []func(*QQClient, *ClientDisconnectedEvent) logHandlers []func(*QQClient, *LogEvent) - serverUpdatedHandlers []func(*QQClient, *ServerUpdatedEvent) + serverUpdatedHandlers []func(*QQClient, *ServerUpdatedEvent) bool notifyHandlers []func(*QQClient, IGroupNotifyEvent) offlineFileHandlers []func(*QQClient, *OfflineFileEvent) groupMessageReceiptHandlers sync.Map @@ -107,7 +107,7 @@ func (c *QQClient) OnDisconnected(f func(*QQClient, *ClientDisconnectedEvent)) { c.eventHandlers.disconnectHandlers = append(c.eventHandlers.disconnectHandlers, f) } -func (c *QQClient) OnServerUpdated(f func(*QQClient, *ServerUpdatedEvent)) { +func (c *QQClient) OnServerUpdated(f func(*QQClient, *ServerUpdatedEvent) bool) { c.eventHandlers.serverUpdatedHandlers = append(c.eventHandlers.serverUpdatedHandlers, f) } diff --git a/client/global.go b/client/global.go index 468ee308..c8870c59 100644 --- a/client/global.go +++ b/client/global.go @@ -2,9 +2,11 @@ package client import ( "crypto/md5" + "encoding/hex" "encoding/json" "fmt" "github.com/Mrs4s/MiraiGo/binary" + "github.com/Mrs4s/MiraiGo/binary/jce" devinfo "github.com/Mrs4s/MiraiGo/client/pb" "github.com/Mrs4s/MiraiGo/client/pb/msg" "github.com/Mrs4s/MiraiGo/client/pb/oidb" @@ -12,7 +14,9 @@ import ( "github.com/Mrs4s/MiraiGo/utils" "google.golang.org/protobuf/proto" "math/rand" + "net" "sort" + "strings" ) type DeviceInfo struct { @@ -102,7 +106,7 @@ var SystemDeviceInfo = &DeviceInfo{ IMEI: "468356291846738", AndroidId: []byte("MIRAI.123456.001"), APN: []byte("wifi"), - Protocol: AndroidPad, + Protocol: IPad, Version: &Version{ Incremental: []byte("5891938"), Release: []byte("10"), @@ -167,10 +171,10 @@ func genVersionInfo(p ClientProtocol) *versionInfo { SubSigmap: 0x10400, MainSigMap: 34869472, } - case AndroidPad: // Dumped from qq-hd v5.8.9 + case IPad: return &versionInfo{ ApkId: "com.tencent.minihd.qq", - AppId: 537065549, + AppId: 537065739, SortVersionName: "5.8.9", BuildTime: 1595836208, ApkSign: []byte{170, 57, 120, 244, 31, 217, 111, 249, 145, 74, 102, 158, 24, 100, 116, 199}, @@ -197,7 +201,7 @@ func (info *DeviceInfo) ToJson() []byte { IMEI: info.IMEI, Protocol: func() int { switch info.Protocol { - case AndroidPad: + case IPad: return 0 case AndroidPhone: return 1 @@ -234,7 +238,7 @@ func (info *DeviceInfo) ReadJson(d []byte) error { case 2: info.Protocol = AndroidWatch default: - info.Protocol = AndroidPad + info.Protocol = IPad } SystemDeviceInfo.GenNewGuid() SystemDeviceInfo.GenNewTgtgtKey() @@ -272,6 +276,53 @@ func (info *DeviceInfo) GenDeviceInfoData() []byte { return data } +func getSSOAddress() ([]*net.TCPAddr, error) { + protocol := genVersionInfo(SystemDeviceInfo.Protocol) + key, _ := hex.DecodeString("F0441F5FF42DA58FDCF7949ABA62D411") + payload := jce.NewJceWriter(). // see ServerConfig.d + WriteInt64(0, 1).WriteInt64(0, 2).WriteByte(1, 3). + WriteString("00000", 4).WriteInt32(100, 5). + WriteInt32(int32(protocol.AppId), 6).WriteString(SystemDeviceInfo.IMEI, 7). + WriteInt64(0, 8).WriteInt64(0, 9).WriteInt64(0, 10). + WriteInt64(0, 11).WriteByte(0, 12).WriteInt64(0, 13).WriteByte(1, 14).Bytes() + buf := &jce.RequestDataVersion2{ + Map: map[string]map[string][]byte{"HttpServerListReq": {"ConfigHttp.HttpServerListReq": packUniRequestData(payload)}}, + } + pkt := &jce.RequestPacket{ + IVersion: 2, + SServantName: "ConfigHttp", + SFuncName: "HttpServerListReq", + SBuffer: buf.ToBytes(), + } + tea := binary.NewTeaCipher(key) + rsp, err := utils.HttpPostBytes("https://configsvr.msf.3g.qq.com/configsvr/serverlist.jsp", tea.Encrypt(binary.NewWriterF(func(w *binary.Writer) { + w.WriteIntLvPacket(0, func(w *binary.Writer) { + w.Write(pkt.ToBytes()) + }) + }))) + if err != nil { + return nil, err + } + rspPkt := &jce.RequestPacket{} + data := &jce.RequestDataVersion2{} + rspPkt.ReadFrom(jce.NewJceReader(tea.Decrypt(rsp)[4:])) + data.ReadFrom(jce.NewJceReader(rspPkt.SBuffer)) + reader := jce.NewJceReader(data.Map["HttpServerListRes"]["ConfigHttp.HttpServerListRes"][1:]) + servers := []jce.SsoServerInfo{} + reader.ReadSlice(&servers, 2) + var adds []*net.TCPAddr + for _, s := range servers { + if strings.Contains(s.Server, "com") { + continue + } + adds = append(adds, &net.TCPAddr{ + IP: net.ParseIP(s.Server), + Port: int(s.Port), + }) + } + return adds, nil +} + func (c *QQClient) parsePrivateMessage(msg *msg.Message) *message.PrivateMessage { friend := c.FindFriend(msg.Head.FromUin) var sender *message.Sender @@ -459,7 +510,7 @@ func (b *groupMessageBuilder) build() *msg.Message { return base } -func packRequestDataV3(data []byte) (r []byte) { +func packUniRequestData(data []byte) (r []byte) { r = append([]byte{0x0A}, data...) r = append(r, 0x0B) return diff --git a/client/group_file.go b/client/group_file.go index 68155f58..fe873408 100644 --- a/client/group_file.go +++ b/client/group_file.go @@ -142,6 +142,16 @@ func (fs *GroupFileSystem) GetDownloadUrl(file *GroupFile) string { return fs.client.GetGroupFileUrl(file.GroupCode, file.FileId, file.BusId) } +// DeleteFile 删除群文件,需要管理权限. +// 返回错误, 空为删除成功 +func (fs *GroupFileSystem) DeleteFile(parentFolderId, fileId string, busId int32) string { + i, err := fs.client.sendAndWait(fs.client.buildGroupFileDeleteReqPacket(fs.GroupCode, parentFolderId, fileId, busId)) + if err != nil { + return err.Error() + } + return i.(string) +} + // OidbSvc.0x6d8_1 func (c *QQClient) buildGroupFileListRequestPacket(groupCode int64, folderId string, startIndex uint32) (uint16, []byte) { seq := c.nextSeq() @@ -229,6 +239,27 @@ func (c *QQClient) buildGroupFileDownloadReqPacket(groupCode int64, fileId strin return seq, packet } +func (c *QQClient) buildGroupFileDeleteReqPacket(groupCode int64, parentFolderId, fileId string, busId int32) (uint16, []byte) { + seq := c.nextSeq() + body := &oidb.D6D6ReqBody{DeleteFileReq: &oidb.DeleteFileReqBody{ + GroupCode: groupCode, + AppId: 3, + BusId: busId, + ParentFolderId: parentFolderId, + FileId: fileId, + }} + b, _ := proto.Marshal(body) + req := &oidb.OIDBSSOPkg{ + Command: 1750, + ServiceType: 3, + Bodybuffer: b, + ClientVersion: "android 8.4.8", + } + payload, _ := proto.Marshal(req) + packet := packets.BuildUniPacket(c.Uin, seq, "OidbSvc.0x6d6_3", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload) + return seq, packet +} + func decodeOIDB6d81Response(c *QQClient, _ uint16, payload []byte) (interface{}, error) { pkg := oidb.OIDBSSOPkg{} rsp := oidb.D6D8RspBody{} @@ -242,7 +273,7 @@ func decodeOIDB6d81Response(c *QQClient, _ uint16, payload []byte) (interface{}, } // OidbSvc.0x6d6_2 -func decodeOIDB6d6Response(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { +func decodeOIDB6d62Response(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { pkg := oidb.OIDBSSOPkg{} rsp := oidb.D6D6RspBody{} if err := proto.Unmarshal(payload, &pkg); err != nil { @@ -258,3 +289,18 @@ func decodeOIDB6d6Response(_ *QQClient, _ uint16, payload []byte) (interface{}, url := hex.EncodeToString(rsp.DownloadFileRsp.DownloadUrl) return fmt.Sprintf("http://%s/ftn_handler/%s/", ip, url), nil } + +func decodeOIDB6d63Response(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { + pkg := oidb.OIDBSSOPkg{} + rsp := oidb.D6D6RspBody{} + if err := proto.Unmarshal(payload, &pkg); err != nil { + return nil, err + } + if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil { + return nil, err + } + if rsp.DeleteFileRsp == nil { + return "", nil + } + return rsp.DeleteFileRsp.ClientWording, nil +} diff --git a/client/group_info.go b/client/group_info.go index bd790921..baa57f8b 100644 --- a/client/group_info.go +++ b/client/group_info.go @@ -77,8 +77,8 @@ func (c *QQClient) buildGroupSearchPacket(keyword string) (uint16, []byte) { head := jce.NewJceWriter() head.WriteInt32(2, 0) buf := &jce.RequestDataVersion3{Map: map[string][]byte{ - "ReqHead": packRequestDataV3(head.Bytes()), - "ReqSearch": packRequestDataV3(req.ToBytes()), + "ReqHead": packUniRequestData(head.Bytes()), + "ReqSearch": packUniRequestData(req.ToBytes()), }} pkt := &jce.RequestPacket{ IVersion: 3, diff --git a/client/notify.go b/client/notify.go index bfa90359..c52c9206 100644 --- a/client/notify.go +++ b/client/notify.go @@ -33,7 +33,7 @@ type ( // grayTipProcessor 提取出来专门用于处理群内 notify tips func (c *QQClient) grayTipProcessor(groupId int64, tipInfo *notify.GeneralGrayTipInfo) { switch tipInfo.TemplId { - case 10043, 1136: // 戳一戳 + case 10043, 1136, 1132: // 戳一戳 var sender int64 = 0 receiver := c.Uin for _, templ := range tipInfo.MsgTemplParam { diff --git a/message/message.go b/message/message.go index 00392a9a..f21bbd6f 100644 --- a/message/message.go +++ b/message/message.go @@ -432,6 +432,9 @@ func ParseMessageElems(elems []*msg.Elem) []IMessageElement { } } if elem.CustomFace != nil { + if len(elem.CustomFace.Md5) == 0 { + continue + } res = append(res, &ImageElement{ Filename: elem.CustomFace.FilePath, Size: elem.CustomFace.Size, diff --git a/protocol/packets/global.go b/protocol/packets/global.go index cccdc0fb..167314fa 100644 --- a/protocol/packets/global.go +++ b/protocol/packets/global.go @@ -11,6 +11,7 @@ var ErrUnknownFlag = errors.New("unknown flag") var ErrInvalidPayload = errors.New("invalid payload") var ErrDecryptFailed = errors.New("decrypt failed") var ErrSessionExpired = errors.New("session expired") +var ErrPacketDropped = errors.New("packet dropped") type ISendingPacket interface { CommandId() uint16 @@ -121,7 +122,7 @@ func ParseIncomingPacket(payload, d2key []byte) (*IncomingPacket, error) { func parseSsoFrame(payload []byte, flag2 byte) (*IncomingPacket, error) { reader := binary.NewReader(payload) if reader.ReadInt32()-4 > int32(reader.Len()) { - return nil, errors.New("dropped") + return nil, ErrPacketDropped } seqId := reader.ReadInt32() retCode := reader.ReadInt32()