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

📄 qqclient.java

📁 MilyQQ是一个使用控制台的QQ客户端,基于LumaQQ的核心JQL包开发,只有一个可执行的jar包(MilyQQ.jar),携带方便,由于是Java程序,因此理论上应该可以运行于所有平台,不过基于
💻 JAVA
📖 第 1 页 / 共 5 页
字号:
    private synchronized void setListenerChanged(boolean b) {
    	listenerChanged = b;
    }

    /**
     * 得到listener changed标志
     *
     * @return
     * 		true表示有新的listener添加了进来
     */
    private synchronized boolean isListenerChanged() {
    	return listenerChanged;
    }

    /**
     * 检查监听器是否已经改变,如果是则更新监听器
     */
    private synchronized void checkListenerChange() {
    	if(isListenerChanged()) {
    		qqListenersBackup.clear();
    		qqListenersBackup.addAll(qqListeners);
    		setListenerChanged(false);
    	}
    }

    /**
     * 触发QQ事件
     * @param e QQEvent
     */
    public void fireQQEvent(QQEvent e) {
    	checkListenerChange();
		int size = qqListenersBackup.size();
		for(int i = 0; i < size; i++)
			qqListenersBackup.get(i).qqEvent(e);
    }

    /**
     * 登陆,使用缺省端口
     *
     * @throws Exception
     * 				如果登录出错
     */
    public void login() throws Exception {
        if (user != null && !logging && loginServer != null) {
	        // 登陆
            if(user.isUdp())
                login(loginServer, QQ.QQ_PORT_UDP);
            else
                login(loginServer, tcpLoginPort);
       }
    }

    /**
     * 用指定的服务器和端口登录
     *
     * @param server 登陆服务器
     * @param p 登陆端口
     * @throws Exception
     * 				如果登录出错
     */
    protected void login(String server, int p) throws Exception {
        // 检查是否设置了用户名和密码
        if (user != null) {
        	// 停止以前的线程,如果有的话
        	logout();
        	// 创建Selector
    	    porter = new Porter();
    	    // 创建端口管理器
    	    gate = new PortGate(this, porter);
        	// 设置状态为正在登陆
        	logging = true;
            // 检查是什么登陆模式,udp还是tcp
            try {
                IPort port = null;
	            if (user.isUdp()) {
	                //log.debug("使用UDP服务器: " + server + " 端口:" + p);
	                // 创建端口类
	                if(proxyType == QQ.QQ_PROXY_SOCKS5) {
	                    //log.debug("使用Socks 5代理 " + proxyAddress);
		                port = installUDPSocks5Port(MAIN_PORT, proxyAddress, new InetSocketAddress(server, p), proxyUsername, proxyPassword, false);
	                } else
	                    port = installUDPPort(MAIN_PORT, new InetSocketAddress(server, p), false);
	            } else {
                    //log.debug("使用TCP服务器: " + server + " 端口: " + p);
                    // 创建发送类和接收类
                    if(proxyType == QQ.QQ_PROXY_SOCKS5) {
                        //log.debug("使用Socks 5代理 " + proxyAddress);
                        port = installTCPSocks5Port(MAIN_PORT, proxyAddress, new InetSocketAddress(server, p), proxyUsername, proxyPassword, false);
                    } else if(proxyType == QQ.QQ_PROXY_HTTP) {
                        //log.debug("使用HTTP代理 " + proxyAddress);
                        port = installTCPHttpPort(MAIN_PORT, proxyAddress, new InetSocketAddress(server, p), proxyUsername, proxyPassword, false);
                    } else
                        port = installTCPPort(MAIN_PORT, new InetSocketAddress(server, p), false);
                }

                // 如果登录令牌还是空,就构造请求登录令牌包,如果不是,直接登录
                OutPacket packet = null;
                if(user.getLoginToken() == null)
                    packet = new RequestLoginTokenPacket(user);
                else
                    packet = new LoginPacket(user);
                // 启动端口
            	porter.start();
            	port.start();
                // 发送请求包
                gate.send(MAIN_PORT, packet, false);
            } catch (UnknownHostException e) {
                throw new Exception("服务器名称无法解析");
            } catch (UnresolvedAddressException e) {
			    throw new Exception("无法解析服务器地址");
			} catch (Exception e) {
			    throw e;
			}
        }
    }

    /**
     * 退出QQ会话
     */
    public void logout() {
        // 得到当前登录状态
        boolean isLoggedIn = user.isLoggedIn();
	    // 设置用户状态
    	if(!loginRedirect)
	    	user.setLoginToken(null);
    	user.setLoggedIn(false);
    	// 设置正在登录标志为false
    	logging = false;
    	loginRedirect = false;

    	if(gate != null) {
	    	if(gate.hasPort(MAIN_PORT)) {
		    	// 清空发送队列
		    	gate.clearSendQueue(MAIN_PORT);
		    	// 如果已经登录了,则发送logout包
		    	if(isLoggedIn) {
			    	LogoutPacket packet = new LogoutPacket(user);
				//发4次
				for(int i=0;i<4;i++)
					gate.send(MAIN_PORT, packet, false);
		    	}
	    	}
	    	// 清空包监视缓冲
            gate.clearMonitorCache();
    	}
    	// 执行清理工作
    	if(keepAliveFuture != null) {
    		keepAliveFuture.cancel(false);
    		keepAliveFuture = null;
    	}
    	resendTrigger.clear();
    	clean(gate, porter);
    	gate = null;
    	porter = null;
    }

    /**
     * 释放这个QQClient,如果不继续使用QQClient,则必须释放此客户端以便
     * SingleExecutor释放资源
     */
    public void release() {
    	executor.decreaseClient();
    }

    /**
     * 处理Keep Alive成功信息,对Keep Alive Success,QQClient不作什么
     * 进一步的分析,只是顺便刷新一下好友状态
     *
     * @param e
     */
    private void processKeepAliveSuccess(QQEvent e) {
        GetOnlineOpPacket packet = new GetOnlineOpPacket(user);
        sendPacket(packet);
    }

	/**
	 * 处理登陆成功事件
	 */
	private void processLoginSuccess() {
	    if(!user.isLoggedIn()) {
			user.setLoggedIn(true);
			this.logging = false;
			// 请求密钥
			//requestKey(QQ.QQ_REQUEST_UNKNOWN_KEY);
			//requestKey(QQ.QQ_REQUEST_FILE_AGENT_KEY);
			// 得到我的信息
			GetUserInfoPacket guiPacket = new GetUserInfoPacket(user);
			sendPacket(guiPacket);
			// 手动更改我的在线状态,虽然服务器可能也会给我发送这样的信息
			ChangeStatusPacket csPacket = new ChangeStatusPacket(user);
			csPacket.setShowFakeCam(user.isShowFakeCam());
			sendPacket(csPacket);
			// 调度keep alive动作
			keepAliveFuture = executor.scheduleWithFixedDelay(keepAliveTrigger, QQ.QQ_INTERVAL_KEEP_ALIVE, QQ.QQ_INTERVAL_KEEP_ALIVE, TimeUnit.MILLISECONDS);
	    }
	}

    /**
     * 处理普通消息事件,只是发一个确认而已
     *
     * @param e
     */
    private void processReceiveIM(QQEvent e) {
        // 得到包
        ReceiveIMPacket packet = (ReceiveIMPacket)e.getSource();

        // 生成确认包
        ReceiveIMReplyPacket reply = new ReceiveIMReplyPacket(packet.reply, user);
        reply.setSequence(packet.getSequence());
		gate.send(MAIN_PORT, reply, false);
    }

	/* (non-Javadoc)
	 * @see edu.tsinghua.lumaqq.QQListener#qqEvent(edu.tsinghua.lumaqq.QQEvent)
	 */
	public void qqEvent(QQEvent e) {
		switch(e.type) {
		    case QQEvent.QQ_GET_LOGIN_TOKEN_SUCCESS:
		        processGetLoginTokenSuccess();
		    	break;
		    case QQEvent.QQ_GET_LOGIN_TOKEN_FAIL:
		        //processGetLoginTokenFail();
		    	break;
			case QQEvent.QQ_LOGIN_SUCCESS:
				processLoginSuccess();
				break;
			case QQEvent.QQ_KEEP_ALIVE_SUCCESS:
			    processKeepAliveSuccess(e);
				break;
			case QQEvent.QQ_RECEIVE_NORMAL_IM:
				processNormalIM(e);
				break;
			case QQEvent.QQ_KICKED_OUT_BY_SYSTEM:
			case QQEvent.QQ_RECEIVE_CLUSTER_IM:
			case QQEvent.QQ_RECEIVE_TEMP_CLUSTER_IM:
			case QQEvent.QQ_RECEIVE_UNKNOWN_CLUSTER_IM:
			case QQEvent.QQ_REQUEST_SEND_FILE:
			case QQEvent.QQ_ACCEPT_SEND_FILE:
			case QQEvent.QQ_REJECT_SEND_FILE:
			case QQEvent.QQ_CANCEL_SEND_FILE:
			case QQEvent.QQ_NOTIFY_FILE_TRANSFER_ARGS:
			case QQEvent.QQ_REQUEST_ME_CONNECT:
			case QQEvent.QQ_UNKNOWN_TYPE_IM:
			case QQEvent.QQ_REQUEST_JOIN_CLUSTER:
			case QQEvent.QQ_REQUEST_JOIN_CLUSTER_APPROVED:
			case QQEvent.QQ_REQUEST_JOIN_CLUSTER_REJECTED:
			case QQEvent.QQ_I_AM_ADDED_TO_CLUSTER:
			case QQEvent.QQ_I_AM_REMOVED_FROM_CLUSTER:
			case QQEvent.QQ_RECEIVE_DUPLICATED_IM:
			case QQEvent.QQ_ADMIN_ENTITLED:
			case QQEvent.QQ_ADMIN_WITHDRAWED:
			case QQEvent.QQ_FRIEND_SIGNATURE_CHANGED:
			case QQEvent.QQ_RECEIVE_SMS:
			case QQEvent.QQ_RECEIVE_TEMP_SESSION_IM:
			    processReceiveIM(e);
				break;
			case QQEvent.QQ_OPERATION_TIMEOUT:
			    switch(e.operation) {
			        case QQ.QQ_CMD_LOGIN:
			        case QQ.QQ_CMD_REQUEST_LOGIN_TOKEN:
						processLoginTimeout();
			        	break;
			    }
				break;
			case QQEvent.QQ_CONNECTION_LOST:
				processConnectionLost();
				break;
		}
	}

    /**
	 * 处理请求登录令牌成功事件
     */
    private void processGetLoginTokenSuccess() {
        LoginPacket packet = new LoginPacket(user);
		gate.send(MAIN_PORT, packet, false);
    }

    /**
	 * 处理普通消息事件,核心层的处理是检查机器人设置,如果机器人打开了,则自动返回消息
	 *
	 * @param e
	 * 		QQEvent
	 */
	private void processNormalIM(QQEvent e) {
		// 先返回确认
		processReceiveIM(e);

		// 得到消息包
		ReceiveIMPacket packet = (ReceiveIMPacket)e.getSource();
		doRobot(packet);
	}

	/**
	 * 检查机器人设置,如果机器人打开了,发送一条机器人消息
	 *
	 * @param packet
	 * 		接受消息包
	 * @param receiver
	 * 		接收者
	 */
	private void doRobot(ReceiveIMPacket packet) {
		// 检查机器人设置
		if(isRobotMode()) {
			if(robot != null) {
			    String reply = robot.getReply(packet);
			    if(reply != null)
			        sendIM(packet.header.sender, reply);
			}
		}
	}

	/**
	 * 处理连接丢失事件
	 */
	private void processConnectionLost() {
		user.setLoggedIn(false);
		logout();
	}

	/**
	 * 处理登陆超时事件
	 */
	private void processLoginTimeout() {
		logging = false;
		logout();
	}

	/**
	 * 发送临时会话消息
	 *
	 * @param receiver
	 * @param message
	 */
	public void sendTempSessionIM(int receiver, String message, String myNick) {
		sendTempSessionIM(receiver,
				message,
				myNick,
				"宋体",
				false,
				false,
				false,
				9,
				0,
				0,
				0);
	}

	/**
	 * 发送临时会话消息
	 *
	 * @param receiver
	 * @param message
	 * @param fontName
	 * @param bold
	 * @param italic
	 * @param underline
	 * @param size
	 * @param red
	 * @param green
	 * @param blue
	 */
	public void sendTempSessionIM(int receiver,
			String message,
			String myNick,
            String fontName,
            boolean bold,
            boolean italic,
            boolean underline,
            int size,
            int red,
            int green,
            int blue) {
		if(user.isLoggedIn()) {
			TempSessionOpPacket packet = new TempSessionOpPacket(user);
			packet.setSubCommand(QQ.QQ_SUB_CMD_SEND_TEMP_SESSION_IM);
	        packet.setReceiver(receiver);
	        packet.setMessage(message);
	        packet.setFontName(fontName);
	        packet.setFontSize((byte)(size & 0xFF));
	        packet.setRed((byte)(red & 0xFF));
	        packet.setGreen((byte)(green & 0xFF));
	        packet.setBlue((byte)(blue & 0xFF));
	        packet.setBold(bold);
	        packet.setItalic(italic);
	        packet.setUnderline(underline);
    		gate.send(MAIN_PORT, packet, true);
		}
	}

    /**
     * 发送一个消息,用给定的字体
     * @param receiver 接受者QQ号
     * @param message 消息
     * @param fontName 字体
     */
    public void sendIM(int receiver, String message) {
        this.sendIM(receiver, message, QQ.QQ_IM_NORMAL_REPLY);
    }

    /**
     * 发送一条消息,可以指定回复类型
     * @param receiver 接收者QQ号
     * @param message 消息
     * @param fontName 字体名
     * @param replyType 回复方式,正常回复还是自动回复
     */
    public void sendIM(int receiver, String message, byte replyType) {
        this.sendIM(receiver, message, "宋体", false, false, false, 9, 0, 0, 0, replyType);
    }

    /**
     * 发送一个消息,指定字体和字体颜色
     *
     * @param receiver 接受者QQ号
     * @param message 消息
     * @param fontName 字体
     * @param bold 是否粗体
     * @param italic 是否斜体
     * @param underline 是否下划线
     * @param size 字体大小,最大是31
     * @param red 颜色Red
     * @param green 颜色Green
     * @param blue 颜色Blue
     * @param replyType 回复类型,自动回复还是正常回复
     */
    public void sendIM(
            int receiver,
            String message,
            String fontName,
            boolean bold,
            boolean italic,
            boolean underline,
            int size,
            i

⌨️ 快捷键说明

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