/*
* 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.irc;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import net.sf.kraken.muc.MUCTransportRoom;
import net.sf.kraken.pseudoroster.PseudoRoster;
import net.sf.kraken.pseudoroster.PseudoRosterItem;
import net.sf.kraken.pseudoroster.PseudoRosterManager;
import net.sf.kraken.registration.Registration;
import net.sf.kraken.roster.TransportBuddy;
import net.sf.kraken.session.TransportSession;
import net.sf.kraken.type.*;
import net.sf.kraken.util.StringUtils;
import org.apache.log4j.Logger;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.util.JiveGlobals;
import org.xmpp.packet.JID;
import f00f.net.irc.martyr.IRCConnection;
import f00f.net.irc.martyr.commands.AwayCommand;
import f00f.net.irc.martyr.commands.IsonCommand;
import f00f.net.irc.martyr.commands.ListCommand;
import f00f.net.irc.martyr.commands.MessageCommand;
import f00f.net.irc.martyr.commands.NamesCommand;
import f00f.net.irc.martyr.commands.QuitCommand;
import f00f.net.irc.martyr.services.AutoReconnect;
import f00f.net.irc.martyr.services.AutoRegister;
import f00f.net.irc.martyr.services.AutoResponder;
/**
* @author Daniel Henninger
*/
public class IRCSession extends TransportSession<IRCBuddy> {
static Logger Log = Logger.getLogger(IRCSession.class);
/**
* Timer to check for online status.
*/
public Timer timer = new Timer();
/**
* Interval at which status is checked.
*/
private int timerInterval = 30000; // 30 seconds
/**
* Status checker.
*/
StatusCheck statusCheck;
public IRCSession(Registration registration, JID jid, IRCTransport transport, Integer priority) {
super(registration, jid, transport, priority);
pseudoRoster = PseudoRosterManager.getInstance().getPseudoRoster(registration);
for (String contact : pseudoRoster.getContacts()) {
getBuddyManager().storeBuddy(new IRCBuddy(getBuddyManager(), contact, pseudoRoster.getItem(contact)));
}
}
/**
* Our pseudo roster.
*
* No server side buddy list, so we track it all here.
*/
private PseudoRoster pseudoRoster;
public IRCConnection connection;
private AutoResponder autoResponder;
private AutoRegister autoRegister;
private AutoReconnect autoReconnect;
private IRCListener listener;
public IRCConnection getConnection() {
return connection;
}
@Override
public void logIn(PresenceType presenceType, String verboseStatus) {
connection = new IRCConnection();
autoResponder = new AutoResponder(connection);
// autoReconnect = new AutoReconnect(connection);
autoRegister = new AutoRegister(connection, getRegistration().getNickname(), getRegistration().getNickname(), "IM Gateway User", getRegistration().getPassword());
listener = new IRCListener(this);
listener.enable();
new Thread() {
@Override
public void run() {
try {
connection.connect(JiveGlobals.getProperty("plugin.gateway.irc.connecthost", "irc.freenode.net"),
JiveGlobals.getIntProperty("plugin.gateway.irc.connectport", 7000));
setPresence(PresenceType.available);
setLoginStatus(TransportLoginStatus.LOGGED_IN);
try {
getTransport().syncLegacyRoster(getJID(), getBuddyManager().getBuddies());
}
catch (UserNotFoundException e) {
Log.debug("IRC: Error finding user while syncing legacy roster.");
}
List<String> buddyList = new ArrayList<String>();
for (TransportBuddy buddy : getBuddyManager().getBuddies()) {
buddyList.add(buddy.getName());
}
if (!buddyList.isEmpty()) {
connection.sendCommand(new IsonCommand(StringUtils.join(buddyList, " ")));
}
statusCheck = new StatusCheck();
timer.schedule(statusCheck, timerInterval, timerInterval);
getBuddyManager().activate();
}
catch (UnknownHostException e) {
Log.debug("IRC: Unable to connect to host:", e);
setFailureStatus(ConnectionFailureReason.CAN_NOT_CONNECT);
sessionDisconnected("IRC server does not appear to exist.");
}
catch (IOException e) {
Log.debug("IRC: Connection error while trying to connect ot IRC server:", e);
setFailureStatus(ConnectionFailureReason.CAN_NOT_CONNECT);
sessionDisconnected("Connection failed while trying to contact IRC server..");
}
}
}.start();
}
@Override
public void logOut() {
connection.sendCommand(new QuitCommand());
cleanUp();
sessionDisconnectedNoReconnect(null);
}
@Override
public void cleanUp() {
if (timer != null) {
try {
timer.cancel();
}
catch (Exception e) {
// Ignore
}
timer = null;
}
if (statusCheck != null) {
try {
statusCheck.cancel();
}
catch (Exception e) {
// Ignore
}
statusCheck = null;
}
if (listener != null) {
try {
listener.disable();
}
catch (Exception e) {
// Ignore
}
listener = null;
}
if (autoResponder != null) {
try {
autoResponder.disable();
}
catch (Exception e) {
// Ignore
}
autoResponder = null;
}
if (autoRegister != null) {
try {
autoRegister.disable();
}
catch (Exception e) {
// Ignore
}
autoRegister = null;
}
if (autoReconnect != null) {
try {
autoReconnect.disable();
}
catch (Exception e) {
// Ignore
}
autoReconnect = null;
}
if (connection != null) {
try {
connection.disconnect();
}
catch (Exception e) {
// Ignore
}
connection = null;
}
}
@Override
public void updateStatus(PresenceType presenceType, String verboseStatus) {
String awayMsg = ((IRCTransport)getTransport()).convertJabStatusToIRC(presenceType, verboseStatus);
if (awayMsg == null) {
try {
connection.sendCommand(new AwayCommand());
// setPresence(PresenceType.available);
}
catch (Exception e) {
// Ignore: is due to lost connection during logout typically
}
}
else {
try {
connection.sendCommand(new AwayCommand(awayMsg));
// setPresence(PresenceType.away);
}
catch (Exception e) {
// Ignore: is due to lost connection during logout typically
}
}
}
@Override
public void addContact(JID jid, String nickname, ArrayList<String> groups) {
String contact = getTransport().convertJIDToID(jid);
PseudoRosterItem rosterItem;
if (pseudoRoster.hasItem(contact)) {
rosterItem = pseudoRoster.getItem(contact);
rosterItem.setNickname(nickname);
rosterItem.setGroups(groups);
}
else {
rosterItem = pseudoRoster.createItem(contact, nickname, groups);
}
getBuddyManager().storeBuddy(new IRCBuddy(getBuddyManager(), contact, rosterItem));
// connection.sendCommand(new IsonCommand(contact));
}
@Override
public void removeContact(IRCBuddy contact) {
String ircContact = getTransport().convertJIDToID(contact.getJID());
pseudoRoster.removeItem(ircContact);
}
@Override
public void updateContact(IRCBuddy contact) {
String ircContact = getTransport().convertJIDToID(contact.getJID());
if (pseudoRoster.hasItem(ircContact)) {
PseudoRosterItem rosterItem = pseudoRoster.getItem(ircContact);
rosterItem.setNickname(contact.getNickname());
rosterItem.setGroups((List<String>)contact.getGroups());
// connection.sendCommand(new IsonCommand(ircContact));
}
else {
PseudoRosterItem rosterItem = pseudoRoster.createItem(ircContact, contact.getNickname(), (List<String>)contact.getGroups());
getBuddyManager().storeBuddy(new IRCBuddy(getBuddyManager(), ircContact, rosterItem));
// connection.sendCommand(new IsonCommand(ircContact));
}
}
/**
* @see net.sf.kraken.session.TransportSession#acceptAddContact(JID)
*/
@Override
public void acceptAddContact(JID jid) {
final String userID = getTransport().convertJIDToID(jid);
Log.debug("IRC: accept-adding is currently not implemented."
+ " Cannot accept-add: " + userID);
// TODO: Currently unimplemented
}
@Override
public void sendMessage(JID jid, String message) {
connection.sendCommand(new MessageCommand(getTransport().convertJIDToID(jid), message));
}
@Override
public void sendChatState(JID jid, ChatStateType chatState) {
// Nothing to do here
}
/**
* @see net.sf.kraken.session.TransportSession#sendBuzzNotification(org.xmpp.packet.JID, String)
*/
@Override
public void sendBuzzNotification(JID jid, String message) {
}
/**
* @see net.sf.kraken.session.TransportSession#updateLegacyAvatar(String, byte[])
*/
@Override
public void updateLegacyAvatar(String type, byte[] data) {
}
/**
* @see net.sf.kraken.session.TransportSession#getRooms()
*/
@Override
public void getRooms() {
if (getTransport().getMUCTransport().isRoomCacheOutOfDate()) {
getTransport().getMUCTransport().clearRoomCache();
connection.sendCommand(new ListCommand());
getTransport().getMUCTransport().updateRoomCacheTimestamp();
}
else {
// This will be ignored if no one asked for it.
getTransport().getMUCTransport().sendRooms(getJID(), getTransport().getMUCTransport().getCachedRooms());
}
}
/**
* @see net.sf.kraken.session.TransportSession#getRoomInfo(String room)
*/
@Override
public void getRoomInfo(String room) {
if (getTransport().getMUCTransport().isRoomCacheOutOfDate()) {
connection.sendCommand(new ListCommand(room));
}
else {
// This will be ignored if no one asked for it.
MUCTransportRoom mucRoom = getTransport().getMUCTransport().getCachedRoom(room);
if (mucRoom != null) {
getTransport().getMUCTransport().sendRoomInfo(getJID(), getTransport().getMUCTransport().convertIDToJID(mucRoom.getName(), null), mucRoom);
}
else {
getTransport().getMUCTransport().cancelPendingRequest(getJID(), getTransport().getMUCTransport().convertIDToJID(room, null), NameSpace.DISCO_INFO);
}
}
}
/**
* @see net.sf.kraken.session.TransportSession#getRoomMembers(String room)
*/
@Override
public void getRoomMembers(String room) {
// transport.cancelPendingRequest(getSession().getJID(), transport.convertIDToJID(roomname, nickname), BaseMUCTransport.DISCO_ITEMS);
connection.sendCommand(new NamesCommand(room));
}
private class StatusCheck extends TimerTask {
/**
* Send ISON to IRC to check on status of contacts.
*/
@Override
public void run() {
List<String> buddyList = new ArrayList<String>();
for (TransportBuddy buddy : getBuddyManager().getBuddies()) {
buddyList.add(buddy.getName());
}
if (!buddyList.isEmpty()) {
connection.sendCommand(new IsonCommand(buddyList));
}
}
}
}