/*
* 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.yahoo;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import net.sf.kraken.BaseTransport;
import net.sf.kraken.pseudoroster.PseudoRosterItem;
import net.sf.kraken.type.ConnectionFailureReason;
import net.sf.kraken.type.TransportLoginStatus;
import net.sf.kraken.util.chatstate.ChatStateEventSource;
import org.apache.log4j.Logger;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.NotFoundException;
import org.openymsg.network.*;
import org.openymsg.network.event.*;
import org.openymsg.support.MessageDecoder;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;
import org.xmpp.packet.Presence;
/**
* Handles incoming packets from Yahoo.
*
* This takes care of events we don't do anything with yet by logging them.
*
* @author Daniel Henninger
* Heavily inspired by Noah Campbell's work.
*/
@SuppressWarnings({"ThrowableResultOfMethodCallIgnored"})
public class YahooListener implements SessionListener {
static Logger Log = Logger.getLogger(YahooListener.class);
/**
* Handles converting messages between formats.
*/
private MessageDecoder messageDecoder = new MessageDecoder();
/**
* Indicator for whether we've gotten through the initial email notification.
*/
private Boolean emailInitialized = false;
/**
* Creates a Yahoo session listener affiliated with a session.
*
* @param session The YahooSession instance we are associatd with.
*/
public YahooListener(YahooSession session) {
this.yahooSessionRef = new WeakReference<YahooSession>(session);
}
/**
* The transport session we are affiliated with.
*/
WeakReference<YahooSession> yahooSessionRef;
/**
* Returns the Yahoo session this listener is attached to.
*
* @return Yahoo session we are attached to.
*/
public YahooSession getSession() {
return yahooSessionRef.get();
}
/**
* @see org.openymsg.network.event.SessionAdapter#messageReceived(org.openymsg.network.event.SessionEvent)
*/
public void messageReceived(SessionEvent event) {
getSession().getTransport().sendMessage(
getSession().getJID(),
getSession().getTransport().convertIDToJID(event.getFrom()),
messageDecoder.decodeToText(event.getMessage())
);
}
/**
* @see org.openymsg.network.event.SessionAdapter#offlineMessageReceived(org.openymsg.network.event.SessionEvent)
*/
public void offlineMessageReceived(SessionEvent event) {
getSession().getTransport().sendMessage(
getSession().getJID(),
getSession().getTransport().convertIDToJID(event.getFrom()),
messageDecoder.decodeToText(event.getMessage())
);
}
/**
* @see org.openymsg.network.event.SessionAdapter#newMailReceived(org.openymsg.network.event.SessionNewMailEvent)
*/
public void newMailReceived(SessionNewMailEvent event) {
if (JiveGlobals.getBooleanProperty("plugin.gateway.yahoo.mailnotifications", true) && (emailInitialized || event.getMailCount() > 0)) {
if (!emailInitialized) {
getSession().getTransport().sendMessage(
getSession().getJID(),
getSession().getTransport().getJID(),
LocaleUtils.getLocalizedString("gateway.yahoo.mail", "kraken", Arrays.asList(Integer.toString(event.getMailCount()))),
Message.Type.headline
);
}
else {
getSession().getTransport().sendMessage(
getSession().getJID(),
getSession().getTransport().getJID(),
LocaleUtils.getLocalizedString("gateway.yahoo.newmail", "kraken"),
Message.Type.headline
);
}
}
emailInitialized = true;
}
/**
* @see org.openymsg.network.event.SessionAdapter#friendsUpdateReceived(org.openymsg.network.event.SessionFriendEvent)
*/
public void friendsUpdateReceived(SessionFriendEvent event) {
YahooUser user = event.getUser();
Log.debug("Yahoo: Got status update: "+user);
if (getSession().getBuddyManager().isActivated()) {
try {
YahooBuddy yahooBuddy = getSession().getBuddyManager().getBuddy(getSession().getTransport().convertIDToJID(user.getId()));
yahooBuddy.yahooUser = user;
yahooBuddy.setPresenceAndStatus(((YahooTransport)getSession().getTransport()).convertYahooStatusToXMPP(user.getStatus(), user.getCustomStatus()), user.getCustomStatusMessage());
}
catch (NotFoundException e) {
// Not in our list, lets change that.
PseudoRosterItem rosterItem = getSession().getPseudoRoster().getItem(user.getId());
String nickname = null;
if (rosterItem != null) {
nickname = rosterItem.getNickname();
}
if (nickname == null) {
nickname = user.getId();
}
YahooBuddy yahooBuddy = new YahooBuddy(getSession().getBuddyManager(), user, nickname, user.getGroupIds(), rosterItem);
getSession().getBuddyManager().storeBuddy(yahooBuddy);
yahooBuddy.setPresenceAndStatus(((YahooTransport)getSession().getTransport()).convertYahooStatusToXMPP(user.getStatus(), user.getCustomStatus()), user.getCustomStatusMessage());
//TODO: Something is amiss with openymsg-- telling us we have our full buddy list too early
//Log.debug("Yahoo: Received presense notification for contact we don't care about: "+event.getFrom());
}
}
else {
getSession().getBuddyManager().storePendingStatus(getSession().getTransport().convertIDToJID(user.getId()), ((YahooTransport)getSession().getTransport()).convertYahooStatusToXMPP(user.getStatus(), user.getCustomStatus()), user.getCustomStatusMessage());
}
}
/**
* @see org.openymsg.network.event.SessionAdapter#friendAddedReceived(org.openymsg.network.event.SessionFriendEvent)
*/
public void friendAddedReceived(SessionFriendEvent event) {
// TODO: This means a friend -we- added is now added, do we want to use this
// Presence p = new Presence(Presence.Type.subscribe);
// p.setTo(getSession().getJID());
// p.setFrom(getSession().getTransport().convertIDToJID(event.getFrom()));
// getSession().getTransport().sendPacket(p);
}
/**
* @see org.openymsg.network.event.SessionAdapter#friendRemovedReceived(org.openymsg.network.event.SessionFriendEvent)
*/
public void friendRemovedReceived(SessionFriendEvent event) {
// TODO: This means a friend -we- removed is now gone, do we want to use this
// Presence p = new Presence(Presence.Type.unsubscribe);
// p.setTo(getSession().getJID());
// p.setFrom(getSession().getTransport().convertIDToJID(event.getFrom()));
// getSession().getTransport().sendPacket(p);
}
/**
* @see org.openymsg.network.event.SessionAdapter#chatJoinReceived(org.openymsg.network.event.SessionChatEvent)
*/
public void chatJoinReceived(SessionChatEvent sessionChatEvent) {
}
/**
* @see org.openymsg.network.event.SessionAdapter#chatExitReceived(org.openymsg.network.event.SessionChatEvent)
*/
public void chatExitReceived(SessionChatEvent sessionChatEvent) {
}
/**
* @see org.openymsg.network.event.SessionAdapter#connectionClosed(org.openymsg.network.event.SessionEvent)
*/
public void connectionClosed(SessionEvent event) {
Log.debug(event == null ? "closed event is null":event.toString());
if (getSession().isLoggedIn()) {
getSession().setLoginStatus(TransportLoginStatus.DISCONNECTED);
getSession().sessionDisconnectedNoReconnect(null);
}
}
/**
* @see org.openymsg.network.event.SessionAdapter#fileTransferReceived(org.openymsg.network.event.SessionFileTransferEvent)
*/
public void fileTransferReceived(SessionFileTransferEvent event) {
Log.debug(event.toString());
}
/**
* @see org.openymsg.network.event.SessionAdapter#listReceived(org.openymsg.network.event.SessionListEvent)
*/
public void listReceived(SessionListEvent event) {
// We just got the entire contact list. Lets sync up.
getSession().syncUsers();
}
/**
* @see org.openymsg.network.event.SessionAdapter#buzzReceived(org.openymsg.network.event.SessionEvent)
*/
public void buzzReceived(SessionEvent event) {
getSession().getTransport().sendAttentionNotification(
getSession().getJID(),
getSession().getTransport().convertIDToJID(event.getFrom()),
messageDecoder.decodeToText(event.getMessage())
);
}
/**
* @see org.openymsg.network.event.SessionAdapter#errorPacketReceived(org.openymsg.network.event.SessionErrorEvent)
*/
public void errorPacketReceived(SessionErrorEvent event) {
Log.debug("Error from yahoo: "+event.getMessage()+", Code:"+event.getCode());
getSession().getTransport().sendMessage(
getSession().getJID(),
getSession().getTransport().getJID(),
LocaleUtils.getLocalizedString("gateway.yahoo.error", "kraken")+" "+event.getMessage(),
Message.Type.error
);
}
/**
* @see org.openymsg.network.event.SessionAdapter#inputExceptionThrown(org.openymsg.network.event.SessionExceptionEvent)
*/
public void inputExceptionThrown(SessionExceptionEvent event) {
Log.debug("Input error from yahoo: "+event.getMessage(), event.getException());
if (event.getException().getClass().equals(LoginRefusedException.class)) {
String reason = LocaleUtils.getLocalizedString("gateway.yahoo.loginrefused", "kraken");
LoginRefusedException e = (LoginRefusedException)event.getException();
AuthenticationState state = e.getStatus();
if (state == AuthenticationState.BADUSERNAME) {
reason = LocaleUtils.getLocalizedString("gateway.yahoo.unknownuser", "kraken");
getSession().setFailureStatus(ConnectionFailureReason.USERNAME_OR_PASSWORD_INCORRECT);
getSession().sessionDisconnectedNoReconnect(reason);
}
else if (state == AuthenticationState.BAD) {
reason = LocaleUtils.getLocalizedString("gateway.yahoo.badpassword", "kraken");
getSession().setFailureStatus(ConnectionFailureReason.USERNAME_OR_PASSWORD_INCORRECT);
getSession().sessionDisconnectedNoReconnect(reason);
}
else if (state == AuthenticationState.LOCKED) {
reason = LocaleUtils.getLocalizedString("gateway.yahoo.accountlocked", "kraken");
getSession().setFailureStatus(ConnectionFailureReason.LOCKED_OUT);
getSession().sessionDisconnectedNoReconnect(reason);
}
else {
getSession().setFailureStatus(ConnectionFailureReason.UNKNOWN);
getSession().sessionDisconnectedNoReconnect(reason);
}
}
}
/**
* @see org.openymsg.network.event.SessionAdapter#notifyReceived(org.openymsg.network.event.SessionNotifyEvent)
*/
public void notifyReceived(SessionNotifyEvent event) {
Log.debug(event.toString());
if (event.isTyping()) {
final BaseTransport<YahooBuddy> transport = getSession().getTransport();
final ChatStateEventSource chatStateEventSource = transport.getChatStateEventSource();
final JID localJid = getSession().getJID();
final JID legacyJid = transport.convertIDToJID(event.getFrom());
if (event.isOn()) {
chatStateEventSource.isComposing(legacyJid, localJid);
}
else {
chatStateEventSource.isPaused(legacyJid, localJid);
}
}
}
/**
* @see org.openymsg.network.event.SessionAdapter#contactRequestReceived(org.openymsg.network.event.SessionEvent)
*/
/** is gone??
@Override
public void contactRequestReceived(SessionEvent event) {
final Presence p = new Presence(Presence.Type.subscribe);
p.setTo(getSession().getJID());
p.setFrom(getSession().getTransport().convertIDToJID(event.getFrom()));
getSession().getTransport().sendPacket(p);
}
*/
/**
* @see org.openymsg.network.event.SessionAdapter#contactRejectionReceived(org.openymsg.network.event.SessionFriendRejectedEvent)
*/
public void contactRejectionReceived(SessionFriendRejectedEvent event) {
// TODO: Is this correct? unsubscribed for a rejection?
Log.debug(event.toString());
Presence p = new Presence(Presence.Type.unsubscribed);
p.setTo(getSession().getJID());
p.setFrom(getSession().getTransport().convertIDToJID(event.getFrom()));
getSession().getTransport().sendPacket(p);
}
/**
* @see org.openymsg.network.event.SessionAdapter#chatMessageReceived(org.openymsg.network.event.SessionChatEvent)
*/
public void chatMessageReceived(SessionChatEvent event) {
Log.debug(event.toString());
}
/**
* @see org.openymsg.network.event.SessionAdapter#chatUserUpdateReceived(org.openymsg.network.event.SessionChatEvent)
*/
public void chatUserUpdateReceived(SessionChatEvent event) {
Log.debug(event.toString());
}
/**
* A contact has accepted our subscription request
*/
public void contactAcceptedReceived(SessionFriendAcceptedEvent event) {
final Set<String> groups = new HashSet<String>();
groups.add(event.getGroupName());
final YahooUser user = new YahooUser(event.getFrom());
// TODO clean up the next line. This implementation of constructor for YahooBuddy seems to be inappropriate here.
final YahooBuddy buddy = new YahooBuddy(getSession().getBuddyManager(), user, null, groups, null);
getSession().getBuddyManager().storeBuddy(buddy);
final Presence p = new Presence(Presence.Type.subscribed);
p.setTo(getSession().getJID());
p.setFrom(getSession().getTransport().convertIDToJID(event.getFrom()));
getSession().getTransport().sendPacket(p);
}
/**
* @see org.openymsg.network.event.SessionAdapter#chatConnectionClosed(org.openymsg.network.event.SessionEvent)
*/
public void chatConnectionClosed(SessionEvent event) {
Log.debug(event.toString());
}
/**
* Dispatches an event immediately to all listeners, instead of queuing. it.
*
* @param event
* The event to be dispatched.
*/
public void dispatch(FireEvent event) {
final SessionEvent ev = event.getEvent();
switch (event.getType()) {
case LOGOFF:
connectionClosed(ev);
break;
case Y6_STATUS_UPDATE:
friendsUpdateReceived((SessionFriendEvent) ev);
break;
case MESSAGE:
messageReceived(ev);
break;
case X_OFFLINE:
offlineMessageReceived(ev);
break;
case NEWMAIL:
newMailReceived((SessionNewMailEvent) ev);
break;
case CONTACTNEW:
//TODO: contactRequestReceived((SessionAuthorizationEvent) ev);
break;
case CONFDECLINE:
//TODO: conferenceInviteDeclinedReceived((SessionConferenceDeclineInviteEvent) ev);
break;
case CONFINVITE:
//TODO: conferenceInviteReceived((SessionConferenceInviteEvent) ev);
break;
case CONFLOGON:
//TODO: conferenceLogonReceived((SessionConferenceLogonEvent) ev);
break;
case CONFLOGOFF:
//TODO: conferenceLogoffReceived((SessionConferenceLogoffEvent) ev);
break;
case CONFMSG:
//TODO: conferenceMessageReceived((SessionConferenceMessageEvent) ev);
break;
case FILETRANSFER:
fileTransferReceived((SessionFileTransferEvent) ev);
break;
case NOTIFY:
if (ev instanceof SessionNotifyEvent) {
notifyReceived((SessionNotifyEvent) ev);
}
else {
// probably a SessionPictureEvent, not handled
}
break;
case LIST:
listReceived((SessionListEvent) ev);
break;
case FRIENDADD:
SessionFriendEvent friendAddEvent = (SessionFriendEvent) ev;
if (friendAddEvent.isFailure()) {
//TODO: friendsUpdateFailureReceived((SessionFriendFailureEvent) ev);
}
else {
friendAddedReceived((SessionFriendEvent) ev);
}
break;
case FRIENDREMOVE:
friendRemovedReceived((SessionFriendEvent) ev);
break;
case GOTGROUPRENAME:
//TODO: groupRenameReceived((SessionGroupEvent) ev);
break;
case CONTACTREJECT:
contactRejectionReceived((SessionFriendRejectedEvent) ev);
break;
case CHATJOIN:
chatJoinReceived((SessionChatEvent) ev);
break;
case CHATEXIT:
chatExitReceived((SessionChatEvent) ev);
break;
case CHATDISCONNECT:
chatConnectionClosed(ev);
break;
case CHATMSG:
chatMessageReceived((SessionChatEvent) ev);
break;
case X_CHATUPDATE:
chatUserUpdateReceived((SessionChatEvent) ev);
break;
case X_ERROR:
errorPacketReceived((SessionErrorEvent) ev);
break;
case X_EXCEPTION:
inputExceptionThrown((SessionExceptionEvent) ev);
break;
case X_BUZZ:
buzzReceived(ev);
break;
case LOGON:
logonReceived(ev);
break;
case X_CHATCAPTCHA:
//TODO: chatCaptchaReceived((SessionChatEvent) ev);
break;
case PICTURE:
//TODO: pictureReceived((SessionPictureEvent) ev);
break;
case Y7_AUTHORIZATION:
if (ev instanceof SessionAuthorizationEvent) {
//TODO: contactRequestReceived((SessionAuthorizationEvent) ev);
}
else if (ev instanceof SessionFriendRejectedEvent) {
contactRejectionReceived((SessionFriendRejectedEvent) ev);
}
else if (ev instanceof SessionFriendAcceptedEvent) {
contactAcceptedReceived((SessionFriendAcceptedEvent) ev);
}
else {
throw new IllegalArgumentException("Don't know how to handle '" + event.getType() + "' event: " + event);
}
break;
default:
throw new IllegalArgumentException("Don't know how to handle service type '" + event.getType() + "'");
}
}
/**
* Listens for logon event (successful logon)
* @param ev Sessino event
*/
private void logonReceived(SessionEvent ev) {
try {
getSession().getYahooSession().setStatus(((YahooTransport)getSession().getTransport()).convertXMPPStatusToYahoo(getSession().getPresence()));
}
catch (IOException e) {
Log.debug("Yahoo login caused IO exception:", e);
getSession().getTransport().sendMessage(
getSession().getJID(),
getSession().getTransport().getJID(),
LocaleUtils.getLocalizedString("gateway.yahoo.unknownerror", "kraken"),
Message.Type.error
);
getSession().setLoginStatus(TransportLoginStatus.LOGGED_OUT);
getSession().setFailureStatus(ConnectionFailureReason.CAN_NOT_CONNECT);
getSession().sessionDisconnected(LocaleUtils.getLocalizedString("gateway.yahoo.unknownerror", "kraken"));
}
getSession().syncUsers();
}
}