@ -7,9 +7,13 @@
package net.java.sip.communicator.impl.protocol.irc ;
package net.java.sip.communicator.impl.protocol.irc ;
import java.io.* ;
import java.io.* ;
import java.security.* ;
import java.util.* ;
import java.util.* ;
import javax.net.ssl.* ;
import net.java.sip.communicator.impl.protocol.irc.ModeParser.ModeEntry ;
import net.java.sip.communicator.impl.protocol.irc.ModeParser.ModeEntry ;
import net.java.sip.communicator.service.certificate.* ;
import net.java.sip.communicator.service.protocol.* ;
import net.java.sip.communicator.service.protocol.* ;
import net.java.sip.communicator.service.protocol.event.* ;
import net.java.sip.communicator.service.protocol.event.* ;
import net.java.sip.communicator.util.* ;
import net.java.sip.communicator.util.* ;
@ -61,7 +65,7 @@ public class IrcStack
* Connection state of a successful IRC connection .
* Connection state of a successful IRC connection .
* /
* /
private IIRCState connectionState ;
private IIRCState connectionState ;
/ * *
/ * *
* The cached channel list .
* The cached channel list .
*
*
@ -133,20 +137,16 @@ public void connect(String host, int port, String password,
this . joined . clear ( ) ;
this . joined . clear ( ) ;
this . irc = new IRCApiImpl ( true ) ;
this . irc = new IRCApiImpl ( true ) ;
// FIXME Currently, the secure connection is created by
// explicitly creating an SSLContext for 'SSL'. According
// to Ingo (in a mailing list conversation) it is better to
// use the CertificateService for this. This should be
// implemented in the irc-api library, though.
this . params . setServer ( new IRCServer ( host , port , password ,
secureConnection ) ) ;
synchronized ( this . irc )
synchronized ( this . irc )
{
{
this . params . setServer ( new IRCServer ( host , port , password ,
secureConnection ) ) ;
this . params . setCustomContext ( getCustomSSLContext ( host ) ) ;
this . irc . addListener ( new ServerListener ( ) ) ;
this . irc . addListener ( new ServerListener ( ) ) ;
connectSynchronized ( ) ;
connectSynchronized ( ) ;
}
}
}
}
/ * *
/ * *
* Perform synchronized connect operation .
* Perform synchronized connect operation .
*
*
@ -195,7 +195,7 @@ public void onFailure(Exception e)
. trace ( "Waiting for the connection to be established ..." ) ;
. trace ( "Waiting for the connection to be established ..." ) ;
result . wait ( ) ;
result . wait ( ) ;
}
}
this . connectionState = result . getValue ( ) ;
this . connectionState = result . getValue ( ) ;
// TODO Implement connection timeout and a way to recognize that
// TODO Implement connection timeout and a way to recognize that
// the timeout occurred.
// the timeout occurred.
@ -232,6 +232,30 @@ public void onFailure(Exception e)
}
}
}
}
/ * *
* Create a custom SSL context for this particular server .
*
* @return returns a customized SSL context or < tt > null < / tt > if one cannot
* be created .
* /
private SSLContext getCustomSSLContext ( String hostname )
{
SSLContext context = null ;
try
{
CertificateService cs =
IrcActivator . getCertificateVerificationService ( ) ;
X509TrustManager tm =
cs . getTrustManager ( hostname ) ;
context = cs . getSSLContext ( tm ) ;
}
catch ( GeneralSecurityException e )
{
LOGGER . error ( "failed to create custom SSL context" , e ) ;
}
return context ;
}
/ * *
/ * *
* Disconnect from the IRC server
* Disconnect from the IRC server
* /
* /
@ -239,8 +263,8 @@ public void disconnect()
{
{
if ( this . connectionState = = null & & this . irc = = null )
if ( this . connectionState = = null & & this . irc = = null )
return ;
return ;
synchronized ( this . joined )
synchronized ( this . joined )
{
{
// Leave all joined channels.
// Leave all joined channels.
for ( ChatRoomIrcImpl channel : this . joined . values ( ) )
for ( ChatRoomIrcImpl channel : this . joined . values ( ) )
@ -248,7 +272,7 @@ public void disconnect()
leave ( channel ) ;
leave ( channel ) ;
}
}
}
}
synchronized ( this . irc )
synchronized ( this . irc )
{
{
// Disconnect and clean up
// Disconnect and clean up
this . irc . disconnect ( ) ;
this . irc . disconnect ( ) ;
@ -575,7 +599,7 @@ public void onFailure(Exception e)
. trace ( "Finished waiting for join operation for channel '"
. trace ( "Finished waiting for join operation for channel '"
+ chatroom . getIdentifier ( ) + "' to complete." ) ;
+ chatroom . getIdentifier ( ) + "' to complete." ) ;
// TODO How to handle 480 (+j): Channel throttle exceeded?
// TODO How to handle 480 (+j): Channel throttle exceeded?
Exception e = joinSignal . getException ( ) ;
Exception e = joinSignal . getException ( ) ;
if ( e ! = null )
if ( e ! = null )
{
{
@ -666,10 +690,12 @@ public void command(ChatRoomIrcImpl chatroom, String command)
int endOfNick = command . indexOf ( ' ' ) ;
int endOfNick = command . indexOf ( ' ' ) ;
if ( endOfNick = = - 1 )
if ( endOfNick = = - 1 )
{
{
throw new IllegalArgumentException ( "Invalid private message format. Message was not sent." ) ;
throw new IllegalArgumentException (
"Invalid private message format. "
+ "Message was not sent." ) ;
}
}
target = command . substring ( 0 , endOfNick ) ;
target = command . substring ( 0 , endOfNick ) ;
command = command . substring ( endOfNick + 1 ) ;
command = command . substring ( endOfNick + 1 ) ;
}
}
else
else
{
{
@ -703,12 +729,12 @@ private static ChatRoomMemberRole convertMemberMode(char modeSymbol)
}
}
/ * *
/ * *
* A listener for server - level messages ( any messages that are related to the
* A listener for server - level messages ( any messages that are related to
* server, the connection , that are not related to any chatroom in
* the server, the connection , that are not related to any chatroom in
* particular ) or that are personal message from user to local user .
* particular ) or that are personal message from user to local user .
* /
* /
private class ServerListener
private class ServerListener
extends VariousMessageListenerAdapter
extends VariousMessageListenerAdapter
{
{
/ * *
/ * *
* Print out server notices for debugging purposes and for simply
* Print out server notices for debugging purposes and for simply
@ -744,10 +770,9 @@ public void onServerNumericMessage(ServerNumericMessage msg)
@Override
@Override
public void onError ( ErrorMessage msg )
public void onError ( ErrorMessage msg )
{
{
LOGGER . debug ( "ERROR: " + msg . getSource ( ) + ": "
LOGGER . debug ( "ERROR: " + msg . getSource ( ) + ": " + msg . getText ( ) ) ;
+ msg . getText ( ) ) ;
}
}
/ * *
/ * *
* Upon receiving a private message from a user , deliver that to a
* Upon receiving a private message from a user , deliver that to a
* private chat room and create one if it does not exist . We can ignore
* private chat room and create one if it does not exist . We can ignore
@ -780,8 +805,8 @@ public void onUserPrivMessage(UserPrivMsg msg)
* @param user the source user
* @param user the source user
* @param text the message
* @param text the message
* /
* /
private void deliverReceivedMessageToPrivateChat ( ChatRoomIrcImpl chatroom ,
private void deliverReceivedMessageToPrivateChat (
String user , String text )
ChatRoomIrcImpl chatroom , String user , String text )
{
{
ChatRoomMember member = chatroom . getChatRoomMember ( user ) ;
ChatRoomMember member = chatroom . getChatRoomMember ( user ) ;
MessageIrcImpl message =
MessageIrcImpl message =
@ -813,7 +838,7 @@ private ChatRoomIrcImpl initiatePrivateChatRoom(String user)
return chatroom ;
return chatroom ;
}
}
}
}
/ * *
/ * *
* A chat room listener .
* A chat room listener .
*
*
@ -924,9 +949,10 @@ public void onChannelPart(ChanPartMessage msg)
}
}
catch ( NullPointerException e )
catch ( NullPointerException e )
{
{
System . err
LOGGER
. println ( "This should not have happened. Please report this as it is a bug." ) ;
. warn (
e . printStackTrace ( ) ;
"This should not have happened. Please report this as it is a bug." ,
e ) ;
}
}
}
}
}
}
@ -959,8 +985,7 @@ public void onChannelKick(ChannelKick msg)
{
{
ChatRoomMember kicker =
ChatRoomMember kicker =
this . chatroom . getChatRoomMember ( user ) ;
this . chatroom . getChatRoomMember ( user ) ;
this . chatroom . fireMemberPresenceEvent ( kickedMember ,
this . chatroom . fireMemberPresenceEvent ( kickedMember , kicker ,
kicker ,
ChatRoomMemberPresenceChangeEvent . MEMBER_KICKED ,
ChatRoomMemberPresenceChangeEvent . MEMBER_KICKED ,
msg . getText ( ) ) ;
msg . getText ( ) ) ;
}
}
@ -1214,9 +1239,9 @@ sourceMember, new Date(),
ChatRoomMessageReceivedEvent . SYSTEM_MESSAGE_RECEIVED ) ;
ChatRoomMessageReceivedEvent . SYSTEM_MESSAGE_RECEIVED ) ;
break ;
break ;
case UNKNOWN :
case UNKNOWN :
LOGGER . info ( "Unknown mode: "
LOGGER . info ( "Unknown mode: " + ( mode . isAdded ( ) ? "+" : "-" )
+ ( mode . isAdded ( ) ? "+" : "-" ) + mode . getParams ( ) [ 0 ]
+ mode . getParams ( ) [ 0 ] + ". Original mode string: '"
+ ". Original mode string: '" + msg . getModeStr ( ) + "'" ) ;
+ msg . getModeStr ( ) + "'" ) ;
break ;
break ;
default :
default :
LOGGER . info ( "Unsupported mode '"
LOGGER . info ( "Unsupported mode '"
@ -1395,16 +1420,43 @@ private static class ServerParameters
implements IServerParameters
implements IServerParameters
{
{
/ * *
* Nick name .
* /
private String nick ;
private String nick ;
/ * *
* Alternative nick names .
* /
private List < String > alternativeNicks = new ArrayList < String > ( ) ;
private List < String > alternativeNicks = new ArrayList < String > ( ) ;
/ * *
* Real name .
* /
private String real ;
private String real ;
/ * *
* Ident .
* /
private String ident ;
private String ident ;
/ * *
* IRC server .
* /
private IRCServer server ;
private IRCServer server ;
/ * *
* Custom SSL Context .
* /
private SSLContext sslContext = null ;
/ * *
* Construct ServerParameters instance .
* @param nickName nick name
* @param realName real name
* @param ident ident
* @param server IRC server instance
* /
private ServerParameters ( String nickName , String realName ,
private ServerParameters ( String nickName , String realName ,
String ident , IRCServer server )
String ident , IRCServer server )
{
{
@ -1415,54 +1467,128 @@ private ServerParameters(String nickName, String realName,
this . server = server ;
this . server = server ;
}
}
/ * *
* Get nick name .
*
* @return returns nick name
* /
@Override
@Override
public String getNickname ( )
public String getNickname ( )
{
{
return this . nick ;
return this . nick ;
}
}
/ * *
* Set new nick name .
*
* @param nick nick name
* /
public void setNickname ( String nick )
public void setNickname ( String nick )
{
{
this . nick = checkNick ( nick ) ;
this . nick = checkNick ( nick ) ;
}
}
/ * *
* Verify nick name .
*
* @param nick nick name
* @return returns nick name
* @throws IllegalArgumentException throws
* < tt > IllegalArgumentException < / tt > if an invalid nick name
* is provided .
* /
private String checkNick ( String nick )
private String checkNick ( String nick )
{
{
if ( nick = = null )
if ( nick = = null )
throw new IllegalArgumentException ( "a nick name must be provided" ) ;
throw new IllegalArgumentException (
if ( nick . startsWith ( "#" ) )
"a nick name must be provided" ) ;
throw new IllegalArgumentException ( "the nick name must not start with '#' since this is reserved for IRC channels" ) ;
if ( nick . startsWith ( "#" ) )
throw new IllegalArgumentException (
"the nick name must not start with '#' "
+ "since this is reserved for IRC channels" ) ;
return nick ;
return nick ;
}
}
/ * *
* Get alternative nick names .
*
* @return returns list of alternatives
* /
@Override
@Override
public List < String > getAlternativeNicknames ( )
public List < String > getAlternativeNicknames ( )
{
{
return this . alternativeNicks ;
return this . alternativeNicks ;
}
}
/ * *
* Get ident string .
*
* @return returns ident
* /
@Override
@Override
public String getIdent ( )
public String getIdent ( )
{
{
return this . ident ;
return this . ident ;
}
}
/ * *
* Get real name
*
* @return returns real name
* /
@Override
@Override
public String getRealname ( )
public String getRealname ( )
{
{
return this . real ;
return this . real ;
}
}
/ * *
* Get server
*
* @return returns server instance
* /
@Override
@Override
public IRCServer getServer ( )
public IRCServer getServer ( )
{
{
return this . server ;
return this . server ;
}
}
/ * *
* Set server instance .
*
* @param server IRC server instance
* /
public void setServer ( IRCServer server )
public void setServer ( IRCServer server )
{
{
if ( server = = null )
throw new IllegalArgumentException ( "server cannot be null" ) ;
this . server = server ;
this . server = server ;
}
}
/ * *
* Get the SSL Context .
*
* Returns the custom SSLContext or null in case there is no
* custom implementation .
*
* @return returns the SSLContext or null
* /
@Override
public SSLContext getCustomContext ( )
{
return this . sslContext ;
}
/ * *
* Set custom SSLContext .
*
* @param context the custom SSLContext
* /
public void setCustomContext ( SSLContext context )
{
this . sslContext = context ;
}
}
}
/ * *
/ * *