/*
* (c) 2000-2009 Carlos G�mez Rodr�guez, todos los derechos reservados / all rights reserved.
* Licencia en license/bsd.txt / License in license/bsd.txt
*/
package eu.irreality.age.irc;
//package irc;
import java.net.*;
import java.util.*;
import java.io.*;
import eu.irreality.age.util.networking.LocalIPObtainer;
public class IrcSocket extends Thread
{
BufferedReader fromServer;
PrintStream toServer;
IrcListener ircListener;
Socket socket;
static final char X_DELIM = (char) 1; //extended content delimiter
public IrcSocket(String server, int port, IrcListener ircListener) throws Exception
{
socket = new Socket(InetAddress.getByName(server),port);
toServer = new PrintStream(socket.getOutputStream());
fromServer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
this.ircListener = ircListener;
this.start();
}
public void joinChannel(String channel)
{ toServer.println("JOIN "+channel);
};
public void partChannel(String channel)
{ toServer.println("PART "+channel);
};
public void sendChannel(String channel, String line)
{ toServer.println("PRIVMSG "+channel+" :"+line);
};
public void setChannelTopic(String channel, String topic)
{ toServer.println("TOPIC "+channel+" :"+topic);
};
public void sendPrivate(String nick, String line)
{ toServer.println("PRIVMSG "+nick+" :"+line);
};
public void setNick(String nick)
{ toServer.println("NICK "+nick);
};
public void sendPing(String nick)
{ toServer.println("PING "+nick);
};
public void sendPong(String nick)
{ toServer.println("PONG :"+nick);
};
public void sendCtcpPing(String nick , String args)
{
toServer.println("PRIVMSG "+nick+" :"+(char)1+"PING "+args+(char)1);
}
public void login(String nick, String realName)
{ this.setNick(nick); toServer.println("USER "+nick+" <host> <server> :"+realName);
}
public void setMode(String channel, String target, String mode)
{ toServer.println("MODE "+channel+" "+mode+" "+target);
};
public void setAway(String reason)
{ toServer.println("AWAY "+reason);
};
public void quit(String reason)
{ toServer.println("QUIT :"+reason);
};
/*DCC SUPPORT BEGIN*/
final static short DCC_ANY = 0; //pased to sendDccChatRequest, will open the server on any free port.
/*
This is a nonblocking call.
Returns an IrcDccChatSocket not yet connected. Will notify the listener when connected.
*/
public IrcDccChatSocket sendDccChatRequest ( String nick , short port /*or DCC_ANY*/, IrcDccListener idl ) throws java.io.IOException
{
//System.out.println("Going to send DCC chat request\n");
long addressAsLong = 0;
ServerSocket dccSocket = new ServerSocket ( port );
//System.out.println("Socket created at port " + dccSocket.getLocalPort() + "\n");
//InetAddress ia = /*dccSocket.getInetAddress();*/InetAddress.getLocalHost();
//InetAddress ia = LocalIPObtainer.getLocalHost(); //testing as of 2011-11-08
//TODO: Let the user select the external IP address to receive DCC's on
//Or maybe we'll need to use whatismyip because the machine doesn't know its external ip!
InetAddress ia;
ia = LocalIPObtainer.askForIpAbroad();
if ( ia == null ) //whatismyip failed.
ia = socket.getLocalAddress(); //testing as of 2011-11-08
/*
System.err.println("Addr: " + ia);
if ( ia.isLoopbackAddress() || ia.isLinkLocalAddress() || LocalIPObtainer.isIPv4Private(ia) )
{
ia = LocalIPObtainer.getLocalHost();
System.err.println("Correction: " + ia);
}
*/
byte[] b = ia.getAddress();
//System.out.println("Converting address " + ia + "(" + b + ")" + "\n");
//System.out.println("Host addr: " + ia.getHostAddress() );
//System.out.println("Local socket addr: " + dccSocket.getLocalSocketAddress() );
//System.out.println("Local host addr: " + InetAddress.getLocalHost() );
for ( int i = 0 ; i < b.length ; i++ )
{
addressAsLong = (addressAsLong << 8);
addressAsLong += (b[i]>=0)?(b[i]):(256+b[i]) ; System.out.println(" " + (int)b[i]);
//System.out.println("addressAsLong " + addressAsLong);
}
//System.out.println("Sending privmsg:\n");
//System.out.println ( "PRIVMSG "+nick+" :"+((char)1)+"DCC CHAT CHAT "+ addressAsLong + " " + dccSocket.getLocalPort() + ((char)1));
toServer.println ( "PRIVMSG "+nick+" :"+((char)1)+"DCC CHAT CHAT "+ addressAsLong + " " + dccSocket.getLocalPort() + ((char)1));
return new IrcDccChatSocket ( dccSocket , idl , nick );
}
public IrcDccChatSocket acceptDccChatRequest ( String nick , InetAddress addr , short port , IrcDccListener idl ) throws java.io.IOException
{
return new IrcDccChatSocket ( addr , port , idl , nick );
}
/*DCC SUPPORT END*/
public void run()
{
try
{
while(true)
{
IrcCommand c = new IrcCommand(fromServer.readLine());
switch(c.type)
{
case IrcCommand.NoticeType: ircListener.noticeMsg(c.from, c.content); break;
case IrcCommand.ModeType: ircListener.changeMode(c.from, c.to, c.content); break;
case IrcCommand.QuitType: ircListener.quitMsg(c.from, c.content); break;
case IrcCommand.TopicType: ircListener.channelTopic(c.channel, c.content); break;
case IrcCommand.JoinType: ircListener.channelJoin(c.channel, c.from); break;
case IrcCommand.PartType: ircListener.channelPart(c.channel, c.from); break;
case IrcCommand.NickType: ircListener.nickChange(c.from, c.content); break;
case IrcCommand.PingType: ircListener.ping(c.content); sendPong(c.content); break;
case IrcCommand.KickType: ircListener.kick(c.channel,c.from,c.to,c.content); break;
case IrcCommand.NickListType: ircListener.nickList(c.channel, c.content); break;
case IrcCommand.UnknownType: ircListener.unknownMsg(c.command); break;
case IrcCommand.ServerMsgType: ircListener.serverMsg(c.content); break;
case IrcCommand.NotOnChannelType: ircListener.notOnChannel(c.channel); break;
case IrcCommand.NotChannelOpType: ircListener.notChannelOp(c.channel); break;
case IrcCommand.TopicChangeType:
ircListener.topicChange(c.channel,c.from,c.content); break;
case IrcCommand.TopicSetByType:
ircListener.topicSetBy(c.channel, c.from, c.content); break;
case IrcCommand.PrivMsgType:
//parse extended content according to X-DELIM
StringTokenizer st = new StringTokenizer ( c.content , ""+X_DELIM , true );
boolean terminamos = false;
boolean extended = false;
for (;;)
{
if ( st.hasMoreTokens() )
{
String tok = st.nextToken();
if ( tok.equals(""+X_DELIM) )
{
extended = !extended; //extended content delimiter
}
else
{
if ( !extended )
{
if (c.to.charAt(0) == '#')
ircListener.channelMsg(c.from, c.to, tok);
else
ircListener.privateMsg(c.from, tok);
}
else
{
String even_content = tok;
//extended content!
StringTokenizer extTok = new StringTokenizer (even_content);
if ( !extTok.hasMoreTokens() )
{
continue;
}
else
{
String command = extTok.nextToken();
String arguments = concatTokenizedString(extTok);
if ( command.equalsIgnoreCase("ACTION") )
{
if (c.to.charAt(0) == '#')
ircListener.channelAction(c.from, c.to, arguments);
else
ircListener.privateAction(c.from, arguments);
}
else if ( command.equalsIgnoreCase("DCC") )
{
//DCC request.
StringTokenizer argTok = new StringTokenizer ( arguments );
if ( !argTok.hasMoreTokens() )
{
continue;
}
else
{
try
{
String type = argTok.nextToken();
if ( type.equalsIgnoreCase("CHAT") )
{
//DCC chat request.
String arg = argTok.nextToken();
String addr = argTok.nextToken();
String port = argTok.nextToken();
System.out.println("Argument: " + arg);
System.out.println("Address: " + addr);
System.out.println("Port: " + port);
//build InetAddress and port
long iaddr = Long.valueOf ( addr ).longValue();
System.out.println("Iaddr is " + iaddr);
//byte[] b = new byte[4];
String s = ""; //string representation of the IP address
for ( int i = 0 ; i < 4 ; i++ )
{
//host byte order
System.out.println("Byte: " + ( new Long( iaddr%256 ) ) );
System.out.println("Casted byte: " + ( new Long( iaddr%256 ) ).byteValue() );
//b[i] = ( new Integer( iaddr%256 ) ).byteValue();
s="."+s;
s = String.valueOf ( (iaddr%256>=0)?(iaddr%256):(256+iaddr%256) ) + s;
iaddr = iaddr >> 8;
}
System.out.println("Stringed address: " + s.substring(0,s.length()-1) );
InetAddress ia = InetAddress.getByName( s.substring(0,s.length()-1) );
short dccport = Short.valueOf(port).shortValue();
ircListener.dccChatRequest ( c.from , ia , dccport );
System.out.println("Converted address: " + ia);
}
else
{
//we don't treat sends
System.out.println("Type is unknown");
ircListener.unknownMsg(even_content);
continue;
} //end else
} //end try
catch ( Exception e )
{
//wrong format dcc message
System.out.println("Wrong format");
ircListener.unknownMsg(even_content);
continue;
} //end catch
} //end else (if argtok has no more tokens)
}
else if ( command.equalsIgnoreCase("PING") )
{
ircListener.ctcpPing ( c.from , arguments );
sendCtcpPing ( c.from , arguments );
} //end else if (command is...)
} //end else (if extd. text has tokens)
} //end else (text is extended)
} //end if (not x_delim)
} //end if (more tokens exist)
else
{
break;
}
} //end for [infinite]
break;
case IrcCommand.AwayMsgType:
if (c.to.charAt(0) == '#')
ircListener.channelAwayMsg(c.to, c.from, c.content);
else
ircListener.privateAwayMsg(c.from, c.content);
break;
default: System.out.println("*** Not catched event type "+c.type+":"+c.command);
} //end case switch
} //end infinite loop
} //end try
catch (Exception e)
{
;
}
} //end method run()
String concatTokenizedString (StringTokenizer st)
{
String s = st.nextToken();
while (st.hasMoreTokens()) s+=" "+st.nextToken();
return s;
}
} //end class