github.com/Mrs4s/MiraiGo@v0.0.0-20240226124653-54bdd873e3fe/client/private_msg.go (about) 1 package client 2 3 import ( 4 "math/rand" 5 "time" 6 7 "github.com/pkg/errors" 8 9 "github.com/Mrs4s/MiraiGo/client/pb/msg" 10 "github.com/Mrs4s/MiraiGo/internal/proto" 11 "github.com/Mrs4s/MiraiGo/message" 12 ) 13 14 func (c *QQClient) SendPrivateMessage(target int64, m *message.SendingMessage) *message.PrivateMessage { 15 mr := int32(rand.Uint32()) 16 var seq int32 17 t := time.Now().Unix() 18 imgCount := 0 19 frag := true 20 for _, e := range m.Elements { 21 switch e.Type() { 22 case message.Image: 23 imgCount++ 24 case message.Reply: 25 frag = false 26 } 27 } 28 msgLen := message.EstimateLength(m.Elements) 29 if msgLen > message.MaxMessageSize || imgCount > 50 { 30 return nil 31 } 32 if frag && (msgLen > 300 || imgCount > 2) && target == c.Uin { 33 div := int32(rand.Uint32()) 34 fragmented := m.ToFragmented() 35 for i, elems := range fragmented { 36 fseq := c.nextFriendSeq() 37 if i == 0 { 38 seq = fseq 39 } 40 _, pkt := c.buildFriendSendingPacket(target, fseq, mr, int32(len(fragmented)), int32(i), div, t, elems) 41 _ = c.sendPacket(pkt) 42 } 43 } else { 44 seq = c.nextFriendSeq() 45 if target != c.Uin { 46 _, pkt := c.buildFriendSendingPacket(target, seq, mr, 1, 0, 0, t, m.Elements) 47 _ = c.sendPacket(pkt) 48 } 49 } 50 c.stat.MessageSent.Add(1) 51 ret := &message.PrivateMessage{ 52 Id: seq, 53 InternalId: mr, 54 Self: c.Uin, 55 Target: target, 56 Time: int32(t), 57 Sender: &message.Sender{ 58 Uin: c.Uin, 59 Nickname: c.Nickname, 60 IsFriend: true, 61 }, 62 Elements: m.Elements, 63 } 64 go c.SelfPrivateMessageEvent.dispatch(c, ret) 65 return ret 66 } 67 68 func (c *QQClient) SendGroupTempMessage(groupCode, target int64, m *message.SendingMessage) *message.TempMessage { 69 group := c.FindGroup(groupCode) 70 if group == nil { 71 return nil 72 } 73 if c.FindFriend(target) != nil { 74 pm := c.SendPrivateMessage(target, m) 75 return &message.TempMessage{ 76 Id: pm.Id, 77 GroupCode: group.Code, 78 GroupName: group.Name, 79 Self: c.Uin, 80 Sender: pm.Sender, 81 Elements: m.Elements, 82 } 83 } 84 mr := int32(rand.Uint32()) 85 seq := c.nextFriendSeq() 86 t := time.Now().Unix() 87 _, pkt := c.buildGroupTempSendingPacket(group.Uin, target, seq, mr, t, m) 88 _ = c.sendPacket(pkt) 89 c.stat.MessageSent.Add(1) 90 return &message.TempMessage{ 91 Id: seq, 92 GroupCode: group.Code, 93 GroupName: group.Name, 94 Self: c.Uin, 95 Sender: &message.Sender{ 96 Uin: c.Uin, 97 Nickname: c.Nickname, 98 IsFriend: true, 99 }, 100 Elements: m.Elements, 101 } 102 } 103 104 func (c *QQClient) sendWPATempMessage(target int64, sig []byte, m *message.SendingMessage) *message.TempMessage { 105 mr := int32(rand.Uint32()) 106 seq := c.nextFriendSeq() 107 t := time.Now().Unix() 108 _, pkt := c.buildWPATempSendingPacket(target, sig, seq, mr, t, m) 109 _ = c.sendPacket(pkt) 110 c.stat.MessageSent.Add(1) 111 return &message.TempMessage{ 112 Id: seq, 113 Self: c.Uin, 114 Sender: &message.Sender{ 115 Uin: c.Uin, 116 Nickname: c.Nickname, 117 IsFriend: true, 118 }, 119 Elements: m.Elements, 120 } 121 } 122 123 func (s *TempSessionInfo) SendMessage(m *message.SendingMessage) (*message.TempMessage, error) { 124 switch s.Source { 125 case GroupSource: 126 return s.client.SendGroupTempMessage(s.GroupCode, s.Sender, m), nil 127 case ConsultingSource: 128 return s.client.sendWPATempMessage(s.Sender, s.sig, m), nil 129 default: 130 return nil, errors.New("unsupported message source") 131 } 132 } 133 134 /* this function is unused 135 func (c *QQClient) buildGetOneDayRoamMsgRequest(target, lastMsgTime, random int64, count uint32) (uint16, []byte) { 136 seq := c.nextSeq() 137 req := &msg.PbGetOneDayRoamMsgReq{ 138 PeerUin: proto.Uint64(uint64(target)), 139 LastMsgTime: proto.Uint64(uint64(lastMsgTime)), 140 Random: proto.Uint64(uint64(random)), 141 ReadCnt: proto.Some(count), 142 } 143 payload, _ := proto.Marshal(req) 144 packet := packets.BuildUniPacket(c.Uin, seq, "MessageSvc.PbGetOneDayRoamMsg", 1, c.SessionId, EmptyBytes, c.sigInfo.d2Key, payload) 145 return seq, packet 146 } 147 */ 148 149 // MessageSvc.PbSendMsg 150 func (c *QQClient) buildFriendSendingPacket(target int64, msgSeq, r, pkgNum, pkgIndex, pkgDiv int32, time int64, m []message.IMessageElement) (uint16, []byte) { 151 var ptt *msg.Ptt 152 if len(m) > 0 { 153 if p, ok := m[0].(*message.PrivateVoiceElement); ok { 154 ptt = p.Ptt 155 m = []message.IMessageElement{} 156 } 157 } 158 req := &msg.SendMessageRequest{ 159 RoutingHead: &msg.RoutingHead{C2C: &msg.C2C{ToUin: proto.Some(target)}}, 160 ContentHead: &msg.ContentHead{PkgNum: proto.Some(pkgNum), PkgIndex: proto.Some(pkgIndex), DivSeq: proto.Some(pkgDiv)}, 161 MsgBody: &msg.MessageBody{ 162 RichText: &msg.RichText{ 163 Elems: message.ToProtoElems(m, false), 164 Ptt: ptt, 165 }, 166 }, 167 MsgSeq: proto.Some(msgSeq), 168 MsgRand: proto.Some(r), 169 SyncCookie: syncCookie(time), 170 } 171 payload, _ := proto.Marshal(req) 172 return c.uniPacket("MessageSvc.PbSendMsg", payload) 173 } 174 175 // MessageSvc.PbSendMsg 176 func (c *QQClient) buildGroupTempSendingPacket(groupUin, target int64, msgSeq, r int32, time int64, m *message.SendingMessage) (uint16, []byte) { 177 req := &msg.SendMessageRequest{ 178 RoutingHead: &msg.RoutingHead{GrpTmp: &msg.GrpTmp{ 179 GroupUin: proto.Some(groupUin), 180 ToUin: proto.Some(target), 181 }}, 182 ContentHead: &msg.ContentHead{PkgNum: proto.Int32(1)}, 183 MsgBody: &msg.MessageBody{ 184 RichText: &msg.RichText{ 185 Elems: message.ToProtoElems(m.Elements, false), 186 }, 187 }, 188 MsgSeq: proto.Some(msgSeq), 189 MsgRand: proto.Some(r), 190 SyncCookie: syncCookie(time), 191 } 192 payload, _ := proto.Marshal(req) 193 return c.uniPacket("MessageSvc.PbSendMsg", payload) 194 } 195 196 func (c *QQClient) buildWPATempSendingPacket(uin int64, sig []byte, msgSeq, r int32, time int64, m *message.SendingMessage) (uint16, []byte) { 197 req := &msg.SendMessageRequest{ 198 RoutingHead: &msg.RoutingHead{WpaTmp: &msg.WPATmp{ 199 ToUin: proto.Uint64(uint64(uin)), 200 Sig: sig, 201 }}, 202 ContentHead: &msg.ContentHead{PkgNum: proto.Int32(1)}, 203 MsgBody: &msg.MessageBody{ 204 RichText: &msg.RichText{ 205 Elems: message.ToProtoElems(m.Elements, false), 206 }, 207 }, 208 MsgSeq: proto.Some(msgSeq), 209 MsgRand: proto.Some(r), 210 SyncCookie: syncCookie(time), 211 } 212 payload, _ := proto.Marshal(req) 213 return c.uniPacket("MessageSvc.PbSendMsg", payload) 214 } 215 216 func syncCookie(time int64) []byte { 217 cookie, _ := proto.Marshal(&msg.SyncCookie{ 218 Time: proto.Some(time), 219 Ran1: proto.Int64(rand.Int63()), 220 Ran2: proto.Int64(rand.Int63()), 221 Const1: proto.Some(syncConst1), 222 Const2: proto.Some(syncConst2), 223 Const3: proto.Int64(0x1d), 224 }) 225 return cookie 226 }