diff --git a/client/group_file.go b/client/group_file.go index 65060217..5e1ddd87 100644 --- a/client/group_file.go +++ b/client/group_file.go @@ -169,7 +169,7 @@ func (fs *GroupFileSystem) UploadFile(p, name, folderId string) error { SourceType: message.SourceGroup, PrimaryID: fs.GroupCode, } - return fs.client._UploadFile(target, f) + return fs.client.UploadFile(target, f) } func (fs *GroupFileSystem) GetDownloadUrl(file *GroupFile) string { diff --git a/client/pb/msg/msg.pb.go b/client/pb/msg/msg.pb.go index 88e71fdf..66247e93 100644 --- a/client/pb/msg/msg.pb.go +++ b/client/pb/msg/msg.pb.go @@ -108,10 +108,16 @@ type C2CMsgInfo struct { } type RoutingHead struct { - C2C *C2C `protobuf:"bytes,1,opt"` - Grp *Grp `protobuf:"bytes,2,opt"` - GrpTmp *GrpTmp `protobuf:"bytes,3,opt"` - WpaTmp *WPATmp `protobuf:"bytes,6,opt"` + C2C *C2C `protobuf:"bytes,1,opt"` + Grp *Grp `protobuf:"bytes,2,opt"` + GrpTmp *GrpTmp `protobuf:"bytes,3,opt"` + WpaTmp *WPATmp `protobuf:"bytes,6,opt"` + Trans_0X211 *Trans0X211 `protobuf:"bytes,15,opt"` +} + +type Trans0X211 struct { + ToUin proto.Option[uint64] `protobuf:"varint,1,opt"` + CcCmd proto.Option[uint32] `protobuf:"varint,2,opt"` } type WPATmp struct { diff --git a/client/pb/msg/msg.proto b/client/pb/msg/msg.proto index 68c673c1..b84cc83b 100644 --- a/client/pb/msg/msg.proto +++ b/client/pb/msg/msg.proto @@ -101,6 +101,7 @@ message RoutingHead { optional Grp grp = 2; optional GrpTmp grpTmp = 3; optional WPATmp wpaTmp = 6; + optional Trans0x211 trans_0X211 = 15; /* Dis dis = 4; DisTmp disTmp = 5; @@ -112,7 +113,6 @@ message RoutingHead { TransCmd? transCmd = 12; AccostTmp? accostTmp = 13; PubGroupTmp? pubGroupTmp = 14; - Trans0x211? trans0x211 = 15; BusinessWPATmp? businessWpaTmp = 16; AuthTmp? authTmp = 17; BsnsTmp? bsnsTmp = 18; @@ -123,6 +123,11 @@ message RoutingHead { */ } +message Trans0x211 { + optional uint64 toUin = 1; + optional uint32 ccCmd = 2; +} + message WPATmp { optional uint64 toUin = 1; optional bytes sig = 2; diff --git a/client/upload_file.go b/client/upload_file.go index c986198c..3fe3b512 100644 --- a/client/upload_file.go +++ b/client/upload_file.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "math/rand" + "time" "github.com/pkg/errors" @@ -13,6 +14,7 @@ import ( "github.com/Mrs4s/MiraiGo/client/internal/network" "github.com/Mrs4s/MiraiGo/client/pb/cmd0x346" "github.com/Mrs4s/MiraiGo/client/pb/exciting" + "github.com/Mrs4s/MiraiGo/client/pb/msg" "github.com/Mrs4s/MiraiGo/internal/proto" "github.com/Mrs4s/MiraiGo/message" "github.com/Mrs4s/MiraiGo/utils" @@ -57,7 +59,13 @@ func (f *LocalFile) init() { var fsWaiter = utils.NewUploadWaiter() -func (c *QQClient) _UploadFile(target message.Source, file *LocalFile) error { +func (c *QQClient) UploadFile(target message.Source, file *LocalFile) error { + switch target.SourceType { + case message.SourceGroup, message.SourcePrivate: // ok + default: + return errors.New("not implemented") + } + file.init() // 同文件等待其他线程上传 fkey := string(file.sha1) @@ -147,7 +155,46 @@ func (c *QQClient) _UploadFile(target message.Source, file *LocalFile) error { _, pkt := c.buildGroupFileFeedsRequest(target.PrimaryID, string(rsp.Uuid), rsp.BusID, rand.Int31()) return c.sendPacket(pkt) } - return errors.New("not implemented") + // 私聊文件 + _, pkt = c.buildPrivateFileUploadSuccReq(target, rsp) + err = c.sendPacket(pkt) + if err != nil { + return err + } + uid := target.PrimaryID + msgSeq := c.nextFriendSeq() + content, _ := proto.Marshal(&msg.SubMsgType0X4Body{ + NotOnlineFile: &msg.NotOnlineFile{ + FileType: proto.Int32(0), + FileUuid: rsp.Uuid, + FileMd5: file.md5, + FileName: []byte(file.FileName), + FileSize: proto.Int64(file.size), + Subcmd: proto.Int32(1), + }, + }) + req := &msg.SendMessageRequest{ + RoutingHead: &msg.RoutingHead{ + Trans_0X211: &msg.Trans0X211{ + ToUin: proto.Uint64(uint64(uid)), + CcCmd: proto.Uint32(4), + }, + }, + ContentHead: &msg.ContentHead{ + PkgNum: proto.Int32(1), + PkgIndex: proto.Int32(0), + DivSeq: proto.Int32(0), + }, + MsgBody: &msg.MessageBody{ + MsgContent: content, + }, + MsgSeq: proto.Some(msgSeq), + MsgRand: proto.Some(int32(rand.Uint32())), + SyncCookie: syncCookie(time.Now().Unix()), + } + payload, _ := proto.Marshal(req) + _, p := c.uniPacket("MessageSvc.PbSendMsg", payload) + return c.sendPacket(p) } func (c *QQClient) buildPrivateFileUploadReqPacket(target message.Source, file *LocalFile) (uint16, []byte) { @@ -188,3 +235,19 @@ func decodePrivateFileUploadReq(_ *QQClient, _ *network.IncomingPacketInfo, payl } return r, nil } + +func (c *QQClient) buildPrivateFileUploadSuccReq(target message.Source, rsp *fileUploadRsp) (uint16, []byte) { + req := &cmd0x346.C346ReqBody{ + Cmd: 800, + Seq: 7, + UploadSuccReq: &cmd0x346.UploadSuccReq{ + SenderUin: c.Uin, + RecverUin: target.PrimaryID, + Uuid: rsp.Uuid, + }, + BusinessId: 3, + ClientType: 102, + } + pkt, _ := proto.Marshal(req) + return c.uniPacket("OfflineFilleHandleSvr.pb_ftn_CMD_REQ_UPLOAD_SUCC-800", pkt) +}