mirror of
https://github.com/Mrs4s/MiraiGo.git
synced 2025-05-04 11:07:40 +08:00
Merge branch 'master' of github.com:/Mrs4s/MiraiGo
This commit is contained in:
commit
d8cae988c6
@ -34,7 +34,7 @@ func (w *JceWriter) WriteByte(b, tag byte) *JceWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *JceWriter) WriteBool(b bool, tag byte) {
|
func (w *JceWriter) WriteBool(b bool, tag byte) {
|
||||||
var by byte = 0
|
var by byte
|
||||||
if b {
|
if b {
|
||||||
by = 1
|
by = 1
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,8 @@ type encoder struct {
|
|||||||
|
|
||||||
func (msg DynamicProtoMessage) Encode() []byte {
|
func (msg DynamicProtoMessage) Encode() []byte {
|
||||||
en := &encoder{}
|
en := &encoder{}
|
||||||
|
|
||||||
|
//nolint:staticcheck
|
||||||
for id, value := range msg {
|
for id, value := range msg {
|
||||||
key := id << 3
|
key := id << 3
|
||||||
switch v := value.(type) {
|
switch v := value.(type) {
|
||||||
|
@ -97,11 +97,12 @@ func (r *Reader) ReadTlvMap(tagSize int) (m TlvMap) {
|
|||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
var k uint16
|
var k uint16
|
||||||
if tagSize == 1 {
|
switch tagSize {
|
||||||
|
case 1:
|
||||||
k = uint16(r.ReadByte())
|
k = uint16(r.ReadByte())
|
||||||
} else if tagSize == 2 {
|
case 2:
|
||||||
k = r.ReadUInt16()
|
k = r.ReadUInt16()
|
||||||
} else if tagSize == 4 {
|
case 4:
|
||||||
k = uint16(r.ReadInt32())
|
k = uint16(r.ReadInt32())
|
||||||
}
|
}
|
||||||
if k == 255 {
|
if k == 255 {
|
||||||
|
@ -29,7 +29,7 @@ func (t TEA) Encrypt(src []byte) (dst []byte) {
|
|||||||
block := binary.BigEndian.Uint64(dst[i:])
|
block := binary.BigEndian.Uint64(dst[i:])
|
||||||
holder = block ^ iv1
|
holder = block ^ iv1
|
||||||
iv1 = t.encode(holder)
|
iv1 = t.encode(holder)
|
||||||
iv1 = iv1 ^ iv2
|
iv1 ^= iv2
|
||||||
iv2 = holder
|
iv2 = holder
|
||||||
binary.BigEndian.PutUint64(dst[i:], iv1)
|
binary.BigEndian.PutUint64(dst[i:], iv1)
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package client
|
|||||||
import (
|
import (
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -14,7 +13,6 @@ import (
|
|||||||
"github.com/Mrs4s/MiraiGo/client/pb/msg"
|
"github.com/Mrs4s/MiraiGo/client/pb/msg"
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb/oidb"
|
"github.com/Mrs4s/MiraiGo/client/pb/oidb"
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb/profilecard"
|
"github.com/Mrs4s/MiraiGo/client/pb/profilecard"
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb/qweb"
|
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb/structmsg"
|
"github.com/Mrs4s/MiraiGo/client/pb/structmsg"
|
||||||
"github.com/Mrs4s/MiraiGo/internal/crypto"
|
"github.com/Mrs4s/MiraiGo/internal/crypto"
|
||||||
"github.com/Mrs4s/MiraiGo/internal/packets"
|
"github.com/Mrs4s/MiraiGo/internal/packets"
|
||||||
@ -1080,6 +1078,7 @@ func (c *QQClient) buildQuitGroupPacket(groupCode int64) (uint16, []byte) {
|
|||||||
return seq, packet
|
return seq, packet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* this function is unused
|
||||||
// LightAppSvc.mini_app_info.GetAppInfoById
|
// LightAppSvc.mini_app_info.GetAppInfoById
|
||||||
func (c *QQClient) buildAppInfoRequestPacket(id string) (uint16, []byte) {
|
func (c *QQClient) buildAppInfoRequestPacket(id string) (uint16, []byte) {
|
||||||
seq := c.nextSeq()
|
seq := c.nextSeq()
|
||||||
@ -1099,6 +1098,7 @@ func (c *QQClient) buildAppInfoRequestPacket(id string) (uint16, []byte) {
|
|||||||
packet := packets.BuildUniPacket(c.Uin, seq, "LightAppSvc.mini_app_info.GetAppInfoById", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
|
packet := packets.BuildUniPacket(c.Uin, seq, "LightAppSvc.mini_app_info.GetAppInfoById", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
|
||||||
return seq, packet
|
return seq, packet
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
func (c *QQClient) buildWordSegmentationPacket(data []byte) (uint16, []byte) {
|
func (c *QQClient) buildWordSegmentationPacket(data []byte) (uint16, []byte) {
|
||||||
seq := c.nextSeq()
|
seq := c.nextSeq()
|
||||||
|
@ -95,11 +95,9 @@ type QQClient struct {
|
|||||||
fileStorageInfo *jce.FileStoragePushFSSvcList
|
fileStorageInfo *jce.FileStoragePushFSSvcList
|
||||||
|
|
||||||
// message state
|
// message state
|
||||||
lastMessageSeq int32
|
|
||||||
msgSvcCache *utils.Cache
|
msgSvcCache *utils.Cache
|
||||||
lastC2CMsgTime int64
|
lastC2CMsgTime int64
|
||||||
transCache *utils.Cache
|
transCache *utils.Cache
|
||||||
lastLostMsg string
|
|
||||||
groupSysMsgCache *GroupSystemMessages
|
groupSysMsgCache *GroupSystemMessages
|
||||||
groupMsgBuilders sync.Map
|
groupMsgBuilders sync.Map
|
||||||
onlinePushCache *utils.Cache
|
onlinePushCache *utils.Cache
|
||||||
@ -107,7 +105,6 @@ type QQClient struct {
|
|||||||
groupSeq int32
|
groupSeq int32
|
||||||
friendSeq int32
|
friendSeq int32
|
||||||
heartbeatEnabled bool
|
heartbeatEnabled bool
|
||||||
groupDataTransSeq int32
|
|
||||||
highwayApplyUpSeq int32
|
highwayApplyUpSeq int32
|
||||||
eventHandlers *eventHandlers
|
eventHandlers *eventHandlers
|
||||||
|
|
||||||
@ -150,6 +147,13 @@ type handlerInfo struct {
|
|||||||
params requestParams
|
params requestParams
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *handlerInfo) getParams() requestParams {
|
||||||
|
if h == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return h.params
|
||||||
|
}
|
||||||
|
|
||||||
var decoders = map[string]func(*QQClient, *incomingPacketInfo, []byte) (interface{}, error){
|
var decoders = map[string]func(*QQClient, *incomingPacketInfo, []byte) (interface{}, error){
|
||||||
"wtlogin.login": decodeLoginResponse,
|
"wtlogin.login": decodeLoginResponse,
|
||||||
"wtlogin.exchange_emp": decodeExchangeEmpResponse,
|
"wtlogin.exchange_emp": decodeExchangeEmpResponse,
|
||||||
@ -174,7 +178,6 @@ var decoders = map[string]func(*QQClient, *incomingPacketInfo, []byte) (interfac
|
|||||||
"OidbSvc.0xd79": decodeWordSegmentation,
|
"OidbSvc.0xd79": decodeWordSegmentation,
|
||||||
"OidbSvc.0x990": decodeTranslateResponse,
|
"OidbSvc.0x990": decodeTranslateResponse,
|
||||||
"SummaryCard.ReqSummaryCard": decodeSummaryCardResponse,
|
"SummaryCard.ReqSummaryCard": decodeSummaryCardResponse,
|
||||||
"LightAppSvc.mini_app_info.GetAppInfoById": decodeAppInfoResponse,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -547,10 +550,8 @@ func (c *QQClient) GetForwardMessage(resID string) *message.ForwardMessage {
|
|||||||
if m == nil {
|
if m == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var (
|
var item *msg.PbMultiMsgItem
|
||||||
item *msg.PbMultiMsgItem
|
ret := &message.ForwardMessage{Nodes: []*message.ForwardNode{}}
|
||||||
ret = &message.ForwardMessage{Nodes: []*message.ForwardNode{}}
|
|
||||||
)
|
|
||||||
for _, iter := range m.Items {
|
for _, iter := range m.Items {
|
||||||
if iter.GetFileName() == m.FileName {
|
if iter.GetFileName() == m.FileName {
|
||||||
item = iter
|
item = iter
|
||||||
@ -560,16 +561,15 @@ func (c *QQClient) GetForwardMessage(resID string) *message.ForwardMessage {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
for _, m := range item.GetBuffer().GetMsg() {
|
for _, m := range item.GetBuffer().GetMsg() {
|
||||||
|
name := m.Head.GetFromNick()
|
||||||
|
if m.Head.GetMsgType() == 82 && m.Head.GroupInfo != nil {
|
||||||
|
name = m.Head.GroupInfo.GetGroupCard()
|
||||||
|
}
|
||||||
ret.Nodes = append(ret.Nodes, &message.ForwardNode{
|
ret.Nodes = append(ret.Nodes, &message.ForwardNode{
|
||||||
SenderId: m.Head.GetFromUin(),
|
SenderId: m.Head.GetFromUin(),
|
||||||
SenderName: func() string {
|
SenderName: name,
|
||||||
if m.Head.GetMsgType() == 82 && m.Head.GroupInfo != nil {
|
Time: m.Head.GetMsgTime(),
|
||||||
return m.Head.GroupInfo.GetGroupCard()
|
Message: message.ParseMessageElems(m.Body.RichText.Elems),
|
||||||
}
|
|
||||||
return m.Head.GetFromNick()
|
|
||||||
}(),
|
|
||||||
Time: m.Head.GetMsgTime(),
|
|
||||||
Message: message.ParseMessageElems(m.Body.RichText.Elems),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
@ -866,10 +866,6 @@ func (c *QQClient) nextQWebSeq() int64 {
|
|||||||
return atomic.AddInt64(&c.qwebSeq, 1)
|
return atomic.AddInt64(&c.qwebSeq, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *QQClient) nextGroupDataTransSeq() int32 {
|
|
||||||
return atomic.AddInt32(&c.groupDataTransSeq, 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *QQClient) nextHighwayApplySeq() int32 {
|
func (c *QQClient) nextHighwayApplySeq() int32 {
|
||||||
return atomic.AddInt32(&c.highwayApplyUpSeq, 2)
|
return atomic.AddInt32(&c.highwayApplyUpSeq, 2)
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ import (
|
|||||||
"github.com/Mrs4s/MiraiGo/client/pb/msg"
|
"github.com/Mrs4s/MiraiGo/client/pb/msg"
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb/oidb"
|
"github.com/Mrs4s/MiraiGo/client/pb/oidb"
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb/profilecard"
|
"github.com/Mrs4s/MiraiGo/client/pb/profilecard"
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb/qweb"
|
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb/structmsg"
|
"github.com/Mrs4s/MiraiGo/client/pb/structmsg"
|
||||||
"github.com/Mrs4s/MiraiGo/internal/proto"
|
"github.com/Mrs4s/MiraiGo/internal/proto"
|
||||||
"github.com/Mrs4s/MiraiGo/utils"
|
"github.com/Mrs4s/MiraiGo/utils"
|
||||||
@ -204,8 +203,7 @@ func decodeExchangeEmpResponse(c *QQClient, _ *incomingPacketInfo, payload []byt
|
|||||||
reader.ReadUInt16()
|
reader.ReadUInt16()
|
||||||
m := reader.ReadTlvMap(2)
|
m := reader.ReadTlvMap(2)
|
||||||
if t != 0 {
|
if t != 0 {
|
||||||
c.Error("exchange_emp error: %v", t)
|
return nil, errors.Errorf("exchange_emp failed: %v", t)
|
||||||
return nil, errors.New("exchange_emp failed")
|
|
||||||
}
|
}
|
||||||
if cmd == 15 {
|
if cmd == 15 {
|
||||||
c.decodeT119R(m[0x119])
|
c.decodeT119R(m[0x119])
|
||||||
@ -795,6 +793,7 @@ func decodeWordSegmentation(_ *QQClient, _ *incomingPacketInfo, payload []byte)
|
|||||||
return nil, errors.New("no word received")
|
return nil, errors.New("no word received")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* unused
|
||||||
// LightAppSvc.mini_app_info.GetAppInfoById
|
// LightAppSvc.mini_app_info.GetAppInfoById
|
||||||
func decodeAppInfoResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
|
func decodeAppInfoResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
|
||||||
pkg := qweb.QWebRsp{}
|
pkg := qweb.QWebRsp{}
|
||||||
@ -810,6 +809,7 @@ func decodeAppInfoResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (
|
|||||||
}
|
}
|
||||||
return rsp.AppInfo, nil
|
return rsp.AppInfo, nil
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
func ignoreDecoder(_ *QQClient, _ *incomingPacketInfo, _ []byte) (interface{}, error) {
|
func ignoreDecoder(_ *QQClient, _ *incomingPacketInfo, _ []byte) (interface{}, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -157,10 +157,7 @@ var SystemDeviceInfo = &DeviceInfo{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var EmptyBytes = make([]byte, 0)
|
||||||
EmptyBytes = []byte{}
|
|
||||||
NumberRange = "0123456789"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
r := make([]byte, 16)
|
r := make([]byte, 16)
|
||||||
@ -174,8 +171,9 @@ func init() {
|
|||||||
func GenRandomDevice() {
|
func GenRandomDevice() {
|
||||||
r := make([]byte, 16)
|
r := make([]byte, 16)
|
||||||
rand.Read(r)
|
rand.Read(r)
|
||||||
SystemDeviceInfo.Display = []byte("MIRAI." + utils.RandomStringRange(6, NumberRange) + ".001")
|
const numberRange = "0123456789"
|
||||||
SystemDeviceInfo.FingerPrint = []byte("mamoe/mirai/mirai:10/MIRAI.200122.001/" + utils.RandomStringRange(7, NumberRange) + ":user/release-keys")
|
SystemDeviceInfo.Display = []byte("MIRAI." + utils.RandomStringRange(6, numberRange) + ".001")
|
||||||
|
SystemDeviceInfo.FingerPrint = []byte("mamoe/mirai/mirai:10/MIRAI.200122.001/" + utils.RandomStringRange(7, numberRange) + ":user/release-keys")
|
||||||
SystemDeviceInfo.BootId = binary.GenUUID(r)
|
SystemDeviceInfo.BootId = binary.GenUUID(r)
|
||||||
SystemDeviceInfo.ProcVersion = []byte("Linux version 3.0.31-" + utils.RandomString(8) + " (android-build@xxx.xxx.xxx.xxx.com)")
|
SystemDeviceInfo.ProcVersion = []byte("Linux version 3.0.31-" + utils.RandomString(8) + " (android-build@xxx.xxx.xxx.xxx.com)")
|
||||||
rand.Read(r)
|
rand.Read(r)
|
||||||
@ -498,8 +496,7 @@ func qualityTest(addr string) (int64, error) {
|
|||||||
return 0, errors.Wrap(err, "failed to connect to server during quality test")
|
return 0, errors.Wrap(err, "failed to connect to server during quality test")
|
||||||
}
|
}
|
||||||
_ = conn.Close()
|
_ = conn.Close()
|
||||||
end := time.Now()
|
return time.Since(start).Milliseconds(), nil
|
||||||
return end.Sub(start).Milliseconds(), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *QQClient) parsePrivateMessage(msg *msg.Message) *message.PrivateMessage {
|
func (c *QQClient) parsePrivateMessage(msg *msg.Message) *message.PrivateMessage {
|
||||||
@ -582,10 +579,12 @@ func (b *groupMessageBuilder) build() *msg.Message {
|
|||||||
return base
|
return base
|
||||||
}
|
}
|
||||||
|
|
||||||
func packUniRequestData(data []byte) (r []byte) {
|
func packUniRequestData(data []byte) []byte {
|
||||||
r = append([]byte{0x0A}, data...)
|
r := make([]byte, 0, len(data)+2)
|
||||||
|
r = append(r, 0x0a)
|
||||||
|
r = append(r, data...)
|
||||||
r = append(r, 0x0B)
|
r = append(r, 0x0B)
|
||||||
return
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func genForwardTemplate(resID, preview, title, brief, source, summary string, ts int64, items []*msg.PbMultiMsgItem) *message.ForwardElement {
|
func genForwardTemplate(resID, preview, title, brief, source, summary string, ts int64, items []*msg.PbMultiMsgItem) *message.ForwardElement {
|
||||||
|
@ -22,20 +22,18 @@ import (
|
|||||||
"github.com/Mrs4s/MiraiGo/utils"
|
"github.com/Mrs4s/MiraiGo/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type guildImageUploadResponse struct {
|
||||||
guildImageUploadResponse struct {
|
UploadKey []byte
|
||||||
UploadKey []byte
|
UploadIp []uint32
|
||||||
UploadIp []uint32
|
UploadPort []uint32
|
||||||
UploadPort []uint32
|
Width int32
|
||||||
Width int32
|
Height int32
|
||||||
Height int32
|
Message string
|
||||||
Message string
|
DownloadIndex string
|
||||||
DownloadIndex string
|
FileId int64
|
||||||
FileId int64
|
ResultCode int32
|
||||||
ResultCode int32
|
IsExists bool
|
||||||
IsExists bool
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
decoders["ImgStore.QQMeetPicUp"] = decodeGuildImageStoreResponse
|
decoders["ImgStore.QQMeetPicUp"] = decodeGuildImageStoreResponse
|
||||||
@ -205,20 +203,18 @@ func (s *GuildService) pullChannelMessages(guildId, channelId, beginSeq, endSeq,
|
|||||||
param.Version = []uint64{eventVersion}
|
param.Version = []uint64{eventVersion}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
withVersionFlag := uint32(0)
|
||||||
|
if eventVersion != 0 {
|
||||||
|
withVersionFlag = 1
|
||||||
|
}
|
||||||
|
directFlag := uint32(0)
|
||||||
|
if direct {
|
||||||
|
directFlag = 1
|
||||||
|
}
|
||||||
payload, _ := proto.Marshal(&channel.ChannelMsgReq{
|
payload, _ := proto.Marshal(&channel.ChannelMsgReq{
|
||||||
ChannelParam: param,
|
ChannelParam: param,
|
||||||
WithVersionFlag: proto.Uint32(func() uint32 {
|
WithVersionFlag: &withVersionFlag,
|
||||||
if eventVersion != 0 {
|
DirectMessageFlag: &directFlag,
|
||||||
return 1
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}()),
|
|
||||||
DirectMessageFlag: proto.Uint32(func() uint32 {
|
|
||||||
if direct {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}()),
|
|
||||||
})
|
})
|
||||||
seq := s.c.nextSeq()
|
seq := s.c.nextSeq()
|
||||||
packet := packets.BuildUniPacket(s.c.Uin, seq, "trpc.group_pro.synclogic.SyncLogic.GetChannelMsg", 1, s.c.OutGoingPacketSessionId, []byte{}, s.c.sigInfo.d2Key, payload)
|
packet := packets.BuildUniPacket(s.c.Uin, seq, "trpc.group_pro.synclogic.SyncLogic.GetChannelMsg", 1, s.c.OutGoingPacketSessionId, []byte{}, s.c.sigInfo.d2Key, payload)
|
||||||
|
@ -124,10 +124,9 @@ func (c *QQClient) GetGroupHonorInfo(groupCode int64, honorType HonorType) (*Gro
|
|||||||
/* -------- TextToSpeech -------- */
|
/* -------- TextToSpeech -------- */
|
||||||
|
|
||||||
func (c *QQClient) GetTts(text string) ([]byte, error) {
|
func (c *QQClient) GetTts(text string) ([]byte, error) {
|
||||||
url := "https://textts.qq.com/cgi-bin/tts"
|
apiUrl := "https://textts.qq.com/cgi-bin/tts"
|
||||||
bt, _ := json.Marshal(text)
|
data := fmt.Sprintf(`{"appid": "201908021016","sendUin": %v,"text": %q}`, c.Uin, text)
|
||||||
data := fmt.Sprintf(`{"appid": "201908021016","sendUin": %v,"text": %s}`, c.Uin, bt)
|
rsp, err := utils.HttpPostBytesWithCookie(apiUrl, []byte(data), c.getCookies())
|
||||||
rsp, err := utils.HttpPostBytesWithCookie(url, []byte(data), c.getCookies())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to post to tts server")
|
return nil, errors.Wrap(err, "failed to post to tts server")
|
||||||
}
|
}
|
||||||
|
@ -32,27 +32,25 @@ func init() {
|
|||||||
|
|
||||||
var imgWaiter = utils.NewUploadWaiter()
|
var imgWaiter = utils.NewUploadWaiter()
|
||||||
|
|
||||||
type (
|
type imageUploadResponse struct {
|
||||||
imageUploadResponse struct {
|
UploadKey []byte
|
||||||
UploadKey []byte
|
UploadIp []uint32
|
||||||
UploadIp []uint32
|
UploadPort []uint32
|
||||||
UploadPort []uint32
|
ResourceId string
|
||||||
ResourceId string
|
Message string
|
||||||
Message string
|
FileId int64
|
||||||
FileId int64
|
Width int32
|
||||||
Width int32
|
Height int32
|
||||||
Height int32
|
ResultCode int32
|
||||||
ResultCode int32
|
IsExists bool
|
||||||
IsExists bool
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *QQClient) UploadGroupImage(groupCode int64, img io.ReadSeeker) (*message.GroupImageElement, error) {
|
func (c *QQClient) UploadGroupImage(groupCode int64, img io.ReadSeeker) (*message.GroupImageElement, error) {
|
||||||
_, _ = img.Seek(0, io.SeekStart) // safe
|
_, _ = img.Seek(0, io.SeekStart) // safe
|
||||||
fh, length := utils.ComputeMd5AndLength(img)
|
fh, length := utils.ComputeMd5AndLength(img)
|
||||||
_, _ = img.Seek(0, io.SeekStart)
|
_, _ = img.Seek(0, io.SeekStart)
|
||||||
|
|
||||||
key := hex.EncodeToString(fh)
|
key := string(fh)
|
||||||
imgWaiter.Wait(key)
|
imgWaiter.Wait(key)
|
||||||
defer imgWaiter.Done(key)
|
defer imgWaiter.Done(key)
|
||||||
|
|
||||||
|
@ -95,12 +95,13 @@ func decodeMultiApplyDownResponse(_ *QQClient, _ *incomingPacketInfo, payload []
|
|||||||
return nil, errors.New("not found")
|
return nil, errors.New("not found")
|
||||||
}
|
}
|
||||||
rsp := body.MultimsgApplydownRsp[0]
|
rsp := body.MultimsgApplydownRsp[0]
|
||||||
prefix := func() string {
|
|
||||||
if rsp.MsgExternInfo != nil && rsp.MsgExternInfo.ChannelType == 2 {
|
var prefix string
|
||||||
return "https://ssl.htdata.qq.com"
|
if rsp.MsgExternInfo != nil && rsp.MsgExternInfo.ChannelType == 2 {
|
||||||
}
|
prefix = "https://ssl.htdata.qq.com"
|
||||||
return fmt.Sprintf("http://%s:%d", binary.UInt32ToIPV4Address(uint32(rsp.Uint32DownIp[0])), body.MultimsgApplydownRsp[0].Uint32DownPort[0])
|
} else {
|
||||||
}()
|
prefix = fmt.Sprintf("http://%s:%d", binary.UInt32ToIPV4Address(uint32(rsp.Uint32DownIp[0])), body.MultimsgApplydownRsp[0].Uint32DownPort[0])
|
||||||
|
}
|
||||||
b, err := utils.HttpGetBytes(fmt.Sprintf("%s%s", prefix, string(rsp.ThumbDownPara)), "")
|
b, err := utils.HttpGetBytes(fmt.Sprintf("%s%s", prefix, string(rsp.ThumbDownPara)), "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to download by multi apply down")
|
return nil, errors.Wrap(err, "failed to download by multi apply down")
|
||||||
|
@ -75,7 +75,7 @@ func (c *QQClient) ConnectionQualityTest() *ConnectionQualityInfo {
|
|||||||
}()
|
}()
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
if _, err := utils.HttpGetBytes("https://ssl.htdata.qq.com", ""); err == nil {
|
if _, err := utils.HttpGetBytes("https://ssl.htdata.qq.com", ""); err == nil {
|
||||||
r.LongMessageServerResponseLatency = time.Now().Sub(start).Milliseconds()
|
r.LongMessageServerResponseLatency = time.Since(start).Milliseconds()
|
||||||
} else {
|
} else {
|
||||||
c.Error("test long message server response latency error: %v", err)
|
c.Error("test long message server response latency error: %v", err)
|
||||||
r.LongMessageServerResponseLatency = 9999
|
r.LongMessageServerResponseLatency = 9999
|
||||||
@ -335,12 +335,7 @@ func (c *QQClient) netLoop() {
|
|||||||
decoded, err = decoder(c, &incomingPacketInfo{
|
decoded, err = decoder(c, &incomingPacketInfo{
|
||||||
SequenceId: pkt.SequenceId,
|
SequenceId: pkt.SequenceId,
|
||||||
CommandName: pkt.CommandName,
|
CommandName: pkt.CommandName,
|
||||||
Params: func() requestParams {
|
Params: info.getParams(),
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return info.params
|
|
||||||
}(),
|
|
||||||
}, pkt.Payload)
|
}, pkt.Payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Debug("decode pkt %v error: %+v", pkt.CommandName, err)
|
c.Debug("decode pkt %v error: %+v", pkt.CommandName, err)
|
||||||
|
@ -131,6 +131,7 @@ func (s *TempSessionInfo) SendMessage(m *message.SendingMessage) (*message.TempM
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* this function is unused
|
||||||
func (c *QQClient) buildGetOneDayRoamMsgRequest(target, lastMsgTime, random int64, count uint32) (uint16, []byte) {
|
func (c *QQClient) buildGetOneDayRoamMsgRequest(target, lastMsgTime, random int64, count uint32) (uint16, []byte) {
|
||||||
seq := c.nextSeq()
|
seq := c.nextSeq()
|
||||||
req := &msg.PbGetOneDayRoamMsgReq{
|
req := &msg.PbGetOneDayRoamMsgReq{
|
||||||
@ -143,6 +144,7 @@ func (c *QQClient) buildGetOneDayRoamMsgRequest(target, lastMsgTime, random int6
|
|||||||
packet := packets.BuildUniPacket(c.Uin, seq, "MessageSvc.PbGetOneDayRoamMsg", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
|
packet := packets.BuildUniPacket(c.Uin, seq, "MessageSvc.PbGetOneDayRoamMsg", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
|
||||||
return seq, packet
|
return seq, packet
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// MessageSvc.PbSendMsg
|
// MessageSvc.PbSendMsg
|
||||||
func (c *QQClient) buildFriendSendingPacket(target int64, msgSeq, r, pkgNum, pkgIndex, pkgDiv int32, time int64, m []message.IMessageElement) (uint16, []byte) {
|
func (c *QQClient) buildFriendSendingPacket(target int64, msgSeq, r, pkgNum, pkgIndex, pkgDiv int32, time int64, m []message.IMessageElement) (uint16, []byte) {
|
||||||
|
@ -35,7 +35,7 @@ func (c *QQClient) UploadGroupPtt(groupCode int64, voice io.ReadSeeker) (*messag
|
|||||||
pttWaiter.Wait(key)
|
pttWaiter.Wait(key)
|
||||||
defer pttWaiter.Done(key)
|
defer pttWaiter.Done(key)
|
||||||
|
|
||||||
ext := c.buildGroupPttStoreBDHExt(groupCode, fh[:], int32(length), 0, int32(length))
|
ext := c.buildGroupPttStoreBDHExt(groupCode, fh, int32(length), 0, int32(length))
|
||||||
rsp, err := c.highwaySession.UploadBDH(highway.BdhInput{
|
rsp, err := c.highwaySession.UploadBDH(highway.BdhInput{
|
||||||
CommandID: 29,
|
CommandID: 29,
|
||||||
Body: voice,
|
Body: voice,
|
||||||
@ -60,8 +60,8 @@ func (c *QQClient) UploadGroupPtt(groupCode int64, voice io.ReadSeeker) (*messag
|
|||||||
Ptt: &msg.Ptt{
|
Ptt: &msg.Ptt{
|
||||||
FileType: proto.Int32(4),
|
FileType: proto.Int32(4),
|
||||||
SrcUin: &c.Uin,
|
SrcUin: &c.Uin,
|
||||||
FileMd5: fh[:],
|
FileMd5: fh,
|
||||||
FileName: proto.String(hex.EncodeToString(fh[:]) + ".amr"),
|
FileName: proto.String(hex.EncodeToString(fh) + ".amr"),
|
||||||
FileSize: proto.Int32(int32(length)),
|
FileSize: proto.Int32(int32(length)),
|
||||||
GroupFileKey: pkt.TryupPttRsp[0].FileKey,
|
GroupFileKey: pkt.TryupPttRsp[0].FileKey,
|
||||||
BoolValid: proto.Bool(true),
|
BoolValid: proto.Bool(true),
|
||||||
@ -81,7 +81,7 @@ func (c *QQClient) UploadPrivatePtt(target int64, voice io.ReadSeeker) (*message
|
|||||||
pttWaiter.Wait(key)
|
pttWaiter.Wait(key)
|
||||||
defer pttWaiter.Done(key)
|
defer pttWaiter.Done(key)
|
||||||
|
|
||||||
ext := c.buildC2CPttStoreBDHExt(target, fh[:], int32(length), int32(length))
|
ext := c.buildC2CPttStoreBDHExt(target, fh, int32(length), int32(length))
|
||||||
rsp, err := c.highwaySession.UploadBDH(highway.BdhInput{
|
rsp, err := c.highwaySession.UploadBDH(highway.BdhInput{
|
||||||
CommandID: 26,
|
CommandID: 26,
|
||||||
Body: voice,
|
Body: voice,
|
||||||
@ -107,8 +107,8 @@ func (c *QQClient) UploadPrivatePtt(target int64, voice io.ReadSeeker) (*message
|
|||||||
FileType: proto.Int32(4),
|
FileType: proto.Int32(4),
|
||||||
SrcUin: &c.Uin,
|
SrcUin: &c.Uin,
|
||||||
FileUuid: pkt.ApplyUploadRsp.Uuid,
|
FileUuid: pkt.ApplyUploadRsp.Uuid,
|
||||||
FileMd5: fh[:],
|
FileMd5: fh,
|
||||||
FileName: proto.String(hex.EncodeToString(fh[:]) + ".amr"),
|
FileName: proto.String(hex.EncodeToString(fh) + ".amr"),
|
||||||
FileSize: proto.Int32(int32(length)),
|
FileSize: proto.Int32(int32(length)),
|
||||||
// Reserve: constructPTTExtraInfo(1, int32(len(voice))), // todo length
|
// Reserve: constructPTTExtraInfo(1, int32(len(voice))), // todo length
|
||||||
BoolValid: proto.Bool(true),
|
BoolValid: proto.Bool(true),
|
||||||
|
@ -101,15 +101,14 @@ func (c *QQClient) SendGuildMusicShare(guildID, channelID uint64, msg *message.M
|
|||||||
func (c *QQClient) buildRichMsgSendingPacket(guild uint64, target int64, msg *message.MusicShareElement, sendType uint32) (uint16, []byte) {
|
func (c *QQClient) buildRichMsgSendingPacket(guild uint64, target int64, msg *message.MusicShareElement, sendType uint32) (uint16, []byte) {
|
||||||
seq := c.nextSeq()
|
seq := c.nextSeq()
|
||||||
tp := musicType[msg.MusicType] // MusicType
|
tp := musicType[msg.MusicType] // MusicType
|
||||||
|
msgStyle := uint32(0)
|
||||||
|
if msg.MusicUrl != "" {
|
||||||
|
msgStyle = 4
|
||||||
|
}
|
||||||
body := &oidb.DB77ReqBody{
|
body := &oidb.DB77ReqBody{
|
||||||
AppId: tp.appID,
|
AppId: tp.appID,
|
||||||
AppType: tp.appType,
|
AppType: tp.appType,
|
||||||
MsgStyle: func() uint32 {
|
MsgStyle: msgStyle,
|
||||||
if msg.MusicUrl == "" {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return 4
|
|
||||||
}(),
|
|
||||||
ClientInfo: &oidb.DB77ClientInfo{
|
ClientInfo: &oidb.DB77ClientInfo{
|
||||||
Platform: tp.platform,
|
Platform: tp.platform,
|
||||||
SdkVersion: tp.sdkVersion,
|
SdkVersion: tp.sdkVersion,
|
||||||
|
303
client/stash.go
303
client/stash.go
@ -1,303 +0,0 @@
|
|||||||
// UNCHECKED
|
|
||||||
|
|
||||||
package client
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
|
||||||
"io"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Stash will store the data for the client, this will speed up booting
|
|
||||||
// the QQ client but some data may not sync with the server. So it is
|
|
||||||
// recommended to use this in development mode only.
|
|
||||||
|
|
||||||
//go:generate stringer -type=syncMarker -trimprefix=syncMarker
|
|
||||||
type syncMarker int8
|
|
||||||
|
|
||||||
const (
|
|
||||||
syncMarkerNone syncMarker = iota
|
|
||||||
syncMarkerFriendList
|
|
||||||
syncMarkerFriendInfo
|
|
||||||
syncMarkerGroupList
|
|
||||||
syncMarkerGroupInfo
|
|
||||||
syncMarkerGroupMemberList
|
|
||||||
syncMarkerGroupMemberInfo
|
|
||||||
)
|
|
||||||
|
|
||||||
type StashSyncMarkerError struct {
|
|
||||||
marker syncMarker
|
|
||||||
expected syncMarker
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *StashSyncMarkerError) Error() string {
|
|
||||||
return "stash sync marker error: expected " + e.expected.String() + ", got " + e.marker.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteStash will write the stash to the given writer.
|
|
||||||
func WriteStash(client *QQClient, writer io.Writer) {
|
|
||||||
var out intWriter
|
|
||||||
w := stashWriter{
|
|
||||||
stringIndex: make(map[string]uint64),
|
|
||||||
}
|
|
||||||
|
|
||||||
w.friendList(client.FriendList)
|
|
||||||
w.groupList(client.GroupList)
|
|
||||||
|
|
||||||
out.uvarint(uint64(w.strings.Len()))
|
|
||||||
out.uvarint(uint64(w.data.Len()))
|
|
||||||
_, _ = io.Copy(&out, &w.strings)
|
|
||||||
_, _ = io.Copy(&out, &w.data)
|
|
||||||
_, _ = io.Copy(writer, &out)
|
|
||||||
}
|
|
||||||
|
|
||||||
type stashWriter struct {
|
|
||||||
data intWriter
|
|
||||||
strings intWriter
|
|
||||||
stringIndex map[string]uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *stashWriter) string(s string) {
|
|
||||||
off, ok := w.stringIndex[s]
|
|
||||||
if !ok {
|
|
||||||
off = uint64(w.strings.Len())
|
|
||||||
w.strings.uvarint(uint64(len(s)))
|
|
||||||
_, _ = w.strings.WriteString(s)
|
|
||||||
w.stringIndex[s] = off
|
|
||||||
}
|
|
||||||
w.uvarint(off)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *stashWriter) sync(marker syncMarker) { w.data.uvarint(uint64(marker)) }
|
|
||||||
func (w *stashWriter) uvarint(v uint64) { w.data.uvarint(v) }
|
|
||||||
func (w *stashWriter) svarint(v int64) { w.data.svarint(v) }
|
|
||||||
|
|
||||||
func (w *stashWriter) int64(v int64) {
|
|
||||||
var buf [8]byte
|
|
||||||
binary.LittleEndian.PutUint64(buf[:], uint64(v))
|
|
||||||
_, _ = w.data.Write(buf[:])
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *stashWriter) friendList(list []*FriendInfo) {
|
|
||||||
w.sync(syncMarkerFriendList)
|
|
||||||
w.uvarint(uint64(len(list)))
|
|
||||||
for _, friend := range list {
|
|
||||||
w.sync(syncMarkerFriendInfo)
|
|
||||||
w.int64(friend.Uin)
|
|
||||||
w.string(friend.Nickname)
|
|
||||||
w.string(friend.Remark)
|
|
||||||
w.svarint(int64(friend.FaceId))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *stashWriter) groupList(list []*GroupInfo) {
|
|
||||||
w.sync(syncMarkerGroupList)
|
|
||||||
w.uvarint(uint64(len(list)))
|
|
||||||
for _, group := range list {
|
|
||||||
w.sync(syncMarkerGroupInfo)
|
|
||||||
w.int64(group.Uin)
|
|
||||||
w.int64(group.Code)
|
|
||||||
w.string(group.Name)
|
|
||||||
w.string(group.Memo)
|
|
||||||
w.int64(group.OwnerUin)
|
|
||||||
w.uvarint(uint64(group.GroupCreateTime))
|
|
||||||
w.uvarint(uint64(group.MemberCount))
|
|
||||||
w.uvarint(uint64(group.MaxMemberCount))
|
|
||||||
w.svarint(group.LastMsgSeq)
|
|
||||||
|
|
||||||
w.groupMemberList(group.Members)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *stashWriter) groupMemberList(list []*GroupMemberInfo) {
|
|
||||||
w.sync(syncMarkerGroupMemberList)
|
|
||||||
w.uvarint(uint64(len(list)))
|
|
||||||
for _, member := range list {
|
|
||||||
w.sync(syncMarkerGroupMemberInfo)
|
|
||||||
w.int64(member.Uin)
|
|
||||||
w.uvarint(uint64(member.Gender))
|
|
||||||
w.string(member.Nickname)
|
|
||||||
w.string(member.CardName)
|
|
||||||
w.uvarint(uint64(member.Level))
|
|
||||||
w.int64(member.JoinTime)
|
|
||||||
w.int64(member.LastSpeakTime)
|
|
||||||
w.string(member.SpecialTitle)
|
|
||||||
w.svarint(member.SpecialTitleExpireTime)
|
|
||||||
w.svarint(member.ShutUpTimestamp)
|
|
||||||
w.uvarint(uint64(member.Permission))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type intWriter struct {
|
|
||||||
bytes.Buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *intWriter) svarint(x int64) {
|
|
||||||
w.uvarint(uint64(x)<<1 ^ uint64(x>>63))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *intWriter) uvarint(x uint64) {
|
|
||||||
var buf [binary.MaxVarintLen64]byte
|
|
||||||
n := binary.PutUvarint(buf[:], x)
|
|
||||||
_, _ = w.Write(buf[:n])
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadStash will read the stash from the given reader and apply to the given QQClient.
|
|
||||||
func ReadStash(client *QQClient, data string) (err error) {
|
|
||||||
in := newIntReader(data)
|
|
||||||
sl := int64(in.uvarint())
|
|
||||||
dl := int64(in.uvarint())
|
|
||||||
whence, err := in.Seek(0, io.SeekCurrent)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
sData := data[whence : whence+sl]
|
|
||||||
dData := data[whence+sl : whence+sl+dl]
|
|
||||||
|
|
||||||
r := stashReader{
|
|
||||||
data: newIntReader(dData),
|
|
||||||
strings: newIntReader(sData),
|
|
||||||
stringIndex: make(map[uint64]string),
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
if e, ok := r.(error); ok {
|
|
||||||
err = e
|
|
||||||
return
|
|
||||||
}
|
|
||||||
panic(r)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
client.FriendList = r.friendList()
|
|
||||||
client.GroupList = r.groupList(client)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type stashReader struct {
|
|
||||||
data intReader
|
|
||||||
strings intReader
|
|
||||||
stringIndex map[uint64]string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *stashReader) string() string {
|
|
||||||
off := r.data.uvarint()
|
|
||||||
if off == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
if s, ok := r.stringIndex[off]; ok {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
_, _ = r.strings.Seek(int64(off), io.SeekStart)
|
|
||||||
l := int64(r.strings.uvarint())
|
|
||||||
whence, _ := r.strings.Seek(0, io.SeekCurrent)
|
|
||||||
s := r.strings.data[whence : whence+l]
|
|
||||||
r.stringIndex[off] = s
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *stashReader) sync(marker syncMarker) {
|
|
||||||
got := syncMarker(r.data.uvarint())
|
|
||||||
if got != marker {
|
|
||||||
panic(&StashSyncMarkerError{
|
|
||||||
marker: got,
|
|
||||||
expected: marker,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *stashReader) friendList() []*FriendInfo {
|
|
||||||
r.sync(syncMarkerFriendList)
|
|
||||||
l := r.uvarint()
|
|
||||||
list := make([]*FriendInfo, l)
|
|
||||||
for i := uint64(0); i < l; i++ {
|
|
||||||
r.sync(syncMarkerFriendInfo)
|
|
||||||
list[i] = &FriendInfo{
|
|
||||||
Uin: r.int64(),
|
|
||||||
Nickname: r.string(),
|
|
||||||
Remark: r.string(),
|
|
||||||
FaceId: int16(r.svarint()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *stashReader) groupList(client *QQClient) []*GroupInfo {
|
|
||||||
r.sync(syncMarkerGroupList)
|
|
||||||
l := r.uvarint()
|
|
||||||
list := make([]*GroupInfo, l)
|
|
||||||
for i := uint64(0); i < l; i++ {
|
|
||||||
r.sync(syncMarkerGroupInfo)
|
|
||||||
list[i] = &GroupInfo{
|
|
||||||
Uin: r.int64(),
|
|
||||||
Code: r.int64(),
|
|
||||||
Name: r.string(),
|
|
||||||
Memo: r.string(),
|
|
||||||
OwnerUin: r.int64(),
|
|
||||||
GroupCreateTime: uint32(r.uvarint()),
|
|
||||||
GroupLevel: uint32(r.uvarint()),
|
|
||||||
MemberCount: uint16(r.uvarint()),
|
|
||||||
MaxMemberCount: uint16(r.uvarint()),
|
|
||||||
client: client,
|
|
||||||
}
|
|
||||||
list[i].Members = r.groupMemberList(list[i])
|
|
||||||
list[i].LastMsgSeq = r.svarint()
|
|
||||||
}
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *stashReader) groupMemberList(group *GroupInfo) []*GroupMemberInfo {
|
|
||||||
r.sync(syncMarkerGroupMemberList)
|
|
||||||
l := r.uvarint()
|
|
||||||
list := make([]*GroupMemberInfo, l)
|
|
||||||
for i := uint64(0); i < l; i++ {
|
|
||||||
r.sync(syncMarkerGroupMemberInfo)
|
|
||||||
list[i] = &GroupMemberInfo{
|
|
||||||
Group: group,
|
|
||||||
Uin: r.int64(),
|
|
||||||
Gender: byte(r.uvarint()),
|
|
||||||
Nickname: r.string(),
|
|
||||||
CardName: r.string(),
|
|
||||||
Level: uint16(r.uvarint()),
|
|
||||||
JoinTime: r.int64(),
|
|
||||||
LastSpeakTime: r.int64(),
|
|
||||||
SpecialTitle: r.string(),
|
|
||||||
SpecialTitleExpireTime: r.svarint(),
|
|
||||||
ShutUpTimestamp: r.svarint(),
|
|
||||||
Permission: MemberPermission(r.uvarint()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *stashReader) uvarint() uint64 { return r.data.uvarint() }
|
|
||||||
func (r *stashReader) svarint() int64 { return r.data.svarint() }
|
|
||||||
|
|
||||||
func (r *stashReader) int64() int64 {
|
|
||||||
var buf [8]byte
|
|
||||||
_, _ = r.data.Read(buf[:])
|
|
||||||
return int64(binary.LittleEndian.Uint64(buf[:]))
|
|
||||||
}
|
|
||||||
|
|
||||||
type intReader struct {
|
|
||||||
data string
|
|
||||||
*strings.Reader
|
|
||||||
}
|
|
||||||
|
|
||||||
func newIntReader(s string) intReader {
|
|
||||||
return intReader{
|
|
||||||
data: s,
|
|
||||||
Reader: strings.NewReader(s),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *intReader) svarint() int64 {
|
|
||||||
i, _ := binary.ReadVarint(r)
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *intReader) uvarint() uint64 {
|
|
||||||
i, _ := binary.ReadUvarint(r)
|
|
||||||
return i
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
// Code generated by "stringer -type=syncMarker -trimprefix=syncMarker"; DO NOT EDIT.
|
|
||||||
|
|
||||||
package client
|
|
||||||
|
|
||||||
import "strconv"
|
|
||||||
|
|
||||||
func _() {
|
|
||||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
|
||||||
// Re-run the stringer command to generate them again.
|
|
||||||
var x [1]struct{}
|
|
||||||
_ = x[syncMarkerNone-0]
|
|
||||||
_ = x[syncMarkerFriendList-1]
|
|
||||||
_ = x[syncMarkerFriendInfo-2]
|
|
||||||
_ = x[syncMarkerGroupList-3]
|
|
||||||
_ = x[syncMarkerGroupInfo-4]
|
|
||||||
_ = x[syncMarkerGroupMemberList-5]
|
|
||||||
_ = x[syncMarkerGroupMemberInfo-6]
|
|
||||||
}
|
|
||||||
|
|
||||||
const _syncMarker_name = "NoneFriendListFriendInfoGroupListGroupInfoGroupMemberListGroupMemberInfo"
|
|
||||||
|
|
||||||
var _syncMarker_index = [...]uint8{0, 4, 14, 24, 33, 42, 57, 72}
|
|
||||||
|
|
||||||
func (i syncMarker) String() string {
|
|
||||||
if i < 0 || i >= syncMarker(len(_syncMarker_index)-1) {
|
|
||||||
return "syncMarker(" + strconv.FormatInt(int64(i), 10) + ")"
|
|
||||||
}
|
|
||||||
return _syncMarker_name[_syncMarker_index[i]:_syncMarker_index[i+1]]
|
|
||||||
}
|
|
@ -138,31 +138,26 @@ func (c *QQClient) buildSystemMsgNewGroupPacket(suspicious bool) (uint16, []byte
|
|||||||
// ProfileService.Pb.ReqSystemMsgAction.Group
|
// ProfileService.Pb.ReqSystemMsgAction.Group
|
||||||
func (c *QQClient) buildSystemMsgGroupActionPacket(reqID, requester, group int64, msgType int32, isInvite, accept, block bool, reason string) (uint16, []byte) {
|
func (c *QQClient) buildSystemMsgGroupActionPacket(reqID, requester, group int64, msgType int32, isInvite, accept, block bool, reason string) (uint16, []byte) {
|
||||||
seq := c.nextSeq()
|
seq := c.nextSeq()
|
||||||
|
subSrcId := int32(31)
|
||||||
|
groupMsgType := int32(1)
|
||||||
|
if isInvite {
|
||||||
|
subSrcId = 10016
|
||||||
|
groupMsgType = 2
|
||||||
|
}
|
||||||
|
infoType := int32(12)
|
||||||
|
if accept {
|
||||||
|
infoType = 11
|
||||||
|
}
|
||||||
req := &structmsg.ReqSystemMsgAction{
|
req := &structmsg.ReqSystemMsgAction{
|
||||||
MsgType: msgType,
|
MsgType: msgType,
|
||||||
MsgSeq: reqID,
|
MsgSeq: reqID,
|
||||||
ReqUin: requester,
|
ReqUin: requester,
|
||||||
SubType: 1,
|
SubType: 1,
|
||||||
SrcId: 3,
|
SrcId: 3,
|
||||||
SubSrcId: func() int32 {
|
SubSrcId: subSrcId,
|
||||||
if isInvite {
|
GroupMsgType: groupMsgType,
|
||||||
return 10016
|
|
||||||
}
|
|
||||||
return 31
|
|
||||||
}(),
|
|
||||||
GroupMsgType: func() int32 {
|
|
||||||
if isInvite {
|
|
||||||
return 2
|
|
||||||
}
|
|
||||||
return 1
|
|
||||||
}(),
|
|
||||||
ActionInfo: &structmsg.SystemMsgActionInfo{
|
ActionInfo: &structmsg.SystemMsgActionInfo{
|
||||||
Type: func() int32 {
|
Type: infoType,
|
||||||
if accept {
|
|
||||||
return 11
|
|
||||||
}
|
|
||||||
return 12
|
|
||||||
}(),
|
|
||||||
GroupCode: group,
|
GroupCode: group,
|
||||||
Blacklist: block,
|
Blacklist: block,
|
||||||
Msg: reason,
|
Msg: reason,
|
||||||
@ -178,6 +173,10 @@ func (c *QQClient) buildSystemMsgGroupActionPacket(reqID, requester, group int64
|
|||||||
// ProfileService.Pb.ReqSystemMsgAction.Friend
|
// ProfileService.Pb.ReqSystemMsgAction.Friend
|
||||||
func (c *QQClient) buildSystemMsgFriendActionPacket(reqID, requester int64, accept bool) (uint16, []byte) {
|
func (c *QQClient) buildSystemMsgFriendActionPacket(reqID, requester int64, accept bool) (uint16, []byte) {
|
||||||
seq := c.nextSeq()
|
seq := c.nextSeq()
|
||||||
|
infoType := int32(3)
|
||||||
|
if accept {
|
||||||
|
infoType = 2
|
||||||
|
}
|
||||||
req := &structmsg.ReqSystemMsgAction{
|
req := &structmsg.ReqSystemMsgAction{
|
||||||
MsgType: 1,
|
MsgType: 1,
|
||||||
MsgSeq: reqID,
|
MsgSeq: reqID,
|
||||||
@ -186,12 +185,7 @@ func (c *QQClient) buildSystemMsgFriendActionPacket(reqID, requester int64, acce
|
|||||||
SrcId: 6,
|
SrcId: 6,
|
||||||
SubSrcId: 7,
|
SubSrcId: 7,
|
||||||
ActionInfo: &structmsg.SystemMsgActionInfo{
|
ActionInfo: &structmsg.SystemMsgActionInfo{
|
||||||
Type: func() int32 {
|
Type: infoType,
|
||||||
if accept {
|
|
||||||
return 2
|
|
||||||
}
|
|
||||||
return 3
|
|
||||||
}(),
|
|
||||||
Blacklist: false,
|
Blacklist: false,
|
||||||
AddFrdSNInfo: &structmsg.AddFrdSNInfo{},
|
AddFrdSNInfo: &structmsg.AddFrdSNInfo{},
|
||||||
},
|
},
|
||||||
|
@ -205,12 +205,12 @@ func NewUrlShare(url, title, content, image string) *ServiceElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRichXml(template string, ResId int64) *ServiceElement {
|
func NewRichXml(template string, resID int64) *ServiceElement {
|
||||||
if ResId == 0 {
|
if resID == 0 {
|
||||||
ResId = 60 // 默认值60
|
resID = 60 // 默认值60
|
||||||
}
|
}
|
||||||
return &ServiceElement{
|
return &ServiceElement{
|
||||||
Id: int32(ResId),
|
Id: int32(resID),
|
||||||
Content: template,
|
Content: template,
|
||||||
SubType: "xml",
|
SubType: "xml",
|
||||||
}
|
}
|
||||||
|
@ -138,8 +138,7 @@ func (e *GroupImageElement) Pack() (r []*msg.Elem) {
|
|||||||
return []*msg.Elem{elem}
|
return []*msg.Elem{elem}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *FriendImageElement) Pack() (r []*msg.Elem) {
|
func (e *FriendImageElement) Pack() []*msg.Elem {
|
||||||
r = []*msg.Elem{}
|
|
||||||
image := &msg.NotOnlineImage{
|
image := &msg.NotOnlineImage{
|
||||||
FilePath: &e.ImageId,
|
FilePath: &e.ImageId,
|
||||||
ResId: &e.ImageId,
|
ResId: &e.ImageId,
|
||||||
|
@ -298,20 +298,17 @@ func ToProtoElems(elems []IMessageElement, generalFlags bool) (r []*msg.Elem) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func ToSrcProtoElems(elems []IMessageElement) (r []*msg.Elem) {
|
var photoTextElem IMessageElement = NewText("[图片]")
|
||||||
for _, elem := range elems {
|
|
||||||
switch elem.Type() {
|
func ToSrcProtoElems(elems []IMessageElement) []*msg.Elem {
|
||||||
case Image:
|
elems2 := make([]IMessageElement, len(elems))
|
||||||
r = append(r, &msg.Elem{
|
copy(elems2, elems)
|
||||||
Text: &msg.Text{
|
for i, elem := range elems2 {
|
||||||
Str: proto.String("[图片]"),
|
if elem.Type() == Image {
|
||||||
},
|
elems2[i] = photoTextElem
|
||||||
})
|
|
||||||
default:
|
|
||||||
r = append(r, ToProtoElems([]IMessageElement{elem}, false)...)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return ToProtoElems(elems2, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseMessageElems(elems []*msg.Elem) []IMessageElement {
|
func ParseMessageElems(elems []*msg.Elem) []IMessageElement {
|
||||||
@ -431,11 +428,9 @@ func ParseMessageElems(elems []*msg.Elem) []IMessageElement {
|
|||||||
if isOk := strings.Contains(content, "<?xml"); isOk {
|
if isOk := strings.Contains(content, "<?xml"); isOk {
|
||||||
res = append(res, NewRichXml(content, int64(elem.RichMsg.GetServiceId())))
|
res = append(res, NewRichXml(content, int64(elem.RichMsg.GetServiceId())))
|
||||||
continue
|
continue
|
||||||
} else {
|
} else if json.Valid(utils.S2B(content)) {
|
||||||
if json.Valid(utils.S2B(content)) {
|
res = append(res, NewRichJson(content))
|
||||||
res = append(res, NewRichJson(content))
|
continue
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
res = append(res, NewText(content))
|
res = append(res, NewText(content))
|
||||||
}
|
}
|
||||||
@ -444,12 +439,12 @@ func ParseMessageElems(elems []*msg.Elem) []IMessageElement {
|
|||||||
if len(elem.CustomFace.Md5) == 0 {
|
if len(elem.CustomFace.Md5) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
url := func() string {
|
var url string
|
||||||
if elem.CustomFace.GetOrigUrl() == "" {
|
if elem.CustomFace.GetOrigUrl() == "" {
|
||||||
return "https://gchat.qpic.cn/gchatpic_new/0/0-0-" + strings.ReplaceAll(binary.CalculateImageResourceId(elem.CustomFace.Md5)[1:37], "-", "") + "/0?term=2"
|
url = "https://gchat.qpic.cn/gchatpic_new/0/0-0-" + strings.ReplaceAll(binary.CalculateImageResourceId(elem.CustomFace.Md5)[1:37], "-", "") + "/0?term=2"
|
||||||
}
|
} else {
|
||||||
return "https://gchat.qpic.cn" + elem.CustomFace.GetOrigUrl()
|
url = "https://gchat.qpic.cn" + elem.CustomFace.GetOrigUrl()
|
||||||
}()
|
}
|
||||||
if strings.Contains(elem.CustomFace.GetOrigUrl(), "qmeet") {
|
if strings.Contains(elem.CustomFace.GetOrigUrl(), "qmeet") {
|
||||||
res = append(res, &GuildImageElement{
|
res = append(res, &GuildImageElement{
|
||||||
FileId: int64(elem.CustomFace.GetFileId()),
|
FileId: int64(elem.CustomFace.GetFileId()),
|
||||||
|
@ -68,6 +68,6 @@ func SendICMPRequest(addr *net.IPAddr, seq int) (int64, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, errors.Wrap(err, "read icmp conn error")
|
return 0, errors.Wrap(err, "read icmp conn error")
|
||||||
}
|
}
|
||||||
duration := time.Now().Sub(start).Milliseconds()
|
duration := time.Since(start).Milliseconds()
|
||||||
return duration, nil
|
return duration, nil
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ func RandomString(len int) string {
|
|||||||
|
|
||||||
func RandomStringRange(length int, str string) string {
|
func RandomStringRange(length int, str string) string {
|
||||||
sb := strings.Builder{}
|
sb := strings.Builder{}
|
||||||
|
sb.Grow(length)
|
||||||
for i := 0; i < length; i++ {
|
for i := 0; i < length; i++ {
|
||||||
sb.WriteByte(str[rand.Intn(len(str))])
|
sb.WriteByte(str[rand.Intn(len(str))])
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user