📄 basicfamilyprocessor.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;
/*
import static org.apache.commons.codec.digest.DigestUtils.md5;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.tsinghua.lumaqq.qq.beans.QQUser;
import edu.tsinghua.lumaqq.qq.events.IPacketListener;
import edu.tsinghua.lumaqq.qq.events.PacketEvent;
import edu.tsinghua.lumaqq.qq.events.QQEvent;
import edu.tsinghua.lumaqq.qq.packets.BasicInPacket;
import edu.tsinghua.lumaqq.qq.packets.ErrorPacket;
import edu.tsinghua.lumaqq.qq.packets.OutPacket;
import edu.tsinghua.lumaqq.qq.packets.PacketHistory;
import edu.tsinghua.lumaqq.qq.packets.PacketParseException;
import edu.tsinghua.lumaqq.qq.packets.in.AddFriendAuthReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.AddFriendExReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.AdvancedSearchUserReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.AuthorizeReplyPacket;
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.FriendLevelOpReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.GetFriendListReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.GetOnlineOpReplyPacket;
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.PrivacyDataOpReplyPacket;
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.SignatureOpReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.SystemNotificationPacket;
import edu.tsinghua.lumaqq.qq.packets.in.TempSessionOpReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.UnknownInPacket;
import edu.tsinghua.lumaqq.qq.packets.in.UploadGroupFriendReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.UserPropertyOpReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.WeatherOpReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.out.ClusterCommandPacket;
import edu.tsinghua.lumaqq.qq.packets.out.ModifyInfoPacket;
import edu.tsinghua.lumaqq.qq.packets.out.SendIMPacket;
*/
/**
* 这个类处理基本协议族包事件
*
* @author luma
*/
class BasicFamilyProcessor implements IPacketListener {
// Log对象
//static Log log = LogFactory.getLog(BasicFamilyProcessor.class);
// QQ客户端
private QQClient client;
// QQ用户,我们将在收到登陆包后设置user不为null,所以如果user为null意味着尚未登陆
private QQUser user;
// 检查重复包的类
private PacketHistory monitor;
public BasicFamilyProcessor(QQClient client) {
this.client = client;
this.user = null;
this.monitor = client.getHistory();
}
// 处理登陆应答
private void processLoginReply(BasicInPacket in) {
QQEvent e;
LoginReplyPacket packet = (LoginReplyPacket)in;
// 开始判断应答内容
switch(packet.replyCode) {
case QQ.QQ_REPLY_OK:
//log.debug("登陆成功,用户IP为: " + Util.getIpStringFromBytes(packet.ip) + " 端口: " + packet.port);
// 登陆成功的话我们就设置用户的一些信息,然后触发事件
user.setSessionKey(packet.sessionKey);
user.setIp(packet.ip);
user.setServerIp(packet.serverIp);
user.setLastLoginIp(packet.lastLoginIp);
user.setPort(packet.port);
user.setServerPort(packet.serverPort);
user.setLoginTime(packet.loginTime);
user.setLastLoginTime(packet.lastLoginTime);
user.setClientKey(packet.clientKey);
// 得到文件传输密钥
byte[] b = new byte[4 + QQ.QQ_LENGTH_KEY];
b[0] = (byte)((user.getQQ() >>> 24) & 0xFF);
b[1] = (byte)((user.getQQ() >>> 16) & 0xFF);
b[2] = (byte)((user.getQQ() >>> 8) & 0xFF);
b[3] = (byte)(user.getQQ() & 0xFF);
System.arraycopy(user.getSessionKey(), 0, b, 4, QQ.QQ_LENGTH_KEY);
//user.setFileSessionKey(md5(b));
user.setFileSessionKey(Util.md5(b));
// 触发事件
e = new QQEvent(packet);
e.type = QQEvent.QQ_LOGIN_SUCCESS;
client.fireQQEvent(e);
break;
case QQ.QQ_REPLY_LOGIN_PASSWORD_ERROR:
//log.debug("用户密码错误,错误信息: " + packet.replyMessage);
// 如果是密码错误,触发事件
e = new QQEvent(packet);
e.type = QQEvent.QQ_LOGIN_PASSWORD_ERROR;
client.fireQQEvent(e);
break;
case QQ.QQ_REPLY_LOGIN_REDIRECT:
//log.debug("登陆重定向");
if(Util.isIpZero(packet.redirectIp)) {
//log.debug("地址重定向到0,随机选取其他服务器再登录");
e = new QQEvent(packet);
e.type = QQEvent.QQ_LOGIN_REDIRECT_NULL;
client.fireQQEvent(e);
} else {
// 如果是登陆重定向,继续登陆
client.setLoginRedirect(true);
try {
client.login(Util.getIpStringFromBytes(packet.redirectIp), packet.redirectPort);
} catch (Exception e1) {
//log.error(e1.getMessage());
}
}
break;
default:
//log.debug("未知登陆错误");
// 如果是其他未知错误,触发事件
e = new QQEvent(packet);
e.type = QQEvent.QQ_LOGIN_UNKNOWN_ERROR;
client.fireQQEvent(e);
break;
}
}
/**
* 判断包是否时登录前可以出现的包,有些包是在登录前可以处理的,如果不是,应该缓存起来等
* 到登录成功后再处理,不过但是在实际中观察发现,登录之前收到的东西基本没用,可以不管
*
* @param cmd
* @return
*/
private boolean isPreLoginPacket(BasicInPacket in) {
switch(in.getCommand()) {
case QQ.QQ_CMD_REQUEST_LOGIN_TOKEN:
case QQ.QQ_CMD_LOGIN:
return true;
case QQ.QQ_CMD_UNKNOWN:
return in instanceof ErrorPacket;
default:
return false;
}
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.protocol.qq.PacketListener#packetArrived(edu.tsinghua.lumaqq.protocol.qq.PacketEvent)
*/
public void packetArrived(PacketEvent e) {
BasicInPacket in = (BasicInPacket) e.getSource();
if(in instanceof UnknownInPacket) {
//log.debug("收到一个未知格式包");
return;
}
// 显示调试信息
/* if(in instanceof ErrorPacket)
//log.debug("开始处理错误通知包,错误类型:" + Util.getErrorString(((ErrorPacket)in).errorCode));
System.err.println("开始处理错误通知包,错误类型:" + Util.getErrorString(((ErrorPacket)in).errorCode));
else
//log.debug("开始处理" + in.toString());
System.err.println("开始处理" + in.toString());
*/
// 检查目前是否已经登录
if(user == null || !user.isLoggedIn()) {
/*
* 按理说应该把在登陆之前时收到的包缓存起来,但是在实际中观察发现,登录之前收到的
* 东西基本没用,所以在这里不做任何事情,简单的抛弃这个包
*/
if(!isPreLoginPacket(in))
return;
}
// 这里检查是不是服务器发回的确认包
// 为什么要检查这个呢,因为有些包是服务器主动发出的,对于这些包我们是不需要
// 从超时发送队列中移除的,如果是服务器的确认包,那么我们就需要把超时发送队列
// 中包移除
switch (in.getCommand()) {
// 这三种包是服务器先发出的,我们要确认
case QQ.QQ_CMD_RECV_IM:
case QQ.QQ_CMD_RECV_MSG_SYS:
case QQ.QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS:
break;
// 其他情况我们删除超时队列中的包
default:
client.removeResendPacket(in);
//log.debug("包" + (int)in.getSequence() + "的确认已经收到,将不再发送");
break;
}
// 现在开始判断包的类型,作出相应的处理
switch (in.getCommand()) {
case QQ.QQ_CMD_REQUEST_LOGIN_TOKEN:
this.user = client.getUser();
processRequestLoginTokenReply(in);
break;
case QQ.QQ_CMD_KEEP_ALIVE:
processKeepAliveReply(in);
break;
case QQ.QQ_CMD_MODIFY_INFO:
processModifyInfoReply(in);
break;
case QQ.QQ_CMD_SEARCH_USER:
processSearchUserReply(in);
break;
case QQ.QQ_CMD_ADD_FRIEND_EX:
processAddFriendExReply(in);
break;
case QQ.QQ_CMD_DELETE_FRIEND:
processDeleteFriendReply(in);
break;
case QQ.QQ_CMD_REMOVE_SELF:
processRemoveSelfReply(in);
break;
case QQ.QQ_CMD_ADD_FRIEND_AUTH:
processAddFriendAuthReply(in);
break;
case QQ.QQ_CMD_GET_USER_INFO:
processGetUserInfoReply(in);
break;
case QQ.QQ_CMD_CHANGE_STATUS:
processChangeStatusReply(in);
break;
case QQ.QQ_CMD_SEND_IM:
processSendIMReply(in);
break;
case QQ.QQ_CMD_RECV_IM:
processReceiveIM(in);
break;
case QQ.QQ_CMD_SEND_SMS:
processSendSMSReply(in);
break;
case QQ.QQ_CMD_LOGIN:
processLoginReply(in);
break;
case QQ.QQ_CMD_GET_FRIEND_LIST:
processGetFriendListReply(in);
break;
case QQ.QQ_CMD_GET_ONLINE_OP:
processGetFriendOnlineReply(in);
break;
case QQ.QQ_CMD_RECV_MSG_SYS:
processSystemNotification(in);
break;
case QQ.QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS:
processFriendChangeStatus(in);
break;
case QQ.QQ_CMD_UPLOAD_GROUP_FRIEND:
processUploadGroupFriendReply(in);
break;
case QQ.QQ_CMD_DOWNLOAD_GROUP_FRIEND:
processDownloadGroupFriendReply(in);
break;
case QQ.QQ_CMD_GROUP_DATA_OP:
processGroupNameOpReply(in);
break;
case QQ.QQ_CMD_FRIEND_DATA_OP:
processFriendDataOpReply(in);
break;
case QQ.QQ_CMD_CLUSTER_CMD:
processClusterCommandReply(in);
break;
case QQ.QQ_CMD_REQUEST_KEY:
processRequestKeyReply(in);
break;
case QQ.QQ_CMD_ADVANCED_SEARCH:
processAdvancedSearchReply(in);
break;
case QQ.QQ_CMD_AUTHORIZE:
processAuthorizeReply(in);
break;
case QQ.QQ_CMD_SIGNATURE_OP:
processSignatureOpReply(in);
break;
case QQ.QQ_CMD_USER_PROPERTY_OP:
processUserPropertyOpReply(in);
break;
case QQ.QQ_CMD_FRIEND_LEVEL_OP:
processFriendLevelOpReply(in);
break;
case QQ.QQ_CMD_WEATHER_OP:
processWeatherOpReply(in);
break;
case QQ.QQ_CMD_TEMP_SESSION_OP:
processTempSessionOpReply(in);
break;
case QQ.QQ_CMD_PRIVACY_DATA_OP:
processPrivacyDataOpReply(in);
break;
case QQ.QQ_CMD_UNKNOWN:
processUnknown(in);
break;
default:
break;
}
}
/**
* 处理隐私选项操作回复包
*
* @param in
*/
private void processPrivacyDataOpReply(BasicInPacket in) {
QQEvent e;
PrivacyDataOpReplyPacket packet = (PrivacyDataOpReplyPacket)in;
switch(packet.replyCode) {
case QQ.QQ_REPLY_OK:
e = new QQEvent(packet);
e.type = QQEvent.QQ_PRIVACY_DATA_OP_SUCCESS;
client.fireQQEvent(e);
break;
default:
e = new QQEvent(packet);
e.type = QQEvent.QQ_PRIVACY_DATA_OP_FAIL;
client.fireQQEvent(e);
break;
}
}
/**
* 处理临时会话回复包
*
* @param in
*/
private void processTempSessionOpReply(BasicInPacket in) {
QQEvent e;
TempSessionOpReplyPacket packet = (TempSessionOpReplyPacket)in;
switch(packet.replyCode) {
case QQ.QQ_REPLY_OK:
case QQ.QQ_REPLY_MAYBE_OFFLINE:
e = new QQEvent(packet);
e.type = QQEvent.QQ_SEND_TEMP_SESSOIN_IM_SUCCESS;
client.fireQQEvent(e);
break;
default:
e = new QQEvent(packet);
e.type = QQEvent.QQ_SEND_TEMP_SESSION_IM_FAIL;
client.fireQQEvent(e);
break;
}
}
/**
* 处理天气预报操作回复包
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -