由于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]
hi,能提供一个jar包吗?mail:guxing203@gmail.com
[Reply]
您好!能提供一下最新版的支持QQ的jar包给我吗,多谢了.我的邮箱:ruloo2004@hotmail.com
[Reply]
需要支持SPARK2.5.8的JAR
最好告诉我怎么使用这个东西,我很喜欢
谢谢
maplescg@tzc.edu.cn
[Reply]
麻煩一下. 急需2.5.8 jar 支援 qq. 麻煩可發給我嗎?
mailto: xfile_x@hotmail.co
[Reply]
lizongbo reply on 6月 5th, 2008:
文件在:
618119.com/docs/xmpp/Spark2.5.8.rar
过段时间清理。
您好!能提供一下最新版的支持QQ的jar包给我吗(openfire3.52),多谢了.我的邮箱jhe.zheng@gmail.com
[Reply]
lizongbo reply on 7月 12th, 2008:
Openfire的gateway已经直接支持了。