📄 receiveimpacket.java
字号:
* 13. 尾部
*
* 如果是好友属性改变通知
* 1. 头部
* 2. 发送者QQ号,4字节,一般是10000
* 3. 接收者QQ号,4字节
* 4. 包序号(并非我们发送时候的序号,因为这个是4字节,可能是服务器端得总序号)
* 5. 发送者IP,如果是服务器转发的,那么ip就是服务器ip, 4字节
* 6. 发送者端口,如果是服务器转发的,那么就是服务器的端口,2字节
* 7. 消息类型,2字节,0x001E
* 8. 好友QQ号,4字节
* 9. 好友属性,4字节
* 10. 未知的16字节
* 11. 尾部
* </pre>
*
* @see NormalIM
* @see NormalIMHeader
* @see ReceiveIMHeader
* @see ClusterIM
* @see FileTransferArgs
* @see FileInfo
* @see TempSessionIM
* @see SMS
* @see QQLive
*
* @author luma
*/
@DocumentalPacket
@PacketName("接收消息包")
@RelatedPacket({ReceiveIMReplyPacket.class})
@LinkedEvent({QQ_RECEIVE_DUPLICATED_IM,
QQ_RECEIVE_NORMAL_IM,
QQ_REQUEST_SEND_FILE,
QQ_REJECT_SEND_FILE,
QQ_ACCEPT_SEND_FILE,
QQ_NOTIFY_FILE_TRANSFER_ARGS,
QQ_REQUEST_ME_CONNECT,
QQ_CANCEL_SEND_FILE,
QQ_UNKNOWN_TYPE_IM,
QQ_KICKED_OUT_BY_SYSTEM,
QQ_RECEIVE_SYS_MESSAGE,
QQ_RECEIVE_CLUSTER_IM,
QQ_RECEIVE_TEMP_CLUSTER_IM,
QQ_RECEIVE_UNKNOWN_CLUSTER_IM,
QQ_RECEIVE_SMS,
QQ_RECEIVE_TEMP_SESSION_IM,
QQ_I_AM_ADDED_TO_CLUSTER,
QQ_I_AM_REMOVED_FROM_CLUSTER,
QQ_REQUEST_JOIN_CLUSTER_APPROVED,
QQ_REQUEST_JOIN_CLUSTER_REJECTED,
QQ_REQUEST_JOIN_CLUSTER,
QQ_ADMIN_ENTITLED,
QQ_ADMIN_WITHDRAWED,
QQ_FRIEND_SIGNATURE_CHANGED,
QQ_RECEIVE_DISK_NOTIFICATION,
QQ_RECEIVE_QQLIVE,
QQ_RECEIVE_MEMBER_LOGIN_HINT,
QQ_FRIEND_PROPERTY_CHANGED,
QQ_FRIEND_CUSTOM_HEAD_CHANGED})
public class ReceiveIMPacket extends BasicInPacket {
// 用于发送确认
public byte[] reply;
// 为true时表示收到的消息是空的
public boolean empty;
// 整个包的头
public ReceiveIMHeader header;
// 仅用于普通消息时
public NormalIMHeader normalHeader;
public NormalIM normalIM;
// 仅用于系统通知时
public byte systemMessageType;
public String sysMessage;
// 仅用于文件传输时
public FileInfo fileInfo;
public FileTransferArgs fileArgs;
public byte transferType;
// 仅用于群普通消息时
public ClusterIM clusterIM;
// 仅用于其他类型群消息
public int externalId;
public byte clusterType;
public int sender;
public String message;
// 用于群通知时
public byte role;
public byte opCode;
public int memberQQ;
// 用户个性签名通知
public int signatureOwner;
public int modifiedTime;
public String signature;
// 用于手机短信消息
public SMS sms;
// 临时会话消息
public TempSessionIM tempSessionIM;
// QQ直播消息
public QQLive qqlive;
// 自定义头像变化通知
public List<CustomHead> headChanges;
// 用户属性变化
public UserPropertyChange propertyChange;
/**
* 构造函数
* @param buf 缓冲区
* @param length 包长度
* @throws PacketParseException 解析错误
*/
public ReceiveIMPacket(ByteBuffer buf, int length, QQUser user) throws PacketParseException {
super(buf, length, user);
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.qq.packets.InPacket#getPacketName()
*/
@Override
public String getPacketName() {
return "Receive IM Packet";
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.qq.packets.InPacket#parseBody(java.nio.ByteBuffer)
*/
@Override
protected void parseBody(ByteBuffer buf) throws PacketParseException {
empty = false;
// 检查消息长度,至少要有16字节,因为我们需要前16字节做为确认发回
if(buf.remaining() < 16)
throw new PacketParseException("收到的消息太短,抛弃该消息");
// 得到前16个字节用作回复
reply = new byte[16];
buf.get(reply);
// 读取消息头
buf.rewind();
header = new ReceiveIMHeader();
header.readBean(buf);
// 检查输入流可用字节
if(!buf.hasRemaining()) {
empty = true;
return;
}
// 判断消息类型
int len = 0;
switch(header.type) {
case QQ.QQ_RECV_IM_FRIEND:
case QQ.QQ_RECV_IM_STRANGER:
/* 是从好友或者陌生人处发来的消息 */
parseNormalIM(buf);
break;
case QQ.QQ_RECV_IM_TEMP_SESSION:
tempSessionIM = new TempSessionIM();
tempSessionIM.readBean(buf);
break;
case QQ.QQ_RECV_IM_SYS_MESSAGE:
/* 是系统消息 */
parseSystemMessage(buf);
break;
case QQ.QQ_RECV_IM_CLUSTER:
/* 群消息 */
parseClusterIM(buf);
break;
case QQ.QQ_RECV_IM_TEMP_CLUSTER:
/* 临时群消息 */
parseTempClusterIM(buf);
break;
case QQ.QQ_RECV_IM_UNKNOWN_CLUSTER:
parseUnknownClusterIM(buf);
break;
case QQ.QQ_RECV_IM_BIND_USER:
sms = new SMS();
sms.readBindUserSMS(buf);
break;
case QQ.QQ_RECV_IM_MOBILE_QQ:
sms = new SMS();
sms.readMobileQQSMS(buf);
break;
case QQ.QQ_RECV_IM_MOBILE_QQ_2:
sms = new SMS();
sms.readMobileQQ2SMS(buf);
break;
case QQ.QQ_RECV_IM_MOBILE:
sms = new SMS();
sms.readMobileSMS(buf);
break;
case QQ.QQ_RECV_IM_CREATE_CLUSTER:
case QQ.QQ_RECV_IM_ADDED_TO_CLUSTER:
case QQ.QQ_RECV_IM_DELETED_FROM_CLUSTER:
externalId = buf.getInt();
clusterType = buf.get();
sender = buf.getInt();
break;
case QQ.QQ_RECV_IM_APPROVE_JOIN_CLUSTER:
case QQ.QQ_RECV_IM_REJECT_JOIN_CLUSTER:
case QQ.QQ_RECV_IM_REQUEST_JOIN_CLUSTER:
externalId = buf.getInt();
clusterType = buf.get();
sender = buf.getInt();
len = buf.get() & 0xFF;
byte[] b = new byte[len];
buf.get(b);
message = Util.getString(b);
break;
case QQ.QQ_RECV_IM_CLUSTER_NOTIFICATION:
externalId = buf.getInt();
clusterType = buf.get();
opCode = buf.get();
memberQQ = buf.getInt();
role = buf.get();
sender = externalId;
break;
case QQ.QQ_RECV_IM_SIGNATURE_CHANGE:
signatureOwner = buf.getInt();
modifiedTime = buf.getInt();
len = buf.get() & 0xFF;
signature = Util.getString(buf, len);
break;
case QQ.QQ_RECV_IM_QQLIVE:
// QQLive message
qqlive = new QQLive();
qqlive.readBean(buf);
break;
case QQ.QQ_RECV_IM_MEMBER_LOGIN_HINT:
buf.get();
break;
case QQ.QQ_RECV_IM_CUSTOM_HEAD_CHANGE:
int count = buf.get() & 0xFF;
if(count > 0) {
headChanges = new ArrayList<CustomHead>();
while(buf.hasRemaining()) {
CustomHead change = new CustomHead();
change.readBean(buf);
headChanges.add(change);
}
}
break;
case QQ.QQ_RECV_IM_PROPERTY_CHANGE:
propertyChange = new UserPropertyChange();
propertyChange.readBean(buf);
break;
default:
// 其他类型的消息我们现在没有办法处理,忽略
break;
}
}
/**
* @param buf
*/
private void parseUnknownClusterIM(ByteBuffer buf) {
clusterIM = new ClusterIM(QQ.QQ_RECV_IM_UNKNOWN_CLUSTER);
clusterIM.readBean(buf);
}
/**
* 解析临时组消息
*
* @param buf
*/
private void parseTempClusterIM(ByteBuffer buf) {
clusterIM = new ClusterIM(QQ.QQ_RECV_IM_TEMP_CLUSTER);
clusterIM.readBean(buf);
}
/**
* 解析群普通消息
*/
private void parseClusterIM(ByteBuffer buf) {
clusterIM = new ClusterIM(QQ.QQ_RECV_IM_CLUSTER);
clusterIM.readBean(buf);
}
/**
* 解析系统消息
*/
private void parseSystemMessage(ByteBuffer buf) {
// 系统消息类型
systemMessageType = buf.get();
// 系统消息长度
int len = buf.get() & 0xFF;
// 系统消息
sysMessage = Util.getString(buf, len);
}
/**
* 解析普通消息
*/
private void parseNormalIM(ByteBuffer buf) throws PacketParseException {
try {
// 读入普通消息头
normalHeader = new NormalIMHeader();
normalHeader.readBean(buf);
// 判断普通消息类型
if(normalHeader.type == QQ.QQ_IM_TYPE_TEXT) {
normalIM = new NormalIM();
normalIM.readBean(buf);
} else if(normalHeader.type == QQ.QQ_IM_TYPE_UDP_REQUEST
|| normalHeader.type == QQ.QQ_IM_TYPE_TCP_REQUEST){
fileArgs = new FileTransferArgs();
fileArgs.readBean(buf);
fileInfo = new FileInfo();
fileInfo.readBean(buf);
} else if(normalHeader.type == QQ.QQ_IM_TYPE_ACCEPT_UDP_REQUEST
|| normalHeader.type == QQ.QQ_IM_TYPE_NOTIFY_IP) {
fileArgs = new FileTransferArgs();
fileArgs.readBean(buf);
}
log.debug("收到的普通消息类型为:" + Util.getNormalIMTypeString(normalHeader.type));
} catch (Exception e) {
throw new PacketParseException(e.getMessage());
}
}
/**
* @return
* 消息种类
*/
public int getMessageCategory() {
switch(header.type) {
case QQ.QQ_RECV_IM_SYS_MESSAGE:
return QQ.QQ_IM_FROM_SYS;
case QQ.QQ_RECV_IM_FRIEND:
case QQ.QQ_RECV_IM_STRANGER:
return QQ.QQ_IM_FROM_USER;
case QQ.QQ_RECV_IM_TEMP_SESSION:
return QQ.QQ_IM_FROM_TEMP_SESSION;
case QQ.QQ_RECV_IM_CLUSTER:
case QQ.QQ_RECV_IM_TEMP_CLUSTER:
case QQ.QQ_RECV_IM_UNKNOWN_CLUSTER:
return QQ.QQ_IM_FROM_CLUSTER;
case QQ.QQ_RECV_IM_BIND_USER:
case QQ.QQ_RECV_IM_MOBILE_QQ:
case QQ.QQ_RECV_IM_MOBILE_QQ_2:
case QQ.QQ_RECV_IM_MOBILE:
return QQ.QQ_IM_FROM_SMS;
default:
return QQ.QQ_IM_FROM_SYS;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -