/*
Eteria IRC Client, an RFC 1459 compliant client program written in Java.
Copyright (C) 2000-2001 Javier Kohen <jkohen at tough.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
import java.applet.AudioClip;
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.lang.reflect.*;
import java.net.*;
import java.text.ChoiceFormat;
import java.text.Collator;
import java.text.MessageFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import ar.com.jkohen.applet.*;
import ar.com.jkohen.awt.ChatPanel;
import ar.com.jkohen.awt.ImageCanvas;
import ar.com.jkohen.awt.NickInfo;
import ar.com.jkohen.awt.event.ChatPanelEvent;
import ar.com.jkohen.awt.event.ChatPanelListener;
import ar.com.jkohen.awt.MircSmileyTextArea;
import ar.com.jkohen.awt.TextAttributePicker;
import ar.com.jkohen.irc.*;
import ar.com.jkohen.net.*;
import ar.com.jkohen.util.*;
/**
* This is Eteria IRC Client's core class. It contains the main control loop, some high level communication methods and topmost-GUI code.
*
* @author Javier Kohen
*/
public class EIRC extends Applet implements ClientProcess, Observer, ActionListener, ItemListener, MouseListener, ChatPanelListener, WindowListener
{
/**
* Program's name.
* Used as part of "About" info.
*/
public final static String PACKAGE = "Eteria IRC Client";
/**
* Program's release version.
* Used as part of "About" info.
* Should be either a "YYYYMMDD" date or a "X.Y.Z" version number.
*/
public final static String VERSION = "Beta 20081014 19:43";
/**
* Program's release extra version.
* Used as part of "About" info.
* Should be a String describing in-site's modifications.
*/
public final static String VERSION_EXTRA = "Version www.coolsmile.net + avatars";
/**
* Author's name.
* Used as part of "About" info.
*/
public final static String AUTHOR = "Javier Kohen";
private static Hashtable commands;
private static ResourceBundle user_commands;
private static Resources res;
private Collator collator;
private Vector channels;
private CollatedHashtable channel_windows;
private CollatedHashtable privates;
private Vector ignore_list;
private Vector names;
// These are used to build the channel list from the server replies to the LIST command.
private Vector list_reply;
// private boolean missing_default_channel_in_list;
// Used to build the users list from the server replies to the WHO command.
private Vector who_reply;
// Store a channel's +b/e/I list
private Vector list;
private ConfigurationProperties properties;
private static Font mainfont = new Font("Helvetica", Font.PLAIN, 11);
private static Color mainbg = SystemColor.control;
private static Color mainfg = SystemColor.controlText;
private static Color textbg = SystemColor.window;
private static Color textfg = SystemColor.textText;
private static Color selbg = SystemColor.textHighlight;
private static Color selfg = SystemColor.textHighlightText;
/* GUI. */
private Image main_icon;
private TextField nick_entry;
private Label label;
private Label away;
private PopupMenu menu;
private ControlPanel control_panel;
private ChatPanelContainer chat_panel;
private StatusWindow status;
private ChanListWindow chan_list;
private WhoListWindow who_list;
private OutputWindow debug_window;
private Frame f;
private boolean application = false;
private Hashtable color_list;
private String current_server;
private String status_tag;
private String current_nick, username, realname;
private String new_nick;
private String original_nick;
private ServerProcess server;
private IRCServices irc_services;
private boolean is_away;
private String away_str;
/* Configuration properties. */
private boolean special_services;
private int debug_traffic;
private String date_pattern;
private String nicksrv_pass;
private String irc_pass;
private String quit_message;
private boolean request_motd;
private boolean see_everything_from_server;
private boolean see_join;
private boolean see_invite;
private boolean on_dcc_notify_peer;
private String service_bots;
private boolean hideip;
private boolean focus_opening_privates;
private boolean no_privates;
private boolean auto_list;
private String user_modes;
private int write_color;
private int scroll_speed;
private int silent;
private AudioClip event_sounds[];
private String net_encoding;
private String network_name = "";
private String default_join;
private int restrict_join;
private boolean connected;
private boolean logged_in;
private boolean quit_sent;
private boolean server_admin;
private boolean ircop_override;
private boolean who_invisible;
private boolean login_time;
// Dialogs.
private static Configurator configurator;
private static ModeList mode_list;
private static TextAreaCopy tac;
private static ASLBox asl;
private static HelpBox help;
private MessageFormat chan_title, private_title, chanlist_title, wholist_title;
static
{
commands = new Hashtable(50, 1);
commands.put("ping", new Integer(-1));
commands.put("nick", new Integer(-2));
commands.put("join", new Integer(-3));
commands.put("mode", new Integer(-4));
commands.put("part", new Integer(-5));
commands.put("quit", new Integer(-6));
commands.put("kick", new Integer(-7));
commands.put("topic", new Integer(-8));
commands.put("privmsg", new Integer(-9));
commands.put("notice", new Integer(-10));
commands.put("error", new Integer(-11));
commands.put("wallops", new Integer(-12));
commands.put("invite", new Integer(-13));
commands.put("pong", new Integer(-14));
commands.put("001", new Integer(001));
commands.put("232", new Integer(232));
commands.put("251", new Integer(251));
commands.put("301", new Integer(301));
commands.put("303", new Integer(303));
commands.put("302", new Integer(302));
commands.put("305", new Integer(305));
commands.put("306", new Integer(306));
commands.put("307", new Integer(307));
commands.put("310", new Integer(310));
commands.put("311", new Integer(311));
commands.put("312", new Integer(312));
commands.put("313", new Integer(313));
commands.put("314", new Integer(314));
commands.put("315", new Integer(315));
commands.put("317", new Integer(317));
commands.put("318", new Integer(318)); // No action needed.
commands.put("319", new Integer(319));
commands.put("320", new Integer(320));
commands.put("321", new Integer(321));
commands.put("322", new Integer(322));
commands.put("323", new Integer(323));
commands.put("324", new Integer(324));
commands.put("329", new Integer(329)); // No action needed.
commands.put("331", new Integer(331));
commands.put("332", new Integer(332));
commands.put("333", new Integer(333));
commands.put("335", new Integer(335));
commands.put("346", new Integer(346));
commands.put("347", new Integer(347));
commands.put("348", new Integer(348));
commands.put("349", new Integer(349));
commands.put("352", new Integer(352));
commands.put("353", new Integer(353));
commands.put("366", new Integer(366));
commands.put("367", new Integer(367));
commands.put("368", new Integer(368));
commands.put("371", new Integer(371));
commands.put("372", new Integer(372));
commands.put("375", new Integer(375));
commands.put("376", new Integer(376));
commands.put("378", new Integer(378));
commands.put("381", new Integer(381));
commands.put("391", new Integer(391));
commands.put("401", new Integer(401));
commands.put("404", new Integer(404));
commands.put("406", new Integer(406));
commands.put("421", new Integer(421));
commands.put("422", new Integer(422));
commands.put("432", new Integer(432));
commands.put("433", new Integer(433));
commands.put("437", new Integer(437));
commands.put("438", new Integer(438));
commands.put("447", new Integer(447));
commands.put("461", new Integer(461));
commands.put("464", new Integer(464));
commands.put("465", new Integer(465));
commands.put("471", new Integer(471));
commands.put("473", new Integer(473));
commands.put("474", new Integer(474));
commands.put("475", new Integer(475));
commands.put("477", new Integer(477));
commands.put("478", new Integer(478));
commands.put("481", new Integer(481));
commands.put("482", new Integer(482));
commands.put("491", new Integer(491));
commands.put("536", new Integer(536));
commands.put("600", new Integer(600));
commands.put("601", new Integer(601));
commands.put("604", new Integer(604));
commands.put("605", new Integer(605));
}
/**
* Constructor for Applet instances.
* Must be present, even if empty.
*/
public EIRC()
{
}
public EIRC(boolean b)
{
this.application = b;
}
/**
* Execution starts here when the program is run out of Applet context.
* This method supplies a simple substitute for the Applet viewer.
*
* @param args a <code>String[]</code> containing command-line arguments.
*/
public static void main(String args[])
{
EIRC eirc = new EIRC(true);
eirc.setStub(new SimpleAppletStub(args));
eirc.init();
eirc.start();
}
public void init()
{
this.collator = RFC1459.getCollator();
this.channels = new Vector();
this.channel_windows = new CollatedHashtable(collator);
this.privates = new CollatedHashtable(collator);
this.ignore_list = new Vector();
this.names = new Vector();
this.event_sounds = new AudioClip[res.EVENTS];
res = new Resources(this, getParameter("language"));
/* Get main configuration
*/
Properties default_props = new Properties();
try
{
default_props.load(getClass().getResourceAsStream("configuration.properties"));
this.properties = new ConfigurationProperties(default_props);
} catch (IOException ex)
{
System.err.println(ex);
this.properties = new ConfigurationProperties();
}
properties.addObserver(this);
/* Read user's colors and sounds configurations
*/
Vector sound_list = new Vector();
color_list = new Hashtable();
for (Enumeration e = default_props.keys(); e.hasMoreElements() ;)
{
String key = (String)e.nextElement();
try
{
if (key.indexOf("sound.") == 0 && Integer.parseInt(key.substring(6)) > 0)
sound_list.addElement(default_props.getProperty(key));
if (key.indexOf("color.") == 0)
color_list.put(key.substring(6), Color.decode(default_props.getProperty(key)));
}
catch(NumberFormatException ex) {}
}
/* Load sounds in background
*/
if (properties.getBoolean("load_sounds"))
{
res.addObserver(this);
res.cacheSounds(sound_list, default_props.getProperty("sound.path"));
}
/* Force an update to initialize some variables to their defaults.
*/
update(properties, null);
// EIRC.user_commands = ResourceBundle.getBundle("Commands");
EIRC.user_commands = new Commands();
/* Read text colors
*/
Color fixedColors[] = new Color[16]; // 16 colors + 2 (fg/bg) internal.
for (int i = 0; i < fixedColors.length; i++)
{
try
{
fixedColors[i] = Color.decode(properties.getString("n" + i));
}
catch (Exception ex)
{
fixedColors[i] = Color.black;
System.err.println(ex);
}
}
MircSmileyTextArea.setColors(fixedColors);
TextAttributePicker.setColors(fixedColors);
int order[] = new int[16];
try
{
for (int i = 0; i < order.length; i++)
order[i] = Integer.parseInt(properties.getString("c" + i));
}
catch (Exception ex)
{
for (int i = 0; i < order.length; i++)
order[i] = i;
}
TextAttributePicker.setOrder(order);
for (Enumeration e = Resources.lang_resource.propertyNames(); e.hasMoreElements() ;)
{
String key = (String)e.nextElement();
if (key.indexOf("tld.") == 0)
NickInfo.addTLD(key.substring(key.indexOf(".") + 1), res.getString(key));
}
try
{
NickInfo.setParseASLType(Integer.parseInt(properties.getString("default_asl")));
} catch (NumberFormatException e) {}
chan_title = new MessageFormat(res.getString("top_panel.chan"));
private_title = new MessageFormat(res.getString("top_panel.private"));
chanlist_title = new MessageFormat(res.getString("top_panel.chanlist"));
wholist_title = new MessageFormat(res.getString("top_panel.wholist"));
main_icon = res.getImage("icon");
irc_services = new IRCServices(this);
SimpleAppletContext.setPath(default_props.getProperty("navigator"));
this.default_join = getParameter("join");
String t, n = "Helvetica";
int s = 12;
if ((t = getParameter("font_name")) != null)
n = t;
try
{
if ((t = getParameter("font_size")) != null)
s = Integer.parseInt(t);
}
catch (NumberFormatException e) {}
this.mainfont = new Font(n, Font.PLAIN, s);
try
{
if ((t = getParameter("mainbg")) != null)
this.mainbg = Color.decode(t);
}
catch (NumberFormatException e) {}
try
{
if ((t = getParameter("mainfg")) != null)
this.mainfg = Color.decode(t);
}
catch (NumberFormatException e) {}
try
{
if ((t = getParameter("textbg")) != null)
this.textbg = Color.decode(t);
}
catch (NumberFormatException e) {}
try
{
if ((t = getParameter("textfg")) != null)
this.textfg = Color.decode(t);
}
catch (NumberFormatException e) {}
try
{
if ((t = getParameter("selbg")) != null)
this.selbg = Color.decode(t);
}
catch (NumberFormatException e) {}
try
{
if ((t = getParameter("selfg")) != null)
this.selfg = Color.decode(t);
}
catch (NumberFormatException e) {}
// Send traffic to stderr.
// Turn off for production setups!
debug_traffic = 0;
if ((t = getParameter("debug_traffic")) != null)
{
try
{
debug_traffic = Integer.parseInt(t);
} catch (NumberFormatException e) {}
}
write_color = 1;
if ((t = getParameter("write_color")) != null)
{
try
{
write_color = Integer.parseInt(t);
if (write_color < 0 || write_color > 15)
write_color = 1;
} catch (NumberFormatException e) {}
properties.setInt("write_color", write_color);
}
if ((t = getParameter("nicksrv_pass")) == null)
t = "";
properties.setString("nicksrv_pass", t);
if ((t = getParameter("user_modes")) != null)
{
user_modes = "";
for (int i = 0; i < t.length(); i++)
{
char c = t.charAt(i);
if (Character.isLetter(c) || c == '+' || c == '-')
user_modes += c;
}
}
/* Create main GUI. */
// try
// {
// if (Class.forName("com.ms.security.PolicyEngine") != null)
// com.ms.security.PolicyEngine.assertPermission(com.ms.security.PermissionID.UI);
// }
// catch (Exception ex) {}
t = getParameter("spawn_frame");
if ((t != null && !t.equals("0")) || application)
{
f = new Frame(makeWindowTitle(""));
f.setIconImage(main_icon);
f.addWindowListener(this);
int width = 600;
int height = 400;
try
{
width = Integer.parseInt(getParameter("width"));
height = Integer.parseInt(getParameter("height"));
}
catch (Exception ex) {}
initGUI(f);
f.pack();
f.setSize(width, height);
Toolkit tkit = getToolkit();
f.setLocation((tkit.getScreenSize().width - f.getSize().width) / 2, (tkit.getScreenSize().height - f.getSize().height) / 2);
f.show();
f.addWindowListener(this);
f.setName("main");
}
else
{
f = null;
initGUI(this);
}
setBackground(mainbg);
setForeground(mainfg);
setSelectedBackground(selbg);
setFont(mainfont);
/* Event listeners and observers. */
nick_entry.addActionListener(this);
away.addMouseListener(this);
properties.addObserver(chan_list);
properties.addObserver(who_list);
properties.addObserver(status);
properties.addObserver(irc_services);
chan_list.update(properties, null);
who_list.update(properties, null);
status.update(properties, null);
irc_services.update(properties, null);
/* Misc. GUI init. */
if ((t = getParameter("nickname")) != null)
{
char [] str = t.toCharArray();
// Replace every '?' occurrence by a random decimal digit.
for (int i = 0; i < str.length; i++)
if ('?' == str[i])
str[i] = Character.forDigit((int) Math.floor(Math.random() * 10.0), 10);
nick_entry.setText(String.valueOf(str));
original_nick = String.valueOf(str);
}
if ((t = getParameter("irc_pass")) != null && t.length() > 0)
properties.setString("irc_pass", t);
username = "cool";
realname = "smile";
if ((t = getParameter("username")) != null && t.length() > 0)
username = t;
if ((t = getParameter("realname")) != null && t.length() > 0)
realname = t;
if (debug_traffic > 0)
{
String propertyNames[] = { "file.separator", "line.separator", "path.separator", "java.class.version", "java.vendor", "java.vendor.url", "java.version", "os.name", "os.arch", "os.version" };
debug(getAppletInfo());
debug("\n");
for (int i = 0; i < propertyNames.length; i++)
debug(propertyNames[i] + " = " + System.getProperty(propertyNames[i]));
debug("\n");
Locale l = Locale.getDefault();
debug("country = " + l.getCountry() + " (" + l.getDisplayCountry() + ")");
debug("language = " + l.getLanguage() + " (" + l.getDisplayLanguage() + ")");
debug("encoding = " + new java.io.OutputStreamWriter(System.out).getEncoding());
debug("\n");
}
}
public void openASL()
{
String t = getParameter("asl");
if((t != null && !t.equals("0")) || t == null)
{
if (asl == null)
{
asl = new ASLBox(this, getFrame(), res.getString("asl.connection"));
asl.addWindowListener(this);
asl.setName("asl");
}
else
{
asl.toFront();
}
asl.init(nick_entry.getText(), nicksrv_pass, realname);
}
}
public void start()
{
String t = getParameter("login");
// See if auto-login was requested.
if (t != null && !t.equals("0"))
{
// Can't login if no nickname was provided.
if ((t = getParameter("nickname")) == null || t.length() == 0)
status.printError(res.getString("eirc.s26"));
else
connect();
}
else
{
openASL();
}
}
public void stop()
{
disconnect();
closePrivates();
}
public void destroy()
{
// Remove all components from container.
removeAll();
}
private void initGUI(Container cont)
{
String t;
GridBagLayout gb = new GridBagLayout();
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(4, 4, 4, 4);
cont.setLayout(gb);
label = new Label(res.getString("eirc.enter_nick"), Label.RIGHT);
gbc.anchor = GridBagConstraints.EAST;
gb.setConstraints(label, gbc);
label.setBackground(mainbg);
t = getParameter("gui_nick");
if (t == null || !t.equals("0"))
cont.add(label);
this.nick_entry = new TextField(9);
gbc.anchor = GridBagConstraints.WEST;
gb.setConstraints(nick_entry, gbc);
nick_entry.setBackground(textbg);
if (t == null || !t.equals("0"))
cont.add(nick_entry);
this.menu = new PopupMenu();
CheckboxMenuItem cbm = new CheckboxMenuItem(res.getString("eirc.away_custom"));
cbm.addItemListener(this);
menu.add(cbm);
menu.addSeparator();
StringTokenizer tk = new StringTokenizer(res.getString("eirc.away_list"), "/");
while (tk.hasMoreTokens())
{
cbm = new CheckboxMenuItem(tk.nextToken());
cbm.addItemListener(this);
menu.add(cbm);
}
away = new Label(res.getString("eirc.away"));
gbc.anchor = GridBagConstraints.EAST;
gb.setConstraints(away, gbc);
t = getParameter("gui_away");
if (t == null || !t.equals("0"))
cont.add(away);
away.add(menu);
away.setBackground(mainbg);
away.setForeground(Color.blue);
/*
** Check if we can add some buttons.
*/
boolean enabled[] = new boolean[ControlPanel.COMPONENTS];
for (int i = 0; i < ControlPanel.COMPONENTS; i++)
enabled[i] = true;
t = getParameter("gui_chanlist");
if (t != null && t.equals("0"))
enabled[ControlPanel.CHANNELS] = false;
t = getParameter("gui_userlist");
if (t != null && t.equals("0"))
enabled[ControlPanel.WHO] = false;
t = getParameter("gui_options");
if (t != null && t.equals("0"))
enabled[ControlPanel.SETUP] = false;
t = getParameter("gui_help");
if (t != null && t.equals("0"))
enabled[ControlPanel.HELP] = false;
t = getParameter("gui_connect");
if (t != null && t.equals("0"))
enabled[ControlPanel.CONNECT] = false;
this.control_panel = new ControlPanel(this, enabled);
gbc.anchor = GridBagConstraints.EAST;
gb.setConstraints(control_panel, gbc);
cont.add(control_panel);
gbc.anchor = GridBagConstraints.CENTER;
gbc.gridy = 1;
this.chat_panel = new ChatPanelContainer(this);
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.fill = GridBagConstraints.BOTH;
gb.setConstraints(chat_panel, gbc);
cont.add(chat_panel);
/* Create and add Channel list window. */
String tag = "*Chans*";
this.chan_list = new ChanListWindow(this, tag);
chan_list.setForeground(mainfg);
chan_list.setBackground(mainbg);
chan_list.setTextBackground(textbg);
chan_list.setTextForeground(textfg);
// chan_list.setSelectedForeground(selfg);
chan_list.setSelectedBackground(selbg);
chat_panel.addPanel(chan_list, tag);
/* Create and add Who list window. */
tag = "*Who*";
this.who_list = new WhoListWindow(this, tag);
who_list.setForeground(mainfg);
who_list.setBackground(mainbg);
who_list.setTextBackground(textbg);
// who_list.setTextForeground(textfg);
who_list.setSelectedForeground(selfg);
who_list.setSelectedBackground(selbg);
chat_panel.addPanel(who_list, tag);
/* Create and add StatusWindow. */
status_tag = Resources.getString("eirc.status");
String title = Resources.getString("status_panel");
this.status = new StatusWindow(this, status_tag);
status.setBackground(mainbg);
status.setForeground(mainfg);
status.setTextBackground(textbg);
status.setTextForeground(textfg);
status.setSelectedBackground(selbg);
status.requestFocus();
chat_panel.add(status, status_tag, true);
chat_panel.setTitle(status_tag, title);
chat_panel.show(status_tag);
cont.setBackground(mainbg);
cont.setForeground(mainfg);
cont.setFont(mainfont);
}
public String getAppletInfo()
{
return (PACKAGE + " " + VERSION + "\n" + VERSION_EXTRA + ", an RFC 1459 compliant client program written in Java.\n" + "Copyright (C) 2000-2001 Javier Kohen <jkohen at tough.com>");
}
public String[][] getParameterInfo()
{
return param_info;
}
void connect()
{
String host = null;
if (current_server != null)
host = current_server;
else
host = getParameter("server");
if (host == null || host.length() == 0)
{
host = getDocumentBase().getHost();
if (host.length() == 0)
host = "localhost";
}
connect(host);
}
void connect(String host)
{
int port = 6667; // Set default port.
try
{
port = Integer.parseInt(getParameter("port"));
} catch (Exception e) {}
connect(host, port);
}
synchronized void connect(String host, int port)
{
if (nick_entry.getText().length() == 0)
{
status.printError(res.getString("eirc.s1"));
return;
}
status.printInfo(res.getString("eirc.login"));
/* See if this Applet can connect promiscuously.
* No Exceptions will be thrown out of Applet context.
*/
InetAddress server_addr = null;
Socket s = null;
ServerThread st = null;
try
{
if (Class.forName("netscape.security.PrivilegeManager") != null)
netscape.security.PrivilegeManager.enablePrivilege("UniversalConnect");
if (System.getProperty("java.vendor").indexOf("Microsoft") >= 0)
{
if (Class.forName("com.ms.security.PolicyEngine") != null)
com.ms.security.PolicyEngine.assertPermission(com.ms.security.PermissionID.NETIO);
}
/* Resolve server's address. */
InetAddress [] addresses = InetAddress.getAllByName(host);
server_addr = addresses[(int) Math.floor(Math.random() * addresses.length)];
/* Establish a connection to the server. */
s = createSocket(server_addr, port);
/* Spawn a new thread to handle the connection. */
st = new ServerThread(this, s, net_encoding);
}
catch (UnknownHostException e)
{
Object a[] = { host };
String ptn = res.getString("eirc.s2");
status.printError(MessageFormat.format(ptn, a));
return;
}
catch (IOException e)
{
Object a[] = { server_addr.getHostName(), new Integer(port) };
String ptn = res.getString("eirc.s3");
status.printError(MessageFormat.format(ptn, a));
return;
}
catch (SecurityException e)
{
status.printError(res.getString("eirc.not_in_applet"));
return;
}
catch (Exception e)
{
status.printError(res.getString("eirc.not_in_applet"));
return;
}
if (connected)
disconnect();
this.quit_sent = false;
properties.addObserver(st);
this.server = st;
st.start();
this.connected = true;
/* Login into server. */
login();
this.current_server = host;
/* Enable controls that depend on being connected. */
control_panel.setConnected(true);
/*
** Enable previously opened windows.
*/
/* Enable opened channels and re-join */
String c;
String p[] = { "", "" };
for (Enumeration e = channel_windows.elements(); e.hasMoreElements(); )
{
ChannelWindow w = (ChannelWindow)e.nextElement();
if (w != null)
{
if (p[0].length() > 0)
{
p[0] += ",";
p[1] += ",";
}
c = w.getChannel().getTag();
if (c != null)
{
p[0] += c;
c = w.getChannel().getKey();
if (c.length() == 0) c = " ";
p[1] += c;
}
w.setEnabled(true);
}
}
if (p[0].length() > 0)
sendMessage("JOIN", p);
/* Enable privates */
for (Enumeration e = privates.elements(); e.hasMoreElements(); )
{
PrivateWindow pw = (PrivateWindow) e.nextElement();
pw.setEnabled(true);
}
status.clear();
chan_list.clear();
who_list.clear();
}
public Socket createSocket(InetAddress addr, int port) throws java.io.IOException
{
Socket s = null;
/*
try
{
port = Integer.parseInt(getParameter("ssl"));
}
catch (Exception e) {}
if (port > 0)
{
try
{
Class SSLClass = Class.forName("javax.net.ssl.SSLSocket");
if(SSLClass != null)
{
/*
** SSLSocketFactory factory = (SSLSocketFactory)SSLSocketFactory.getDefault();
** SSLSocket ssl = (SSLSocket)factory.createSocket(server_addr, port);
*/
/*
Class FactoryCLass = Class.forName("javax.net.ssl.SSLSocketFactory");
Method getdefault = FactoryCLass.getMethod("getDefault", null);
Object factory = getdefault.invoke(null, null);
Method createsocket = FactoryCLass.getMethod("createSocket", new Class[] { InetAddress.class, int.class });
Object ssl = createsocket.invoke(factory, new Object[] { addr, new Integer(port) } );
s = (Socket)ssl;
}
}
catch (ClassNotFoundException e)
{
System.out.println("Your Java system is too old and does not support SSL. You should update at www.java.com");
}
catch (Exception e)
{
System.out.println("SSL connection failed.");
}
*/
s = new Socket(addr, port);
return(s);
}
public void connect(String nick, String pass, String realname)
{
this.nick_entry.setText(nick);
this.nicksrv_pass = pass;
this.realname = realname;
connect();
}
private synchronized void login()
{
if (!connected)
return;
if (irc_pass != null && irc_pass.length() > 0)
{
String p[] = { irc_pass };
sendMessage("PASS", p);
}
this.new_nick = nick_entry.getText();
String n[] = { new_nick };
sendMessage("NICK", n);
String u[] = { username, "0", "0", realname };
sendMessage("USER", u);
}
public synchronized void disconnect()
{
/* Disable controls that depend on being connected.
*/
control_panel.setConnected(false);
if (!connected)
return;
/* Logout from server.
*/
logout();
/* Kill the connection.
*/
Socket s = server.getSocket();
server.disconnect();
try
{
s.close();
}
catch (IOException e)
{
// System.err.println(e);
}
this.connected = false;
status.printError(res.getString("eirc.disconnected"));
chat_panel.show(status_tag);
/* Close what should be closed on disconnection.
*/
// closePrivates();
// closeChannels();
/* Disable opened windows.
*/
/* Disable opened channels */
for (Enumeration e = channel_windows.elements(); e.hasMoreElements(); )
{
ChannelWindow w = (ChannelWindow)e.nextElement();
w.setEnabled(false);
w.clearUsers();
}
/* Disable privates */
for (Enumeration e = privates.elements(); e.hasMoreElements(); )
{
PrivateWindow pw = (PrivateWindow) e.nextElement();
pw.setEnabled(false);
}
/*
** Reset away
*/
away.setForeground(Color.blue);
for (int i = 0; i < menu.getItemCount(); i++)
{
MenuItem mi = menu.getItem(i);
if (mi instanceof CheckboxMenuItem)
((CheckboxMenuItem)mi).setState(false);
}
is_away = false;
/*
** Clear modes
*/
setGlobalModes("-*");
}
private synchronized void logout()
{
// if (!logged_in)
// return;
if (!quit_sent)
{
String p[] = { quit_message };
sendMessage("QUIT", p);
}
this.logged_in = false;
}
private synchronized void pos_login()
{
if (!connected)
return;
this.current_nick = new_nick;
status.requestFocus();
if (request_motd)
{
String p[] = { };
sendMessage("MOTD", p);
}
if (user_modes != null && user_modes.length() > 0)
{
String p[] = { this.current_nick, user_modes };
sendMessage("MODE", p);
}
if (chan_list != null && auto_list)
chan_list.listChannels();
if (default_join != null && default_join.length() > 0)
{
String p[] = null;
default_join = default_join.trim();
int space = default_join.indexOf(" ");
if (space > 0)
{
// Keyed channels
p = new String[2];
p[0] = default_join.substring(0, space);
p[1] = default_join.substring(space + 1);
}
else
{
p = new String[1];
p[0] = default_join;
}
sendMessage("JOIN", p);
default_join = null;
}
}
public void printMode(ChannelWindow cw, String prefix, String param, String msg_tag, int sound)
{
if (msg_tag != null)
{
Object a[] = { prefix, param };
String ptn = res.getString(msg_tag);
cw.printInfo(MessageFormat.format(ptn, a));
}
/*
** Play an event sound only if user is focused on the channel
*/
if (sound > -1 && cw == getCurrentPanel())
playSound(sound);
}
public void debug(String s)
{
if (debug_traffic == 1 || debug_window == null)
System.err.println(s);
if (debug_traffic == 2 && debug_window != null)
debug_window.printServerNotice(s, "Debug");
}
public void processMessage(Message m)
{
String command_key = m.getCommand().toLowerCase();
String mask = m.getPrefix();
String params[] = m.getParameters();
Integer t_cmd = (Integer)commands.get(command_key);
String prefix = mask;
int endOff = mask.indexOf('!');
int atHost = mask.indexOf('@');
if (endOff != -1)
{
prefix = mask.substring(0, endOff);
if (atHost > endOff)
{
String user = mask.substring(endOff + 1, atHost);
String host = mask.substring(atHost + 1);
if (!NickInfo.hasInfos(prefix) && !isService(prefix))
{
NickInfo.add(prefix, "", user, host);
// Retrieve user's info.
String p[] = { prefix };
sendMessage("WHO", p);
}
}
}
if (debug_traffic > 0 || t_cmd == null)
{
// Strip CRLF from the end of the message.
String t = m.toString();
t = t.substring(0, t.length() - 2);
if (debug_traffic > 0)
{
SimpleDateFormat date_format = new SimpleDateFormat(date_pattern);
debug("< " + date_format.format(new Date()) + " " + t);
}
if (t_cmd == null)
{
if (see_everything_from_server)
{
try
{
// We don't care about the result, we just want to know if it's a number.
Integer.parseInt(command_key);
// Numeric command, take the crud out of it.
StringBuffer buf = new StringBuffer(params[1]);
for (int i = 2; i < params.length; i++)
{
buf.append(' ');
buf.append(params[i]);
}
status.printUnmangled(buf.toString());
}
catch (NumberFormatException e)
{
// Not numeric command.
status.printUnmangled(t);
}
}
return;
}
}
// This flag is checked by NOTICE and PRIVMSG handlers.
boolean is_prefix_ignored = false;
String addr = NickInfo.getInetAddr(prefix);
if (addr != null)
is_prefix_ignored = ignore_list.contains(addr);
int command = t_cmd.intValue();
switch (command)
{
case -1: // PING
{
String p[] = { params[0] };
sendMessage("PONG", p);
break;
}
case -2: // NICK
{
if (prefix.equals(current_nick))
{
// Self nick change
current_nick = params[0];
nick_entry.setText(current_nick);
Object a[] = { current_nick };
String ptn = res.getString("eirc.s4");
getCurrentPanel().printInfo(MessageFormat.format(ptn, a));
}
else
{
// Other's nick change
Object a[] = { prefix, params[0] };
String ptn = res.getString("eirc.s5");
String msg_text = MessageFormat.format(ptn, a);
OutputWindow [] ow = getUserPanels(prefix);
for (int i = 0; i < ow.length; i++)
ow[i].printInfo(msg_text);
}
// Update nick from nick info entries
NickInfo.changeNick(prefix, params[0]);
// Update private window (if there's one) accordingly
if (privates.containsKey(prefix) && !privates.containsKey(params[0]))
{
PrivateWindow pw = (PrivateWindow) privates.get(prefix);
pw.setUser(params[0]);
chat_panel.rename(prefix, params[0]);
Object o[] = { params[0] };
chat_panel.setTitle(params[0], private_title.format(o));
privates.remove(prefix);
privates.put(params[0], pw);
}
// Update channel window accordingly
for (Enumeration e = channels.elements(); e.hasMoreElements(); )
{
Channel channel = (Channel) e.nextElement();
if (channel.contains(prefix))
channel.rename(prefix, params[0]);
}
break;
}
case -3: // JOIN
{
// If it's me, just open the channel window.
if (current_nick.equals(prefix))
{
openChannel(params[0]);
// Retrieve users' info.
String p[] = { params[0] };
sendMessage("WHO", p);
}
else
{
Channel channel = getChannel(params[0]);
if (channel != null)
{
channel.add(prefix);
if (see_join)
{
ChannelWindow cw = getChannelWindow(params[0]);
Object a[] = { prefix };
String ptn = res.getString("eirc.s6");
cw.printInfo(MessageFormat.format(ptn, a));
if (cw == getCurrentPanel())
playSound(res.EVENT_JOIN);
}
updateChanTitle(getChannel(params[0]));
}
}
break;
}
case -4: // MODE
{
String [] modes_params;
if (params.length > 2)
{
modes_params = new String [params.length - 2];
for (int i = 0; i < modes_params.length; i++)
modes_params[i] = params[i + 2];
}
else
{
modes_params = new String[1];
modes_params[0] = params[0];
}
// Process server wide user modes.
if (!Channel.isChannel(params[0]))
{
setGlobalModes(params[1]);
// Refresh all channels' popup menus.
for (Enumeration e = channels.elements(); e.hasMoreElements(); )
{
Channel channel = (Channel) e.nextElement();
channel.refresh();
}
break;
}
Channel channel = getChannel(params[0]);
channel.setModes(params[1], modes_params);
ChannelWindow cw = getChannelWindow(params[0]);
boolean sign = false;
char modes[] = params[1].toCharArray();
int j = 0;
for (int i = 0; i < modes.length; i++)
{
String msg_tag = null;
int sound = -1;
switch (modes[i])
{
case '+':
sign = true;
break;
case '-':
sign = false;
break;
case 'v':
msg_tag = sign ? "eirc.+v" : "eirc.-v";
sound = sign ? res.EVENT_OP : res.EVENT_DEOP;
printMode(cw, prefix, modes_params[j++], msg_tag, sound);
break;
case 'o':
msg_tag = sign ? "eirc.+o" : "eirc.-o";
sound = sign ? res.EVENT_OP: res.EVENT_DEOP;
printMode(cw, prefix, modes_params[j++], msg_tag, sound);
break;
case 'h':
msg_tag = sign ? "eirc.+h" : "eirc.-h";
sound = sign ? res.EVENT_OP: res.EVENT_DEOP;
printMode(cw, prefix, modes_params[j++], msg_tag, sound);
break;
case 'b':
msg_tag = sign ? "eirc.+b" : "eirc.-b";
sound = sign ? res.EVENT_BAN : -1;
printMode(cw, prefix, modes_params[j++], msg_tag, sound);
break;
case 'e':
msg_tag = sign ? "eirc.+e" : "eirc.-e";
printMode(cw, prefix, modes_params[j++], msg_tag, sound);
break;
case 'I':
msg_tag = sign ? "eirc.+I" : "eirc.-I";
printMode(cw, prefix, modes_params[j++], msg_tag, sound);
break;
// Channel modes
case 'm':
msg_tag = sign ? "eirc.+m" : "eirc.-m";
printMode(cw, prefix, modes_params[0], msg_tag, sound);
break;
case 's':
msg_tag = sign ? "eirc.+s" : "eirc.-s";
printMode(cw, prefix, modes_params[0], msg_tag, sound);
break;
case 'i':
msg_tag = sign ? "eirc.+i" : "eirc.-i";
printMode(cw, prefix, modes_params[0], msg_tag, sound);
break;
case 'k':
msg_tag = sign ? "eirc.+k" : "eirc.-k";
printMode(cw, prefix, modes_params[j++], msg_tag, sound);
break;
case 'l':
msg_tag = sign ? "eirc.+l" : "eirc.-l";
printMode(cw, prefix, sign ? modes_params[j++] : "", msg_tag, sound);
break;
// User modes not RFC compliant. //////////////////////////
case 'a':
msg_tag = sign ? "eirc.+a" : "eirc.-a";
sound = sign ? res.EVENT_OP: res.EVENT_DEOP;
printMode(cw, prefix, modes_params[j++], msg_tag, sound);
break;
case 'q':
msg_tag = sign ? "eirc.+q" : "eirc.-q";
sound = sign ? res.EVENT_OP: res.EVENT_DEOP;
printMode(cw, prefix, modes_params[j++], msg_tag, sound);
break;
// Channel modes not RFC compliant. //////////////////////////
case 'r':
msg_tag = sign ? "eirc.+r" : "eirc.-r";
printMode(cw, prefix, modes_params[0], msg_tag, sound);
break;
case 'N':
msg_tag = sign ? "eirc.+N" : "eirc.-N";
printMode(cw, prefix, modes_params[0], msg_tag, sound);
break;
/////////////////////////////////////////////////////////////
// These modes aren't handled, but are known to carry a parameter which must be skipped.
// case 'I':
// j++;
// break;
}
}
break;
}
case -5: // PART
{
if (current_nick.equals(prefix))
{
closeChannel(params[0]);
}
else
{
Channel channel = getChannel(params[0]);
channel.remove(prefix);
if (see_join)
{
ChannelWindow cw = getChannelWindow(params[0]);
String part_msg = "";
if (params.length >= 2)
part_msg = params[1];
Object a[] = { prefix, part_msg };
String ptn = res.getString("eirc.s8");
cw.printInfo(MessageFormat.format(ptn, a));
if (cw == getCurrentPanel())
playSound(res.EVENT_PART);
}
updateChanTitle(getChannel(params[0]));
}
break;
}
case -6: // QUIT
{
Object a[] = { prefix, params[0] };
String ptn = res.getString("eirc.s9");
String msg_text = MessageFormat.format(ptn, a);
OutputWindow [] ow = getUserPanels(prefix);
for (int i = 0; i < ow.length; i++)
{
ow[i].printInfo(msg_text);
if(ow[i] == (OutputWindow)getCurrentPanel())
playSound(res.EVENT_QUIT);
}
// Remove the user from the channels she was in.
for (Enumeration e = channels.elements(); e.hasMoreElements(); )
{
Channel channel = (Channel) e.nextElement();
channel.remove(prefix);
}
updateChanTitle(getChannel(params[0]));
// Remove nick info entry.
NickInfo.remove(prefix);
break;
}
case -7: // KICK
{
String reason = (params[2] != null ? params[2] : "");
if (current_nick.equals(params[1]))
{
closeChannel(params[0]);
Object a[] = { params[0], prefix, reason };
String ptn = res.getString(