lizongbo at 618119.com 工作,生活,Android,前端,Linode,Ubuntu,nginx,java,apache,tomcat,Resin,mina,Hessian,XMPP,RPC

2008年01月4日

为OpenFire和Spark增加QQTransport–Openfire篇(二)

Filed under: Java — 标签:, , — lizongbo @ 08:40

由于Saprk 和 OpenFire的代码与实际发布的版本中不一致,增加了不少东西,因此直接添加替换文件存在一些问题,所以在此只贴出代码作为记录,不提供打包好的jar文件。如需相关jar,可在此留言,我再打包支持Spark版本2.5.8和OpenFire 3.4.3的相关jar,放到服务器供下载,最重要的QQSession代码如下(目前只实现了基本的普通聊天消息):

[code]

package org.jivesoftware.openfire.gateway.protocols.qq;

import org.apache.log4j.Logger;
import org.jivesoftware.util.Log;
import org.jivesoftware.openfire.gateway.registration.Registration;
import org.jivesoftware.openfire.gateway.roster.TransportBuddy;
import org.jivesoftware.openfire.gateway.session.TransportSession;
import org.jivesoftware.openfire.gateway.type.ChatStateType;
import org.jivesoftware.openfire.gateway.type.PresenceType;
import org.jivesoftware.openfire.gateway.type.TransportLoginStatus;
import org.jivesoftware.openfire.roster.Roster;
import org.jivesoftware.openfire.roster.RosterItem;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.util.Base64;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.NotFoundException;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;
import org.xmpp.packet.Presence;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import edu.tsinghua.lumaqq.qq.QQ;
import edu.tsinghua.lumaqq.qq.QQClient;
import edu.tsinghua.lumaqq.qq.beans.QQUser;
import edu.tsinghua.lumaqq.qq.beans.QQFriend;
import edu.tsinghua.lumaqq.qq.beans.ClusterIM;
import edu.tsinghua.lumaqq.qq.net.PortGateFactory;
import edu.tsinghua.lumaqq.qq.events.IQQListener;
import edu.tsinghua.lumaqq.qq.events.QQEvent;
import java.util.Date;
import edu.tsinghua.lumaqq.qq.packets.in.GetFriendListReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.DownloadGroupFriendReplyPacket;
import edu.tsinghua.lumaqq.qq.beans.DownloadFriendEntry;
import edu.tsinghua.lumaqq.qq.beans.ClusterInfo;
import edu.tsinghua.lumaqq.qq.packets.in.ClusterCommandReplyPacket;
import java.util.HashMap;
import edu.tsinghua.lumaqq.qq.packets.in.ReceiveIMPacket;
import java.text.SimpleDateFormat;
import edu.tsinghua.lumaqq.qq.beans.NormalIM;
import edu.tsinghua.lumaqq.qq.packets.in.GetOnlineOpReplyPacket;
import edu.tsinghua.lumaqq.qq.beans.FriendOnlineEntry;
import edu.tsinghua.lumaqq.qq.packets.in.FriendChangeStatusPacket;
/**
*
* <p>Title: QQSession</p>
*
* <p>Description: 感谢Luma</p>
*
* <p>Copyright: Copyright (c) 2007</p>
*
* <p>Company: </p>
*
* @author lizongbo
* @version 1.0
*/
public class QQSession extends TransportSession implements IQQListener {
private QQClient qqclient;
private QQUser qquser;

private final String udpServerList[] = {“219.133.60.36”,
“219.133.49.171”,
“sz2.tencent.com”, // 61.144.238.146
“sz3.tencent.com”, // 202.104.129.251
“sz4.tencent.com”, // 202.104.129.254
“sz5.tencent.com”, // 61.141.194.203
“sz6.tencent.com”, // 202.104.129.252
“sz7.tencent.com”, // 202.104.129.253
};
public QQSession(Registration registration, JID jid,
QQTransport transport, Integer priority) {
super(registration, jid, transport, priority);
Log.debug(“Creating QQ session for ” + registration.getUsername());
qquser = new QQUser(Integer.parseInt(registration.getUsername()),
registration.getPassword());
qquser.setStatus(QQ.QQ_LOGIN_MODE_NORMAL);
qquser.setUdp(true);
qquser.setShowFakeCam(false);
qqclient = new QQClient();
qqclient.setUser(qquser);
qqclient.setConnectionPoolFactory(new PortGateFactory());

}

public void updateStatus(PresenceType presenceType, String string) {
if (isLoggedIn()) {
try {
qquser.setStatus(((QQTransport) getTransport()).
convertJabStatusToQQ(presenceType));
//qqclient.sendPacket(null);
} catch (IllegalStateException e) {
}
}

}

public void addContact(JID jID, String string, ArrayList arrayList) {

System.out.println(jID + ”  ” + string + ”  ” + arrayList);

}

public void removeContact(TransportBuddy transportBuddy) {
System.out.println(“removeContact”);
}

public void updateContact(TransportBuddy transportBuddy) {
System.out.println(“transportBuddy”);
}

public void sendMessage(JID jID, String message) {
System.out.println(“发送消息到:” + jID + ” 内容为:” + message);
int qqNum = Integer.parseInt(getTransport().convertJIDToID(jID));
qqclient.sendIM(qqNum, message.getBytes());

}

public void sendChatState(JID jID, ChatStateType chatStateType) {
System.out.println(“sendChatState” + jID + ” ” + chatStateType);
}

public void sendBuzzNotification(JID jID, String string) {
System.out.println(“sendBuzzNotification” + jID + ” ” + string);
}

public void logIn(PresenceType presenceType, String string) {
if (!this.isLoggedIn()) {
try {
Log.debug(“Logging in to QQ session for ” + qquser.getQQ());
setLoginStatus(TransportLoginStatus.LOGGING_IN);
qqclient.addQQListener(this); //注册事件监听器
//                String qqserver = “219.133.60.36”;
String qqserver = udpServerList[(int) Math.round(Math.random() *
udpServerList.length)];
qqclient.setLoginServer(qqserver);
// qqclient.setLoginServer(“sz4.tencent.com”);
System.out.println(“开始登陆 ” + qqclient.getUser().getQQ() + ” 到 ” +
qqserver);
qqclient.login();

} catch (Exception e) {
Log.error(“QQ user is not able to log in: ” + qquser.getQQ(), e);
}
}
}

public void logOut() {
System.out.println(“退出”);
setLoginStatus(TransportLoginStatus.LOGGING_OUT);
qqclient.logout();
Presence p = new Presence(Presence.Type.unavailable);
p.setTo(getJID()); //qq图标显示为离线状态
p.setFrom(getTransport().getJID());
getTransport().sendPacket(p);
setLoginStatus(TransportLoginStatus.LOGGED_OUT);

}

public void cleanUp() {
}

public void updateLegacyAvatar(String string, byte[] byteArray) {
}

public QQClient getQqclient() {
return qqclient;
}

public QQUser getQquser() {
return qquser;
}

public void qqEvent(QQEvent e) {
System.out.println(” qq事件: ” + e.type + ” ” + e.getSource());
switch (e.type) {
case QQEvent.QQ_LOGIN_SUCCESS:
System.out.println(“登陆成功, 等待状态改变.”);
getRegistration().setLastLogin(new Date());
setLoginStatus(TransportLoginStatus.LOGGED_IN);
break;
case QQEvent.QQ_LOGIN_FAIL:
setLoginStatus(TransportLoginStatus.LOGGING_OUT);
case QQEvent.QQ_LOGIN_REDIRECT_NULL:
case QQEvent.QQ_LOGIN_UNKNOWN_ERROR:
System.out.println(qqclient.getUser().getQQ() +
“登陆失败,退出.”);
qqclient.logout();
break;
case QQEvent.QQ_CHANGE_STATUS_SUCCESS:
System.out.println(“改变状态完成.”);
Presence p = new Presence();
p.setTo(getJID());
p.setFrom(getTransport().getJID());
p.setStatus(“空闲”); //将Spark里的qq图标显示为在线状态
getTransport().sendPacket(p);
qqclient.downloadGroup();
qqclient.getFriendList();
qqclient.downloadFriend(0);
break;
case QQEvent.QQ_CHANGE_STATUS_FAIL:
System.out.println(“改变状态失败.”);
break;
case QQEvent.QQ_GET_FRIEND_LIST_SUCCESS:
processFriendList(e);
break;
case QQEvent.QQ_DOWNLOAD_GROUP_FRIEND_SUCCESS:
processGroupFriend(e);
break;
case QQEvent.QQ_DOWNLOAD_GROUP_FRIEND_FAIL:
System.out.println(“下载好友分组失败, 注销!”);
qqclient.logout();
break;
case QQEvent.QQ_GET_CLUSTER_INFO_SUCCESS:
processClusterInfo(e);
break;
case QQEvent.QQ_GET_CLUSTER_INFO_FAIL:
System.out.println(“得到群信息错误. 注销!”);
qqclient.logout();
break;
case QQEvent.QQ_GET_MEMBER_INFO_SUCCESS:
processMemberInfo(e);
break;
case QQEvent.QQ_GET_MEMBER_INFO_FAIL:
System.out.println(“得到成员信息错误. 注销!”);
qqclient.logout();
break;
case QQEvent.QQ_RECEIVE_CLUSTER_IM:
processClusterIM(e);
break;
case QQEvent.QQ_RECEIVE_NORMAL_IM:
processNormalIM(e);
break;
case QQEvent.QQ_CONNECTION_BROKEN:
System.out.println(“连接被打断, 重新连接…”);
try {
qqclient.login();
} catch (Exception ex) {
ex.printStackTrace();
}
break
;
case QQEvent.QQ_CONNECTION_LOST:
System.out.println(“连接被丢失, 重新连接…”);
try {
qqclient.login();
} catch (Exception ex) {
ex.printStackTrace();
}
break
;
case QQEvent.QQ_OPERATION_TIMEOUT:
qqclient.logout();
break;
case QQEvent.QQ_GET_FRIEND_ONLINE_SUCCESS:
processFriendOnline(e);
break;
case QQEvent.QQ_FRIEND_CHANGE_STATUS:
processFriendChangeStatus(e);
break;
case QQEvent.QQ_GET_USER_INFO_SUCCESS:
break;
case QQEvent.QQ_GET_WEATHER_SUCCESS:
break;
case QQEvent.QQ_GET_WEATHER_FAIL:

//回复包里面没有有用信息,所以不处理了
break;
case QQEvent.QQ_GET_SIGNATURE_SUCCESS:
break;
case QQEvent.QQ_GET_SIGNATURE_FAIL:
break;
case QQEvent.QQ_RECEIVE_SYS_MESSAGE:
System.out.println(“QQ系统广播,不理它”);
break;
default:
System.out.println(“未知消息” + e.type + “,不理睬”);
}

}

//处理好友名单
private void processFriendList(QQEvent e) {
try {
GetFriendListReplyPacket p =
(GetFriendListReplyPacket) e.getSource();
this.getBuddyManager().activate();
List<TransportBuddy> legacyusers = new ArrayList<TransportBuddy>();
for (QQFriend f : p.friends) {
System.out.println(“处理好友名单 processFriendList ” + f.qqNum + ” ” +
f.nick);
TransportBuddy tb = new TransportBuddy(getBuddyManager(),
f.qqNum + “”, f.nick, null);
legacyusers.add(tb);
this.getBuddyManager().storeBuddy(tb);
}
if (p.position != 0xFFFF) {
getQqclient().getFriendList(p.position);
} else {
//                getTransport().syncLegacyRoster(getJID(),
//                                                legacyusers);
System.out.println(“获取好友列表完成.”);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}

private void processGroupFriend(QQEvent e) {
try {
DownloadGroupFriendReplyPacket p =
(DownloadGroupFriendReplyPacket) e.getSource();
for (DownloadFriendEntry entry : p.friends) {
if (entry.isCluster()) {
getQqclient().getClusterInfo(entry.qqNum);
}
}
if (p.beginFrom != 0) {
getQqclient().downloadFriend(p.beginFrom);
} else {
System.out.println(“下载好友分组完成.”);
//下载好友分组完成,继续下载在线好友列表
getQqclient().getFriendOnline();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}

private void processClusterInfo(QQEvent e) {
try {
ClusterCommandReplyPacket p = (ClusterCommandReplyPacket) e.
getSource();
ClusterInfo info = p.info;
//p.description,p.notice两个字段用在info中
// 如果是固定群,externalId表示外部ID,如果是临时群,这个表示父群ID
//clusters.put(info.externalId, info.name);
//保存外部ID到内部ID的索引
//clustersIn.put(info.externalId, info.clusterId);
//p.members字段为群成员列表,元素类型为Integer,包含了成员的QQ号
getQqclient().getClusterMemberInfo(info.clusterId,
p.members);
} catch (Exception ex) {
ex.printStackTrace();
}
}

private void processMemberInfo(QQEvent e) {
try {
ClusterCommandReplyPacket p = (ClusterCommandReplyPacket) e.
getSource();
HashMap<Integer, String> temp = new HashMap<Integer, String>();
List<TransportBuddy> legacyusers = new ArrayList<TransportBuddy>();
for (Object obj : p.memberInfos) {
QQFriend m = (QQFriend) obj;
//群信息全部保存到一个临时hash表
System.out.println(“获取好友信息 processMemberInfo ” + m.qqNum + ” ” +
m.nick);
legacyusers.add(new TransportBuddy(getBuddyManager(),
m.qqNum + “”, m.nick, null));
TransportBuddy tb = new TransportBuddy(getBuddyManager(),
m.qqNum + “”, m.nick, null);
this.getBuddyManager().storeBuddy(tb);

// temp.put(m.qqNum, m.nick);
//保存一个全部群成员的hash表
//membersAll.put(m.qqNum,m.nick);
}
//            getTransport().syncLegacyRoster(getJID(),
//                                            legacyusers);

//                if(membersIndex.containsKey(p.clusterId)){
//                    //如果外表中已经含有同样的群号键值,则先取出来,放到上面的temp表中
//                    for (Map.Entry<Integer, String> entry
//                        : membersIndex.get(p.clusterId).entrySet()){
//                        temp.put(entry.getKey(),entry.getValue());
//                    }
//                    //然后再把temp表保存到外表中
//                    membersIndex.put(p.clusterId,temp);
//                }else{
//                    //没有键值就直接往里面压
//                    membersIndex.put(p.clusterId,temp);
//                }
} catch (Exception ex) {
ex.printStackTrace();
}
}

private void processClusterIM(QQEvent e) {
try {
SimpleDateFormat sdf = new SimpleDateFormat(“MM-dd HH:mm”);
ReceiveIMPacket p = (ReceiveIMPacket) e.getSource();
ClusterIM im = p.clusterIM;
String sDate = sdf.format(new Date(im.sendTime));
} catch (Exception ex) {
ex.printStackTrace();
}
}

//处理普通消息
private void processNormalIM(QQEvent e) {
try {
ReceiveIMPacket p = (ReceiveIMPacket) e.getSource();
NormalIM im = p.normalIM;
Message m = new Message();
m.setType(Message.Type.chat);
m.setTo(getJIDWithHighestPriority());
m.setFrom(getTransport().convertIDToJID(“” +
p.normalHeader.sender));
String b = ” “;
try {
b = new String(im.messageBytes);
} catch (Exception ex) {
ex.printStackTrace();
}
m.setBody(b);
// System.out.println(“消息为:” + m);
getTransport().sendPacket(m);
} catch (Exception ex) {
ex.printStackTrace();
}
}

private void processFriendOnline(QQEvent e) {
try {
GetOnlineOpReplyPacket p =
(GetOnlineOpReplyPacket) e.getSource();
for (FriendOnlineEntry f : p.onlineFriends) {
System.out.println(“下载在线好友 ” + f.status.qqNum);
System.out.println(“发送” + f.status.qqNum + ” 的在线状态”);
Presence pp = new Presence();
pp.setFrom(this.getTransport().convertIDToJID(“” +
f.status.qqNum));
pp.setTo(this.getJID());
pp.setShow(Presence.Show.chat);
System.out.println(pp.toXML());
this.getTransport().sendPacket(pp);
}
if (!p.finished) {
getQqclient().getFriendOnline(p.position);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}

private void processFriendChangeStatus(QQEvent e) {
try {
FriendChangeStatusPacket p =
(FriendChangeStatusPacket) e.getSource();
System.out.print(p.friendQQ + ” 改变状态为” + p.status + “>”);
Presence pp = new Presence();
pp.setFrom(this.getTransport().convertIDToJID(“” + p.friendQQ));
pp.setTo(this.getJID());
((QQTransport)this.getTransport()).setUpPresencePacket(pp, p.status);
System.out.println(pp.toXML());
this.getTransport().sendPacket(pp);

} catch (Exception ex) {
ex.printStackTrace();
}
}
}
[/code]

Powered by WordPress