/*
* (c) Copyright 2007-2008 by Edgar Kalkowski (eMail@edgar-kalkowski.de)
*
* This file is part of the ErkiTalk Java Client.
*
* The ErkiTalk Java Client 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 3 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, see <http://www.gnu.org/licenses/>.
*/
package erki.talk.clients.ed;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ConnectException;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.imageio.ImageIO;
import erki.talk.Crypto;
import erki.talk.DHKeyExchange;
public class ConnectionThread extends Thread {
private static final String AWAY_ICON = "res"
+ System.getProperty("file.separator") + "msgs.png";
private String host = null;
private int port;
private PrintWriter sockOut = null;
private GUIThread gui = null;
private boolean blockSound = false;
private long pause = 0;
private String topic = null;
private Crypto crypto = null;
private DHKeyExchange keyExchange = null;
private boolean encrypt = false;
private boolean killed = false;
private BufferedImage icon;
public ConnectionThread(String host, int port, GUIThread gui) {
super();
this.host = host;
this.port = port;
this.gui = gui;
try {
icon = ImageIO.read(new File(AWAY_ICON));
} catch (IOException e) {
}
}
public void kill() {
killed = true;
}
@Override
public void run() {
super.run();
Socket sock = null;
BufferedReader sockIn = null;
while (!gui.isReady()) {
try {
sleep(33);
} catch (InterruptedException e) {
e.printStackTrace();
System.exit(-1);
}
}
while (!killed) {
encrypt = false;
crypto = null;
keyExchange = null;
topic = null;
try {
sock = new Socket(host, port);
sockIn = new BufferedReader(new InputStreamReader(sock
.getInputStream(), "UTF-8"));
sockOut = new PrintWriter(new OutputStreamWriter(sock
.getOutputStream(), "UTF-8"), true);
sockOut.println("PONG");
sockOut.flush();
sockOut.println("NICK " + gui.getInputKeyListener().getNick());
sockOut.println("TOPIC");
String fromServer = null;
while ((fromServer = sockIn.readLine()) != null) {
pause = 0;
if (encrypt) {
try {
fromServer = crypto.decrypt(fromServer);
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
System.exit(-1);
} catch (BadPaddingException e) {
e.printStackTrace();
System.exit(-1);
}
}
if (fromServer.toUpperCase().equals("AUTHED")) {
gui.appendLineToOutputBuffer("#I: You are "
+ "successfully authed.");
} else if (fromServer.toUpperCase().equals("BEGINUSERS")) {
gui.appendLineToOutputBuffer("#I: ---- Begin user "
+ "list ----");
} else if (fromServer.toUpperCase().equals("DEREGISTERED")) {
gui.appendLineToOutputBuffer("#I: Your password has "
+ "been deleted.");
} else if (fromServer.toUpperCase().equals("ENDUSERS")) {
gui.appendLineToOutputBuffer("#I: ----- End user list "
+ "-----");
} else if (fromServer.toUpperCase().startsWith("ENCRYPT ")) {
String pubKey = fromServer.substring("ENCRYPT "
.length());
keyExchange.injectPublicKey(pubKey);
crypto = new Crypto(keyExchange.getSecretKey());
encrypt = true;
gui.appendLineToOutputBuffer("#I: Connection is "
+ "encrypted now.");
} else if (fromServer.toUpperCase().startsWith("ERROR ")) {
gui.appendLineToOutputBuffer("#E: "
+ fromServer.substring("ERROR ".length()));
} else if (fromServer.toUpperCase().startsWith("INDIRECT ")) {
String nick = fromServer.substring(
"INDIRECT ".length(), fromServer.indexOf(':'));
String txt = fromServer.substring(fromServer
.indexOf(':') + 2);
gui.appendLineToOutputBuffer(nick + " " + txt);
} else if (fromServer.toUpperCase().startsWith("INFO ")) {
gui.appendLineToOutputBuffer("#I: "
+ fromServer.substring("INFO ".length()));
} else if (fromServer.toUpperCase().startsWith("ISAUTHED ")) {
String nick = fromServer.substring(
"ISAUTHED ".length(), fromServer.indexOf(':'));
String bool = fromServer.substring(fromServer
.indexOf(':') + 2);
if (bool.toUpperCase().equals("TRUE")) {
gui.appendLineToOutputBuffer("#I: User " + nick
+ " is authed");
} else if (bool.toUpperCase().equals("FALSE")) {
gui.appendLineToOutputBuffer("#I: User " + nick
+ " is NOT authed.");
} else {
gui.appendLineToOutputBuffer("#E: The server's "
+ "answer confuses me.");
}
} else if (fromServer.toUpperCase().startsWith(
"ISENCRYPTED ")) {
String nick = fromServer.substring("ISENCRYPTED "
.length(), fromServer.indexOf(':'));
String bool = fromServer.substring(fromServer
.indexOf(':') + 2);
if (bool.toUpperCase().equals("TRUE")) {
gui.appendLineToOutputBuffer("#I: User " + nick
+ " uses an encrypted connection.");
} else if (bool.toUpperCase().equals("FALSE")) {
gui.appendLineToOutputBuffer("#I: User " + nick
+ " does NOT use an encrypted connection!");
} else {
gui.appendLineToOutputBuffer("#E: The server's "
+ "answer confuses me.");
}
} else if (fromServer.startsWith("JOIN ")) {
gui.appendLineToOutputBuffer("#I: "
+ fromServer.substring("JOIN ".length())
+ " has joined the chat.");
} else if (fromServer.startsWith("NEWNICK ")) {
String oldNick = fromServer.substring("NEWNICK "
.length(), fromServer.indexOf(':'));
String newNick = fromServer.substring(fromServer
.indexOf(':') + 2);
gui.appendLineToOutputBuffer("#I: " + oldNick
+ " is now known as " + newNick + ".");
} else if (fromServer.toUpperCase().startsWith("NEWTOPIC ")) {
String nick = fromServer.substring(
"NEWTOPIC ".length(), fromServer.indexOf(':'));
String topic = fromServer.substring(fromServer
.indexOf(':') + 2);
gui.appendLineToOutputBuffer("#I: " + nick
+ " changed the topic from »" + this.topic
+ "« to »" + topic + "«.");
this.topic = topic;
} else if (fromServer.toUpperCase().equals("PING")) {
sendToServer("PONG");
continue;
} else if (fromServer.toUpperCase().equals("PLAIN")) {
encrypt = false;
crypto = null;
keyExchange = null;
gui.appendLineToOutputBuffer("#I: Encryption "
+ "disabled. Switched back to plain text.");
} else if (fromServer.toUpperCase().equals("PONG")) {
// Do nothing.
} else if (fromServer.toUpperCase().startsWith("PM ")) {
String nick = fromServer.substring("PM ".length(),
fromServer.indexOf(':'));
String txt = fromServer.substring(fromServer
.indexOf(':') + 2);
gui.appendLineToOutputBuffer("#PM: " + nick + ": "
+ txt);
} else if (fromServer.toUpperCase().startsWith("QUIT ")) {
if (fromServer.indexOf(':') == -1) {
gui.appendLineToOutputBuffer(fromServer
.substring("QUIT ".length())
+ " has left.");
} else {
gui.appendLineToOutputBuffer(fromServer.substring(
"QUIT ".length(), fromServer.indexOf(':'))
+ " has left ("
+ fromServer.substring(fromServer
.indexOf(':') + 2) + ").");
}
} else if (fromServer.toUpperCase().equals("REGISTERED")) {
gui.appendLineToOutputBuffer("#I: You have "
+ "successfully registered a password for "
+ "your nick.");
} else if (fromServer.toUpperCase().startsWith("TEXT ")) {
String txt = fromServer.substring("TEXT ".length());
String nick = txt.substring(0, txt.indexOf(':'));
txt = txt.substring(txt.indexOf(':') + 2);
gui.appendLineToOutputBuffer(nick + ": " + txt);
} else if (fromServer.toUpperCase().startsWith("TOPIC ")) {
String nick = fromServer.substring("TOPIC ".length(),
fromServer.indexOf(':'));
String dateTime = fromServer.substring(fromServer
.indexOf(':') + 2);
String txt = dateTime
.substring(dateTime.indexOf(':') + 5);
dateTime = dateTime.substring(0,
dateTime.indexOf(':') + 3);
if (topic == null) {
topic = txt;
} else {
gui.appendLineToOutputBuffer("#I: The current "
+ "chat topic is »" + txt
+ "« and was set by " + nick + " on "
+ dateTime + ".");
}
} else if (fromServer.toUpperCase().startsWith("USER ")) {
gui.appendLineToOutputBuffer("#I: "
+ fromServer.substring("USER ".length()));
} else {
gui.appendLineToOutputBuffer("#E: I cannot understand "
+ "this line: " + fromServer);
}
if ((gui.getAlarm() == 1
&& (fromServer.toUpperCase().startsWith("TEXT ") || fromServer
.toUpperCase().startsWith("PM ")) && !blockSound)
|| (gui.getAlarm() == 2 && !blockSound)) {
if (icon != null && !gui.hasFocus()) {
gui.setIcon(icon);
}
try {
Runtime.getRuntime().exec("mplayer res/Notify.wav");
} catch (IOException e) {
blockSound = true;
gui.appendLineToOutputBuffer("# Alarm blocked! "
+ "Perhaps »mplayer« is missing?");
}
}
}
} catch (ConnectException e) {
gui.appendLineToOutputBuffer("#E: ConnectException!");
} catch (UnknownHostException e) {
gui.appendLineToOutputBuffer("#E: UnknownHostException!");
} catch (IOException e) {
gui.appendLineToOutputBuffer("#E: IOException!");
}
gui.appendLineToOutputBuffer("#E: No connection to server. "
+ "Trying to reconnect in " + pause / 60000 + " min.");
try {
sleep(pause);
} catch (InterruptedException e) {
pause = -1;
}
if (pause == -1) {
pause = 0;
} else if (pause == 0) {
pause = 60000;
} else {
pause *= 2;
}
}
}
public void setServer(String host) {
this.host = host;
}
public void setPort(int port) {
this.port = port;
}
public boolean sendToServer(String txt) {
if (sockOut == null) {
return false;
}
if (txt.toUpperCase().trim().equals("ENCRYPT")) {
keyExchange = new DHKeyExchange();
txt = "ENCRYPT " + keyExchange.getPublicKey();
}
boolean endcrypt = false;
if (txt.toUpperCase().trim().equals("PLAIN")) {
endcrypt = true;
}
if (encrypt) {
try {
txt = crypto.encrypt(txt);
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
System.exit(-1);
} catch (BadPaddingException e) {
e.printStackTrace();
System.exit(-1);
}
}
if (endcrypt) {
encrypt = false;
keyExchange = null;
crypto = null;
}
sockOut.println(txt);
sockOut.flush();
return true;
}
}