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

📄 clusterimdelegate.java

📁 java写的qq代码实现qq的部分功能
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/*
* 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.ui;

import java.net.InetSocketAddress;

import edu.tsinghua.lumaqq.IconHolder;
import edu.tsinghua.lumaqq.LumaQQ;
import edu.tsinghua.lumaqq.qq.QQ;
import edu.tsinghua.lumaqq.qq.QQClient;
import edu.tsinghua.lumaqq.qq.Util;
import edu.tsinghua.lumaqq.qq.events.QQEvent;
import edu.tsinghua.lumaqq.qq.net.IPort;
import edu.tsinghua.lumaqq.qq.packets.ErrorPacket;
import edu.tsinghua.lumaqq.qq.packets.in.ClusterCommandReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in._05.RequestAgentReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in._05.RequestBeginReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in._05.TransferReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.out.ClusterCommandPacket;
import edu.tsinghua.lumaqq.ui.tool.IMOutParser;
import edu.tsinghua.lumaqq.ui.tool.FileSegmentor;
import edu.tsinghua.lumaqq.ui.tool.MessageIDGenerator;
import edu.tsinghua.lumaqq.utils.FaceUtil;
import edu.tsinghua.lumaqq.xml.faces.Face;

/**
 * 发送一条群消息的流程封装类。发送一条消息不是一个非常easy的过程,必须要判断多种情况,比如
 * 是否含有自定义表情,等等,不同的内容,需要的流程不一样
 * 
 * @author luma
 */
public class ClusterIMDelegate {
    private QQClient client;
    private String originalMessage;
    private String message;
    private int totalFragments;
    private int currentFragment;
    private char messageId;
    private IIMSender sender;
    
    // 用在自定义表情时
    private int sessionId;
    private int[] sessionIdArray;
    private InetSocketAddress agentAddress;
    private IPort port;
    
    private IMOutParser tool;
    
    // 当前发送第几个表情
    private int currentIndex;
    // 一共有几个表情,这个数目包含了重复的
    private int count;
    
    // 期待的请求中转服务器回复包的序号
    private char expectedSequence;
    
    /** 用来中转自定义表情的port名称,这个是缺省名称 */
    private String portName;
    
    /** 最多一次发送多少个自定义表情,这个值是QQ的限制,是否能超过这个限制,没试过 */
    private static final int MAX_CUSTOM_FACES = 20;
    
    // 临时变量,在每个表情发送时,这些变量会被初始化
    private int segmentCount;
    private int nextSegment;    
    private FileSegmentor segmentor;
    private int status;
    
    /** 表情还没开始发送 */
    private static final int BEFORE_SENDING = 0;
    /** 正在发送一个表情,这个表情还没发完 */
    private static final int SENDING_ONE = 1;
    /** 上次已经发完了一个表情 */
    private static final int JUST_FINISH = 2;
    
    public ClusterIMDelegate(QQClient client) {
        this.client = client;      
        tool = new IMOutParser();
        expectedSequence = 0;
    }
    
    /**
     * 开始一个消息发送流程
     */
    public void start() {
        if(originalMessage == null)
            return;
        
        // 对原始消息做预处理
        preprocess();
	    
	    // 通知发送开始
	    sender.notifyStart(originalMessage);   
	    // 执行相应的流程
	    if(tool.hasCustomFace())
	        doCustomFlow();
	    else
	        doNormalFlow();
    }
    
    /**
     * 发送结束
     */
    private void over() {
        resetVariables();
	    sender.notifyOver();
    }
    
    /**
     * 发送失败
     */
    private void fail(String msg) {
        resetVariables();
        sender.notifyFail(msg);
    }
    
    /**
     * 发送超时
     */
    private void timeout() {
        dispose();
        String temp = originalMessage;
        resetVariables();
        sender.notifyTimeout(temp);
    }
    
    /**
     * 重置某些状态变量
     */
    private void resetVariables() {
	    expectedSequence = 0;
	    currentIndex = 0;
        originalMessage = null;
    }
    
	/**
	 * 释放资源
	 */
	public void dispose() {
		if(port == null)
			return;
		
		client.disposePort(portName);
		port = null;
	}

	/**
	 * 发送下一个分片
	 * 
	 * @return
	 * 		true表示发送成功,false表示已经没有更多分片需要发送
	 */
	private boolean sendNextFragment() {
	    // 得到下一个要发送的分片
	    String fragment = getNextFragment();
	    if(fragment == null)
	        return false;
	    sender.send(fragment);
	    return true;
	}
    
    /**
     * 普通消息发送流程
     */
    private void doNormalFlow() {
        sendNextFragment();
    }
    
	/**
	 * @return
	 * 		下一个要发送的分片,如果为null,表示已经发送完成
	 */
	private String getNextFragment() {
	    if(++currentFragment == totalFragments)
	        return null;
	    
	    int start = QQ.MAX_SEND_IM_SIZE * currentFragment;
	    int end = QQ.MAX_SEND_IM_SIZE + start;
	    if(end > message.length())
	        end = message.length();
	    return message.substring(start, end);
	}

    /**
     * 自定义表情发送流程
     */
    private void doCustomFlow() {        
        if(tool.getDistinctFaceCount() > MAX_CUSTOM_FACES) {
            fail(LumaQQ.getString("text.too.more.faces"));
            return;
        }
        // 建立初始连接
        if(port == null)
            agentAddress = selectOriginalAgent(); 
        createPort();
        
        // 发送请求包
        sendRequestAgent();
    }
    
    /**
     * 创建一个到中转服务器的连接
     */
    private void createPort() {
        // 如果这个连接已经建立了,直接返回
        if(port != null)
            return;
        // 首先查询是否存在这样的连接,有则复用,无则创建
        port = client.getPort(agentAddress);
        if(port == null) {        
            try {
                portName = agentAddress.toString() + sender.getSenderId();
                port = client.installTCPPort(portName, agentAddress, true);
            } catch (Exception e) {
                // 失败,结束发送
                port = null;
                fail("Can't establish conection");
                return;
            }   
        } else {
            portName = port.getName();
            port.increaseReference();
        }
    }

    /**
     * 发送请求中转包,使用第一个自定义表情的相关信息
     */
    private void sendRequestAgent() {
        int id = tool.getId(currentIndex);
        FaceUtil util = FaceUtil.getInstance();
        Face face = util.getFace(id);
        byte[] md5 = Util.convertHexStringToByteNoSpace(face.getMd5());
        int imageLength = util.getFaceLength(face.getMd5());        
        expectedSequence = client.requestAgent(sender.getSenderId(), imageLength, md5, face.getFilename(), portName);
    }

    /**
     * 随机选择一个初始代理服务器
     * 
     * @return
     * 		初始代理服务器的地址
     */
    private InetSocketAddress selectOriginalAgent() {        
        String ip = QQ.GROUP_FILE_AGENT[Util.random().nextInt(QQ.GROUP_FILE_AGENT.length)];
        return new InetSocketAddress(ip, 443);
    }
    
    /**
     * 处理QQ事件
     * 
     * @param e
     */
    public void delegateQQEvent(QQEvent e) {
    	switch(e.type) {
    		case QQEvent.QQ_SEND_CLUSTER_IM_EX_SUCCESS:
    		case QQEvent.QQ_SEND_TEMP_CLUSTER_IM_SUCCESS:
    		    processSendIMSuccess(e);
    			break;
			case QQEvent.QQ_SEND_CLUSTER_IM_EX_FAIL:
			case QQEvent.QQ_SEND_TEMP_CLUSTER_IM_FAIL:
			    processSendIMFail(e);
				break;
			case QQEvent.QQ_REQUEST_AGENT_REDIRECT:
			    processRequestAgentRedirect(e);
				break;
			case QQEvent.QQ_REQUEST_AGENT_SUCCESS:
			    processRequestAgentOK(e);
				break;
			case QQEvent.QQ_REQUEST_AGENT_FAIL:
			    processRequestAgentFail(e);
				break;
			case QQEvent.QQ_REQUEST_BEGIN_SUCCESS:
			    processRequestBeginSuccess(e);
				break;
			case QQEvent.QQ_TRANSFER_FACE_SUCCESS:
			    processTransferFaceSuccess(e);
				break;
			case QQEvent.QQ_CONNECTION_BROKEN:
			    processConnectionBroken(e);
				break;
			case QQEvent.QQ_OPERATION_TIMEOUT:
			    switch(e.operation) {

⌨️ 快捷键说明

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