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

📄 basicfamilyprocessor.java

📁 java写的qq代码实现qq的部分功能
💻 JAVA
📖 第 1 页 / 共 4 页
字号:
/*
* 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 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.net.PacketMonitor;
import edu.tsinghua.lumaqq.qq.packets.BasicInPacket;
import edu.tsinghua.lumaqq.qq.packets.ErrorPacket;
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.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.ClusterCommandPacket;
import edu.tsinghua.lumaqq.qq.packets.out.ModifyInfoPacket;
import edu.tsinghua.lumaqq.qq.packets.out.SendIMPacket;


/**
 * 这个类处理基本协议族包事件
 *
 * @author 马若劼
 */
class BasicFamilyProcessor implements IPacketListener {
    // Log对象
    static Log log = LogFactory.getLog(BasicFamilyProcessor.class);

    // QQ客户端
    private QQClient client;
    // QQ用户,我们将在收到登陆包后设置user不为null,所以如果user为null意味着尚未登陆
    private QQUser user;
    // 收到的包计数,注意这个是没有冲突的包的计数,所以超过65535就清0
    private int total;  
    // 检查重复包的类
    private PacketMonitor monitor;

    private static int i = 0;
    
    public BasicFamilyProcessor(QQClient client) {
        this.client = client;
        this.user = null;
        this.total = 0;        
        this.monitor = PacketMonitor.getInstance();
    }    
    
    // 处理登陆应答
    private void processLoginReply(BasicInPacket in) {
    	QQEvent e;
    	LoginReplyPacket packet = (LoginReplyPacket)in;
    	// 开始判断应答内容
    	switch(packet.replyCode) {
    		case QQ.QQ_LOGIN_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_KEY_LENGTH];
    		    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_KEY_LENGTH);
    		    user.setFileSessionKey(Util.doMD5(b));
    		    // 触发事件 
    			e = new QQEvent(packet);
    			e.type = QQEvent.QQ_LOGIN_SUCCESS;
    			client.fireQQEvent(e);
    			break;
    		case QQ.QQ_LOGIN_REPLY_PASSWORD_ERROR:
    			log.debug("用户密码错误,错误信息: " + packet.replyMessage);
    			// 如果是密码错误,触发事件    			
    			e = new QQEvent(packet);
    			e.type = QQEvent.QQ_LOGIN_PASSWORD_ERROR;
    			client.fireQQEvent(e);
    			break;
    		case QQ.QQ_LOGIN_REPLY_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;
    	}
    }

    /* (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;
        }
        
        log.debug("开始处理" + in.toString());
        
        // 检查是否是在登陆之前收到的包,如果是,推迟处理该包
        if(in.getSource() != QQ.QQ_SERVER_0000 && 
                in.getCommand() != QQ.QQ_CMD_LOGIN && 
                (user == null || !user.isLoggedIn())) {
            /*
             * 按理说应该把在登陆之前时收到的包缓存起来,但是在实际中观察发现,登录之前收到的
             * 东西基本没用,所以在这里不做任何事情,简单的抛弃这个包
             */
        	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:
        	    processAddFriendReply(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_LOGIN:
        		processLoginReply(in);
        		break;
        	case QQ.QQ_CMD_GET_FRIEND_LIST:
        		processGetFriendListReply(in);
        		break;
        	case QQ.QQ_CMD_GET_FRIEND_ONLINE:
        		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_SEND_SMS:
        	    processSendSMSReply(in);
        		break;
        	case QQ.QQ_CMD_ADVANCED_SEARCH:
        	    processAdvancedSearchReply(in);
        		break;
        	case QQ.QQ_CMD_UNKNOWN:
        	    processUnknown(in);
        		break;
        	default:
        		break;
        }        	
    }

    /**
     * 处理未知命令包,有些和协议无关的包也使用这个命令,比如ErrorPacket
     * 
     * @param in
     */
    private void processUnknown(BasicInPacket in) {
        QQEvent e;
        if(in instanceof ErrorPacket) {
            ErrorPacket packet = (ErrorPacket)in;
            switch(packet.errorCode) {
                case ErrorPacket.ERROR_REMOTE_CLOSED:
                    e = new QQEvent(packet);
                	e.type = QQEvent.QQ_CONNECTION_BROKEN;
                	client.fireQQEvent(e);
                	break;
            }
        }
    }

    /**
     * 处理高级搜索的回复包
     * 
     * @param in
     */
    private void processAdvancedSearchReply(BasicInPacket in) {
        QQEvent e;
        AdvancedSearchUserReplyPacket packet = (AdvancedSearchUserReplyPacket)in;
        
        if(packet.replyCode == QQ.QQ_ADVANCED_SEARCH_REPLY_OK && !packet.finished) {
            log.debug("高级搜索成功");
            e = new QQEvent(packet);
            e.type = QQEvent.QQ_ADVANCED_SEARCH_USER_SUCCESS;
            client.fireQQEvent(e);
        } else if(packet.replyCode == QQ.QQ_ADVANCED_SEARCH_REPLY_END || packet.finished) {
            log.debug("高级搜索完毕");
            e = new QQEvent(packet);
            e.type = QQEvent.QQ_ADVANCED_SEARCH_USER_END;
            client.fireQQEvent(e);
        } else
            log.debug("高级搜索返回未知回复码");
    }

    /**
     * 处理请求登录令牌的回复包
     * 
     * @param in
     */
    private void processRequestLoginTokenReply(BasicInPacket in) {
        QQEvent e;
        RequestLoginTokenReplyPacket packet = (RequestLoginTokenReplyPacket)in;
        
        if(packet.replyCode == QQ.QQ_REQUEST_LOGIN_TOKEN_REPLY_OK) {
            log.debug("得到登录令牌成功");
            user.setLoginToken(packet.loginToken);
            e = new QQEvent(packet);
            e.type = QQEvent.QQ_GET_LOGIN_TOKEN_SUCCESS;
            client.fireQQEvent(e);
        } else {
            log.debug("得到登录令牌失败");
            e = new QQEvent(packet);
            e.type = QQEvent.QQ_GET_LOGIN_TOKEN_FAIL;
            client.fireQQEvent(e);
        }
    }

    /**
     * 处理发送短消息的回复包
     * @param in
     */
    private void processSendSMSReply(BasicInPacket in) {
        QQEvent e;
        SendSMSReplyPacket packet = (SendSMSReplyPacket)in;
        
        if(packet.toBindUser) {
	        switch(packet.replyCode_1) {
	            case QQ.QQ_SMS_REPLY_OK_1:
	                log.debug("短消息发送成功");
	            	e = new QQEvent(packet);
	            	e.type = QQEvent.QQ_SEND_SMS_SUCCESS;
	            	client.fireQQEvent(e);

⌨️ 快捷键说明

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