github.com/Mrs4s/MiraiGo@v0.0.0-20240226124653-54bdd873e3fe/client/decoders.go (about)

     1  package client
     2  
     3  import (
     4  	"crypto/md5"
     5  	"fmt"
     6  	"net/netip"
     7  	"strconv"
     8  	"strings"
     9  	"sync"
    10  	"time"
    11  
    12  	"github.com/pkg/errors"
    13  
    14  	"github.com/Mrs4s/MiraiGo/binary"
    15  	"github.com/Mrs4s/MiraiGo/binary/jce"
    16  	"github.com/Mrs4s/MiraiGo/client/internal/auth"
    17  	"github.com/Mrs4s/MiraiGo/client/internal/network"
    18  	"github.com/Mrs4s/MiraiGo/client/internal/tlv"
    19  	"github.com/Mrs4s/MiraiGo/client/pb"
    20  	"github.com/Mrs4s/MiraiGo/client/pb/cmd0x352"
    21  	"github.com/Mrs4s/MiraiGo/client/pb/cmd0x6ff"
    22  	"github.com/Mrs4s/MiraiGo/client/pb/msg"
    23  	"github.com/Mrs4s/MiraiGo/client/pb/oidb"
    24  	"github.com/Mrs4s/MiraiGo/client/pb/profilecard"
    25  	"github.com/Mrs4s/MiraiGo/client/pb/structmsg"
    26  	"github.com/Mrs4s/MiraiGo/internal/proto"
    27  	"github.com/Mrs4s/MiraiGo/utils"
    28  )
    29  
    30  var (
    31  	groupJoinLock  sync.Mutex
    32  	groupLeaveLock sync.Mutex
    33  )
    34  
    35  // wtlogin.login
    36  func decodeLoginResponse(c *QQClient, pkt *network.Packet) (any, error) {
    37  	reader := binary.NewReader(pkt.Payload)
    38  	reader.ReadUInt16() // sub command
    39  	t := reader.ReadByte()
    40  	reader.ReadUInt16()
    41  	m, err := tlv.NewDecoder(2, 2).DecodeRecordMap(reader.ReadAvailable())
    42  	if err != nil {
    43  		return nil, err
    44  	}
    45  	if m.Exists(0x402) {
    46  		c.sig.Dpwd = []byte(utils.RandomString(16))
    47  		c.sig.T402 = m[0x402]
    48  		h := md5.Sum(append(append(c.Device().Guid, c.sig.Dpwd...), c.sig.T402...))
    49  		c.sig.G = h[:]
    50  	}
    51  	if m.Exists(0x546) {
    52  		c.sig.T547 = auth.CalcPow(m[0x546])
    53  	}
    54  	// c.logger.Info("login response %v", t)
    55  	if t == 0 { // login success
    56  		// if t150, ok := m[0x150]; ok {
    57  		//  	c.t150 = t150
    58  		// }
    59  		// if t161, ok := m[0x161]; ok {
    60  		//  	c.decodeT161(t161)
    61  		// }
    62  		if m.Exists(0x403) {
    63  			c.sig.RandSeed = m[0x403]
    64  		}
    65  		c.decodeT119(m[0x119], c.Device().TgtgtKey)
    66  		return LoginResponse{
    67  			Success: true,
    68  		}, nil
    69  	}
    70  	if t == 2 {
    71  		c.sig.T104 = m[0x104]
    72  		if m.Exists(0x192) {
    73  			return LoginResponse{
    74  				Success:   false,
    75  				Code:      t,
    76  				VerifyUrl: string(m[0x192]),
    77  				Error:     SliderNeededError,
    78  			}, nil
    79  		}
    80  		if m.Exists(0x165) { // image
    81  			imgData := binary.NewReader(m[0x105])
    82  			signLen := imgData.ReadUInt16()
    83  			imgData.ReadUInt16()
    84  			sign := imgData.ReadBytes(int(signLen))
    85  			return LoginResponse{
    86  				Success:      false,
    87  				Code:         t,
    88  				Error:        NeedCaptcha,
    89  				CaptchaImage: imgData.ReadAvailable(),
    90  				CaptchaSign:  sign,
    91  			}, nil
    92  		} else {
    93  			return LoginResponse{
    94  				Success: false,
    95  				Code:    t,
    96  				Error:   UnknownLoginError,
    97  			}, nil
    98  		}
    99  	} // need captcha
   100  
   101  	if t == 40 {
   102  		return LoginResponse{
   103  			Success:      false,
   104  			Code:         t,
   105  			ErrorMessage: "账号被冻结",
   106  			Error:        UnknownLoginError,
   107  		}, nil
   108  	}
   109  
   110  	if t == 160 || t == 239 {
   111  		if t174, ok := m[0x174]; ok { // 短信验证
   112  			c.sig.T104 = m[0x104]
   113  			c.sig.T174 = t174
   114  			c.sig.RandSeed = m[0x403]
   115  			phone := func() string {
   116  				r := binary.NewReader(m[0x178])
   117  				r.ReadStringShort()
   118  				return r.ReadStringShort()
   119  			}()
   120  			if t204, ok := m[0x204]; ok { // 同时支持扫码验证 ?
   121  				return LoginResponse{
   122  					Success:      false,
   123  					Code:         t,
   124  					Error:        SMSOrVerifyNeededError,
   125  					VerifyUrl:    string(t204),
   126  					SMSPhone:     phone,
   127  					ErrorMessage: string(m[0x17e]),
   128  				}, nil
   129  			}
   130  			return LoginResponse{
   131  				Success:      false,
   132  				Code:         t,
   133  				Error:        SMSNeededError,
   134  				SMSPhone:     phone,
   135  				ErrorMessage: string(m[0x17e]),
   136  			}, nil
   137  		}
   138  
   139  		if _, ok := m[0x17b]; ok { // 二次验证
   140  			c.sig.T104 = m[0x104]
   141  			return LoginResponse{
   142  				Success: false,
   143  				Code:    t,
   144  				Error:   SMSNeededError,
   145  			}, nil
   146  		}
   147  
   148  		if t204, ok := m[0x204]; ok { // 扫码验证
   149  			return LoginResponse{
   150  				Success:      false,
   151  				Code:         t,
   152  				Error:        UnsafeDeviceError,
   153  				VerifyUrl:    string(t204),
   154  				ErrorMessage: "",
   155  			}, nil
   156  		}
   157  	}
   158  
   159  	if t == 162 {
   160  		return LoginResponse{
   161  			Code:  t,
   162  			Error: TooManySMSRequestError,
   163  		}, nil
   164  	}
   165  
   166  	if t == 204 {
   167  		c.sig.T104 = m[0x104]
   168  		c.sig.RandSeed = m[0x403]
   169  		return c.sendAndWait(c.buildDeviceLockLoginPacket())
   170  	} // drive lock
   171  
   172  	if t149, ok := m[0x149]; ok {
   173  		t149r := binary.NewReader(t149)
   174  		t149r.ReadBytes(2)
   175  		t149r.ReadStringShort() // title
   176  		return LoginResponse{
   177  			Success:      false,
   178  			Code:         t,
   179  			Error:        OtherLoginError,
   180  			ErrorMessage: t149r.ReadStringShort(),
   181  		}, nil
   182  	}
   183  
   184  	if t146, ok := m[0x146]; ok {
   185  		t146r := binary.NewReader(t146)
   186  		t146r.ReadBytes(4)      // ver and code
   187  		t146r.ReadStringShort() // title
   188  		return LoginResponse{
   189  			Success:      false,
   190  			Code:         t,
   191  			Error:        OtherLoginError,
   192  			ErrorMessage: t146r.ReadStringShort(),
   193  		}, nil
   194  	}
   195  	c.debug("unknown login response: %v", t)
   196  	for k, v := range m {
   197  		c.debug("Type: %d Value: %x", k, v)
   198  	}
   199  	return nil, errors.Errorf("unknown login response: %v", t) // ?
   200  }
   201  
   202  // StatSvc.register
   203  func decodeClientRegisterResponse(c *QQClient, pkt *network.Packet) (any, error) {
   204  	request := &jce.RequestPacket{}
   205  	request.ReadFrom(jce.NewJceReader(pkt.Payload))
   206  	data := &jce.RequestDataVersion2{}
   207  	data.ReadFrom(jce.NewJceReader(request.SBuffer))
   208  	svcRsp := &jce.SvcRespRegister{}
   209  	svcRsp.ReadFrom(jce.NewJceReader(data.Map["SvcRespRegister"]["QQService.SvcRespRegister"][1:]))
   210  	if svcRsp.Result != "" || svcRsp.ReplyCode != 0 {
   211  		if svcRsp.Result != "" {
   212  			c.error("reg error: %v", svcRsp.Result)
   213  		}
   214  		return nil, errors.New("reg failed")
   215  	}
   216  	return nil, nil
   217  }
   218  
   219  // wtlogin.exchange_emp
   220  func decodeExchangeEmpResponse(c *QQClient, pkt *network.Packet) (any, error) {
   221  	reader := binary.NewReader(pkt.Payload)
   222  	cmd := reader.ReadUInt16()
   223  	t := reader.ReadByte()
   224  	reader.ReadUInt16()
   225  	m, err := tlv.NewDecoder(2, 2).DecodeRecordMap(reader.ReadAvailable())
   226  	if err != nil {
   227  		return nil, err
   228  	}
   229  	if t != 0 {
   230  		return nil, errors.Errorf("exchange_emp failed: %v", t)
   231  	}
   232  	if cmd == 15 {
   233  		c.decodeT119R(m[0x119])
   234  	}
   235  	if cmd == 11 {
   236  		h := md5.Sum(c.sig.D2Key)
   237  		c.decodeT119(m[0x119], h[:])
   238  	}
   239  	return nil, nil
   240  }
   241  
   242  // wtlogin.trans_emp
   243  func decodeTransEmpResponse(c *QQClient, pkt *network.Packet) (any, error) {
   244  	if len(pkt.Payload) < 48 {
   245  		return nil, errors.New("missing payload length")
   246  	}
   247  	reader := binary.NewReader(pkt.Payload)
   248  	reader.ReadBytes(5) // trans req head
   249  	reader.ReadByte()
   250  	reader.ReadUInt16()
   251  	cmd := reader.ReadUInt16()
   252  	reader.ReadBytes(21)
   253  	reader.ReadByte()
   254  	reader.ReadUInt16()
   255  	reader.ReadUInt16()
   256  	reader.ReadInt32()
   257  	reader.ReadInt64()
   258  	body := binary.NewReader(reader.ReadBytes(reader.Len() - 1))
   259  	if cmd == 0x31 {
   260  		body.ReadUInt16()
   261  		body.ReadInt32()
   262  		code := body.ReadByte()
   263  		if code != 0 {
   264  			return nil, errors.Errorf("wtlogin.trans_emp sub cmd 0x31 error: %v", code)
   265  		}
   266  		sig := body.ReadBytesShort()
   267  		body.ReadUInt16()
   268  		m, err := tlv.NewDecoder(2, 2).DecodeRecordMap(body.ReadAvailable())
   269  		if err != nil {
   270  			return nil, err
   271  		}
   272  		if m.Exists(0x17) {
   273  			return &QRCodeLoginResponse{
   274  				State:     QRCodeImageFetch,
   275  				ImageData: m[0x17],
   276  				Sig:       sig,
   277  			}, nil
   278  		}
   279  		return nil, errors.Errorf("wtlogin.trans_emp sub cmd 0x31 error: image not found")
   280  	}
   281  	if cmd == 0x12 {
   282  		aVarLen := body.ReadUInt16()
   283  		if aVarLen != 0 {
   284  			aVarLen-- // 阴间的位移操作
   285  			if body.ReadByte() == 2 {
   286  				body.ReadInt64() // uin ?
   287  				aVarLen -= 8
   288  			}
   289  		}
   290  		if aVarLen > 0 {
   291  			body.ReadBytes(int(aVarLen))
   292  		}
   293  		body.ReadInt32() // app id?
   294  		code := body.ReadByte()
   295  		if code != 0 {
   296  			if code == 0x30 {
   297  				return &QRCodeLoginResponse{State: QRCodeWaitingForScan}, nil
   298  			}
   299  			if code == 0x35 {
   300  				return &QRCodeLoginResponse{State: QRCodeWaitingForConfirm}, nil
   301  			}
   302  			if code == 0x36 {
   303  				return &QRCodeLoginResponse{State: QRCodeCanceled}, nil
   304  			}
   305  			if code == 0x11 {
   306  				return &QRCodeLoginResponse{State: QRCodeTimeout}, nil
   307  			}
   308  			return nil, errors.Errorf("wtlogin.trans_emp sub cmd 0x12 error: %v", code)
   309  		}
   310  		c.Uin = body.ReadInt64()
   311  		c.highwaySession.Uin = strconv.FormatInt(c.Uin, 10)
   312  		body.ReadInt32() // sig create time
   313  		body.ReadUInt16()
   314  		m, err := tlv.NewDecoder(2, 2).DecodeRecordMap(body.ReadAvailable())
   315  		if err != nil {
   316  			return nil, err
   317  		}
   318  		if !m.Exists(0x18) || !m.Exists(0x1e) || !m.Exists(0x19) {
   319  			return nil, errors.New("wtlogin.trans_emp sub cmd 0x12 error: tlv error")
   320  		}
   321  		c.Device().TgtgtKey = m[0x1e]
   322  		return &QRCodeLoginResponse{State: QRCodeConfirmed, LoginInfo: &QRCodeLoginInfo{
   323  			tmpPwd:      m[0x18],
   324  			tmpNoPicSig: m[0x19],
   325  			tgtQR:       m[0x65],
   326  		}}, nil
   327  	}
   328  	return nil, errors.Errorf("unknown trans_emp response: %v", cmd)
   329  }
   330  
   331  // ConfigPushSvc.PushReq
   332  func decodePushReqPacket(c *QQClient, pkt *network.Packet) (any, error) {
   333  	request := &jce.RequestPacket{}
   334  	request.ReadFrom(jce.NewJceReader(pkt.Payload))
   335  	data := &jce.RequestDataVersion2{}
   336  	data.ReadFrom(jce.NewJceReader(request.SBuffer))
   337  	r := jce.NewJceReader(data.Map["PushReq"]["ConfigPush.PushReq"][1:])
   338  	t := r.ReadInt32(1)
   339  	jceBuf := r.ReadBytes(2)
   340  	if len(jceBuf) > 0 {
   341  		switch t {
   342  		case 1:
   343  			ssoPkt := jce.NewJceReader(jceBuf)
   344  			servers := ssoPkt.ReadSsoServerInfos(1)
   345  			if len(servers) > 0 {
   346  				var adds []netip.AddrPort
   347  				for _, s := range servers {
   348  					if strings.Contains(s.Server, "com") {
   349  						continue
   350  					}
   351  					c.debug("got new server addr: %v location: %v", s.Server, s.Location)
   352  					addr, err := netip.ParseAddr(s.Server)
   353  					if err == nil {
   354  						adds = append(adds, netip.AddrPortFrom(addr, uint16(s.Port)))
   355  					}
   356  				}
   357  				f := true
   358  				for _, e := range c.eventHandlers.serverUpdatedHandlers {
   359  					cover(func() {
   360  						if !e(c, &ServerUpdatedEvent{Servers: servers}) {
   361  							f = false
   362  						}
   363  					})
   364  				}
   365  				if f {
   366  					c.SetCustomServer(adds)
   367  				}
   368  				return nil, nil
   369  			}
   370  		case 2:
   371  			fmtPkt := jce.NewJceReader(jceBuf)
   372  			list := &jce.FileStoragePushFSSvcList{}
   373  			list.ReadFrom(fmtPkt)
   374  			c.debug("got file storage svc push.")
   375  			// c.fileStorageInfo = list
   376  			rsp := cmd0x6ff.C501RspBody{}
   377  			if err := proto.Unmarshal(list.BigDataChannel.PbBuf, &rsp); err == nil && rsp.RspBody != nil {
   378  				c.highwaySession.SigSession = rsp.RspBody.SigSession
   379  				c.highwaySession.SessionKey = rsp.RspBody.SessionKey
   380  				for _, srv := range rsp.RspBody.Addrs {
   381  					if srv.ServiceType.Unwrap() == 10 {
   382  						for _, addr := range srv.Addrs {
   383  							c.highwaySession.AppendAddr(addr.Ip.Unwrap(), addr.Port.Unwrap())
   384  						}
   385  					}
   386  					/*
   387  						if srv.ServiceType.Unwrap() == 21 {
   388  							for _, addr := range srv.Addrs {
   389  								c.otherSrvAddrs = append(c.otherSrvAddrs, fmt.Sprintf("%v:%v", binary.UInt32ToIPV4Address(addr.Ip.Unwrap()), addr.Port.Unwrap()))
   390  							}
   391  						}
   392  
   393  					*/
   394  				}
   395  			}
   396  		}
   397  	}
   398  
   399  	seq := r.ReadInt64(3)
   400  	_, resp := c.buildConfPushRespPacket(t, seq, jceBuf)
   401  	return nil, c.sendPacket(resp)
   402  }
   403  
   404  // MessageSvc.PbGetMsg
   405  func decodeMessageSvcPacket(c *QQClient, pkt *network.Packet) (any, error) {
   406  	rsp := msg.GetMessageResponse{}
   407  	err := proto.Unmarshal(pkt.Payload, &rsp)
   408  	if err != nil {
   409  		return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
   410  	}
   411  	c.c2cMessageSyncProcessor(&rsp, pkt.Params)
   412  	return nil, nil
   413  }
   414  
   415  // MessageSvc.PushNotify
   416  func decodeSvcNotify(c *QQClient, pkt *network.Packet) (any, error) {
   417  	request := &jce.RequestPacket{}
   418  	request.ReadFrom(jce.NewJceReader(pkt.Payload[4:]))
   419  	data := &jce.RequestDataVersion2{}
   420  	data.ReadFrom(jce.NewJceReader(request.SBuffer))
   421  	if len(data.Map) == 0 {
   422  		_, err := c.sendAndWait(c.buildGetMessageRequestPacket(msg.SyncFlag_START, time.Now().Unix()))
   423  		return nil, err
   424  	}
   425  	notify := &jce.RequestPushNotify{}
   426  	notify.ReadFrom(jce.NewJceReader(data.Map["req_PushNotify"]["PushNotifyPack.RequestPushNotify"][1:]))
   427  	if decoder, typ := peekC2CDecoder(notify.MsgType); decoder != nil {
   428  		// notify.MsgType != 85 && notify.MsgType != 36 moves to _c2c_decoders.go [nonSvcNotifyTroopSystemMsgDecoders]
   429  		if typ == troopSystemMsgDecoders {
   430  			c.exceptAndDispatchGroupSysMsg()
   431  			return nil, nil
   432  		}
   433  		if typ == sysMsgDecoders {
   434  			_, pkt := c.buildSystemMsgNewFriendPacket()
   435  			return nil, c.sendPacket(pkt)
   436  		}
   437  	}
   438  	_, err := c.sendAndWait(c.buildGetMessageRequestPacket(msg.SyncFlag_START, time.Now().Unix()))
   439  	return nil, err
   440  }
   441  
   442  // SummaryCard.ReqSummaryCard
   443  func decodeSummaryCardResponse(_ *QQClient, pkt *network.Packet) (any, error) {
   444  	request := &jce.RequestPacket{}
   445  	request.ReadFrom(jce.NewJceReader(pkt.Payload))
   446  	data := &jce.RequestDataVersion2{}
   447  	data.ReadFrom(jce.NewJceReader(request.SBuffer))
   448  	rsp := func() *jce.JceReader {
   449  		if r, ok := data.Map["RespSummaryCard"]["SummaryCard.RespSummaryCard"]; ok {
   450  			return jce.NewJceReader(r[1:])
   451  		}
   452  		return jce.NewJceReader(data.Map["RespSummaryCard"]["SummaryCard_Old.RespSummaryCard"][1:])
   453  	}()
   454  	info := &SummaryCardInfo{
   455  		Sex:      rsp.ReadByte(1),
   456  		Age:      rsp.ReadByte(2),
   457  		Nickname: rsp.ReadString(3),
   458  		Level:    rsp.ReadInt32(5),
   459  		City:     rsp.ReadString(7),
   460  		Sign:     rsp.ReadString(8),
   461  		Mobile:   rsp.ReadString(11),
   462  		Uin:      rsp.ReadInt64(23),
   463  	}
   464  	vipInfo := rsp.ReadMapIntVipInfo(29) // 1 -> vip, 3 -> svip
   465  	if v1, v3 := vipInfo[1], vipInfo[3]; v1 != nil || v3 != nil {
   466  		if v1.Open != 0 {
   467  			info.VipLevel = fmt.Sprintf("vip%d", v1.Level)
   468  		}
   469  		if v3.Open != 0 {
   470  			info.VipLevel = fmt.Sprintf("svip%d", v3.Level)
   471  		}
   472  	}
   473  
   474  	richSign := rsp.ReadBytes(32)
   475  	records, _ := tlv.NewDecoder(1, 1).Decode(richSign)
   476  	for _, r := range records {
   477  		if r.Tag == 3 {
   478  			info.Sign = string(r.Value)
   479  		}
   480  	}
   481  
   482  	info.LoginDays = rsp.ReadInt64(36)
   483  	services := rsp.ReadByteArrArr(46)
   484  	readService := func(buf []byte) (*profilecard.BusiComm, []byte) {
   485  		r := binary.NewReader(buf)
   486  		r.ReadByte()
   487  		l1 := r.ReadInt32()
   488  		l2 := r.ReadInt32()
   489  		comm := r.ReadBytes(int(l1))
   490  		d := r.ReadBytes(int(l2))
   491  		c := &profilecard.BusiComm{}
   492  		_ = proto.Unmarshal(comm, c)
   493  		return c, d
   494  	}
   495  	for _, buf := range services {
   496  		comm, payload := readService(buf)
   497  		if comm.Service.Unwrap() == 16 {
   498  			rsp := profilecard.GateVaProfileGateRsp{}
   499  			_ = proto.Unmarshal(payload, &rsp)
   500  			if rsp.QidInfo != nil {
   501  				info.Qid = rsp.QidInfo.Qid.Unwrap()
   502  			}
   503  		}
   504  	}
   505  	return info, nil
   506  }
   507  
   508  // friendlist.getFriendGroupList
   509  func decodeFriendGroupListResponse(_ *QQClient, pkt *network.Packet) (any, error) {
   510  	request := &jce.RequestPacket{}
   511  	request.ReadFrom(jce.NewJceReader(pkt.Payload))
   512  	data := &jce.RequestDataVersion3{}
   513  	data.ReadFrom(jce.NewJceReader(request.SBuffer))
   514  	r := jce.NewJceReader(data.Map["FLRESP"][1:])
   515  	totalFriendCount := r.ReadInt16(5)
   516  	friends := r.ReadFriendInfos(7)
   517  	l := make([]*FriendInfo, 0, len(friends))
   518  	for _, f := range friends {
   519  		l = append(l, &FriendInfo{
   520  			Uin:      f.FriendUin,
   521  			Nickname: f.Nick,
   522  			Remark:   f.Remark,
   523  			FaceId:   f.FaceId,
   524  		})
   525  	}
   526  	rsp := &FriendListResponse{
   527  		TotalCount: int32(totalFriendCount),
   528  		List:       l,
   529  	}
   530  	return rsp, nil
   531  }
   532  
   533  // friendlist.delFriend
   534  func decodeFriendDeleteResponse(_ *QQClient, pkt *network.Packet) (any, error) {
   535  	request := &jce.RequestPacket{}
   536  	request.ReadFrom(jce.NewJceReader(pkt.Payload))
   537  	data := &jce.RequestDataVersion3{}
   538  	data.ReadFrom(jce.NewJceReader(request.SBuffer))
   539  	r := jce.NewJceReader(data.Map["DFRESP"][1:])
   540  	if ret := r.ReadInt32(2); ret != 0 {
   541  		return nil, errors.Errorf("delete friend error: %v", ret)
   542  	}
   543  	return nil, nil
   544  }
   545  
   546  // friendlist.GetTroopListReqV2
   547  func decodeGroupListResponse(c *QQClient, pkt *network.Packet) (any, error) {
   548  	request := &jce.RequestPacket{}
   549  	request.ReadFrom(jce.NewJceReader(pkt.Payload))
   550  	data := &jce.RequestDataVersion3{}
   551  	data.ReadFrom(jce.NewJceReader(request.SBuffer))
   552  	r := jce.NewJceReader(data.Map["GetTroopListRespV2"][1:])
   553  	vecCookie := r.ReadBytes(4)
   554  	groups := r.ReadTroopNumbers(5)
   555  	l := make([]*GroupInfo, 0, len(groups))
   556  	for _, g := range groups {
   557  		l = append(l, &GroupInfo{
   558  			Uin:            g.GroupUin,
   559  			Code:           g.GroupCode,
   560  			Name:           g.GroupName,
   561  			OwnerUin:       g.GroupOwnerUin,
   562  			MemberCount:    uint16(g.MemberNum),
   563  			MaxMemberCount: uint16(g.MaxGroupMemberNum),
   564  			client:         c,
   565  		})
   566  	}
   567  	if len(vecCookie) > 0 {
   568  		rsp, err := c.sendAndWait(c.buildGroupListRequestPacket(vecCookie))
   569  		if err != nil {
   570  			return nil, err
   571  		}
   572  		l = append(l, rsp.([]*GroupInfo)...)
   573  	}
   574  	return l, nil
   575  }
   576  
   577  // friendlist.GetTroopMemberListReq
   578  func decodeGroupMemberListResponse(_ *QQClient, pkt *network.Packet) (any, error) {
   579  	request := &jce.RequestPacket{}
   580  	request.ReadFrom(jce.NewJceReader(pkt.Payload))
   581  	data := &jce.RequestDataVersion3{}
   582  	data.ReadFrom(jce.NewJceReader(request.SBuffer))
   583  	r := jce.NewJceReader(data.Map["GTMLRESP"][1:])
   584  	members := r.ReadTroopMemberInfos(3)
   585  	next := r.ReadInt64(4)
   586  	l := make([]*GroupMemberInfo, 0, len(members))
   587  	for _, m := range members {
   588  		permission := Member
   589  		if m.Flag&1 != 0 {
   590  			permission = Administrator
   591  		}
   592  		l = append(l, &GroupMemberInfo{
   593  			Uin:             m.MemberUin,
   594  			Nickname:        m.Nick,
   595  			Gender:          m.Gender,
   596  			CardName:        m.Name,
   597  			Level:           uint16(m.MemberLevel),
   598  			JoinTime:        m.JoinTime,
   599  			LastSpeakTime:   m.LastSpeakTime,
   600  			SpecialTitle:    m.SpecialTitle,
   601  			ShutUpTimestamp: m.ShutUpTimestap,
   602  			Permission:      permission,
   603  		})
   604  	}
   605  	return &groupMemberListResponse{
   606  		NextUin: next,
   607  		list:    l,
   608  	}, nil
   609  }
   610  
   611  // group_member_card.get_group_member_card_info
   612  func decodeGroupMemberInfoResponse(c *QQClient, pkt *network.Packet) (any, error) {
   613  	rsp := pb.GroupMemberRspBody{}
   614  	if err := proto.Unmarshal(pkt.Payload, &rsp); err != nil {
   615  		return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
   616  	}
   617  	if rsp.MemInfo == nil || (rsp.MemInfo.Nick == nil && rsp.MemInfo.Age == 0) {
   618  		return nil, errors.WithStack(ErrMemberNotFound)
   619  	}
   620  	group := c.FindGroup(rsp.GroupCode)
   621  	permission := Member
   622  	if rsp.MemInfo.Uin == group.OwnerUin {
   623  		permission = Owner
   624  	}
   625  	if rsp.MemInfo.Role == 2 {
   626  		permission = Administrator
   627  	}
   628  	return &GroupMemberInfo{
   629  		Group:         group,
   630  		Uin:           rsp.MemInfo.Uin,
   631  		Gender:        byte(rsp.MemInfo.Sex),
   632  		Nickname:      string(rsp.MemInfo.Nick),
   633  		CardName:      string(rsp.MemInfo.Card),
   634  		Level:         uint16(rsp.MemInfo.Level),
   635  		JoinTime:      rsp.MemInfo.Join,
   636  		LastSpeakTime: rsp.MemInfo.LastSpeak,
   637  		SpecialTitle:  string(rsp.MemInfo.SpecialTitle),
   638  		Permission:    permission,
   639  	}, nil
   640  }
   641  
   642  // LongConn.OffPicUp
   643  func decodeOffPicUpResponse(_ *QQClient, pkt *network.Packet) (any, error) {
   644  	rsp := cmd0x352.RspBody{}
   645  	if err := proto.Unmarshal(pkt.Payload, &rsp); err != nil {
   646  		return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
   647  	}
   648  	if rsp.FailMsg != nil {
   649  		return &imageUploadResponse{
   650  			ResultCode: -1,
   651  			Message:    string(rsp.FailMsg),
   652  		}, nil
   653  	}
   654  	if rsp.Subcmd.Unwrap() != 1 || len(rsp.TryupImgRsp) == 0 {
   655  		return &imageUploadResponse{
   656  			ResultCode: -2,
   657  		}, nil
   658  	}
   659  	imgRsp := rsp.TryupImgRsp[0]
   660  	if imgRsp.Result.Unwrap() != 0 {
   661  		return &imageUploadResponse{
   662  			ResultCode: int32(imgRsp.Result.Unwrap()),
   663  			Message:    string(imgRsp.FailMsg),
   664  		}, nil
   665  	}
   666  	if imgRsp.FileExit.Unwrap() {
   667  		return &imageUploadResponse{
   668  			IsExists:   true,
   669  			ResourceId: string(imgRsp.UpResid),
   670  		}, nil
   671  	}
   672  	return &imageUploadResponse{
   673  		ResourceId: string(imgRsp.UpResid),
   674  		UploadKey:  imgRsp.UpUkey,
   675  		UploadIp:   imgRsp.UpIp,
   676  		UploadPort: imgRsp.UpPort,
   677  	}, nil
   678  }
   679  
   680  // OnlinePush.PbPushTransMsg
   681  func decodeOnlinePushTransPacket(c *QQClient, pkt *network.Packet) (any, error) {
   682  	info := msg.TransMsgInfo{}
   683  	err := proto.Unmarshal(pkt.Payload, &info)
   684  	if err != nil {
   685  		return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
   686  	}
   687  	data := binary.NewReader(info.MsgData)
   688  	idStr := strconv.FormatInt(info.MsgUid.Unwrap(), 10)
   689  	if _, ok := c.transCache.Get(idStr); ok {
   690  		return nil, nil
   691  	}
   692  	c.transCache.Add(idStr, unit{}, time.Second*15)
   693  	if info.MsgType.Unwrap() == 34 {
   694  		data.ReadInt32()
   695  		data.ReadByte()
   696  		target := int64(uint32(data.ReadInt32()))
   697  		typ := int32(data.ReadByte())
   698  		operator := int64(uint32(data.ReadInt32()))
   699  		if g := c.FindGroupByUin(info.FromUin.Unwrap()); g != nil {
   700  			groupLeaveLock.Lock()
   701  			defer groupLeaveLock.Unlock()
   702  			switch typ {
   703  			case 0x02:
   704  				if target == c.Uin {
   705  					c.GroupLeaveEvent.dispatch(c, &GroupLeaveEvent{Group: g})
   706  				} else if m := g.FindMember(target); m != nil {
   707  					g.removeMember(target)
   708  					c.GroupMemberLeaveEvent.dispatch(c, &MemberLeaveGroupEvent{
   709  						Group:  g,
   710  						Member: m,
   711  					})
   712  				}
   713  			case 0x03:
   714  				if err = c.ReloadGroupList(); err != nil {
   715  					return nil, err
   716  				}
   717  				if target == c.Uin {
   718  					c.GroupLeaveEvent.dispatch(c, &GroupLeaveEvent{
   719  						Group:    g,
   720  						Operator: g.FindMember(operator),
   721  					})
   722  				} else if m := g.FindMember(target); m != nil {
   723  					g.removeMember(target)
   724  					c.GroupMemberLeaveEvent.dispatch(c, &MemberLeaveGroupEvent{
   725  						Group:    g,
   726  						Member:   m,
   727  						Operator: g.FindMember(operator),
   728  					})
   729  				}
   730  			case 0x82:
   731  				if m := g.FindMember(target); m != nil {
   732  					g.removeMember(target)
   733  					c.GroupMemberLeaveEvent.dispatch(c, &MemberLeaveGroupEvent{
   734  						Group:  g,
   735  						Member: m,
   736  					})
   737  				}
   738  			case 0x83:
   739  				if m := g.FindMember(target); m != nil {
   740  					g.removeMember(target)
   741  					c.GroupMemberLeaveEvent.dispatch(c, &MemberLeaveGroupEvent{
   742  						Group:    g,
   743  						Member:   m,
   744  						Operator: g.FindMember(operator),
   745  					})
   746  				}
   747  			case 0x01, 0x81: // kosbot add: 群解散. 暂时这样 See https://github.com/lz1998/ricq/blob/064ddddca19aa0410e2514852e3a151fd9913371/ricq-core/src/command/online_push/decoder.rs#L86
   748  				c.GroupDisbandEvent.dispatch(c, &GroupDisbandEvent{
   749  					Group:    g,
   750  					Operator: g.FindMember(operator),
   751  					Time:     int64(info.MsgTime.Unwrap()),
   752  				})
   753  				if err = c.ReloadGroupList(); err != nil {
   754  					return nil, err
   755  				}
   756  			}
   757  		}
   758  	}
   759  	if info.MsgType.Unwrap() == 44 {
   760  		data.ReadBytes(5)
   761  		var4 := int32(data.ReadByte())
   762  		var5 := int64(0)
   763  		target := int64(uint32(data.ReadInt32()))
   764  		if var4 != 0 && var4 != 1 {
   765  			var5 = int64(uint32(data.ReadInt32()))
   766  		}
   767  		if g := c.FindGroupByUin(info.FromUin.Unwrap()); g != nil {
   768  			if var5 == 0 && data.Len() == 1 {
   769  				newPermission := Member
   770  				if data.ReadByte() == 1 {
   771  					newPermission = Administrator
   772  				}
   773  				mem := g.FindMember(target)
   774  				if mem.Permission != newPermission {
   775  					old := mem.Permission
   776  					mem.Permission = newPermission
   777  					c.GroupMemberPermissionChangedEvent.dispatch(c, &MemberPermissionChangedEvent{
   778  						Group:         g,
   779  						Member:        mem,
   780  						OldPermission: old,
   781  						NewPermission: newPermission,
   782  					})
   783  				}
   784  			}
   785  		}
   786  	}
   787  	return nil, nil
   788  }
   789  
   790  // ProfileService.Pb.ReqSystemMsgNew.Friend
   791  func decodeSystemMsgFriendPacket(c *QQClient, pkt *network.Packet) (any, error) {
   792  	rsp := structmsg.RspSystemMsgNew{}
   793  	if err := proto.Unmarshal(pkt.Payload, &rsp); err != nil {
   794  		return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
   795  	}
   796  	if len(rsp.Friendmsgs) == 0 {
   797  		return nil, nil
   798  	}
   799  	st := rsp.Friendmsgs[0]
   800  	if st.Msg != nil {
   801  		c.NewFriendRequestEvent.dispatch(c, &NewFriendRequest{
   802  			RequestId:     st.MsgSeq,
   803  			Message:       st.Msg.MsgAdditional,
   804  			RequesterUin:  st.ReqUin,
   805  			RequesterNick: st.Msg.ReqUinNick,
   806  			client:        c,
   807  		})
   808  	}
   809  	return nil, nil
   810  }
   811  
   812  // MessageSvc.PushForceOffline
   813  func decodeForceOfflinePacket(c *QQClient, pkt *network.Packet) (any, error) {
   814  	request := &jce.RequestPacket{}
   815  	request.ReadFrom(jce.NewJceReader(pkt.Payload))
   816  	data := &jce.RequestDataVersion2{}
   817  	data.ReadFrom(jce.NewJceReader(request.SBuffer))
   818  	r := jce.NewJceReader(data.Map["req_PushForceOffline"]["PushNotifyPack.RequestPushForceOffline"][1:])
   819  	tips := r.ReadString(2)
   820  	c.Disconnect()
   821  	go c.DisconnectedEvent.dispatch(c, &ClientDisconnectedEvent{Message: tips})
   822  	return nil, nil
   823  }
   824  
   825  // StatSvc.ReqMSFOffline
   826  func decodeMSFOfflinePacket(c *QQClient, _ *network.Packet) (any, error) {
   827  	// c.lastLostMsg = "服务器端强制下线."
   828  	c.Disconnect()
   829  	// 这个decoder不能消耗太多时间, event另起线程处理
   830  	go c.DisconnectedEvent.dispatch(c, &ClientDisconnectedEvent{Message: "服务端强制下线."})
   831  	return nil, nil
   832  }
   833  
   834  // OidbSvc.0xd79
   835  func decodeWordSegmentation(_ *QQClient, pkt *network.Packet) (any, error) {
   836  	rsp := oidb.D79RspBody{}
   837  	err := unpackOIDBPackage(pkt.Payload, &rsp)
   838  	if err != nil {
   839  		return nil, err
   840  	}
   841  	if rsp.Content != nil {
   842  		return rsp.Content.SliceContent, nil
   843  	}
   844  	return nil, errors.New("no word received")
   845  }
   846  
   847  func decodeSidExpiredPacket(c *QQClient, pkt *network.Packet) (any, error) {
   848  	/*
   849  		_, err := c.sendAndWait(c.buildRequestChangeSigPacket(true))
   850  		if err != nil {
   851  			return nil, errors.Wrap(err, "resign client error")
   852  		}
   853  		if err = c.registerClient(); err != nil {
   854  			return nil, errors.Wrap(err, "register error")
   855  		}
   856  		_ = c.sendPacket(c.uniPacketWithSeq(i.SequenceId, "OnlinePush.SidTicketExpired", EmptyBytes))
   857  	*/
   858  	return nil, nil
   859  }
   860  
   861  /* unused
   862  // LightAppSvc.mini_app_info.GetAppInfoById
   863  func decodeAppInfoResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
   864  	pkg := qweb.QWebRsp{}
   865  	rsp := qweb.GetAppInfoByIdRsp{}
   866  	if err := proto.Unmarshal(payload, &pkg); err != nil {
   867  		return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
   868  	}
   869  	if pkg.RetCode.Unwrap() != 0 {
   870  		return nil, errors.New(pkg.ErrMsg.Unwrap())
   871  	}
   872  	if err := proto.Unmarshal(pkg.BusiBuff, &rsp); err != nil {
   873  		return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
   874  	}
   875  	return rsp.AppInfo, nil
   876  }
   877  */
   878  
   879  func ignoreDecoder(_ *QQClient, _ *network.Packet) (any, error) {
   880  	return nil, nil
   881  }