package hudson.plugins.ircbot.v2; import hudson.Util; import hudson.plugins.im.AuthenticationHolder; import hudson.plugins.im.GroupChatIMMessageTarget; import hudson.plugins.im.IMConnection; import hudson.plugins.im.IMConnectionListener; import hudson.plugins.im.IMException; import hudson.plugins.im.IMMessage; import hudson.plugins.im.IMMessageListener; import hudson.plugins.im.IMMessageTarget; import hudson.plugins.im.IMPresence; import hudson.plugins.im.bot.Bot; import hudson.plugins.im.tools.ExceptionHelper; import hudson.plugins.ircbot.IrcPublisher.DescriptorImpl; import hudson.plugins.ircbot.v2.PircConnection.JoinListener; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Logger; import org.acegisecurity.Authentication; import org.jibble.pircbot.IrcException; import org.jibble.pircbot.NickAlreadyInUseException; public class IRCConnection implements IMConnection, JoinListener { private static final Logger LOGGER = Logger.getLogger(IRCConnection.class.getName()); private final DescriptorImpl descriptor; private final AuthenticationHolder authentication; private PircConnection pircConnection; private List<IMMessageTarget> groupChats; private final List<Bot> bots = new ArrayList<Bot>(); private final Map<String, Bot> privateChats = new HashMap<String, Bot>(); public IRCConnection(DescriptorImpl descriptor, AuthenticationHolder authentication) { this.descriptor = descriptor; this.authentication = authentication; if (descriptor.getDefaultTargets() != null) { this.groupChats = descriptor.getDefaultTargets(); } else { this.groupChats = Collections.emptyList(); } } @Override public void close() { if (this.pircConnection != null && this.pircConnection.isConnected()) { this.pircConnection.disconnect(); this.pircConnection.dispose(); } } @Override public boolean isConnected() { return this.pircConnection != null && this.pircConnection.isConnected(); } @Override public boolean connect() { try { this.pircConnection = new PircConnection(this.descriptor.getNick(), this.descriptor.isUseNotice()); this.pircConnection.connect(this.descriptor.getHost(), this.descriptor.getPort(), this.descriptor.getPassword()); LOGGER.info("connected to IRC"); this.pircConnection.addJoinListener(this); final String nickServPassword = this.descriptor.getNickServPassword(); if(Util.fixEmpty(nickServPassword) != null) { this.pircConnection.identify(nickServPassword); } for (IMMessageTarget groupChatName : this.groupChats) { try { getGroupChat(groupChatName); } catch (Exception e) { // if we got here, the IRC connection could be established, but probably the channel name // is invalid LOGGER.warning("Unable to connect to channel '" + groupChatName + "'.\n" + "Message: " + ExceptionHelper.dump(e)); } } pircConnection.addMessageListener(this.descriptor.getNick(), PircConnection.CHAT_ESTABLISHER, new ChatEstablishedListener()); return true; } catch (NickAlreadyInUseException e) { LOGGER.warning("Error connecting to irc: " + e); } catch (IOException e) { LOGGER.warning("Error connecting to irc: " + e); } catch (IrcException e) { LOGGER.warning("Error connecting to irc: " + e); } return false; } private void getGroupChat(IMMessageTarget groupChat) { if (! (groupChat instanceof GroupChatIMMessageTarget)) { LOGGER.warning(groupChat + " is no channel. Cannot join."); return; } GroupChatIMMessageTarget channel = (GroupChatIMMessageTarget)groupChat; LOGGER.info("Trying to join channel " + channel.getName()); if (channel.hasPassword()) { this.pircConnection.joinChannel(channel.getName(), channel.getPassword()); } else { this.pircConnection.joinChannel(channel.getName()); } // TODO: how to check that join was successful (channelJoined is called later - // how long should we possibly wait until we declare that join was unsuccessful?) this.bots.add(new Bot(new IRCChannel(channel.getName(), this.pircConnection), this.descriptor.getNick(), this.descriptor.getHost(), this.descriptor.getCommandPrefix(), this.authentication)); } @Override public void channelJoined(String channelName) { LOGGER.info("Joined channel " + channelName); } @Override public void addConnectionListener(IMConnectionListener listener) { if (this.pircConnection != null) this.pircConnection.addConnectionListener(listener); } @Override public void removeConnectionListener(IMConnectionListener listener) { if (this.pircConnection != null) this.pircConnection.removeConnectionListener(listener); } @Override public void send(IMMessageTarget target, String text) throws IMException { this.pircConnection.sendIMMessage(target.toString(), text); } @Override public void setPresence(IMPresence presence, String statusMessage) throws IMException { if (presence.ordinal() >= IMPresence.OCCUPIED.ordinal()) { if (statusMessage == null || statusMessage.trim().length() == 0) { statusMessage = "away"; } this.pircConnection.sendRawLineViaQueue("AWAY " + statusMessage); } else { this.pircConnection.sendRawLineViaQueue("AWAY"); } } private class ChatEstablishedListener implements IMMessageListener { @Override public void onMessage(IMMessage message) { if(!message.getTo().equals(descriptor.getNick())) { throw new IllegalStateException("Intercepted message to '" + message.getTo() + "'. That shouldn't happen!"); } synchronized (privateChats) { if (privateChats.containsKey(message.getFrom())) { // ignore. We're already in a chat with partner return; } IRCPrivateChat chat = new IRCPrivateChat(pircConnection, descriptor.getUserName(), message.getFrom()); Bot bot = new Bot(chat, descriptor.getNick(), descriptor.getHost(), descriptor.getCommandPrefix(), authentication); privateChats.put(message.getFrom(), bot); // we must replay this message as it could contain a command bot.onMessage(message); } } } }