/*
* Copyright 2006-2010 Daniel Henninger. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package net.sf.kraken.protocols.qq;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.sf.jqql.beans.DownloadFriendEntry;
import net.sf.jqql.beans.FriendOnlineEntry;
import net.sf.jqql.beans.NormalIM;
import net.sf.jqql.beans.QQFriend;
import net.sf.jqql.events.IQQListener;
import net.sf.jqql.events.QQEvent;
import net.sf.jqql.packets.in.*;
import net.sf.jqql.packets.in._08._08GetOnlineOpReplyPacket;
import net.sf.kraken.type.ConnectionFailureReason;
import net.sf.kraken.type.TransportLoginStatus;
import org.apache.log4j.Logger;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.NotFoundException;
public class QQListener implements IQQListener {
static Logger Log = Logger.getLogger(QQListener.class);
private static String defaultGroupName = JiveGlobals.getProperty(
"plugin.gateway.qq.defaultRosterName", "Friends");
// public static final SimpleDateFormat sdf = new SimpleDateFormat(
// "yyyy-MM-dd HH:mm:ss");
private List<String> groupNames = new ArrayList<String>();
private Map<Integer, QQFriend> friends = new HashMap<Integer, QQFriend>();
private Map<Integer, String> friendGroup = new HashMap<Integer, String>();
// private Map<Integer,
// ClusterInfo> clusters = new HashMap<Integer, ClusterInfo>();
// private Map<Integer,
// Map<Integer, String>> clusterMembers = new Hashtable<Integer,
// Map<Integer, String>>(); //group members
/**
* Creates a QQ session listener affiliated with a session.
*
* @param session The QQSession instance we are associated with.
*/
public QQListener(QQSession session) {
this.qqSessionRef = new WeakReference<QQSession>(session);
}
/**
* The transport session we are affiliated with.
*/
WeakReference<QQSession> qqSessionRef;
/**
* Returns the QQ session this listener is attached to.
*
* @return QQ session we are attached to.
*/
public QQSession getSession() {
return qqSessionRef.get();
}
public void qqEvent(QQEvent e) {
Log.debug("QQ: Received - " + e.getSource() + " Event ID: 0x"+Integer.toHexString(e.type));
switch (e.type) {
case QQEvent.LOGIN_OK:
processSuccessfulLogin();
break;
case QQEvent.LOGIN_FAIL:
getSession().setFailureStatus(ConnectionFailureReason.USERNAME_OR_PASSWORD_INCORRECT);
getSession().sessionDisconnectedNoReconnect(null);
break;
case QQEvent.LOGIN_UNKNOWN_ERROR:
case QQEvent.ERROR_CONNECTION_BROKEN:
getSession().setFailureStatus(ConnectionFailureReason.UNKNOWN);
getSession().sessionDisconnected(null);
break;
case QQEvent.USER_STATUS_CHANGE_OK:
processStatusChangeOK((ChangeStatusReplyPacket)e.getSource());
break;
case QQEvent.USER_STATUS_CHANGE_FAIL:
getSession().sessionDisconnected(null);
break;
case QQEvent.FRIEND_DOWNLOAD_GROUPS_OK:
processGroupFriend(e);
break;
case QQEvent.FRIEND_GET_GROUP_NAMES_OK:
processGroupNames(e);
break;
case QQEvent.USER_GET_INFO_OK:
processFriendInfo(e);
break;
// case QQEvent.QQ_GET_CLUSTER_INFO_SUCCESS:
// processClusterInfo(e);
// break;
// case QQEvent.QQ_GET_MEMBER_INFO_SUCCESS:
// processClusterMemberInfo(e);
// break;
// case QQEvent.QQ_RECEIVE_CLUSTER_IM:
// processClusterIM(e);
// break;
case QQEvent.IM_RECEIVED:
processNormalIM((ReceiveIMPacket)e.getSource());
break;
case QQEvent.ERROR_NETWORK:
case QQEvent.ERROR_RUNTIME:
getSession().setFailureStatus(ConnectionFailureReason.CAN_NOT_CONNECT);
getSession().sessionDisconnected(null);
break;
case QQEvent.FRIEND_GET_ONLINE_OK:
processFriendOnline((_08GetOnlineOpReplyPacket)e.getSource());
break;
case QQEvent.FRIEND_STATUS_CHANGED:
processFriendChangeStatus((FriendChangeStatusPacket)e.getSource());
break;
case QQEvent.FRIEND_GET_LIST_OK:
processFriendList((GetFriendListReplyPacket)e.getSource());
break;
case QQEvent.LOGIN_TOUCH:
getSession().getQQClient().sendToken1();
default:
break;
}
}
private void processFriendList(GetFriendListReplyPacket p) {
Log.debug("QQ: processing friend list");
// For whatever reason, this no longer returns anything useful. So we go another route to get info on our peeps.
// try {
// for (QQFriend f : p.friends) {
// Log.debug("Found QQ friend: "+f);
// friends.put(f.qqNum, f);
//
// String groupName = friendGroup.get(f.qqNum);
// if (groupName == null || groupName.trim().length() < 1) {
// groupName = defaultGroupName;
// }
// List<String> gl = new ArrayList<String>();
// gl.add(groupName);
// QQBuddy qqBuddy = new QQBuddy(getSession().getBuddyManager(), f, f.nick, gl);
// getSession().getBuddyManager().storeBuddy(qqBuddy);
// }
// if (p.position != 0xFFFF) {
// getSession().getQQClient().user_GetList(p.position);
// }
// } catch (Exception ex) {
// Log.error("Failed to process friend list: ", ex);
// }
// Lets try the actual sync.
try {
getSession().getTransport().syncLegacyRoster(getSession().getJID(), getSession().getBuddyManager().getBuddies());
}
catch (UserNotFoundException ex) {
Log.debug("Unable to sync QQ contact list for " + getSession().getJID());
}
getSession().getBuddyManager().activate();
getSession().getQQClient().user_GetOnline();
}
private void processGroupFriend(QQEvent e) {
Log.debug("QQ: Processing group friend.");
try {
DownloadGroupFriendReplyPacket p =
(DownloadGroupFriendReplyPacket) e.getSource();
for (DownloadFriendEntry entry : p.friends) {
// if (entry.isCluster()) {
// getSession().getQQClient().getClusterInfo(entry.qqNum);
// } else {
if (groupNames != null && groupNames.size() > entry.group) {
String groupName = groupNames.get(entry.group);
friendGroup.put(entry.qqNum, groupName);
List<String> gl = new ArrayList<String>();
gl.add(groupName);
QQBuddy qqBuddy = new QQBuddy(getSession().getBuddyManager(), entry.qqNum, gl);
getSession().getBuddyManager().storeBuddy(qqBuddy);
} else {
friendGroup.put(entry.qqNum, defaultGroupName);
List<String> gl = new ArrayList<String>();
gl.add(defaultGroupName);
QQBuddy qqBuddy = new QQBuddy(getSession().getBuddyManager(), entry.qqNum, gl);
getSession().getBuddyManager().storeBuddy(qqBuddy);
}
// }
getSession().getQQClient().user_GetInfo(entry.qqNum);
}
// if (p.beginFrom != 0) {
// getSession().getQQClient().getClusterOnlineMember(p.beginFrom);
// }
} catch (Exception ex) {
Log.error("Failed to process group friend: ", ex);
}
getSession().getQQClient().user_GetList();
}
private void processFriendInfo(QQEvent e) {
Log.debug("QQ: Processing friend info request");
GetUserInfoReplyPacket p = (GetUserInfoReplyPacket) e.getSource();
try {
QQBuddy buddy = getSession().getBuddyManager().getBuddy(getSession().getTransport().convertIDToJID(String.valueOf(p.contactInfo.qq)));
buddy.setNickname(p.contactInfo.nick);
buddy.contactInfo = p.contactInfo;
getSession().getBuddyManager().storeBuddy(buddy);
}
catch (NotFoundException nfe) {
Log.debug("QQ: Received buddy "+p.contactInfo.qq+" that we don't know about.");
}
}
private void processGroupNames(QQEvent e) {
Log.debug("QQ: Processing group names");
try {
groupNames.clear();
groupNames.add(defaultGroupName);
GroupDataOpReplyPacket p =
(GroupDataOpReplyPacket) e.getSource();
groupNames.addAll(p.groupNames);
} catch (Exception ex) {
Log.error("Failed to process group names: ", ex);
}
getSession().getQQClient().user_DownloadGroups(0);
}
// private void processClusterInfo(QQEvent e) {
// try {
// ClusterCommandReplyPacket p = (ClusterCommandReplyPacket) e.
// getSource();
// ClusterInfo info = p.info;
// if (QQ.QQ_CLUSTER_TYPE_PERMANENT == info.type) {
// clusters.put(info.externalId, info);
// }
// List<String> gl = new ArrayList<String>();
// gl.add(JiveGlobals.getProperty("plugin.gateway.qq.qqGroupName",
// "QQ Group"));
// TransportBuddy tb = new TransportBuddy(getSession().getBuddyManager(),
// String.valueOf(info.externalId), info.name, gl);
// getSession().getBuddyManager().storeBuddy(tb);
// Presence pp = new Presence();
// pp.setFrom(getSession().getTransport().convertIDToJID(String.valueOf(info.externalId)));
// pp.setTo(getSession().getJID());
// pp.setShow(Presence.Show.chat);
// getSession().getTransport().sendPacket(pp);
// qqclient.getClusterMemberInfo(info.clusterId, p.members);
// } catch (Exception ex) {
// Log.error("Failed to process cluster info: ", ex);
// }
// }
//
// private void processClusterMemberInfo(QQEvent e) {
// try {
// ClusterCommandReplyPacket p = (ClusterCommandReplyPacket) e.
// getSource();
// Map<Integer, String> cmm = new HashMap<Integer, String>();
// for (Object obj : p.memberInfos) {
// QQFriend m = (QQFriend) obj;
// cmm.put(m.qqNum, m.nick);
// }
// int clusterId = 0;
// for (ClusterInfo c : clusters.values()) {
// if (c.clusterId == p.clusterId) {
// clusterId = c.externalId;
// }
// }
// clusterMembers.put(clusterId, cmm);
// } catch (Exception ex) {
// Log.error("Failed to process cluster member info: ", ex);
// }
// }
private void processSuccessfulLogin() {
Log.debug("QQ: Processing successful login");
getSession().setLoginStatus(TransportLoginStatus.LOGGED_IN);
getSession().getQQClient().user_GetGroupNames();
}
private void processStatusChangeOK(ChangeStatusReplyPacket p) {
Log.debug("QQ: Processing status change success");
// if (!getSession().isLoggedIn()) {
// getSession().setLoginStatus(TransportLoginStatus.LOGGED_IN);
// getSession().getQQClient().getFriendList();
// getSession().getQQClient().downloadGroup();
// getSession().getQQClient().getFriendOnline();
// }
}
// private void processClusterIM(QQEvent e) {
// try {
// ReceiveIMPacket p = (ReceiveIMPacket) e.getSource();
// ClusterIM im = p.clusterIM;
// if (clusters.get(im.externalId) == null) {
// qqclient.downloadGroup();
// }
// String sDate = sdf.format(new Date(im.sendTime));
// String clusterName = "";
// try {
// clusterName = clusters.get(im.externalId).name;
// } catch (Exception ex) {
// Log.debug("Failed to get cluster name: ", ex);
// }
// String senderName = " ";
// try {
// senderName = clusterMembers.get(im.externalId).get(im.sender);
// } catch (Exception ex) {
// Log.debug("Failed to get sender name: ", ex);
// }
// String msg = clusterName + "[" + im.externalId + "]"
// + senderName + "(" + im.sender + ") "
// + sDate + ":\n"
// + new String(im.messageBytes) + "\n";
// Message m = new Message();
// m.setType(Message.Type.chat);
// m.setTo(getSession().getJID());
// m.setFrom(getSession().getTransport().convertIDToJID(String.valueOf(im.externalId)));
// String b = " ";
// try {
// b = new String(msg);
// } catch (Exception ex) {
// Log.debug("Failed to string-ify message: ", ex);
// }
// m.setBody(b);
// getSession().getTransport().sendPacket(m);
// } catch (Exception ex) {
// Log.error("Failed to handle cluster IM: ", ex);
// }
// }
/**
* Handles a standard instant message being sent to us.
*
* @param p Event of the message.
*/
private void processNormalIM(ReceiveIMPacket p) {
Log.debug("QQ: Processing normal IM received.");
NormalIM im = p.normalIM;
getSession().getTransport().sendMessage(
getSession().getJID(),
getSession().getTransport().convertIDToJID(String.valueOf(p.normalHeader.sender)),
im.message
);
}
/**
* Handles an event when a friend has come online.
*
* @param p Event to be handled.
*/
private void processFriendOnline(_08GetOnlineOpReplyPacket p) {
Log.debug("QQ: Processing friend online notification");
try {
for (FriendOnlineEntry f : p.onlineFriends) {
Log.debug("QQ: Got an online friend");
if (getSession().getBuddyManager().isActivated()) {
try {
QQBuddy qqBuddy = getSession().getBuddyManager().getBuddy(getSession().getTransport().convertIDToJID(String.valueOf(f.status.qqNum)));
qqBuddy.setPresenceAndStatus(((QQTransport)getSession().getTransport()).convertQQStatusToXMPP(f.status.status), null);
}
catch (NotFoundException ee) {
// Not in our list.
Log.debug("QQ: Received presense notification for contact we don't care about: "+String.valueOf(f.status.qqNum));
}
}
else {
getSession().getBuddyManager().storePendingStatus(getSession().getTransport().convertIDToJID(String.valueOf(f.status.qqNum)), ((QQTransport)getSession().getTransport()).convertQQStatusToXMPP(f.status.status), null);
}
}
// if (!p.finished) {
// qqclient.getUser().user_GetOnline(p.position);
// }
} catch (Exception ex) {
Log.error("Failed to handle friend online event: ", ex);
}
}
/**
* Handles an event where a friend changes their status.
*
* @param p Event representing change.
*/
private void processFriendChangeStatus(FriendChangeStatusPacket p) {
Log.debug("QQ: Processing friend status change event");
try {
if (getSession().getBuddyManager().isActivated()) {
try {
QQBuddy qqBuddy = getSession().getBuddyManager().getBuddy(getSession().getTransport().convertIDToJID(String.valueOf(p.friendQQ)));
qqBuddy.setPresenceAndStatus(((QQTransport)getSession().getTransport()).convertQQStatusToXMPP(p.status), null);
}
catch (NotFoundException ee) {
// Not in our list.
Log.debug("QQ: Received presense notification for contact we don't care about: "+String.valueOf(p.friendQQ));
}
}
else {
getSession().getBuddyManager().storePendingStatus(getSession().getTransport().convertIDToJID(String.valueOf(p.friendQQ)), ((QQTransport)getSession().getTransport()).convertQQStatusToXMPP(p.status), null);
}
} catch (Exception ex) {
Log.error("Failed to handle friend status change event: ", ex);
}
}
}