📄 messagehelper.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.ui.helper;
import static edu.tsinghua.lumaqq.models.MessageSetting.*;
import static edu.tsinghua.lumaqq.resource.Messages.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.graphics.Image;
import edu.tsinghua.lumaqq.LumaQQ;
import edu.tsinghua.lumaqq.MessageQueue;
import edu.tsinghua.lumaqq.Sounder;
import edu.tsinghua.lumaqq.models.Cluster;
import edu.tsinghua.lumaqq.models.GroupType;
import edu.tsinghua.lumaqq.models.ModelRegistry;
import edu.tsinghua.lumaqq.models.Status;
import edu.tsinghua.lumaqq.models.User;
import edu.tsinghua.lumaqq.qq.QQ;
import edu.tsinghua.lumaqq.qq.QQClient;
import edu.tsinghua.lumaqq.qq.Util;
import edu.tsinghua.lumaqq.qq.beans.ClusterIM;
import edu.tsinghua.lumaqq.qq.beans.NormalIM;
import edu.tsinghua.lumaqq.qq.packets.in.ReceiveIMPacket;
import edu.tsinghua.lumaqq.qq.packets.in.SystemNotificationPacket;
import edu.tsinghua.lumaqq.record.IKeyConstants;
import edu.tsinghua.lumaqq.record.RecordEntry;
import edu.tsinghua.lumaqq.resource.Resources;
import edu.tsinghua.lumaqq.ui.MainShell;
import edu.tsinghua.lumaqq.ui.ReceiveIMWindow;
import edu.tsinghua.lumaqq.ui.SMSWindow;
import edu.tsinghua.lumaqq.ui.SendClusterIMWindow;
import edu.tsinghua.lumaqq.ui.SendIMTabWindow;
import edu.tsinghua.lumaqq.ui.SendIMWindow;
import edu.tsinghua.lumaqq.widgets.rich.IRichContent;
/**
* 消息处理帮助类
*
* @author luma
*/
public class MessageHelper {
private static Log log = LogFactory.getLog(MessageHelper.class);
private MainShell main;
private Resources res;
// 分片缓冲,有的长消息会变成几个分片发送,需要保存起来等待所有分片完成
// key是消息id,value是个Object数组,保存了消息的分片
private Map<Integer, Object[]> fragmentCache;
public MessageHelper(MainShell main) {
this.main = main;
res = Resources.getInstance();
fragmentCache = new HashMap<Integer, Object[]>();
}
/**
* 把字节数组转换为String,它为我们处理缺省表情的问题
*
* @param b
* 消息字节数组
* @return
* String
*/
public String convertBytes(byte[] b) {
StringBuffer sb = new StringBuffer();
int offset = 0;
int length = 0;
for(int i = 0; i < b.length; i++) {
if(b[i] == QQ.QQ_TAG_DEFAULT_FACE) {
sb.append(Util.getString(b, offset, length));
sb.append((char)b[i]).append((char)(b[i + 1] & 0xFF));
i++;
offset = i + 1;
length = 0;
} else
length++;
}
if(length > 0)
sb.append(Util.getString(b, offset, length));
return sb.toString();
}
/**
* 检查这个消息是完整消息还是分片
*
* @return
* true表示这个消息是分片消息
*/
private boolean isFragment(NormalIM im) {
return im.totalFragments > 1;
}
/**
* 检查这个消息是完整消息还是分片
*
* @return
* true表示这个消息是分片消息
*/
private boolean isFragment(ClusterIM im) {
return im.fragmentCount > 1;
}
/**
* 添加一个普通消息分片
*
* @param im
*/
private void addFragment(NormalIM im) {
Object[] fragments = fragmentCache.get(im.messageId);
if(fragments == null || fragments.length != im.totalFragments) {
fragments = new Object[im.totalFragments];
fragmentCache.put(im.messageId, fragments);
}
fragments[im.fragmentSequence] = im;
}
/**
* 添加一个群消息分片
*
* @param im
*/
private void addFragment(ClusterIM im) {
Object[] fragments = fragmentCache.get(im.messageId);
if(fragments == null || fragments.length != im.fragmentCount) {
fragments = new Object[im.fragmentCount];
fragmentCache.put((int)im.messageId, fragments);
}
fragments[im.fragmentSequence] = im;
}
/**
* 得到完整的消息,同时把这个消息从分片缓冲中清楚。调用此方法前,必须先用
* isMessageComplete()判断分片是否都已经收到
*
* @param messageId
* 消息id
* @return
* ClusterIM对象
*/
private ClusterIM getIntegratedClusterIM(int messageId) {
Object[] fragments = fragmentCache.remove(messageId);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
for(Object f : fragments) {
try {
baos.write(((ClusterIM)f).messageBytes);
} catch (IOException e) {
}
}
ClusterIM ret = (ClusterIM)fragments[fragments.length - 1];
ret.messageBytes = baos.toByteArray();
ret.message = convertBytes(ret.messageBytes);
return ret;
}
/**
* 得到完整的普通消息
*
* @param messageId
* 消息ID
* @return
* NormalIM对象
*/
private NormalIM getIntegratedNormalIM(int messageId) {
Object[] fragments = fragmentCache.remove(messageId);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
for(Object f : fragments) {
try {
baos.write(((NormalIM)f).messageBytes);
} catch (IOException e) {
}
}
NormalIM ret = (NormalIM)fragments[0];
ret.message = NormalIMFormalizer.deformalize(baos.toByteArray());
return ret;
}
/**
* 检查是否一个长消息的分片都已经收到了
*
* @param messageId
* 消息id
* @return
* true表示已经收到
*/
private boolean isMessageComplete(int messageId) {
if(!fragmentCache.containsKey(messageId))
return false;
Object[] fragments = fragmentCache.get(messageId);
for(Object f : fragments) {
if(f == null)
return false;
}
return true;
}
/**
* 推入一条短信
*
* @param packet
*/
public void putSMS(ReceiveIMPacket packet) {
MessageQueue mq = main.getMessageQueue();
ShellRegistry shellRegistry = main.getShellRegistry();
// 保存消息
Object key = null;
if(packet.sms.sender == 10000) {
/*
* 普通手机
*/
RecordEntry entry = new RecordEntry();
entry.type = IKeyConstants.NORMAL;
entry.owner = 9999;
entry.sender = 0;
entry.senderParent = 0;
entry.receiver = main.getMyModel().qq;
entry.time = System.currentTimeMillis();
entry.message = packet.sms.senderName + '|' + packet.sms.message;
main.getRecordManager().addRecord(entry);
key = packet.sms.senderName;
} else {
/*
* 绑定手机用户和移动QQ用户
*/
RecordEntry entry = new RecordEntry();
entry.type = IKeyConstants.NORMAL;
entry.owner = packet.sms.sender;
entry.sender = packet.sms.sender;
entry.senderParent = 0;
entry.receiver = main.getMyModel().qq;
entry.time = System.currentTimeMillis();
entry.message = packet.sms.message;
main.getRecordManager().addRecord(entry);
key = ModelRegistry.getUser(packet.sms.sender);
if(key == null) {
User f = new User();
f.qq = packet.sms.sender;
key = f;
} else {
// 添加到最近联系人
final User u = (User)key;
main.getDisplay().syncExec(new Runnable() {
public void run() {
main.getBlindHelper().updateLatest(u);
}
});
}
}
if(shellRegistry.hasSMSWindow(key)) {
SMSWindow window = shellRegistry.getSMSWindow(key);
window.putSMS(packet);
if(!window.isActive())
window.startBlink();
} else {
if(!main.getMessageQueue().hasNext())
main.getUIHelper().startBlinkImage(res.getImage(Resources.icoMobile));
if(!main.getMessageQueue().hasSMS())
main.getUIHelper().startBlinkSMSIcon();
mq.putSMS(packet);
// 播放声音
main.getSounder().play(LumaQQ.MSG_SOUND);
}
}
/**
* 推入一个群通知消息,一个群可以有很多种类型的消息,一般来说,除了普通群消息之外的
* 其他消息,我们都看做是一个群通知,也就是要闪那个小喇叭,而不是把他显示在发送消息
* 的窗口中。这样的群通知消息有申请加入群,退出群,同意加入群等等等等。判断的逻辑基
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -