package client import ( "strings" "sync" "github.com/Mrs4s/MiraiGo/binary/jce" "github.com/Mrs4s/MiraiGo/message" "github.com/pkg/errors" ) var ( ErrAlreadyOnline = errors.New("already online") ErrMemberNotFound = errors.New("member not found") ErrNotExists = errors.New("not exists") ) type ( LoginError int MemberPermission int ClientProtocol int LoginResponse struct { Success bool Error LoginError // Captcha info CaptchaImage []byte CaptchaSign []byte // Unsafe device VerifyUrl string // SMS needed SMSPhone string // other error ErrorMessage string } FriendInfo struct { Uin int64 Nickname string Remark string FaceId int16 //msgSeqList *utils.Cache } SummaryCardInfo struct { Uin int64 Sex byte Age uint8 Nickname string Level int32 City string Sign string Mobile string LoginDays int64 } FriendListResponse struct { TotalCount int32 List []*FriendInfo } GroupInfo struct { Uin int64 Code int64 Name string Memo string OwnerUin int64 MemberCount uint16 MaxMemberCount uint16 Members []*GroupMemberInfo client *QQClient lastMsgSeq int64 lock sync.RWMutex } GroupMemberInfo struct { Group *GroupInfo Uin int64 Gender byte Nickname string CardName string Level uint16 JoinTime int64 LastSpeakTime int64 SpecialTitle string SpecialTitleExpireTime int64 Permission MemberPermission } GroupMuteEvent struct { GroupCode int64 OperatorUin int64 TargetUin int64 Time int32 } GroupMessageRecalledEvent struct { GroupCode int64 OperatorUin int64 AuthorUin int64 MessageId int32 Time int32 } FriendMessageRecalledEvent struct { FriendUin int64 MessageId int32 Time int64 } GroupLeaveEvent struct { Group *GroupInfo Operator *GroupMemberInfo } MemberJoinGroupEvent struct { Group *GroupInfo Member *GroupMemberInfo } MemberCardUpdatedEvent struct { Group *GroupInfo OldCard string Member *GroupMemberInfo } INotifyEvent interface { From() int64 Content() string } MemberLeaveGroupEvent struct { Group *GroupInfo Member *GroupMemberInfo Operator *GroupMemberInfo } MemberPermissionChangedEvent struct { Group *GroupInfo Member *GroupMemberInfo OldPermission MemberPermission NewPermission MemberPermission } ClientDisconnectedEvent struct { Message string } NewFriendRequest struct { RequestId int64 Message string RequesterUin int64 RequesterNick string client *QQClient } LogEvent struct { Type string Message string } ServerUpdatedEvent struct { Servers []jce.SsoServerInfo } NewFriendEvent struct { Friend *FriendInfo } OfflineFileEvent struct { FileName string FileSize int64 Sender int64 DownloadUrl string } OcrResponse struct { Texts []*TextDetection `json:"texts"` Language string `json:"language"` } TextDetection struct { Text string `json:"text"` Confidence int32 `json:"confidence"` Coordinates []*Coordinate `json:"coordinates"` } Coordinate struct { X int32 `json:"x"` Y int32 `json:"y"` } AtAllRemainInfo struct { CanAtAll bool `json:"can_at_all"` RemainAtAllCountForGroup uint32 `json:"remain_at_all_count_for_group"` RemainAtAllCountForUin uint32 `json:"remain_at_all_count_for_uin"` } groupMemberListResponse struct { NextUin int64 list []*GroupMemberInfo } imageUploadResponse struct { UploadKey []byte UploadIp []int32 UploadPort []int32 ResourceId string Message string FileId int64 Width int32 Height int32 ResultCode int32 IsExists bool } pttUploadResponse struct { ResultCode int32 Message string IsExists bool ResourceId string UploadKey []byte UploadIp []string UploadPort []int32 FileKey []byte FileId int64 } groupMessageReceiptEvent struct { Rand int32 Seq int32 Msg *message.GroupMessage } ) const ( NeedCaptcha LoginError = 1 OtherLoginError LoginError = 3 UnsafeDeviceError LoginError = 4 SMSNeededError LoginError = 5 TooManySMSRequestError LoginError = 6 SMSOrVerifyNeededError LoginError = 7 SliderNeededError LoginError = 8 UnknownLoginError LoginError = -1 Owner MemberPermission = iota Administrator Member AndroidPhone ClientProtocol = 1 IPad ClientProtocol = 2 AndroidWatch ClientProtocol = 3 MacOS ClientProtocol = 4 ) func (g *GroupInfo) UpdateName(newName string) { if g.AdministratorOrOwner() && newName != "" && strings.Count(newName, "") <= 20 { g.client.updateGroupName(g.Code, newName) g.Name = newName } } func (g *GroupInfo) UpdateMemo(newMemo string) { if g.AdministratorOrOwner() { g.client.updateGroupMemo(g.Code, newMemo) g.Memo = newMemo } } func (g *GroupInfo) UpdateGroupHeadPortrait(img []byte) { if g.AdministratorOrOwner() { _ = g.client.uploadGroupHeadPortrait(g.Uin, img) } } func (g *GroupInfo) MuteAll(mute bool) { if g.AdministratorOrOwner() { g.client.groupMuteAll(g.Code, mute) } } func (g *GroupInfo) Quit() { if g.SelfPermission() != Owner { g.client.quitGroup(g.Code) } } func (g *GroupInfo) SelfPermission() MemberPermission { return g.FindMember(g.client.Uin).Permission } func (g *GroupInfo) AdministratorOrOwner() bool { return g.SelfPermission() == Administrator || g.SelfPermission() == Owner } func (g *GroupInfo) FindMember(uin int64) *GroupMemberInfo { r := g.Read(func(info *GroupInfo) interface{} { return info.FindMemberWithoutLock(uin) }) if r == nil { return nil } return r.(*GroupMemberInfo) } func (g *GroupInfo) FindMemberWithoutLock(uin int64) *GroupMemberInfo { for _, m := range g.Members { f := m if f.Uin == uin { return f } } return nil } func (g *GroupInfo) Update(f func(*GroupInfo)) { g.lock.Lock() defer g.lock.Unlock() f(g) } func (g *GroupInfo) Read(f func(*GroupInfo) interface{}) interface{} { g.lock.RLock() defer g.lock.RUnlock() return f(g) } func (m *GroupMemberInfo) DisplayName() string { if m.CardName == "" { return m.Nickname } return m.CardName } func (m *GroupMemberInfo) EditCard(card string) { if m.CardChangable() && len(card) <= 60 { m.Group.client.editMemberCard(m.Group.Code, m.Uin, card) m.CardName = card } } func (m *GroupMemberInfo) Poke() { m.Group.client.sendGroupPoke(m.Group.Code, m.Uin) } func (m *GroupMemberInfo) SetAdmin(flag bool) { if m.Group.OwnerUin == m.Group.client.Uin { m.Group.client.setGroupAdmin(m.Group.Code, m.Uin, flag) } } func (m *GroupMemberInfo) EditSpecialTitle(title string) { if m.Group.SelfPermission() == Owner && len(title) <= 18 { m.Group.client.editMemberSpecialTitle(m.Group.Code, m.Uin, title) m.SpecialTitle = title } } func (m *GroupMemberInfo) Kick(msg string, block bool) { if m.Uin != m.Group.client.Uin && m.Manageable() { m.Group.client.kickGroupMember(m.Group.Code, m.Uin, msg, block) } } func (m *GroupMemberInfo) Mute(time uint32) { if m.Uin != m.Group.client.Uin && m.Manageable() { if time < 2592000 { m.Group.client.groupMute(m.Group.Code, m.Uin, time) } } } func (m *GroupMemberInfo) Manageable() bool { if m.Uin == m.Group.client.Uin { return true } self := m.Group.SelfPermission() if self == Member || m.Permission == Owner { return false } return m.Permission != Administrator || self == Owner } func (m *GroupMemberInfo) CardChangable() bool { if m.Uin == m.Group.client.Uin { return true } self := m.Group.SelfPermission() if self == Member { return false } return m.Permission != Owner } func (r *UserJoinGroupRequest) Accept() { r.client.SolveGroupJoinRequest(r, true, false, "") } func (r *UserJoinGroupRequest) Reject(block bool, reason string) { r.client.SolveGroupJoinRequest(r, false, block, reason) } func (r *GroupInvitedRequest) Accept() { r.client.SolveGroupJoinRequest(r, true, false, "") } func (r *GroupInvitedRequest) Reject(block bool, reason string) { r.client.SolveGroupJoinRequest(r, false, block, reason) } func (r *NewFriendRequest) Accept() { r.client.SolveFriendRequest(r, true) } func (r *NewFriendRequest) Reject() { r.client.SolveFriendRequest(r, false) }