package net.dewep.intranetepitech;
import java.io.*;
import java.net.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import android.os.Handler;
/*
*
* Class created by Archibald - 08/2013
* http://www.bigint.fr
*
*/
public class Netsoul implements Runnable {
private static final String clientName = "Android IntranetEpitech";
private static final double clientVersion = 0.1;
private String defaultHost = "ns-server.epita.fr";
private int defaultPort = 4242;
private Socket client = null;
BufferedReader is = null;
PrintWriter pw = null;
BufferedOutputStream os = null;
private String callbackfunc = null;
private Thread thread;
private String login = "";
private String pass = "";
private String location = "Android IntranetEpitech";
private String data = "Application par Aur�lien Maigret - http://www.dewep.net";
private Boolean authenticated = false;
private Boolean shutdown = false;
private Handler handler = null;
private int save_connect = 0;
private String save_status = "Pr�t";
static Netsoul _instance = null;
protected void status(int connect, String str)
{
save_connect = connect;
save_status = str;
//Log.d(String.valueOf(save_connect), save_status);
handler.sendMessage(handler.obtainMessage(connect, str));
}
public static Netsoul getInstance() {
if (_instance == null) {
synchronized (Stock.class) {
if (_instance == null) {
//Log.d("instance", "new");
_instance = new Netsoul();
}
}
}
return _instance;
}
public void getStatus()
{
//Log.d(String.valueOf(save_connect), save_status);
handler.sendMessage(handler.obtainMessage(save_connect, save_status));
}
public void init(Handler act) {
if (handler != null)
{
handler = act;
return ;
}
handler = act;
//Log.d("netsoul", "init");
status(-1, "Initialisation...");
System.out.println("INIT");
callbackfunc = null;
new Vector<String>();
System.out.println("target: "+defaultHost+":"+defaultPort);
makeGUI();
status(-1, "Pr�t.");
}
public void start(String data_login, String data_password) {
System.out.println("START");
status(0, "Connexion...");
if ( thread == null ) {
login = data_login;
pass = data_password;
System.out.println("Create background thread");
thread = new Thread(this);
thread.setDaemon(true);
thread.start();
}
else {
status(1, "Connect�.");
// thread.resume();
// thread.
}
}
public void stop() {
System.out.println("STOP");
status(0, "Arr�t.");
// thread.suspend();
}
public void destroy() {
status(0, "Arr�t.");
System.out.println("DESTROY");
if ( thread != null ) {
System.out.println("Stopping background thread");
thread = null;
authenticated = false;
BufferedReader _is = is;
is = null;
shutdown = true;
/*try {
_is.close();
//_is.notify();
pw.close();
//pw.notify();
os.close();
//os.notify();
}
catch(IOException e) {
System.err.println("Error closing BufferedReader");
}*/
// synchronized (thread) {
disconnectSocket(_is);
// }
// thread.notify();
}
}
private void makeGUI() {
/*setLayout(new BorderLayout());
setBackground(Color.lightGray);
setVisible(true);
add(new Label("bsoul", Label.CENTER));*/
}
private void authenticate() {
if (login == null || pass == null) {
System.err.println("no login/pass provided");
return ;
}
else if (authenticated)
return ;
connectSocket();
String line = "";
try {
if (is != null)
line = is.readLine();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
disconnectSocket(is);
return ;
}
System.out.println("auth line: "+line);
String[] params = line.split(" +");
if (!params[0].equals("salut")) {
System.err.println("protocol error: "+line);
disconnectSocket(is);
return ;
}
String nfd = params[1];
String secret = params[2];
String host = params[3];
String port = params[4];
String timestamp = params[5];
//my ($salut, $nfd, $secret, $host, $port, $timestamp) = split(' ', $chain);
pw.print("auth_ag ext_user none none\n");
pw.flush();
System.out.println("sent auth_ag challenge");
try {
line = is.readLine();
} catch (IOException e1) {
System.err.println("challenge read error");
// TODO Auto-generated catch block
e1.printStackTrace();
disconnectSocket(is);
return ;
}
if (!line.equals("rep 002 -- cmd end")) {
System.err.println("protocol error: "+line);
disconnectSocket(is);
return ;
}
else
System.out.println("protocol ok: "+line);
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return ;
}
//byte[] buffer = new byte[1024];
//buffer.
String buffer = secret+"-"+host+"/"+port+pass;
md5.update(buffer.getBytes());
byte[] hash_byte = md5.digest();
String hash = "";
for (int i=0; i < hash_byte.length; i++)
hash += Integer.toString( ( hash_byte[i] & 0xff ) + 0x100, 16).substring(1);
pw.print("ext_user_log "+login+" "+hash+" "+encode(location)+" "+encode(data)+"\n");
pw.flush();
System.out.println("sent auth "+"ext_user_log "+login+" '"+hash+"' "+encode(location)+" "+encode(data));
try {
line = is.readLine();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
return ;
}
if (!line.equals("rep 002 -- cmd end")) {
status(0, "Impossible de s'authentifier.");
callAct("{\"error\":\"Authentication fail: "+line+"\"}");
System.err.println("auth error: "+line);
disconnectSocket(is);
return ;
}
status(1, "Connect�.");
//callAct("{\"success\":\"Authentication succeed\"}");
callAct("{" +
"\"action\":\"loggued\"," +
"\"user\":{" +
"\"id\": \""+nfd+"\"" +
"}" +
"}");
System.out.println("auth ok: "+line);
pw.print("state actif:"+timestamp+"\n");
pw.print("user_cmd msg *:www@*"+clientName+"* msg version+"+clientVersion+"\n");
pw.print("user_cmd who {"+login+"}\n");
pw.print("user_cmd watch_log_user {"+login+"}\n");
pw.flush();
authenticated = true;
}
public void run() {
System.out.println("run()");
// synchronized(mutSend) {
callAct("{\"status\": \"loaded\"}");
while (true) {
synchronized (thread) {
authenticate();
try {
//synchronized (is) {
try {
while (authenticated == true && is != null) {
//System.out.println("waiting for new line");
//is.wait();
try {
String line = is.readLine();
System.out.println("received line: "+line);
dispatchReceivedLine(line);
}
catch(SocketException e) {
System.err.println("SocketException ...");
break ;
}
catch(SocketTimeoutException e) {
System.err.println("Timeout while readline ...");
}
}
}
//catch(InterruptedException e) {
// System.err.println(e);
// e.printStackTrace();
//}
catch(IOException e) {
System.err.println("IOException");
e.printStackTrace();
}
//}
}
catch (NullPointerException e) {
}
if (shutdown == true)
return ;
try {
System.out.println("wait for configuration");
thread.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
//System.out.println("---------------------------------");
if (is != null) {
System.err.println("configuration never received: "+e);
e.printStackTrace();
}
else
System.out.println("exiting loop");
return ;
}
if (shutdown == true)
return ;
//disconnectSocket();
}
}
}
private void dispatchReceivedLine(String line) {
String[] args = line.split(" +");
try {
if (args[0].equals("ping")) {
System.out.println("pong");
pw.print("ping "+args[1]+"\n");
pw.flush();
}
else if (args[0].equals("user_cmd")) {
String identifier = args[1];
String cmd = args[3];
String[] ids = identifier.split(":+");
String[] login_ip = ids[3].split("@+");
if (cmd.equals("who")) {
String sid = args[4];
if (sid.equals("rep")) {
System.out.println("end of command reply");
}
else if (sid.equals("state")) {
String state = args[5];
System.out.println("state change");
callAct("{\"action\":\"state\", \"state\":\""+state+"\"}");
}
else {
String source_login = args[5];
String source_ip = args[6];
String source_location = args[12];
String source_promo = args[13];
String[] source_state_timestamp = args[14].split(":+");
String source_data = args[15];
String time = timestamp_to_date(source_state_timestamp[1]);
// DateFormat stamp =
// DateFormat.getInstance()
if (source_state_timestamp[0].equals("actif"))
source_state_timestamp[0] = "active";
//String source_data = args[13];
System.out.println("user_cmd: info "+identifier+" (state "+source_state_timestamp[0]+", since: "+time+")");
callAct("{" +
"\"action\":\"userstatus\"," +
"\"user\":{" +
"\"id\": \""+protect(sid)+"\"," +
"\"login\":\""+protect(source_login)+"\"," +
"\"location\":\""+protect(decode(source_location))+"\"," +
"\"ip\":\""+protect(source_ip)+"\"," +
"\"promo\":\""+protect(source_promo)+"\"," +
"\"data\":\""+protect(source_data)+"\"" +
"}," +
"\"state\":\""+protect(source_state_timestamp[0])+"\"," +
"\"since\":\""+protect(time)+"\"" +
"}");
}
}
else if (cmd.equals("msg")) {
String text = args[4];
String[] parts = args[5].split("\\*+");
System.out.println("received "+args[5]+" splitted in "+parts.length);
String target_login = parts[1].substring(1);
target_login = target_login.substring(0, target_login.length()-1);
String target_location = parts[2];
System.out.println("forward message "+ids[0]+" "+target_login+"@"+target_location+" from "+login_ip[0]+"@"+decode(ids[5]));
callAct("{" +
"\"action\":\"message\"," +
"\"user\":{" +
"\"id\":\""+protect(ids[0])+"\"," +
"\"login\":\""+protect(login_ip[0])+"\"," +
"\"ip\":\""+protect(login_ip[1])+"\"," +
"\"location\":\""+protect(decode(ids[5]))+"\"," +
"\"promo\":\""+protect(decode(ids[6]))+"\"" +
"}," +
"\"message\":{" +
"\"text\":\""+protect(decode(text))+"\"," +
"\"login\":\""+protect(target_login)+"\"," +
"\"location\":\""+protect(decode(target_location))+"\"" +
"}" +
"}");
}
else if (cmd.equals("login")) {
System.out.println("user_cmd: login "+identifier+" ");
callAct("{" +
"\"action\":\"login\"," +
"\"user\":{" +
"\"id\":\""+protect(ids[0])+"\"," +
"\"login\":\""+protect(login_ip[0])+"\"," +
"\"location\":\""+protect(decode(ids[5]))+"\"," +
"\"ip\":\""+protect(login_ip[1])+"\"" +
"}" +
"}");
}
else if (cmd.equals("logout")) {
System.out.println("user_cmd: logout "+identifier+" ");
callAct("{" +
"\"action\":\"logout\"," +
"\"user\":{" +
"\"id\":\""+protect(ids[0])+"\"," +
"\"login\":\""+protect(login_ip[0])+"\"," +
"\"location\":\""+protect(decode(ids[5]))+"\"," +
"\"ip\":\""+protect(login_ip[1])+"\"" +
"}" +
"}");
}
else if (cmd.equals("state")) {
String[] state_tm = args[4].split(":+");
if (state_tm[0].equals("actif"))
state_tm[0] = "active";
System.out.println("user_cmd: state "+identifier+" to "+state_tm[0]);
String time = timestamp_to_date(state_tm[1]);
callAct("{\"action\":\"state\", \"user\":{\"id\":\""+protect(ids[0])+"\"}, \"state\":\""+protect(state_tm[0])+"\", \"since\":\""+protect(time)+"\"}");
}
else
System.out.println("user_cmd: unrecognized command "+cmd+"");
}
else
System.err.println("Unrecognized message: "+line);
}
catch(ArrayIndexOutOfBoundsException e) {
System.err.println("Unparsable message "+e);
}
}
private String timestamp_to_date(String timestamp) {
long tm = Long.parseLong(timestamp);
Date t = new Date(tm * 1000);
@SuppressWarnings("deprecation")
String time = ""+(1900+t.getYear())+"-"+(t.getMonth()+1 < 10? "0": "")+(t.getMonth()+1)+"-"+(t.getDate() < 10? "0": "")+t.getDate()+" "+(t.getHours() < 10? "0": "")+t.getHours()+":"+(t.getMinutes() < 10? "0": "")+t.getMinutes()+":"+(t.getSeconds() < 10? "0": "")+t.getSeconds();
return time;
}
public boolean setCredential(String user_login, String user_pass, String user_location, String user_data) {
System.out.println("setCredential("+user_login+", ****, "+user_location+", "+user_data+")");
synchronized(thread) {
System.out.println("thread is synchronized");
login = user_login;
pass = user_pass;
location = user_location;
data = user_data;
thread.notify();
// if (is != null)
// is.notify();
}
return true;
}
public boolean sendMessage(String target_login, String target_location, String message) {
synchronized (is) {
//System.out.println("notify thread");
System.out.println("sending message: '"+encode(message)+"' to "+target_login+"@"+encode(target_location));
pw.print("user_cmd msg *:"+target_login+"@*"+encode(target_location)+"* msg "+encode(message)+"\n");
pw.flush();
// messagesToSend.add(message);
// if (messagesToSend.size() > 0) {
// for (int i = 0; i<messagesToSend.size(); i++)
// System.out.println("sending message: '"+messagesToSend.elementAt(i)+"'");
// }
// thread.notify();
}
return true;
}
public String appletVersion() {
return clientName+" "+clientVersion;
}
public boolean watchUser(String target_login) {
synchronized (is) {
//System.out.println("notify thread");
System.out.println("watch login: '"+target_login+"'");
pw.print("user_cmd watch_log_user {"+target_login+","+login+","+login+"}\n");
pw.print("user_cmd who {"+target_login+"}\n");
pw.flush();
}
return true;
}
public boolean disconnect() {
disconnectSocket(is);
authenticated = false;
return true;
}
// public boolean unwatchUser(String target_login) {
// synchronized (is) {
// //System.out.println("notify thread");
// System.out.println("watch login: '"+target_login+"'");
// pw.print("user_cmd watch_log_user {"+target_login+","+login+","+login+"}\n");
// pw.print("user_cmd who {"+target_login+"}\n");
// pw.flush();
// }
// return true;
// }
private static String encode(String str) {
try {
return URLEncoder.encode(str, "ISO-8859-1").replace((CharSequence)"+", (CharSequence)"%20");
}
catch (UnsupportedEncodingException e) {
System.out.println(e);
return null;
}
}
private static String protect(String str) {
return str.replace((CharSequence)"\\", (CharSequence)"\\\\").replace((CharSequence)"\"", (CharSequence)"\\\"");
}
private static String decode(String str) {
try {
return URLDecoder.decode(str, "ISO-8859-1");
}
catch (UnsupportedEncodingException e) {
System.out.println(e);
return null;
}
}
private void callAct(String json) {
if (callbackfunc == null)
return ;
/*try {
//getAppletContext().showDocument(new URL("javascript:"
//+ callbackfunc + "(" + json + (callbackparam != null? ", "+callbackparam: "") + ")"));
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
}*/
}
private boolean connectSocket() {
if (client == null || !client.isConnected() || client.isClosed() || client.isInputShutdown() || client.isOutputShutdown()) {
// System.out.println("Client is not connected");
try {
// System.out.println("Connecting to client");
client = new Socket(defaultHost, defaultPort);
is = new BufferedReader(new InputStreamReader(client.getInputStream()));
os = new BufferedOutputStream(client.getOutputStream());
pw = new PrintWriter(os, false);
client.setSoTimeout(10000);
// System.out.println("Connected to "+targetURL.getHost()+":"+port);
// Status.setText("Connect� � "+this.Host+":"+this.Port);
callAct("{\"success\":\"Connected to "+this.defaultHost+":"+this.defaultPort+"\"}");
}
catch (IOException e) {
callAct("{\"error\":\"Cant connect to "+this.defaultHost+":"+this.defaultPort+"\"}");
System.err.println("Error: Can't connect to "+this.defaultHost+":"+this.defaultPort);
return false;
}
}
// else
// System.out.println("Client is already connected");
return true;
}
private void disconnectSocket(BufferedReader _is) {
try {
try {
if (client != null) {
client.close();
client.notify();
}
if (pw != null) {
pw.close();
pw.notify();
}
if (_is != null) {
_is.close();
_is.notify();
}
}
catch(IOException e) {
System.err.println("Failed to close socket "+e);
}
client = null;
pw = null;
_is = null;
is = null;
// if (client != null) {
// System.out.println("Closing connection");
// client.close();
// }
}
catch (Exception e) {
System.err.println("Error: while closing socket");
}
client = null;
}
}