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

📄 clustersendimexpacket.java

📁 java写的qq代码实现qq的部分功能
💻 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.out;

import java.io.UnsupportedEncodingException;
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;

/**
 * 扩展固定群消息发送包,相对于已经有的固定群消息发送包来说,这个多了一些标志,
 * 同时旧的群消息发送包为了兼容性的考虑TX依然保留:
 * 1.  头部
 * 2.  子命令,1字节,0x1A
 * 3.  群内部ID,4字节
 * 4.  后面的数据的总长度,2字节
 * 5.  Content Type, 2字节,0x0001表示纯文件,0x0002表示有自定义表情
 * 6.  消息分片数,1字节。群消息分片也是最大700字节,但是这个和普通消息不一样的是:这个700包含了这些控制信息
 * 7.  分片序号,1字节,从0开始
 * 8.  消息id,2字节,同一条消息的不同分片id相同
 * 9.  4字节,未知
 * 10. 消息内容
 * 11. 空格和0x00
 * 12. 消息的尾部,包含一些消息的参数,比如字体颜色啦,等等等等,顺序是
 *     1. 字体修饰属性,bold,italic之类的,1字节,具体的设置是
 *         i.   bit0-bit4用来表示字体大小,所以最大是32
 *         ii.  bit5表示是否bold
 *         iii. bit6表示是否italic
 *         iv.  bit7表示是否underline
 *     2. 颜色Red,1字节
 *     3. 颜色Green,1字节
 *     4. 颜色Blue,1字节
 *     5. 1个未知字节,置0先
 *     6. 消息编码,2字节,0x8602为GB,0x0000为EN,其他未知,好像可以自定义,因为服务器好像不干涉
 *     7. 可变长度的一段信息,字体名后面跟一个回车符,比如0xcb, 0xce, 0xcc, 0xe5,表示宋体
 * 13. 1字节,表示11和12部分的字节长度
 * 14. 尾部 
 * 
 * 注意:只有最后一个分片有11, 12, 13部分
 * 
 * @author luma
 */
public class ClusterSendIMExPacket extends ClusterSendIMPacket {
    protected int totalFragments;
    protected int fragmentSequence;
    protected char messageId;
    
    /**
     * @param user
     */
    public ClusterSendIMExPacket(QQUser user) {
        super(user);
        subCommand = QQ.QQ_CLUSTER_CMD_SEND_IM_EX;
        totalFragments = 1;
        fragmentSequence = 0;
        messageId = (char)Util.random().nextInt();
    }

    /**
     * @param buf
     * @param length
     * @param user
     * @throws PacketParseException
     */
    public ClusterSendIMExPacket(ByteBuffer buf, int length, QQUser user)
            throws PacketParseException {
        super(buf, length, user);
    }
    
    /* (non-Javadoc)
     * @see edu.tsinghua.lumaqq.qq.packets.out.ClusterSendIMPacket#getPacketName()
     */
    public String getPacketName() {
        return "Cluster Send IM Ex Packet";
    }
    
    /* (non-Javadoc)
     * @see edu.tsinghua.lumaqq.qq.packets.OutPacket#putBody(java.nio.ByteBuffer)
     */
    protected void putBody(ByteBuffer buf) {
		// 命令类型
		buf.put(subCommand);
		// 群内部ID
		buf.putInt(clusterId);
	    // 后面数据的长度,这个长度需要根据后面的长度计算才能知道,
		// 所以先占个位置		
		int pos = buf.position();
		buf.putChar((char)0);
		// 未知的2字节
		buf.putChar((char)1);
		// 分片数
		buf.put((byte)totalFragments);
		// 分片序号
		buf.put((byte)fragmentSequence);
		// 消息id
		buf.putChar(messageId);
		// 未知4字节
		buf.putInt(0);
	    // 以0结束的消息,首先我们要根据用户设置的message,解析出一个网络可发送的格式
	    // 这一步比较麻烦,暂时想不到好的办法
		byte[] msgBytes = null;
	    int j, i = 0;
	    while((j = message.indexOf((char)QQ.QQ_DEFAULT_FACE_TAG, i)) != -1) {
	    	String sub = message.substring(i, j);
	    	if(!sub.equals("")) {
	    	    msgBytes = Util.getBytes(sub);
			    buf.put(msgBytes);
	    	}
		    buf.put(QQ.QQ_DEFAULT_FACE_TAG);
		    buf.put((byte)(message.charAt(j + 1) & 0xFF));
		    i = j + 2;
	    }
	    if(i < message.length()) {
	    	String sub = message.substring(i);
	    	msgBytes = Util.getBytes(sub);		
		    buf.put(msgBytes);	    	
	    }
	    
		// 只有最后一个分片有后面的部分
		if(fragmentSequence == totalFragments - 1) {
		    // 得到字体名称字节数组
		    byte[] fontBytes;
	        try {
	            fontBytes = fontName.getBytes(QQ.QQ_CHARSET_DEFAULT);
	        } catch (UnsupportedEncodingException e) {
	            fontBytes = SIMSUN;
	        }
	        // 写入长度
		    int cur = buf.position();
		    buf.position(pos);
		    buf.putChar((char)(cur - pos - 2 + fontBytes.length + 10));
		    buf.position(cur);
		    // 空格
	        buf.put((byte)0x20); 
		    buf.put((byte)0);
		    // 消息尾部,字体修饰属性
		    buf.put(fontFlag);
		    // 字体颜色红绿篮
		    buf.put(red);
		    buf.put(green);
		    buf.put(blue);
		    // 一个未知字节
		    buf.put((byte)0);
		    // 消息编码
		    buf.putChar(encoding);
		    // 字体
		    buf.put(fontBytes);
		    // 长度
		    buf.put((byte)(fontBytes.length + 9));  	    
		} else {
	        // 写入长度
		    int cur = buf.position();
		    buf.position(pos);
		    buf.putChar((char)(cur - pos - 2));
		    buf.position(cur);
		}
    }

    /**
     * @return Returns the fragmentSequence.
     */
    public int getFragmentSequence() {
        return fragmentSequence;
    }
    /**
     * @param fragmentSequence The fragmentSequence to set.
     */
    public void setFragmentSequence(int fragmentSequence) {
        this.fragmentSequence = fragmentSequence;
    }
    /**
     * @return Returns the totalFragments.
     */
    public int getTotalFragments() {
        return totalFragments;
    }
    /**
     * @param totalFragments The totalFragments to set.
     */
    public void setTotalFragments(int totalFragments) {
        this.totalFragments = totalFragments;
    }
    /**
     * @return Returns the messageId.
     */
    public char getMessageId() {
        return messageId;
    }
    /**
     * @param messageId The messageId to set.
     */
    public void setMessageId(char messageId) {
        this.messageId = messageId;
    }
}

⌨️ 快捷键说明

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