⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 receiveimpacket.java

📁 LUMAQQ源代码 JAVA 地球人都知道
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/*
* LumaQQ - Java QQ Client
*
* Copyright (C) 2004 luma <stubma@163.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package edu.tsinghua.lumaqq.qq.packets.in;

import static edu.tsinghua.lumaqq.qq.events.QQEvent.*;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

import edu.tsinghua.lumaqq.qq.QQ;
import edu.tsinghua.lumaqq.qq.Util;
import edu.tsinghua.lumaqq.qq.annotation.DocumentalPacket;
import edu.tsinghua.lumaqq.qq.annotation.LinkedEvent;
import edu.tsinghua.lumaqq.qq.annotation.PacketName;
import edu.tsinghua.lumaqq.qq.annotation.RelatedPacket;
import edu.tsinghua.lumaqq.qq.beans.ClusterIM;
import edu.tsinghua.lumaqq.qq.beans.CustomHead;
import edu.tsinghua.lumaqq.qq.beans.FileInfo;
import edu.tsinghua.lumaqq.qq.beans.FileTransferArgs;
import edu.tsinghua.lumaqq.qq.beans.NormalIM;
import edu.tsinghua.lumaqq.qq.beans.NormalIMHeader;
import edu.tsinghua.lumaqq.qq.beans.QQLive;
import edu.tsinghua.lumaqq.qq.beans.QQUser;
import edu.tsinghua.lumaqq.qq.beans.ReceiveIMHeader;
import edu.tsinghua.lumaqq.qq.beans.SMS;
import edu.tsinghua.lumaqq.qq.beans.TempSessionIM;
import edu.tsinghua.lumaqq.qq.beans.UserPropertyChange;
import edu.tsinghua.lumaqq.qq.packets.BasicInPacket;
import edu.tsinghua.lumaqq.qq.packets.PacketParseException;
import edu.tsinghua.lumaqq.qq.packets.out.ReceiveIMReplyPacket;


/**
 * <pre>
 * 别人发来的消息包,如果是普通消息,格式为
 * 1. 头部
 * 2. 发送者QQ号,4字节
 * 3. 接收者QQ号,4字节
 * 4. 包序号(并非我们发送时候的序号,因为这个是4字节,可能是服务器端得总序号)
 * 5. 发送者IP,如果是服务器转发的,那么ip就是服务器ip, 4字节
 * 6. 发送者端口,如果是服务器转发的,那么就是服务器的端口,2字节
 * 7. 消息类型,是好友发的,还是陌生人发的,还是系统消息等等, 2字节
 * 8. 发送者QQ版本,2字节
 * 9. 发送者的QQ号,4字节
 * 10. 接受者的QQ号,4字节
 * 11. md5处理的发送方的uid和session key,16字节
 * 12. 普通消息类型,比如是文本消息还是其他什么消息,2字节
 * 13. 会话ID,2字节,如果是一个操作需要发送多个包才能完成,则这个id必须一致
 * 14. 发送时间,4字节
 * 15. 发送者头像,2字节
 * 16. 是否有字体属性,4字节,有一般是0x00000001
 * 17. 消息的分片数,1字节
 * 18. 分片序号,1字节,从0开始
 * 19. 消息id,2字节,同一条消息的不同分片id相同
 * 20. 消息类型,这里的类型表示是正常回复还是自动回复之类的信息, 1字节
 * 21. 消息正文,长度 = 剩余字节数 - 包尾字体属性长度
 * 22. 字体属性,和SendIMPacket中的相同
 * 23. 尾部
 * 
 * 如果是临时会话消息
 * 2. 发送者QQ号,4字节
 * 3. 接收者QQ号,4字节
 * 4. 包序号(并非我们发送时候的序号,因为这个是4字节,可能是服务器端得总序号)
 * 5. 发送者IP,如果是服务器转发的,那么ip就是服务器ip, 4字节
 * 6. 发送者端口,如果是服务器转发的,那么就是服务器的端口,2字节
 * 7. 消息类型,2字节,这里是0x001F
 * 8. 发送者QQ号,4字节
 * 9. 未知的4字节
 * 10. 发送者昵称长度,1字节
 * 11. 发送者昵称
 * 12. Site名称长度,1字节
 * 13. Site名称
 * 14. 未知的1字节
 * 15. 发送时间,4字节
 * 16. 后面实际内容的长度,2字节
 * Note: 包的结尾有4个未知字节,所以16部分的长度是实际内容长度,不包括那4个字节
 * 17. 消息内容,长度 = 16部分 - 字体属性长度
 * 18. 字体属性,参见SendIMPacket
 * 19. 未知的4字节
 * 20. 尾部
 * 
 * 如果是群通知
 * 1. 头部
 * 2. 群的内部ID,4字节
 * 3. 接收者QQ号,4字节
 * 4. 包序号(并非我们发送时候的序号,因为这个是4字节,可能是服务器端得总序号)
 * 5. 发送者IP,如果是服务器转发的,那么ip就是服务器ip, 4字节
 * 6. 发送者端口,如果是服务器转发的,那么就是服务器的端口,2字节
 * 7. 消息类型,是好友发的,还是陌生人发的,还是系统消息等等, 2字节,0x002C
 * 8. 群的外部ID,4字节
 * 9. 群类型,1字节
 * 10. 操作码,1字节
 * 11. 接受者QQ号,4字节
 * 12. 接受者当前角色,1字节
 * 13. 尾部
 * 
 * 如果是个性签名改变通知
 * 1. 头部
 * 2. 发送者QQ号,在这里是10000,4字节
 * 3. 接受者QQ号,4字节
 * 4. 服务器端包序号,4字节
 * 5. 发送者IP,4字节
 * 6. 发送者端口,2字节
 * 7. 消息类型,2字节,在这里是0x0041
 * 8. 个性签名改变的QQ号,4字节
 * 9. 个性签名改变的时间,4字节
 * 10. 新个性签名的字节长度,1字节
 * 11. 新个性签名
 * 12. 尾部
 * 
 * 如果是系统消息:
 * 1-7. 与普通消息相同,只不过7是0x0030,表示是系统消息
 * 8. 系统消息类型,1字节
 * 9. 系统消息长度,1字节
 * 10. 系统消息
 * 
 * 如果是来自绑定手机的手机短消息,格式为:
 * 1. 头部
 * 2. 发送者QQ号,4字节
 * 3. 接收者QQ号,4字节
 * 4. 包序号(并非我们发送时候的序号,因为这个是4字节,可能是服务器端得总序号)
 * 5. 发送者IP,如果是服务器转发的,那么ip就是服务器ip, 4字节
 * 6. 发送者端口,如果是服务器转发的,那么就是服务器的端口,2字节
 * 7. 消息类型,是好友发的,还是陌生人发的,还是系统消息等等, 2字节,0x000B
 * 8. 未知1字节,0x0
 * 9. 发送者QQ号,4字节
 * 10. 发送者头像,2字节
 * 11. 发送者名称,最多13字节,不足后面补0
 * 12. 未知的1字节,0x4D
 * 13. 消息内容,160字节,如果不足,填0
 * 注:在接收长消息时,13部分前两个字节为固定内容,似乎是用来标识同一消息的分片,但是
 * QQ本身却没有处理这个字段,而是把这个字段也显示出来了,似乎是个bug
 * 14. 尾部
 * 
 * 如果是来自移动QQ用户的手机短消息,格式为:
 * 1. 头部
 * 2. 发送者QQ号,4字节
 * 3. 接收者QQ号,4字节
 * 4. 包序号(并非我们发送时候的序号,因为这个是4字节,可能是服务器端得总序号)
 * 5. 发送者IP,如果是服务器转发的,那么ip就是服务器ip, 4字节
 * 6. 发送者端口,如果是服务器转发的,那么就是服务器的端口,2字节
 * 7. 消息类型,是好友发的,还是陌生人发的,还是系统消息等等, 2字节,0x0013
 * 8. 未知1字节
 * 9. 发送者QQ号,4字节
 * 10. 发送者头像,2字节
 * 11. 发送者名称,最多13字节,不足后面补0
 * 12. 未知的1字节,0x4D
 * 13. 短信发送时间,4字节
 * 14. 未知1字节,0x03
 * 15. 短信内容,160字节,不足填0
 * 注:在接收长消息时,15部分前两个字节为固定内容,似乎是用来标识同一消息的分片,但是
 * QQ本身却没有处理这个字段,而是把这个字段也显示出来了,似乎是个bug
 * 16. 尾部
 * 
 * 如果是来自移动QQ用户的手机短消息(使用的是手机号码),格式为:
 * 1. 头部
 * 2. 发送者QQ号,4字节
 * 3. 接收者QQ号,4字节
 * 4. 包序号(并非我们发送时候的序号,因为这个是4字节,可能是服务器端得总序号)
 * 5. 发送者IP,如果是服务器转发的,那么ip就是服务器ip, 4字节
 * 6. 发送者端口,如果是服务器转发的,那么就是服务器的端口,2字节
 * 7. 消息类型,是好友发的,还是陌生人发的,还是系统消息等等, 2字节,0x0014
 * 8. 未知1字节
 * 9. 移动QQ的手机号,18字节,不足补0
 * 10. 未知的2字节
 * 11. 短信发送时间,4字节
 * 12. 未知1字节,0x03
 * 13. 短信内容,160字节,不足填0
 * 注:在接收长消息时,13部分前两个字节为固定内容,似乎是用来标识同一消息的分片,但是
 * QQ本身却没有处理这个字段,而是把这个字段也显示出来了,似乎是个bug
 * 14. 尾部
 * 
 * 如果是来自普通手机的消息
 * 1. 头部
 * 2. 发送者QQ号,4字节,在这里是10000
 * 3. 接收者QQ号,4字节
 * 4. 包序号(并非我们发送时候的序号,因为这个是4字节,可能是服务器端得总序号)
 * 5. 发送者IP,如果是服务器转发的,那么ip就是服务器ip, 4字节
 * 6. 发送者端口,如果是服务器转发的,那么就是服务器的端口,2字节
 * 7. 消息类型,是好友发的,还是陌生人发的,还是系统消息等等, 2字节,0x000C
 * 8. 未知1字节,0x0
 * 9. 发送者手机号码,20字节,不足填0
 * 10. 短信内容,160字节,不足填0
 * 注:在接收长消息时,15部分前两个字节为固定内容,似乎是用来标识同一消息的分片,但是
 * QQ本身却没有处理这个字段,而是把这个字段也显示出来了,似乎是个bug
 * 11. 尾部
 * 
 * 如果是请求传送文件,格式为
 * 1 - 18. 与普通消息格式相同,差别只有12部分,为0x0035,表示是请求传送文件
 * 19.     未用部分,全0,15字节
 * 20.     传输类型,1字节
 * 21.     连接方式,1字节
 * 22.     请求者外部ip,4字节
 * 23.     请求者QQ端口,2字节,如果连接方式为0x3,则这个部分没有
 * 24.     第一个监听端口,2字节
 * 25.     请求者真实ip,4字节
 * 26.     第二个监听端口,2字节
 * 27.     空格符0x20
 * 28.     分隔符0x1F
 * 29.     文件名,不定长,不包含路径名
 * 30.     分隔符0x1F
 * 31.     文件字节数的字符串形式加“ 字节”
 * 32.     尾部
 * 
 * 如果是接受传送文件的请求,格式为
 * 1 - 18. 与普通消息格式相同,差别只有12部分,对于UDP请求,为0x0037
 * 19 - 26 和0x0035时相同
 * 27.     尾部 
 * 
 * 如果是通知文件传送的端口,格式为
 * 1 - 18. 与普通消息格式相同,差别只有12部分,为0x003B,表示是通知文件传送端口
 * 19 - 26 和0x0035时相同
 * 27. 尾部
 *
 * 未知类型的群消息
 * 1-7. 与普通消息相同,只不过发送者QQ号相当于是群的内部ID,7部分为0x0020
 * 8.   群外部ID,4字节
 * 9.   群类型,1字节
 * 10.  发送者QQ号,4字节
 * 11.  未知的两字节,全0
 * 12.  消息序号,2字节
 * 13.  消息发送时间,4字节
 * 14.  未知的4字节
 * 15.  后面的数据的长度,2字节
 * 16.  以0结尾的消息内容
 * 17.  字体属性,和SendIMPacket中的相同
 * 18.  尾部
 *  
 * 如果是讨论组或者多人对话消息,讨论组和多人对话属于临时群,格式为
 * 1 - 7 部分与普通消息相同,只不过7部分是0x002A
 * 8.   父群内部ID,4字节
 * 9.   群类型,1字节
 * 10.  讨论组内部ID,4字节
 * 11.  发送者QQ号,4字节
 * 12.  未知的两字节,全0
 * 13.  消息序号,2字节
 * 14.  消息发送时间,4字节
 * 15.  Version ID, 4字节,所谓version id,是我这里根据这个字段的意思乱编的。
 *      其作用主要是标识群信息的版本,比如一开始,群内有两个人,这个时候版本是0,然后我删
 *      除一个人,那么群的版本就要加1,于是就变成了1。然后我又加了2个人,于是版本再加2变成3,
 *      假如我再删一个人又加一个人,那么版本就要加2变成5了。为什么要加2呢,因为我做了两次操作,
 *      一次删,一次加,所以版本号加了2,你可能奇怪:为什么我不一次搞定,然后版本加1啊?因为
 *      QQ的协议就是这样,它的协议不能同时做删除和添加成员的操作,晕吧?所以我要做两次操作,
 *      也就是要发两个包才能又加人又删人,所以版本号加了2。客户端对每一个群都要保存这么一个version ID,
 *      一旦收到的消息大于我本地的version id,于是就发个包过去请求得到目前的成员列表。所以你
 *      会看到,QQ在发临时群消息的时候,成员如果变化了,会即时的反映出来,就是如此实现的了。
 *      这个id不光是在修改成员的时候才变,修改基本信息也照样变,用来表示这个群的信息修改过了。
 * 16.  后面内容的长度
 * 17.  Content Type, 2字节,0x0001表示纯文件,0x0002表示有自定义表情
 * 18.  消息的分片数,1字节
 * 19.  分片序号,1字节,从0开始
 * 20.  消息id,2字节,同一条消息的不同分片id相同
 * 21.  4字节,未知
 * 22.  消息正文,长度 = 剩余字节数 - 包尾字体属性长度
 * 23.  字体属性,和SendIMPacket中的相同
 * 24.  尾部
 * 
 * 如果是示范群或会员创建的群发来的消息,这些群都是固定群,格式为
 * 1 - 7 部分与普通消息相同,只不过7部分是0x002B
 * 8.   群外部ID,4字节
 * 9.   群类型,1字节
 * 10.  发送者QQ号,4字节
 * 11.  未知的两字节
 * 12.  消息序号,2字节
 * 13.  消息发送时间,4字节
 * 14.  Version ID, 4字节
 * 15.  后面内容的长度
 * 16.  Content Type, 2字节,0x0001表示纯文件,0x0002表示有自定义表情
 * 17.  消息的分片数,1字节
 * 18.  分片序号,1字节,从0开始
 * 19.  消息id,2字节,同一条消息的不同分片id相同
 * 20.  4字节,未知
 * 21.  消息正文,长度 = 剩余字节数 - 包尾字体属性长度
 * 22.  字体属性,和SendIMPacket中的相同
 * 23.  尾部
 * 
 * 如果是0x0041,可能是向服务器报告最后连接情况的包,格式为
 * 1 - 27. 和0x003B时相同,差别只有命令不同,为0x0041
 * 
 * 如果是取消传送文件请求,格式为:
 * 1 - 18. 与普通消息格式相同,差别只有12部分,为0x0049,表示是取消传送文件
 * 19.     未用部分,全0,15字节
 * 20.     固定字节0x65
 * 21.     尾部
 * 
 * 如果是QQ直播消息:
 * 1. 头部
 * 2. 发送者QQ号,4字节,一般是10000
 * 3. 接收者QQ号,4字节
 * 4. 包序号(并非我们发送时候的序号,因为这个是4字节,可能是服务器端得总序号)
 * 5. 发送者IP,如果是服务器转发的,那么ip就是服务器ip, 4字节
 * 6. 发送者端口,如果是服务器转发的,那么就是服务器的端口,2字节
 * 7. 消息类型,2字节,0x0018
 * 8. 直播消息类型,2字节
 * 9. 后面的内容长度,2字节,exclusive
 * 如果8部分是0x0100,表示普通直播消息
 * 10. 直播标题长度,1字节
 * 11. 标题
 * 12. 直播描述长度,1字节
 * 13. 直播描述
 * 14. 直播URL长度,1字节
 * 15. 直播URL
 * 16. 如果10-15部分加起来的长度没有超过9部分的值,则后面都填0
 * 17. 尾部
 * 如果8部分是0x0400,表示网络硬盘通知
 * 10. 标题
 * 11. 分隔符,1字节,0x02
 * 12. 描述
 * 13. 分隔符,1字节,0x02
 * 14. 好友的QQ号的字符串形式
 * 15. 尾部
 * 
 * 如果是会员登录提示
 * 1. 头部
 * 2. 发送者QQ号,4字节,一般是10000
 * 3. 接收者QQ号,4字节
 * 4. 包序号(并非我们发送时候的序号,因为这个是4字节,可能是服务器端得总序号)
 * 5. 发送者IP,如果是服务器转发的,那么ip就是服务器ip, 4字节
 * 6. 发送者端口,如果是服务器转发的,那么就是服务器的端口,2字节
 * 7. 消息类型,2字节,0x0012
 * 8. 未知1字节
 * 9. 尾部
 * 
 * 如果是自定义头像变化通知
 * 1. 头部
 * 2. 发送者QQ号,4字节,一般是10000
 * 3. 接收者QQ号,4字节
 * 4. 包序号(并非我们发送时候的序号,因为这个是4字节,可能是服务器端得总序号)
 * 5. 发送者IP,如果是服务器转发的,那么ip就是服务器ip, 4字节
 * 6. 发送者端口,如果是服务器转发的,那么就是服务器的端口,2字节
 * 7. 消息类型,2字节,0x0049
 * 8. 头像变化的好友个数,1字节
 * 9. 好友QQ号,4字节
 * 10. 自定义头像最后改变的时间戳,4字节,为从1970-1-1到现在的秒数
 * 11. 自定义头像的MD5值,16字节
 * 12. 如果有更多好友,重复10-11部分

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -