📄 basicparser.java
字号:
/*
* 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;
import java.nio.ByteBuffer;
import edu.tsinghua.lumaqq.qq.PacketParseException;
import edu.tsinghua.lumaqq.qq.QQ;
import edu.tsinghua.lumaqq.qq.Util;
import edu.tsinghua.lumaqq.qq.beans.QQUser;
import edu.tsinghua.lumaqq.qq.net.PacketMonitor;
import edu.tsinghua.lumaqq.qq.packets.in.AddFriendAuthReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.AddFriendReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.AdvancedSearchUserReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.ChangeStatusReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.ClusterCommandReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.DeleteFriendReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.DownloadGroupFriendReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.FriendChangeStatusPacket;
import edu.tsinghua.lumaqq.qq.packets.in.FriendDataOpReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.GetFriendListReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.GetFriendOnlineReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.GetTempClusterOnlineMemberReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.GetUserInfoReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.GroupDataOpReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.KeepAliveReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.LoginReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.ModifyInfoReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.ReceiveIMPacket;
import edu.tsinghua.lumaqq.qq.packets.in.RemoveSelfReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.RequestKeyReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.RequestLoginTokenReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.SearchUserReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.SendIMReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.SendSMSReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.SystemNotificationPacket;
import edu.tsinghua.lumaqq.qq.packets.in.UnknownInPacket;
import edu.tsinghua.lumaqq.qq.packets.in.UploadGroupFriendReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.out.AddFriendAuthPacket;
import edu.tsinghua.lumaqq.qq.packets.out.AddFriendPacket;
import edu.tsinghua.lumaqq.qq.packets.out.AdvancedSearchUserPacket;
import edu.tsinghua.lumaqq.qq.packets.out.ChangeStatusPacket;
import edu.tsinghua.lumaqq.qq.packets.out.ClusterCommandPacket;
import edu.tsinghua.lumaqq.qq.packets.out.DeleteFriendPacket;
import edu.tsinghua.lumaqq.qq.packets.out.DownloadGroupFriendPacket;
import edu.tsinghua.lumaqq.qq.packets.out.FriendDataOpPacket;
import edu.tsinghua.lumaqq.qq.packets.out.GetFriendListPacket;
import edu.tsinghua.lumaqq.qq.packets.out.GetFriendOnlinePacket;
import edu.tsinghua.lumaqq.qq.packets.out.GetUserInfoPacket;
import edu.tsinghua.lumaqq.qq.packets.out.GroupDataOpPacket;
import edu.tsinghua.lumaqq.qq.packets.out.KeepAlivePacket;
import edu.tsinghua.lumaqq.qq.packets.out.LoginPacket;
import edu.tsinghua.lumaqq.qq.packets.out.LogoutPacket;
import edu.tsinghua.lumaqq.qq.packets.out.ModifyInfoPacket;
import edu.tsinghua.lumaqq.qq.packets.out.ReceiveIMReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.out.RemoveSelfPacket;
import edu.tsinghua.lumaqq.qq.packets.out.RequestKeyPacket;
import edu.tsinghua.lumaqq.qq.packets.out.RequestLoginTokenPacket;
import edu.tsinghua.lumaqq.qq.packets.out.SearchUserPacket;
import edu.tsinghua.lumaqq.qq.packets.out.SendIMPacket;
import edu.tsinghua.lumaqq.qq.packets.out.SendSMSPacket;
import edu.tsinghua.lumaqq.qq.packets.out.UnknownOutPacket;
import edu.tsinghua.lumaqq.qq.packets.out.UploadGroupFriendPacket;
/**
* 基本协议族解析器
*
* @author luma
*/
public class BasicParser implements IParser {
private char command, sequence;
private int offset;
private int length;
private boolean udp;
/**
* 得到包的命令和序号
*
* @param buf
*/
private void getCommand(ByteBuffer buf) {
if(!udp) {
command = buf.getChar(offset + 5);
sequence = buf.getChar(offset + 7);
} else {
command = buf.getChar(offset + 3);
sequence = buf.getChar(offset + 5);
}
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.qq.packets.IParser#accept(java.nio.ByteBuffer)
*/
public boolean accept(ByteBuffer buf) {
// 保存偏移
offset = buf.position();
int bufferLength = buf.limit() - buf.position();
if(bufferLength <= 0)
return false;
boolean accept = checkTcp(buf);
if(!accept)
accept = checkUdp(buf);
return accept;
}
/**
* 检查一个包是否是udp包
*
* @param buf
* ByteBuffer
* @return
* true表示是,false表示否
*/
private boolean checkUdp(ByteBuffer buf) {
if(buf.get(offset) == QQ.QQ_HEADER_BASIC_FAMILY) {
// 首先检查是否UDP方式
udp = true;
length = buf.limit() - buf.position();
if(buf.get(offset + length - 1) == QQ.QQ_TAIL_BASIC_FAMILY) {
getCommand(buf);
return true;
}
}
return false;
}
/**
* 检查一个包是否是tcp包
*
* @param buf
* ByteBuffer
* @return
* true表示是
*/
private boolean checkTcp(ByteBuffer buf) {
// buffer length不大于2则连个长度字段都没有
int bufferLength = buf.limit() - buf.position();
if(bufferLength < 2)
return false;
// 如果可读内容小于包长,则这个包还没收完
length = buf.getChar(offset);
if(length > bufferLength)
return false;
// 再检查包头包尾
if(buf.get(offset + 2) == QQ.QQ_HEADER_BASIC_FAMILY) {
udp = false;
if(buf.get(offset + length - 1) == QQ.QQ_TAIL_BASIC_FAMILY) {
getCommand(buf);
return true;
}
}
return false;
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.qq.packets.IParser#getLength()
*/
public int getLength() {
return length;
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.qq.packets.IParser#getHash(java.nio.ByteBuffer)
*/
public int getHash(ByteBuffer buf) {
return command | (sequence << 16);
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.qq.packets.IParser#isIncoming(java.nio.ByteBuffer)
*/
public boolean isIncoming(ByteBuffer buf) {
char source = udp ? buf.getChar(offset + 1) : buf.getChar(offset + 3);
return source != QQ.QQ_CLIENT;
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.qq.packets.IParser#isUdp(java.nio.ByteBuffer)
*/
public boolean isUdp(ByteBuffer buf) {
return udp;
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.qq.packets.IParser#parseIncoming(java.nio.ByteBuffer, int, edu.tsinghua.lumaqq.qq.beans.QQUser)
*/
public InPacket parseIncoming(ByteBuffer buf, int length, QQUser user) throws PacketParseException {
try {
switch(command) {
case QQ.QQ_CMD_REQUEST_LOGIN_TOKEN:
return new RequestLoginTokenReplyPacket(buf, length, user);
case QQ.QQ_CMD_KEEP_ALIVE:
return new KeepAliveReplyPacket(buf, length, user);
case QQ.QQ_CMD_MODIFY_INFO:
return new ModifyInfoReplyPacket(buf, length, user);
case QQ.QQ_CMD_SEARCH_USER:
return new SearchUserReplyPacket(buf, length, user);
case QQ.QQ_CMD_ADD_FRIEND:
return new AddFriendReplyPacket(buf, length, user);
case QQ.QQ_CMD_DELETE_FRIEND:
return new DeleteFriendReplyPacket(buf, length, user);
case QQ.QQ_CMD_REMOVE_SELF:
return new RemoveSelfReplyPacket(buf, length, user);
case QQ.QQ_CMD_ADD_FRIEND_AUTH:
return new AddFriendAuthReplyPacket(buf, length, user);
case QQ.QQ_CMD_GET_USER_INFO:
return new GetUserInfoReplyPacket(buf, length, user);
case QQ.QQ_CMD_CHANGE_STATUS:
return new ChangeStatusReplyPacket(buf, length, user);
case QQ.QQ_CMD_SEND_IM:
return new SendIMReplyPacket(buf, length, user);
case QQ.QQ_CMD_RECV_IM:
return new ReceiveIMPacket(buf, length, user);
case QQ.QQ_CMD_LOGIN:
return new LoginReplyPacket(buf, length, user);
case QQ.QQ_CMD_GET_FRIEND_LIST:
return new GetFriendListReplyPacket(buf, length, user);
case QQ.QQ_CMD_GET_FRIEND_ONLINE:
return new GetFriendOnlineReplyPacket(buf, length, user);
case QQ.QQ_CMD_RECV_MSG_SYS:
return new SystemNotificationPacket(buf, length, user);
case QQ.QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS:
return new FriendChangeStatusPacket(buf, length, user);
case QQ.QQ_CMD_UPLOAD_GROUP_FRIEND:
return new UploadGroupFriendReplyPacket(buf, length, user);
case QQ.QQ_CMD_DOWNLOAD_GROUP_FRIEND:
return new DownloadGroupFriendReplyPacket(buf, length, user);
case QQ.QQ_CMD_GROUP_DATA_OP:
return new GroupDataOpReplyPacket(buf, length, user);
case QQ.QQ_CMD_FRIEND_DATA_OP:
return new FriendDataOpReplyPacket(buf, length, user);
case QQ.QQ_CMD_CLUSTER_CMD:
return new ClusterCommandReplyPacket(buf, length, user);
case QQ.QQ_CMD_REQUEST_KEY:
return new RequestKeyReplyPacket(buf, length, user);
case QQ.QQ_CMD_SEND_SMS:
return new SendSMSReplyPacket(buf, length, user);
case QQ.QQ_CMD_ADVANCED_SEARCH:
return new AdvancedSearchUserReplyPacket(buf, length, user);
case QQ.QQ_CMD_CLUSTER_DATA_OP:
return new GetTempClusterOnlineMemberReplyPacket(buf, length, user);
default:
return new UnknownInPacket(buf, length, user);
}
} catch (PacketParseException e) {
// 如果解析失败,返回null
buf.position(offset);
return new UnknownInPacket(buf, length, user);
}
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.qq.packets.IParser#parseOutcoming(java.nio.ByteBuffer, int, edu.tsinghua.lumaqq.qq.beans.QQUser)
*/
public OutPacket parseOutcoming(ByteBuffer buf, int length, QQUser user) throws PacketParseException {
try {
switch(command) {
case QQ.QQ_CMD_REQUEST_LOGIN_TOKEN:
return new RequestLoginTokenPacket(buf, length, user);
case QQ.QQ_CMD_KEEP_ALIVE:
return new KeepAlivePacket(buf, length, user);
case QQ.QQ_CMD_MODIFY_INFO:
return new ModifyInfoPacket(buf, length, user);
case QQ.QQ_CMD_SEARCH_USER:
return new SearchUserPacket(buf, length, user);
case QQ.QQ_CMD_ADD_FRIEND:
return new AddFriendPacket(buf, length, user);
case QQ.QQ_CMD_DELETE_FRIEND:
return new DeleteFriendPacket(buf, length, user);
case QQ.QQ_CMD_REMOVE_SELF:
return new RemoveSelfPacket(buf, length, user);
case QQ.QQ_CMD_ADD_FRIEND_AUTH:
return new AddFriendAuthPacket(buf, length, user);
case QQ.QQ_CMD_GET_USER_INFO:
return new GetUserInfoPacket(buf, length, user);
case QQ.QQ_CMD_CHANGE_STATUS:
return new ChangeStatusPacket(buf, length, user);
case QQ.QQ_CMD_SEND_IM:
return new SendIMPacket(buf, length, user);
case QQ.QQ_CMD_RECV_IM:
return new ReceiveIMReplyPacket(buf, length, user);
case QQ.QQ_CMD_LOGIN:
return new LoginPacket(buf, length, user);
case QQ.QQ_CMD_GET_FRIEND_LIST:
return new GetFriendListPacket(buf, length, user);
case QQ.QQ_CMD_GET_FRIEND_ONLINE:
return new GetFriendOnlinePacket(buf, length, user);
case QQ.QQ_CMD_UPLOAD_GROUP_FRIEND:
return new UploadGroupFriendPacket(buf, length, user);
case QQ.QQ_CMD_DOWNLOAD_GROUP_FRIEND:
return new DownloadGroupFriendPacket(buf, length, user);
case QQ.QQ_CMD_GROUP_DATA_OP:
return new GroupDataOpPacket(buf, length, user);
case QQ.QQ_CMD_FRIEND_DATA_OP:
return new FriendDataOpPacket(buf, length, user);
case QQ.QQ_CMD_ADVANCED_SEARCH:
return new AdvancedSearchUserPacket(buf, length, user);
case QQ.QQ_CMD_CLUSTER_CMD:
return new ClusterCommandPacket(buf, length, user);
case QQ.QQ_CMD_REQUEST_KEY:
return new RequestKeyPacket(buf, length, user);
case QQ.QQ_CMD_LOGOUT:
return new LogoutPacket(buf, length, user);
case QQ.QQ_CMD_SEND_SMS:
return new SendSMSPacket(buf, length, user);
default:
return new UnknownOutPacket(buf, length, user);
}
} catch (PacketParseException e) {
// 如果解析失败,返回一个未知包
buf.position(offset);
return new UnknownOutPacket(buf, length, user);
}
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.qq.packets.IParser#isDuplicated(java.nio.ByteBuffer)
*/
public boolean isDuplicated(ByteBuffer buf) {
int hash = getHash(buf);
boolean duplicated = PacketMonitor.getInstance().check(new Integer(hash), true);
if(duplicated)
log.debug("包" + Util.getCommandString(command) + " 序号 " + (int)sequence + "重复到达,忽略");
return duplicated;
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.qq.packets.IParser#isDuplicatedNeedReply()
*/
public boolean isDuplicatedNeedReply() {
return command == QQ.QQ_CMD_RECV_IM;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -