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

📄 basicfamilyprocessor.java

📁 MilyQQ是一个使用控制台的QQ客户端,基于LumaQQ的核心JQL包开发,只有一个可执行的jar包(MilyQQ.jar),携带方便,由于是Java程序,因此理论上应该可以运行于所有平台,不过基于
💻 JAVA
📖 第 1 页 / 共 5 页
字号:
/*
* 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 + -