Public Member Functions | Static Public Member Functions | Package Attributes | Private Member Functions | Private Attributes | Static Private Attributes

CryptoPhoneApp Class Reference

The Swing based GUI front-end of the Kryptofon application that implements simple VoIP phone and chat client with encrypted peer-to-peer communication. More...

Inheritance diagram for CryptoPhoneApp:
Inheritance graph
[legend]
Collaboration diagram for CryptoPhoneApp:
Collaboration graph
[legend]

List of all members.

Public Member Functions

 CryptoPhoneApp (String args[])
 Creates a new instance of the CryptoPhoneApp.
void startKryptofonServices ()
 Starts audio interface and UDP peer-to-peer channel.
void stopKryptofonServices ()
 Stops audio interface and UDP peer-to-peer channel.
void keyPressed (KeyEvent ke)
 Implements KeyListener's key pressed event.
void keyReleased (KeyEvent ke)
 Implements KeyListener's key released event.
void keyTyped (KeyEvent ke)
 Implements KeyListener's key typed event.
void actionPerformed (ActionEvent ae)
 Handles events from Swing timer and buttons.
void logMessage (final String str)
 Logs message formated with limited HTML (limited because of JEditorPane)
void attention (String message)
 Displays attention messages to the user from Log subsystem.
String getUserId ()
 Returns configured user ID (username).
void setPbxStatus (String str)
 Updates status message by updating window title.
void report (String cssClass, String str)
 Reports a system message to log.
void reportIncomingTextMessage (String cssClass, String userId, String message)
 Reports incoming message.
void onInvite (final PBXClient.ControlMessage m)
 Handles on INVITE call-back from the PBXClient.
void onRing (final PBXClient.ControlMessage m)
 Handles on RING call-back from the PBXClient.
void onAccept (final PBXClient.ControlMessage m)
 Handles on ACCEPT call-back from the PBXClient.
void onBye (final PBXClient.ControlMessage m)
 Handles on BYE call-back from the PBXClient.
void onInstantMessage (final PBXClient.ControlMessage m)
 Handles on IMSG call-back from the PBXClient.
void deferredOnInvite (final PBXClient.ControlMessage m)
 On INVITE call-back is triggered when PBXClient receives inviting message (indicating that someone is calling us).
void deferredOnRing (final PBXClient.ControlMessage m)
 On RING call-back is triggered when PBXClient receives ringing message (indicating that the peer is alerting end-user).
void deferredOnAccept (final PBXClient.ControlMessage m)
 On ACCEPT call-back is triggered when PBXClient receives accepting message (indicating that the peer has accepted our invite).
void deferredOnBye (final PBXClient.ControlMessage m)
 On BYE call-back is triggered when PBXClient receives 'bye' message (indicating that the peer is clearing i.e.
void deferredOnInstantMessage (final PBXClient.ControlMessage m)
 On IMSG call-back is triggered when PBXClient receives private instant message (encrypted with session's secret key).
void dumpLogArea (String fileName)
 Dumps log area into html file.
StringBuffer getContentsFromResourceOrFile (String path)
 Reads contents of the text file using URL class.
void clearLogArea ()
 Clears log area (with the contents of the "empty" template)
void displayUsage ()
 Displays usage information.
void displayHelp ()
 Displays help.

Static Public Member Functions

static void main (final String args[])
 Main entry point.

Package Attributes

PublicEncryptor remotePublicKey = null
 The last public key received from remote peer.

Private Member Functions

void createLayout ()
 Creates layout of the GUI components.
void createEventListeners ()
 Creates event listeners.
void sendButton_Clicked ()
 Parses input text entered by the user in inputMsg.
void listPeersButton_Clicked ()
 Performs :list command.
void dialButton_Clicked ()
 Performs :invite command.
void secureDialButton_Clicked ()
 Performs :invite+ command.
void hangupButton_Clicked ()
 Performs :bye command.
void formWindowClosing (WindowEvent evt)
 Closes application by gracefully terminating all threads.
void mainTimerEvent ()
 Handles events from application's mainTimer (an instance of the Swing timer).
String[] tokenizeInputMessage ()
 Tokenizes inputMsg into words and returns array of strings.
void parseInputMessage ()
 Parses input message from inputMsg and sends it to chat server.
void sendInstantMessage (String message, boolean forceUnencrypted)
 Sends chat message (encrypted if we have established secure channel with the user).
boolean executeCommand (String cmd, String[] args)
 Parses commands prefixed with ':' character.
PublicEncryptor tryToVerifyInvitingCall (boolean silent)
 Verifies invitor's public key (signed by invitor's private key) against the public keys from authorized keys file.
void acceptIncomingCall (boolean securedIfPossible)
 Accepts incoming invite.

Private Attributes

String serverName = "atlas.dsv.su.se"
 The host name or IP address of the remote chat server.
int serverPort = 9494
 The TCP port where to connect to on remote chat server.
PBXClient pbxChannel = null
 The instance of PBX client connected to remote chat server.
String pbxChannelStatus = ""
 The last status message of the PBX channel (posted by the setPbxStatus()).
Timer mainTimer = null
 Main timer (elapses every 1000 ms)
int reconnectTimeout = -1
 The reconnect delay timer (for timing delay between two reconnections).
int reconnectRetryCount = 0
 Retry counter of number of failed reconnecting attempts.
int localUdpPort = 47000
 The default local UDP port.
DatagramChannel udpChannel = null
 The instance of the UDP transceiver responsible for peer-to-peer communication between two Kryptofons.
AudioInterface audioInterface = null
 The instance of the Audio interface used to access microphone and speaker.
PBXClient.ControlMessage lastMessageFromPBX = null
 The last PBX control message sent to us (waiting to be handled)
String currentInvite = null
 The remote peer (its user id) that we are currently inviting to a call.
int inviteTimeout = -1
 Timer used to detect unresolved invite (i.e.
boolean monitorIfPeerIsSendingVoice = false
 Indicates whether to monitor if peer is sending voice PDUs to us.
JEditorPane logArea
 The log area formatted in HTML.
JSecState securityState
JImageButton sendButton
JImageButton listPeersButton
JImageButton dialButton
JImageButton secureDialButton
JImageButton hangupButton
JLabel imsgLabel
JTextField inputMsg
JLabel idLabel
JTextField userId
JCheckBox autoAnswer

Static Private Attributes

static final long serialVersionUID = -1830703904673318918L
 Implements java.io.Serializable interface.
static final String appTitle = "IP1-10: Kryptofon"
 The common application title prefix.
static final String defaultInputMsg = "<type in message, command or command arguments here>"
 The initial message content of the input text message field.
static final String defaultLogAreaDumpFilename = "mykf-log-area-"
 The default file name where to dump log area contents with :dump command.

Detailed Description

The Swing based GUI front-end of the Kryptofon application that implements simple VoIP phone and chat client with encrypted peer-to-peer communication.

Author:
Mikica B Kocic

Definition at line 66 of file CryptoPhoneApp.java.


Constructor & Destructor Documentation

CryptoPhoneApp.CryptoPhoneApp ( String  args[] )

Creates a new instance of the CryptoPhoneApp.

Parameters:
argsthe command line arguments passed to main

Definition at line 195 of file CryptoPhoneApp.java.

References appTitle, autoAnswer, clearLogArea(), createEventListeners(), createLayout(), defaultInputMsg, dialButton, displayUsage(), getUserId(), hangupButton, idLabel, imsgLabel, crypto.CipherEngine.initialize(), inputMsg, listPeersButton, ui.JImageButton.loadIcon(), logArea, mainTimer, pbxChannel, secureDialButton, securityState, sendButton, serverName, serverPort, pbx.PBXClient.start(), startKryptofonServices(), and userId.

Referenced by main().

    {
        super( appTitle );
        
        setDefaultCloseOperation( WindowConstants.EXIT_ON_CLOSE );

        //////////////////////////////////////////////////////// Create GUI elements /////
        
        /* Fonts and colors
         */
        Font textFont = new Font( Font.SANS_SERIF, Font.PLAIN, 14 );
        UIManager.put( "ToolTip.background", new ColorUIResource( 0xFF, 0xFF, 0xC7 ) );

        /* Application icons
         */
        List<Image> icons = new LinkedList<Image> ();
        icons.add( JImageButton.loadIcon( this, "favicon48.png" ).getImage () );
        icons.add( JImageButton.loadIcon( this, "favicon24.png" ).getImage () );
        icons.add( JImageButton.loadIcon( this, "favicon16.png" ).getImage () );
        setIconImages( icons );
         
        /* Components
         */
        inputMsg = new JTextField( defaultInputMsg, 30 );
        inputMsg.setFont( textFont );
        inputMsg.selectAll ();
        inputMsg.setToolTipText( 
                "<html><head></head><body><p>"
                + "Enter a text message or command here, then press <tt>Enter</tt><br/>"
                + "If you are going to use command buttons or command mnemonics,<br/>"
                + "then put command arguments here (or leave this field empty)."
                + "</p></body></html>"
                );
        
        imsgLabel = new JLabel (); // without the text; holds only mnemonic for the field
        imsgLabel.setFont( textFont );
        imsgLabel.setDisplayedMnemonic( KeyEvent.VK_I );
        imsgLabel.setLabelFor( inputMsg );

        securityState = new JSecState( this );
        
        sendButton = new JImageButton( this,
                "Send message", "chat.png", "chat2.png" );
        sendButton.setMnemonic( KeyEvent.VK_ENTER );
        
        listPeersButton = new JImageButton( this,
                "List kryptofon users (Alt + L)", "listPeers.png", "listPeers2.png" );
        listPeersButton.setMnemonic( KeyEvent.VK_L );
        
        dialButton = new JImageButton( this,
                "Make a call (Alt+C)", "dial.png", "dial2.png" );
        dialButton.setMnemonic( KeyEvent.VK_C );
        
        secureDialButton = new JImageButton( this,
                "Make a secure call (Alt+S)", "secureDial.png", "secureDial2.png" );
        secureDialButton.setMnemonic( KeyEvent.VK_S );
        
        hangupButton = new JImageButton( this,
                "Clear or reject the call (Alt+H)", "hangup.png", "hangup2.png" );
        hangupButton.setMnemonic( KeyEvent.VK_H );
        
        userId = new JTextField ();
        userId.setFont( textFont );
        userId.setText( getUserId () ); // set default user id
        userId.setToolTipText( 
                "<html><head></head><body><p>"
                + "Enter name, which will be used to identify you to other kryptofon peers.<br/>"
                + "The name should be unique and possibly without whitespaces."
                + "</p></body></html>"
                );
        
        idLabel = new JLabel( "My Name:" );
        idLabel.setFont( textFont );
        idLabel.setDisplayedMnemonic( KeyEvent.VK_N );
        idLabel.setLabelFor( userId );

        autoAnswer = new JCheckBox( "Autoanswer" );
        autoAnswer.setMnemonic( KeyEvent.VK_A );
        autoAnswer.setToolTipText( "Toggle auto-answer mode (Alt+A)" );

        logArea = new JEditorPane ();
        logArea.setFont( textFont );
        logArea.setEditable( false );
        logArea.setToolTipText( 
                "<html><head></head><body><p>"
                + "<strong>Log Area</strong><br/>"
                + "Use <tt>:dump</tt> command to save contents into a file"
                + "</p></body></html>"
                );

        clearLogArea ();

        //////////////////////////////////////////////////////// GUI Layout //////////////

        createLayout ();

        /* Set inputMsg field ready for user to type in something...
         */
        inputMsg.requestFocus ();

        //////////////////////////////////////////////////////// Event listeners /////////
        
        createEventListeners ();

        //////////////////////////////////////////////////////// Window Size /////////////
        
        /* Adjust window dimensions not to exceed screen dimensions ...
         */
        Dimension win = new Dimension( 1024, 600 );
        Dimension scsz = Toolkit.getDefaultToolkit().getScreenSize();
        win.width  = Math.min( win.width, scsz.width );
        win.height = Math.min( win.height, scsz.height - 40 );
        setSize( win );
        setMinimumSize( new Dimension( 600, 400 ) );
        
        /* ... then center window on the screen.
         */
        setLocation( ( scsz.width - win.width )/2, ( scsz.height - 40 - win.height )/2 );

        //////////////////////////////////////////////////////// Enable Logging //////////

        /* Enable Log
         */
        Log.setEnabled( Log.ALL   , false );
        Log.setEnabled( Log.VERB  , false );
        Log.setEnabled( Log.PDU   , false );
        Log.setEnabled( Log.AUDIO , false );
        Log.setEnabled( Log.DEBUG , false );
        Log.setEnabled( Log.ATTN  , true  );
        Log.setEnabled( Log.TRACE , true  );
        Log.setEnabled( Log.INFO  , true  );
        Log.setEnabled( Log.WARN  , true  );
        Log.setEnabled( Log.ERROR , true  );

        Log.attn = this; // catch messages in 'attention' channel

        /* Display initial contents in the log area
         */
        displayUsage ();

        //////////////////////////////////////////////////////// Start services //////////
        
        /* Parse arguments: [ <host> [ <port> ] ]
         */
        if ( args.length >= 1 )
        {
            serverName = args[ 0 ];
            if( args.length >= 2 ) try {
                serverPort = Integer.parseInt( args[ 1 ] );
            } catch ( NumberFormatException e ) {
                Log.warn( "Using the default destination TCP port: " + serverPort );
            }
        }

        /* Load authorized public keys and initializes asymmetric and symmetric 
         * ciphering engines
         */
        CipherEngine.initialize ();
        
        /* Start UDP listener and audio interface...
         */
        startKryptofonServices ();
        
        /* Open communication link to server...
         */
        pbxChannel = new PBXClient( serverName, serverPort, this );
        pbxChannel.start ();

        /* Instantiate connection monitor timer (for reconnect supervision)
         */
        mainTimer = new Timer( 1000, this );
        mainTimer.start ();

        Log.trace( "Created instance of the " + this.getClass().toString () );
    }

Member Function Documentation

void CryptoPhoneApp.acceptIncomingCall ( boolean  securedIfPossible ) [private]

Accepts incoming invite.

Procedure is called either automatically from deferredOnInvite() when the auto-answer is turned on, or manually by the user from :accept command).

It first verifies invitor's public key (signed by invitor's private key) against the public keys from authorized keys file.

It then signs local secret key with the local private key, then encrypts signed secret key with our with verified invitor's public key and serializes it as Base64 string.

It sends ACCEPTING message to the peer with the information how to rich us (local IP address and UDP port as well serialized encrypted secret key) and signed/encrypted/encoded secret key.

At the end it creates instance for the call (CallContext class) and the remote peer (RemotePeer class), and binds them to specific CODEC of the audio interface and UDP channel.

The call is finally established at this point.

Definition at line 1857 of file CryptoPhoneApp.java.

References protocol.VoicePDU.ALAW, appTitle, audioInterface, crypto.PublicEncryptor.encryptAndSerialize(), audio.AudioInterface.getByFormat(), crypto.CipherEngine.getCipher(), pbx.PBXClient.getLocalAddress(), protocol.DatagramChannel.getLocalPort(), crypto.CipherEngine.getSignedSecretKey(), protocol.DatagramChannel.hasRemotePeer(), crypto.PublicEncryptor.isActive(), crypto.PublicEncryptor.isVerified(), lastMessageFromPBX, monitorIfPeerIsSendingVoice, pbxChannel, remotePublicKey, report(), securityState, pbx.PBXClient.sendAccept(), protocol.CallContext.setCallEstablished(), ui.JSecState.setState(), tryToVerifyInvitingCall(), udpChannel, and protocol.DatagramChannel.useSymmetricCipher().

Referenced by deferredOnInvite(), dialButton_Clicked(), executeCommand(), and secureDialButton_Clicked().

    {
        if ( this.lastMessageFromPBX == null ) { // There is no INVITE to accept
            return;
        }
        
        PBXClient.ControlMessage m = this.lastMessageFromPBX;
        String verboseRemote = m.getVerboseRemote ();

        /* Can accept only if there is no call in progress.
         */
        if ( udpChannel.hasRemotePeer () ) {
            return;
        }
        
        /* Resolve peers IP address
         */
        InetAddress peerAddr = null;
        try {
            peerAddr = InetAddress.getByName( m.peerAddr );
        } catch( UnknownHostException e ) {
            Log.exception( Log.ERROR, e );
            this.lastMessageFromPBX = null;
            report( "logError", "Unknown remote host '" + m.peerAddr 
                    + "'; clearing the call..." );
            return;
        }

        /* Deserialize remote public key and encrypt our secret key with it.
         * Deserialization also verifies the public key against authorized keys.
         * \see constructor of the PublicEncryptor
         */
        String mySecret = null;
        remotePublicKey = null;
        udpChannel.useSymmetricCipher( null );
        
        if ( securedIfPossible )
        {
            remotePublicKey = tryToVerifyInvitingCall( /*silent*/ true );
            
            if ( remotePublicKey != null && remotePublicKey.isActive () ) 
            {
                mySecret = remotePublicKey.encryptAndSerialize( CipherEngine.getSignedSecretKey() );
                
                udpChannel.useSymmetricCipher( CipherEngine.getCipher () );
            }
        }

        /* Send accepting message to remote peer
         */
        pbxChannel.sendAccept( m.peerUserId,  pbxChannel.getLocalAddress (), 
                udpChannel.getLocalPort (), mySecret );

        /* Create necessary objects needed to establish the call:
         * instances of the RemotePeer and CallContext. 
         */
        RemotePeer remotePeer = new RemotePeer( this.udpChannel, 
                m.peerUserId, peerAddr, m.peerPort );
        
        AudioInterface codec = this.audioInterface.getByFormat( VoicePDU.ALAW );
        
        CallContext call = new CallContext( remotePeer, codec );
        call.setCallEstablished( true );
        monitorIfPeerIsSendingVoice = true;
        
        /* Report what we've done.
         */
        if ( remotePublicKey != null && remotePublicKey.isActive () )
        {
            if ( ! remotePublicKey.isVerified () ) {
                securityState.setState( JSecState.State.UNVERIFIED );
            } else  {
                securityState.setState( JSecState.State.VERIFIED );
            }
            
            report( "logOk", "***** Encrypted call established *****" );
            setTitle( appTitle + "; Established ENCRYPTED call with " + verboseRemote ); 
        }
        else
        {
            securityState.setState( JSecState.State.UNSECURED );
            report( "logError", "***** Un-encrypted call established *****" );
            setTitle( appTitle + "; Established PLAIN call with " + verboseRemote ); 
        }

        this.lastMessageFromPBX = null;
    }
void CryptoPhoneApp.actionPerformed ( ActionEvent  ae )

Handles events from Swing timer and buttons.

Definition at line 703 of file CryptoPhoneApp.java.

References dialButton, dialButton_Clicked(), hangupButton, hangupButton_Clicked(), listPeersButton, listPeersButton_Clicked(), mainTimer, mainTimerEvent(), secureDialButton, secureDialButton_Clicked(), sendButton, and sendButton_Clicked().

    {
        if ( ae.getSource () == mainTimer ) {
            mainTimerEvent ();
        } else if ( ae.getSource () == sendButton ) {
            sendButton_Clicked ();
        } else if ( ae.getSource () == listPeersButton ) {
            listPeersButton_Clicked ();
        } else if ( ae.getSource () == dialButton ) {
            dialButton_Clicked ();
        } else if ( ae.getSource () == secureDialButton ) {
            secureDialButton_Clicked ();
        } else if ( ae.getSource () == hangupButton ) {
            hangupButton_Clicked ();
        }
    }
void CryptoPhoneApp.attention ( String  message )

Displays attention messages to the user from Log subsystem.

Definition at line 857 of file CryptoPhoneApp.java.

References report().

    {
        if ( message.startsWith( "Error" ) ) {
            report( "logError", message );
        } else {
            report( "logInfo", message );
        }
    }
void CryptoPhoneApp.clearLogArea (  )

Clears log area (with the contents of the "empty" template)

Definition at line 2031 of file CryptoPhoneApp.java.

References getContentsFromResourceOrFile(), and logArea.

Referenced by CryptoPhoneApp(), and executeCommand().

    {
        logArea.setContentType( "text/html" );
        StringBuffer sb = getContentsFromResourceOrFile( "resources/empty.html" );
        if ( sb != null ) {
            logArea.setText( sb.toString () );
        } else {
            logArea.setText( "<html><head></head><body></body></html>" );
        }
    }
void CryptoPhoneApp.createEventListeners (  ) [private]

Creates event listeners.

Definition at line 478 of file CryptoPhoneApp.java.

References autoAnswer, dialButton, formWindowClosing(), getUserId(), hangupButton, inputMsg, listPeersButton, logArea, secureDialButton, sendButton, and userId.

Referenced by CryptoPhoneApp().

    {
        addWindowListener( new java.awt.event.WindowAdapter () {
            public void windowClosing( java.awt.event.WindowEvent evt ) {
                formWindowClosing( evt );
            }
        } );

        inputMsg.addKeyListener( this );
        userId.addKeyListener( this );
        autoAnswer.addKeyListener( this );
        logArea.addKeyListener( this );

        sendButton.addKeyListener( this );
        listPeersButton.addKeyListener( this );
        dialButton.addKeyListener( this );
        secureDialButton.addKeyListener( this );
        hangupButton.addKeyListener( this );
        
        sendButton.addActionListener( this );
        listPeersButton.addActionListener( this );
        dialButton.addActionListener( this );
        secureDialButton.addActionListener( this );
        hangupButton.addActionListener( this );

        inputMsg.addFocusListener(
                new FocusListener () {
                    public void focusGained( FocusEvent evt ) {
                        inputMsg.selectAll ();
                    }
                    public void focusLost( FocusEvent evt ) {
                    }
                }
            );

        userId.addFocusListener(
                new FocusListener () {
                    public void focusGained( FocusEvent evt ) {
                        userId.selectAll ();
                    }
                    public void focusLost( FocusEvent evt ) {
                        synchronized( userId ) {
                            userId.setText( getUserId () );
                        }
                    }
                }
            );
    }
void CryptoPhoneApp.createLayout (  ) [private]

Creates layout of the GUI components.

Definition at line 376 of file CryptoPhoneApp.java.

References dialButton, hangupButton, idLabel, imsgLabel, inputMsg, listPeersButton, logArea, secureDialButton, securityState, sendButton, and userId.

Referenced by CryptoPhoneApp().

    {
        /*  Upper: status, inputMsg | buttons | idLabel, userId 
         *  Lower: scrolled logArea 
         */
        GroupLayout layout = new GroupLayout( getContentPane () );
        getContentPane().setLayout( layout );
        layout.setAutoCreateContainerGaps( true );
        layout.setAutoCreateGaps( true );
        
        JScrollPane logPane = new JScrollPane ();
        logPane.setViewportView( logArea );

        JSeparator vertS1 = new JSeparator( JSeparator.VERTICAL );
        JSeparator vertS2 = new JSeparator( JSeparator.VERTICAL );

        int textH = 26; // fixed text field height
        int iconH = 32; // fixed icon height
        int iconW = 32; // fixed icon width
        
        layout.setHorizontalGroup
        (
            layout
                .createParallelGroup( GroupLayout.Alignment.LEADING )
                .addGroup
                ( 
                    layout
                        .createSequentialGroup ()
                        .addGroup
                        ( 
                            layout
                                .createParallelGroup( GroupLayout.Alignment.LEADING )
                                .addGroup
                                (
                                    GroupLayout.Alignment.TRAILING, 
                                    layout
                                        .createSequentialGroup ()
                                        .addComponent( securityState )
                                        .addGap( 5 )
                                        .addComponent( imsgLabel )
                                        .addGap( 0 )
                                        .addComponent( inputMsg )
                                        .addComponent( sendButton, iconW, iconW, iconW )
                                        .addGap( 15 )
                                        .addComponent( vertS1, 4, 4, 4 )
                                        .addGap( 10 )
                                        .addComponent( listPeersButton, iconW, iconW, iconW )
                                        .addComponent( dialButton, iconW, iconW, iconW )
                                        .addComponent( secureDialButton, iconW, iconW, iconW )
                                        .addComponent( hangupButton, iconW, iconW, iconW )
                                        .addGap( 15 )
                                        // .addComponent( autoAnswer )
                                        // .addGap( 10 )
                                        .addComponent( vertS2, 4, 4, 4 )
                                        .addGap( 10 )
                                        .addComponent( idLabel )
                                        .addGap( 5 )
                                        .addComponent( userId )
                                )
                                .addComponent( logPane )
                        )
                )
        );
        
        layout.setVerticalGroup
        (
            layout
                .createParallelGroup( GroupLayout.Alignment.LEADING )
                .addGroup
                (
                    layout
                        .createSequentialGroup ()
                        .addGroup
                        (
                            layout
                                .createParallelGroup( GroupLayout.Alignment.CENTER )
                                .addComponent( securityState )
                                .addComponent( imsgLabel )
                                .addComponent( inputMsg, textH, textH, textH )
                                .addComponent( sendButton, iconH, iconH, iconH )
                                .addComponent( vertS1, iconH, iconH, iconH )
                                .addComponent( listPeersButton, iconH, iconH, iconH )
                                .addComponent( dialButton, iconH, iconH, iconH )
                                .addComponent( secureDialButton, iconH, iconH, iconH )
                                .addComponent( hangupButton, iconH, iconH, iconH )
                                .addComponent( vertS2, iconH, iconH, iconH )
                                .addComponent( idLabel )
                                .addComponent( userId, textH, textH, textH )
                                //.addComponent( autoAnswer )
                        )
                        .addComponent( logPane )
                )
        );
        
        pack();
    }
void CryptoPhoneApp.deferredOnAccept ( final PBXClient.ControlMessage  m )

On ACCEPT call-back is triggered when PBXClient receives accepting message (indicating that the peer has accepted our invite).

It deserializes encrypted secret key used for peer-to-peer communication (if any) and creates instance for the call (CallContext class) as well the remote peer (RemotePeer class), and binds them to specific CODEC (of the audio interface) and the UDP channel (for voice transmission).

The call is finally established at this point.

Definition at line 1624 of file CryptoPhoneApp.java.

References protocol.VoicePDU.ALAW, appTitle, audioInterface, currentInvite, crypto.CipherEngine.deserializeEncryptedSecretKey(), audio.AudioInterface.getByFormat(), crypto.SymmetricCipher.getVerificatorName(), protocol.DatagramChannel.hasRemotePeer(), inviteTimeout, crypto.SymmetricCipher.isActive(), crypto.SymmetricCipher.isVerified(), lastMessageFromPBX, monitorIfPeerIsSendingVoice, report(), securityState, protocol.CallContext.setCallEstablished(), ui.JSecState.setState(), udpChannel, and protocol.DatagramChannel.useSymmetricCipher().

Referenced by onAccept().

    {
        if ( m.peerPort < 1 || m.peerPort > 65535 ) {
            return;
        }
        
        String verboseRemote = m.getVerboseRemote ();
        
        /* Ignore message if we already have the call in progress.
         */
        if ( udpChannel.hasRemotePeer () ) {
            return;
        }
        
        inviteTimeout = -1;
        currentInvite = null;
        
        /* Resolve peers IP address
         */
        InetAddress peerAddr = null;
        try {
            peerAddr = InetAddress.getByName( m.peerAddr );
        } catch( UnknownHostException e ) {
            Log.exception( Log.ERROR, e );
            this.lastMessageFromPBX = null;
            report( "logError", "Unknown remote host '" + m.peerAddr 
                    + "'; clearing the call..." );
            return;
        }

        report( "logInfo", "User " + verboseRemote + " has accepted our invite" );
        
        /* Deserialize encrypted remote secret key and decrypt it with our private key
         */
        SymmetricCipher cipher = null;
        udpChannel.useSymmetricCipher( null );

        if ( m.secret != null ) 
        {
            cipher = CipherEngine.deserializeEncryptedSecretKey( m.secret );
            
            if ( cipher.isActive () ) {
                udpChannel.useSymmetricCipher( cipher );
            } else {
                cipher = null;
            }
        }

        /* Create necessary objects needed to establish the call
         */
        RemotePeer remotePeer = new RemotePeer( this.udpChannel, m.peerUserId, 
                peerAddr, m.peerPort );
        
        AudioInterface codec = this.audioInterface.getByFormat( VoicePDU.ALAW );
        
        CallContext call = new CallContext( remotePeer, codec );
        call.setCallEstablished( true );
        monitorIfPeerIsSendingVoice = true;

        if ( cipher != null && cipher.isActive () )
        {
            if ( ! cipher.isVerified () ) 
            {
                securityState.setState( JSecState.State.UNVERIFIED );
                report( "logError", "Secret key from " + verboseRemote
                        + " could not be authenticated." );
            }
            else 
            {
                securityState.setState( JSecState.State.VERIFIED );
                report( "logOk", "Secret key from " + verboseRemote
                        + " authenticated with public key '" 
                        + cipher.getVerificatorName () + "'" );
            }
            
            report( "logOk", "***** Encrypted call established *****" );
            setTitle( appTitle + "; Established ENCRYPTED call with " + verboseRemote );
        }
        else
        {
            securityState.setState( JSecState.State.UNSECURED );
            report( "logError", "***** Un-encrypted call established *****" );
            setTitle( appTitle + "; Established PLAIN call with " + verboseRemote ); 
        }
    }
void CryptoPhoneApp.deferredOnBye ( final PBXClient.ControlMessage  m )

On BYE call-back is triggered when PBXClient receives 'bye' message (indicating that the peer is clearing i.e.

hanging-up the call).

Definition at line 1714 of file CryptoPhoneApp.java.

References audioInterface, currentInvite, protocol.DatagramChannel.hasRemotePeer(), inviteTimeout, lastMessageFromPBX, logMessage(), pbxChannelStatus, remotePublicKey, protocol.DatagramChannel.removePeer(), report(), securityState, ui.JSecState.setState(), audio.AudioInterface.stopRinging(), udpChannel, and userId.

Referenced by onBye().

    {
        String verboseRemote = m.getVerboseRemote ();
        
        /* If we do not have a call, than remote has rejected our earlier invite
         */
        if ( ! udpChannel.hasRemotePeer () && currentInvite != null ) 
        {
            report( "logInfo", "User " + verboseRemote + " rejected our invite" );
        }
        else /* otheresie, it is a hang-up of the existing call */
        {
            report( "logInfo", "User " + verboseRemote + " is clearing the call" );
            udpChannel.removePeer ();
        }

        audioInterface.stopRinging ();
        userId.setEnabled( true ); // enable back changing user ID
        
        lastMessageFromPBX = null;
        remotePublicKey = null;
        
        report( "logInfo", "***** Call Ended *****" );
        logMessage( "<hr/>" );
        
        securityState.setState( JSecState.State.UNSECURED );
        setTitle( pbxChannelStatus );
        
        inviteTimeout = -1;
        currentInvite = null;
    }
void CryptoPhoneApp.deferredOnInstantMessage ( final PBXClient.ControlMessage  m )

On IMSG call-back is triggered when PBXClient receives private instant message (encrypted with session's secret key).

Definition at line 1750 of file CryptoPhoneApp.java.

References crypto.SymmetricCipher.decrypt(), protocol.DatagramChannel.getUsedSymmetricCipher(), reportIncomingTextMessage(), and udpChannel.

Referenced by onInstantMessage().

    {
        /* Get symmetric ciphering engine for PDUs and messages (if any).
         */
        SymmetricCipher cipher = udpChannel.getUsedSymmetricCipher ();
        if ( cipher == null ) {
            return;
        }

        /* Decrypt instant message and display highlighted contents to the user
         */
        String clearText = cipher.decrypt( m.secret );
        if ( clearText != null ) 
        {
            /* 
             */
            reportIncomingTextMessage( "secureMessage", 
                    m.peerUserId + " [encrypted]", clearText ); 
        }
    }
void CryptoPhoneApp.deferredOnInvite ( final PBXClient.ControlMessage  m )

On INVITE call-back is triggered when PBXClient receives inviting message (indicating that someone is calling us).

It starts ringing and if the application is in auto-answer mode, it accepts incoming call immediately. Otherwise it presents alerting message to the user with information about who's calling.

Definition at line 1501 of file CryptoPhoneApp.java.

References acceptIncomingCall(), appTitle, audioInterface, autoAnswer, pbx.PBXClient.getLocalAddress(), protocol.DatagramChannel.getLocalPort(), crypto.CipherEngine.getSignedPublicKey(), protocol.DatagramChannel.hasRemotePeer(), lastMessageFromPBX, logMessage(), pbxChannel, report(), pbx.PBXClient.sendBye(), pbx.PBXClient.sendRing(), audio.AudioInterface.startRinging(), tryToVerifyInvitingCall(), udpChannel, and userId.

Referenced by onInvite().

    {
        if ( m.peerPort < 1 || m.peerPort > 65535 ) {
            return;
        }
        
        String verboseRemote = m.getVerboseRemote ();

        /* Reject new calls if we already have the call in progress
         */
        if ( udpChannel.hasRemotePeer () ) 
        {
            /* Send 'bye' message to remote peer who is inviting us
             */
            pbxChannel.sendBye( m.peerUserId, "0.0.0.0", 0 );  
            return;
        }

        this.lastMessageFromPBX = m;
        
        logMessage( "<hr/>" );
        report( "logInfo", "User " + verboseRemote + " is inviting us..." );

        if ( m.secret == null ) {
            setTitle( appTitle + "; Incoming PLAIN call from " + verboseRemote ); 
        } else {
            setTitle( appTitle + "; Incoming ENCRYPTED call from " + verboseRemote ); 
        }
        
        this.audioInterface.startRinging ();
        userId.setEnabled( false ); // disable changing user ID

        if ( autoAnswer.isSelected () )
        {
            report( "logInfo", "Auto-answering the call..." );
            acceptIncomingCall( /*secured*/ true );
        }
        else
        {
            tryToVerifyInvitingCall( /*silent*/ false );
            report( "logInfo", "Respond with :accept to answer the call!" );
            
            /* Send 'ringing' message to remote peer with our public key
             */
            pbxChannel.sendRing( m.peerUserId,  pbxChannel.getLocalAddress (), 
                    udpChannel.getLocalPort (), CipherEngine.getSignedPublicKey () );
        }
    }
void CryptoPhoneApp.deferredOnRing ( final PBXClient.ControlMessage  m )

On RING call-back is triggered when PBXClient receives ringing message (indicating that the peer is alerting end-user).

Definition at line 1554 of file CryptoPhoneApp.java.

References audioInterface, currentInvite, crypto.PublicEncryptor.getVerificatorName(), protocol.DatagramChannel.hasRemotePeer(), inviteTimeout, crypto.PublicEncryptor.isActive(), crypto.PublicEncryptor.isVerified(), remotePublicKey, report(), audio.AudioInterface.startRinging(), udpChannel, and userId.

Referenced by onRing().

    {
        if ( m.peerPort < 1 || m.peerPort > 65535 ) {
            return;
        }
        
        String verboseRemote = m.getVerboseRemote ();
        
        /* Ignore the message if we already have the call in progress.
         */
        if ( udpChannel.hasRemotePeer () ) {
            return;
        }
        
        /* Ignore the message if the remote peer is not that we are inviting to a call
         */
        if ( currentInvite == null || ! currentInvite.equalsIgnoreCase( m.peerUserId ) ) {
            return;
        }

        /* Deserialize remote public key.
         * Deserialization also verifies the public key against authorized keys.
         * \see constructor of the PublicEncryptor
         */
        remotePublicKey = null;

        if ( m.secret != null ) 
        {
            remotePublicKey = new PublicEncryptor( m.secret, m.peerUserId );
            if ( ! remotePublicKey.isActive () ) {
                remotePublicKey = null;
            }
        }

        /* Cancel inviteTimeout timer and give information and ringing tone to our user
         */
        report( "logInfo", "User " + verboseRemote + " is alerted..." );
        
        if ( remotePublicKey != null && remotePublicKey.isActive () )
        {
            if ( ! remotePublicKey.isVerified () ) 
            {
                report( "logError", "Reply from " + verboseRemote
                        + " could not be authenticated." );
            }
            else 
            {
                report( "logOk", "Reply from " + verboseRemote
                        + " authenticated with public key '" 
                        + remotePublicKey.getVerificatorName () + "'" );
            }
        }

        inviteTimeout = -1; // Reset only invite timeout (do not reset currentInvite)

        this.audioInterface.startRinging ();
        userId.setEnabled( false ); // disable changing user ID
    }
void CryptoPhoneApp.dialButton_Clicked (  ) [private]

Performs :invite command.

Definition at line 609 of file CryptoPhoneApp.java.

References acceptIncomingCall(), executeCommand(), lastMessageFromPBX, and tokenizeInputMessage().

Referenced by actionPerformed().

    {
        /* If there is outstanding INVITE waiting to be accepted,
         * do accept incoming call instead of making new outgoing call.
         */
        if ( this.lastMessageFromPBX == null ) {
            executeCommand( ":invite", tokenizeInputMessage () );
        } else {
            acceptIncomingCall( /*secured*/ false );
        }
    }
void CryptoPhoneApp.displayHelp (  )

Displays help.

Definition at line 2057 of file CryptoPhoneApp.java.

References getContentsFromResourceOrFile(), and logMessage().

Referenced by executeCommand().

    {
        StringBuffer sb = getContentsFromResourceOrFile( "resources/help.html" );
        
        if ( sb != null && sb.length () > 0 ) {
            logMessage( sb.toString () );
        }
    }
void CryptoPhoneApp.displayUsage (  )

Displays usage information.

Definition at line 2045 of file CryptoPhoneApp.java.

References getContentsFromResourceOrFile(), and logMessage().

Referenced by CryptoPhoneApp(), and executeCommand().

    {
        StringBuffer sb = getContentsFromResourceOrFile( "resources/usage.html" );
        
        if ( sb != null && sb.length () > 0 ) {
            logMessage( sb.toString () );
        }
    }
void CryptoPhoneApp.dumpLogArea ( String  fileName )

Dumps log area into html file.

Definition at line 1950 of file CryptoPhoneApp.java.

References defaultLogAreaDumpFilename, logArea, and report().

Referenced by executeCommand().

    {
        if ( fileName == null || fileName.isEmpty () ) {
            Calendar cal = Calendar.getInstance ();
            SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd-HHmmssSSS" );
            fileName = defaultLogAreaDumpFilename + sdf.format( cal.getTime () ) + ".html";
        }

        try 
        {
            BufferedWriter out = new BufferedWriter( new FileWriter( fileName ) );
            
            synchronized( logArea )
            {
                out.write( logArea.getText () );
            }

            out.close ();
            
            report( "logInfo", "Dumped log area into '" + fileName + "'" );
        }
        catch( IOException e )
        {
            report( "logError", "Failed to dump log area: " + e.getMessage () );
        }
    }
boolean CryptoPhoneApp.executeCommand ( String  cmd,
String[]  args 
) [private]

Parses commands prefixed with ':' character.

Recognized commands are:

  VoIP Calls:
     :inv[ite]    username             aliases: :ca[ll]
     :inv[ite]+   username             aliases: :ca[ll]+
     :acc[ept]                         aliases: :ans[wer]
     :by[e]                            aliases: :ha[ngup]
     :shk[ey]
  VoIP Peers:
     :li[st]    [ username-regex ]
  Chat Messages:
     :br[oadcast]  message
  Connection to Chat Server:
     :clo[se]
     :op[en]    [ host  [ port ] ]
  Application:
     :cl[ear]s[creen]
     :reauth
     :newsecret  [ algorithm [ keysize ] ]
     :du[mp]
     :ex[it]                           aliases: :qu[it]
     :he[lp]
  
Parameters:
cmdcommand name; must begin with ":"
argscommand arguments; may be null or empty array
Returns:
true if command is parsed and executed

Definition at line 1188 of file CryptoPhoneApp.java.

References acceptIncomingCall(), audioInterface, clearLogArea(), pbx.PBXClient.close(), currentInvite, displayHelp(), displayUsage(), dumpLogArea(), crypto.CipherEngine.generateNewSecret(), pbx.PBXClient.getLocalAddress(), protocol.DatagramChannel.getLocalPort(), crypto.CipherEngine.getNamedPublicKey(), protocol.DatagramChannel.getRemotePeer(), protocol.RemotePeer.getRemoteUserId(), crypto.CipherEngine.getSignedPublicKey(), protocol.DatagramChannel.hasRemotePeer(), inviteTimeout, lastMessageFromPBX, logMessage(), pbxChannel, pbxChannelStatus, reconnectRetryCount, crypto.CipherEngine.reloadAuthorizedPublicKeys(), remotePublicKey, protocol.DatagramChannel.removePeer(), report(), securityState, pbx.PBXClient.send(), pbx.PBXClient.sendBye(), sendInstantMessage(), pbx.PBXClient.sendInvite(), pbx.PBXClient.sendListPeers(), serverName, serverPort, ui.JSecState.setState(), pbx.PBXClient.start(), stopKryptofonServices(), audio.AudioInterface.stopRinging(), udpChannel, and userId.

Referenced by dialButton_Clicked(), hangupButton_Clicked(), keyPressed(), listPeersButton_Clicked(), parseInputMessage(), secureDialButton_Clicked(), and stopKryptofonServices().

    {
        cmd = cmd.trim().toLowerCase();

        boolean executed = false;

        if ( args == null ) {
            args = new String[0];
        }

        /* Note bellow that we use both equals() and matches() to resolve command.
         * We need equals() to speed-up lookup for those commands that are executed
         * internally by directly calling executeCommand() with hard-coded argument
         * (contrary to when executeCommand() is called with commnands entered by
         * the user).
         */

        /*------------------------------------------------------------------------------*/
        if ( cmd.equals( ":list" ) || cmd.matches( "^:li(st?)?$" ) )
        {
            pbxChannel.sendListPeers( args.length >= 1 ? args[0] : null );

            executed = true;
        }
        /*------------------------------------------------------------------------------*/
        else if ( cmd.equals( ":who" ) )
        {
            pbxChannel.send( "wwhhoo" );

            executed = true;
        }
        /*------------------------------------------------------------------------------*/
        else if ( cmd.equals( ":bye" ) 
               || cmd.matches( "^:by(e)?$" ) 
               || cmd.matches( "^:ha(n(g(up?)?)?)?$" ) )
        {
            RemotePeer remotePeer = udpChannel.getRemotePeer ();

            if ( remotePeer != null ) 
            {
                report( "logInfo", "***** Call Ended *****" );
                logMessage( "<hr/>" );

                /* Send 'bye' message to remote peer
                 */
                pbxChannel.sendBye( remotePeer.getRemoteUserId (),  
                        pbxChannel.getLocalAddress (), udpChannel.getLocalPort () );
            }
            else if ( currentInvite != null )
            {
                report( "logInfo", "Invite cancelled." );
                logMessage( "<hr/>" );

                /* Send 'bye' message to remote peer
                 */
                pbxChannel.sendBye( currentInvite,  
                        pbxChannel.getLocalAddress (), udpChannel.getLocalPort () );
            }
            else if ( this.lastMessageFromPBX != null ) // call waiting to be accepted
            {
                PBXClient.ControlMessage m = this.lastMessageFromPBX;
                
                String verboseRemote = m.getVerboseRemote ();
                
                report( "logInfo", "Rejecting invite from " + verboseRemote );
                logMessage( "<hr/>" );

                /* Send 'bye' message to remote peer
                 */
                pbxChannel.sendBye( m.peerUserId,  
                        pbxChannel.getLocalAddress (), udpChannel.getLocalPort () );
                
                this.lastMessageFromPBX = null;
            }

            udpChannel.removePeer ();
            audioInterface.stopRinging ();
            userId.setEnabled( true ); // enable back changing user ID
            
            lastMessageFromPBX = null;
            remotePublicKey = null;

            securityState.setState( JSecState.State.UNSECURED );
            setTitle( pbxChannelStatus );
            
            inviteTimeout = -1;
            currentInvite = null;

            executed = true;
        }
        /*------------------------------------------------------------------------------*/
        else if ( cmd.equals( ":invite+" )
               || cmd.matches( "^:inv(i(te?)?)?\\+$" ) 
               || cmd.matches( "^:ca(ll?)?\\+$" ) )
        {
            /* Calls another user WITH encryption enabled 
             */
            if ( udpChannel.hasRemotePeer () || currentInvite != null )
            {
                report( "logError", "Call in progress. Hang up first!" );
                
                executed = true;
            }
            else if ( args.length >= 1 && pbxChannel.isAlive () )
            {
                logMessage( "<hr/>" );
                report( "logInfo", "Inviting '" + args[0] 
                        + "' to encrypted voice call..." );

                currentInvite = args[0];
                inviteTimeout = 3;
                
                userId.setEnabled( false ); // disable changing user ID

                pbxChannel.sendInvite( currentInvite, pbxChannel.getLocalAddress (),
                        udpChannel.getLocalPort (), CipherEngine.getSignedPublicKey () );

                executed = true;
            }
        }
        /*------------------------------------------------------------------------------*/
        else if ( cmd.equals( ":invite" )
               || cmd.matches( "^:inv(i(te?)?)?$" ) 
               || cmd.matches( "^:ca(ll?)?$" ) )
        {
            /* Calls another user WITHOUT encryption enabled 
             */
            if ( udpChannel.hasRemotePeer () || currentInvite != null )
            {
                report( "logError", "Call in progress. Hang up first!" );
                
                executed = true;
            }
            else if ( args.length >= 1 && pbxChannel.isAlive () )
            {
                logMessage( "<hr/>" );
                report( "logInfo", "Inviting '" + args[0]
                        + "' to un-encrypted voice call..." );
                
                currentInvite = args[0];
                inviteTimeout = 3;
                
                userId.setEnabled( false ); // disable changing user ID

                pbxChannel.sendInvite( args[0], pbxChannel.getLocalAddress (),
                        udpChannel.getLocalPort (), null );

                executed = true;
            }
        }
        /*------------------------------------------------------------------------------*/
        else if ( cmd.equals( ":accept" )
               || cmd.matches( "^:acc(e(pt?)?)?$" ) 
               || cmd.matches( "^:ans(w(er?)?)?$" ) )
        {
            acceptIncomingCall( /*secured*/ true );

            executed = true;
        }
        /*------------------------------------------------------------------------------*/
        else if ( cmd.equals( ":broadcast" )
               || cmd.matches( "^:br(o(a(d(c(a(st?)?)?)?)?)?)?$" ) )
        {
            if ( args.length >= 1 ) 
            {
                StringBuffer msg = new StringBuffer ();
                for ( String s : args ) {
                    if ( msg.length () > 0 ) {
                        msg.append( " " );
                    }
                    msg.append( s );
                }
                
                sendInstantMessage( msg.toString () , /*forceUnencrypted*/ true );
    
                executed = true;
            }
        }
        /*------------------------------------------------------------------------------*/
        else if ( cmd.equals( ":mykey" )
               || cmd.matches( "^:my(k(ey?)?)?$" ) )
        {
            sendInstantMessage( "\f========= BEGIN PUBLIC KEY =========\f\f"
                    + CipherEngine.getNamedPublicKey ()
                    + "\f\f========= END PUBLIC KEY ==========="
                    , /*forceUnencrypted*/ false );
        }
        /*------------------------------------------------------------------------------*/
        else if ( cmd.equals( ":close" )
               || cmd.matches( "^:clo(se?)?$" ) )
        {
            logMessage( "<hr/>" );
            reconnectRetryCount = Integer.MAX_VALUE; // suppresses reconnection
            pbxChannel.close ();

            executed = true;
        }
        /*------------------------------------------------------------------------------*/
        else if ( cmd.equals( ":open" )
               || cmd.matches( "^:op(en?)?$" ) )
        {
            /* Opens new connection to chat server
             */
            if ( args.length >= 1 )
            {
                /* Parse arguments first: host name and port
                 */
                serverName = args[0];
                serverPort = 2000; // the default port
                
                if( args.length >= 2 ) try {
                    serverPort = Integer.parseInt( args[1] );
                } catch ( NumberFormatException e ) {
                    report( "logError", "The port must be integer." );
                    return false;
                }
            }
            
            logMessage( "<hr/>" );

            reconnectRetryCount = Integer.MAX_VALUE; // suppresses reconnection
            pbxChannel.close ();
            
            pbxChannel = new PBXClient( serverName, serverPort , this );
            pbxChannel.start ();
            reconnectRetryCount = 0;

            executed = true;
        }
        /*------------------------------------------------------------------------------*/
        else if ( cmd.equals( ":exit" )
               || cmd.matches( "^:ex(it?)?$" ) || cmd.matches( "^:qu(it?)?$" ) )
        {
            stopKryptofonServices ();
            pbxChannel.close ();
            System.exit( 0 );
        }
        /*------------------------------------------------------------------------------*/
        else if ( cmd.equals( ":reauth" ) )
        {
            CipherEngine.reloadAuthorizedPublicKeys ();
            
            executed = true;
        }
        /*------------------------------------------------------------------------------*/
        else if ( cmd.equals( ":newsecret" ) )
        {
            String algorithm = "Blowfish";
            int keySize = 32;
            
            if ( args.length >= 1 ) {
                algorithm = args[0];
            }

            if ( args.length >= 2 ) {
                try {
                    keySize = Integer.parseInt( args[1] );
                } catch ( NumberFormatException e ) {
                    report( "logError", "The key size must be integer." );
                    return false;
                }
            }

            if ( ! CipherEngine.generateNewSecret( algorithm, keySize, /*verbose*/true ) ) 
            {
                /* fail back to blowfish (not to leave user without symmetric cipher)
                 */
                CipherEngine.generateNewSecret( "Blowfish", 32, /*verbose*/false ); 
                return false;
            }

            executed = true;
        }
        /*------------------------------------------------------------------------------*/
        else if ( cmd.equals( ":cls" )
               || cmd.matches( "^:cl(ear)?s(c(r(e(en?)?)?)?)?$" ) )
        {
            clearLogArea (); // clears screen
            displayUsage ();

            executed = true;
        }
        /*------------------------------------------------------------------------------*/
        else if ( cmd.equals( ":help" )
               || cmd.matches( "^:he(lp?)?$" ) )
        {
            displayHelp ();

            executed = true;
        }
        /*------------------------------------------------------------------------------*/
        else if ( cmd.equals( ":dump" )
               || cmd.matches( "^:du(mp?)?$" ) )
        {
            dumpLogArea( args.length >= 1 ? args[0] : null );

            executed = true;
        }
        /*------------------------------------------------------------------------------*/
        
        return executed;
    }
void CryptoPhoneApp.formWindowClosing ( WindowEvent  evt ) [private]

Closes application by gracefully terminating all threads.

Definition at line 647 of file CryptoPhoneApp.java.

References pbx.PBXClient.close(), pbxChannel, and stopKryptofonServices().

Referenced by createEventListeners(), and parseInputMessage().

    {
        stopKryptofonServices ();
        
        if ( pbxChannel != null ) {
            pbxChannel.close ();
        }

        System.exit( 0 );
    }
StringBuffer CryptoPhoneApp.getContentsFromResourceOrFile ( String  path )

Reads contents of the text file using URL class.

Returns:
string buffer containing file contents; null in case of error

Definition at line 1982 of file CryptoPhoneApp.java.

Referenced by clearLogArea(), displayHelp(), and displayUsage().

    {
        StringBuffer sb = new StringBuffer ();

        try 
        {
            /* First, try to read resource from JAR
             */
            URL url = getClass().getResource( path );
            
            /* Then fail to local file 
             */
            if ( url == null ) {
                url = new URL( "file:" + path );
            }
            
            /* Append contents of the file to string buffer
             */
            if ( url != null ) 
            {
                InputStream in = url.openStream ();
                BufferedReader dis = new BufferedReader( new InputStreamReader( in ) );

                String line;
                while ( ( line = dis.readLine () ) != null )
                {
                    sb.append( line + "\n" );
                }

                in.close ();
            }
        }
        catch( MalformedURLException e ) 
        {
            Log.exception( Log.TRACE, e );
            sb = null;
        }
        catch( IOException e )
        {
            Log.exception( Log.TRACE, e );
            sb = null;
        }

        return sb;
    }
String CryptoPhoneApp.getUserId (  )

Returns configured user ID (username).

Definition at line 872 of file CryptoPhoneApp.java.

References userId.

Referenced by createEventListeners(), CryptoPhoneApp(), parseInputMessage(), sendInstantMessage(), and startKryptofonServices().

    {
        String newId = null;
        
        synchronized( userId )
        {
            String oldId = userId.getText ().trim();

            /* Default user id, if not specified */
            if ( oldId.isEmpty () ) {
                oldId = System.getProperty( "user.name" );
            }
            
            /* Ouch. Again empty. Then we are really an anonymous */
            if ( oldId.isEmpty () ) {
                oldId = "[Anonymous]";
            }

            /* Discard spaces from the local userId */
            newId = oldId.replaceAll( "\\s{1,}", "-" );
        }
        
        return newId;
    }
void CryptoPhoneApp.hangupButton_Clicked (  ) [private]

Performs :bye command.

Definition at line 639 of file CryptoPhoneApp.java.

References executeCommand(), and tokenizeInputMessage().

Referenced by actionPerformed().

void CryptoPhoneApp.keyPressed ( KeyEvent  ke )

Implements KeyListener's key pressed event.

Parses input message on ENTER (the same action as it was sendButton_Clicked).

Definition at line 662 of file CryptoPhoneApp.java.

References defaultInputMsg, executeCommand(), inputMsg, parseInputMessage(), and userId.

                                          {
        
        int keyCode = ke.getKeyCode ();
        
        if( ke.getSource () == inputMsg && keyCode == KeyEvent.VK_ENTER )
        {
            if ( defaultInputMsg.equalsIgnoreCase( inputMsg.getText () ) ) { 
                return; // ignore default input message
            }
            
            parseInputMessage ();
        }
        else if( ke.getSource () == userId && keyCode == KeyEvent.VK_ENTER )
        {
            inputMsg.requestFocus ();
        }
        else if( keyCode == KeyEvent.VK_F1 )
        {
            executeCommand( ":help", null );
        }
    }
void CryptoPhoneApp.keyReleased ( KeyEvent  ke )

Implements KeyListener's key released event.

Definition at line 687 of file CryptoPhoneApp.java.

    {
        /* unused */
    }
void CryptoPhoneApp.keyTyped ( KeyEvent  ke )

Implements KeyListener's key typed event.

Definition at line 695 of file CryptoPhoneApp.java.

    {
        /* unused */
    }
void CryptoPhoneApp.listPeersButton_Clicked (  ) [private]

Performs :list command.

Definition at line 601 of file CryptoPhoneApp.java.

References executeCommand().

Referenced by actionPerformed().

    {
        executeCommand( ":list", null );
    }
void CryptoPhoneApp.logMessage ( final String  str )

Logs message formated with limited HTML (limited because of JEditorPane)

Definition at line 833 of file CryptoPhoneApp.java.

References logArea.

Referenced by deferredOnBye(), deferredOnInvite(), displayHelp(), displayUsage(), executeCommand(), mainTimerEvent(), report(), and reportIncomingTextMessage().

    {
        java.awt.EventQueue.invokeLater( 
                new Runnable() {
                    public void run() {
                        synchronized( logArea )
                        {
                            /* Append the string to the end of <body> element...
                             */
                            String html = logArea.getText ();
                            html = html.replace( "</body>", str + "\n</body>" );
                            logArea.setText( html );
                        }
                    }
                }
            );
    }
static void CryptoPhoneApp.main ( final String  args[] ) [static]

Main entry point.

Creates GUI instance of the CryptoPhoneApp application.

Parameters:
argsthe command line arguments

Definition at line 2072 of file CryptoPhoneApp.java.

References CryptoPhoneApp().

    {
        // System.getProperties().list( System.out );
        
        java.awt.EventQueue.invokeLater( 
                new Runnable() {
                    public void run() {
                        new CryptoPhoneApp( args ).setVisible( true );
                    }
                }
            );
    }
void CryptoPhoneApp.mainTimerEvent (  ) [private]

Handles events from application's mainTimer (an instance of the Swing timer).

It monitors status of:

  1. PBXClient connection
  2. connection to remote peer (if any)
  3. awaiting acknowledgment for our last invite message (if any)

If PBXClient connection is detected to be down, the procedure will try to reconnect to chat server after some period of time. If reconnection retry count exceeded maximum, timer will stop retrying.

In case of dead remote peer (not sending UDP packets to us), udpChannel.isPearDead() timer will clear down the call.

In case of unacknowledged invite message, inviteTimeout timer will cancel current inviting.

Definition at line 738 of file CryptoPhoneApp.java.

References currentInvite, protocol.DatagramChannel.getRemotePeer(), protocol.RemotePeer.getRemoteUserId(), inviteTimeout, protocol.DatagramChannel.isPearDead(), logMessage(), monitorIfPeerIsSendingVoice, pbxChannel, reconnectRetryCount, reconnectTimeout, report(), serverName, serverPort, setPbxStatus(), pbx.PBXClient.start(), and udpChannel.

Referenced by actionPerformed().

    {
        //////////////////////////////////////////////////////////////////////////////////
        /* Monitor remote peer's status
         */
        RemotePeer peer = udpChannel.getRemotePeer();
        if ( monitorIfPeerIsSendingVoice 
                && peer != null && udpChannel.isPearDead( /*timeout-millis*/ 2500 ) ) 
        {
            monitorIfPeerIsSendingVoice = false;
            
            report( "logWarn", "Warning: Not receiving voice from '" 
                    + peer.getRemoteUserId () + "'; Maybe it's dead?" );
        }

        //////////////////////////////////////////////////////////////////////////////////
        /* Monitor the last issued invite
         */
        if ( inviteTimeout >= 0 ) // invite timeout is active
        {
            if ( --inviteTimeout < 0 ) // invite timeout reached 
            {
                report( "logError", "It seems that kryptofon user '" + currentInvite 
                        + "' is not connected." );
                report( "logInfo", "Use :list to query available users..." );
                logMessage( "<hr/>" );

                inviteTimeout = -1;
                currentInvite = null;
            }
        }
        
        //////////////////////////////////////////////////////////////////////////////////
        /* Monitor current connection.
         */
        final int maxRetryCount = 3;
        final int reconnectDelay = 2;
        
        if ( pbxChannel != null && pbxChannel.isAlive () ) {
            reconnectTimeout = -1; // disables timer
            return;
        }

        if ( reconnectRetryCount >= maxRetryCount ) {

            if ( reconnectRetryCount == maxRetryCount ) {
                
                ++reconnectRetryCount;
                
                logMessage( "<hr/><div class='logDiv'>"
                    + "<span class='logError'>Press ENTER to quit or type<br/><br/>"
                    + "&nbsp;&nbsp; :open [ &lt;hostname&gt; [ &lt;port&gt; ] ]<br/><br/>"
                    + "to open new connection...</span><br/><br/></div>" 
                    );
                setPbxStatus( "Dead" );
                
                /* Reset defaults */
                serverName = "atlas.dsv.su.se";
                serverPort = 9494;
            }
            
            return; // Leave to the user to quit by pressing ENTER
        } 
            
        if ( reconnectTimeout < 0 )  {
            setPbxStatus( "Disconnected" );
            logMessage( "<hr/><div class='logDiv'>Reconnecting in " 
                    + reconnectDelay + " seconds...</div>"
                    );
            reconnectTimeout = reconnectDelay; // start timer
            return;
        }
        
        if ( --reconnectTimeout > 0 ) {
            return;
        }
        
        logMessage( "<div class='logDiv'>Retry #"
               + ( ++reconnectRetryCount ) 
               + " of max " 
               + maxRetryCount
               + ":<br/></div>"
               );

        reconnectTimeout = -1; // disables timer and restarts new connection

        pbxChannel = new PBXClient( serverName, serverPort , this );
        pbxChannel.start ();
    }
void CryptoPhoneApp.onAccept ( final PBXClient.ControlMessage  m )

Handles on ACCEPT call-back from the PBXClient.

Definition at line 983 of file CryptoPhoneApp.java.

References deferredOnAccept().

    {
        java.awt.EventQueue.invokeLater( 
                new Runnable() {
                    public void run() {
                        deferredOnAccept( m );
                    }
                }
            );
    }
void CryptoPhoneApp.onBye ( final PBXClient.ControlMessage  m )

Handles on BYE call-back from the PBXClient.

Definition at line 998 of file CryptoPhoneApp.java.

References deferredOnBye().

    {
        java.awt.EventQueue.invokeLater( 
                new Runnable() {
                    public void run() {
                        deferredOnBye( m );
                    }
                }
            );
    }
void CryptoPhoneApp.onInstantMessage ( final PBXClient.ControlMessage  m )

Handles on IMSG call-back from the PBXClient.

Definition at line 1013 of file CryptoPhoneApp.java.

References deferredOnInstantMessage().

    {
        java.awt.EventQueue.invokeLater( 
                new Runnable() {
                    public void run() {
                        deferredOnInstantMessage( m );
                    }
                }
            );
    }
void CryptoPhoneApp.onInvite ( final PBXClient.ControlMessage  m )

Handles on INVITE call-back from the PBXClient.

Definition at line 953 of file CryptoPhoneApp.java.

References deferredOnInvite().

    {
        java.awt.EventQueue.invokeLater( 
                new Runnable() {
                    public void run() {
                        deferredOnInvite( m );
                    }
                }
            );
    }
void CryptoPhoneApp.onRing ( final PBXClient.ControlMessage  m )

Handles on RING call-back from the PBXClient.

Definition at line 968 of file CryptoPhoneApp.java.

References deferredOnRing().

    {
        java.awt.EventQueue.invokeLater( 
                new Runnable() {
                    public void run() {
                        deferredOnRing( m );
                    }
                }
            );
    }
void CryptoPhoneApp.parseInputMessage (  ) [private]

Parses input message from inputMsg and sends it to chat server.

If it is a command (the first word is prefixed with ':' character) it spawns executeCommand() for further parsing.

Definition at line 1054 of file CryptoPhoneApp.java.

References defaultInputMsg, executeCommand(), formWindowClosing(), getUserId(), inputMsg, pbxChannel, pbx.PBXClient.send(), sendInstantMessage(), and tokenizeInputMessage().

Referenced by keyPressed(), and sendButton_Clicked().

    {
        /* Split string into words, removing all leading, trailing 
         * and superfluous white-spaces between words
         */
        String[] words = tokenizeInputMessage ();
        
        String cmd = words.length >= 1 ? words[0].toLowerCase () : "";

        /* If it is a command, parse it separately
         */
        if ( cmd.startsWith( ":" ) ) 
        {
            int argCount = words.length - 1;
            int argOffset = 1;
            
            /* If ":" is alone (i.e. separated by whitespace from the next word), 
             * then join it with the next word.
             */
            if ( cmd.equals( ":" ) && words.length >= 2 ) {
                cmd = cmd + words[1];
                argCount = words.length - 2;
                argOffset = 2;
            }

            /* Prepare command arguments... */
            String[] args = new String[ argCount ];
            System.arraycopy( words, argOffset, args, 0, argCount );
            
            /* ... then execute command */
            if ( executeCommand( cmd, args ) ) {
                inputMsg.setText( "" );
            }
            return;
        }

        if ( pbxChannel == null || ! pbxChannel.isAlive () ) // confirms dead-server question
        {
            formWindowClosing( null );
            System.exit( 0 );
        }

        /* Default task: send message to chat server
         */
        String inputInstantMessage = inputMsg.getText ();

        if ( defaultInputMsg.equalsIgnoreCase( inputInstantMessage ) ) 
        { 
            /* ignore default input message */
            return;
        }
        else if ( getUserId().isEmpty () ) // no user id
        {
            pbxChannel.send( inputInstantMessage );
            inputMsg.setText( "" );
            return;
        }

        sendInstantMessage( inputInstantMessage, /*forceUnencrypted*/ false );

        inputMsg.setText( "" );
    }
void CryptoPhoneApp.report ( String  cssClass,
String  str 
)

Reports a system message to log.

Definition at line 922 of file CryptoPhoneApp.java.

References logMessage().

Referenced by acceptIncomingCall(), attention(), deferredOnAccept(), deferredOnBye(), deferredOnInvite(), deferredOnRing(), dumpLogArea(), executeCommand(), mainTimerEvent(), and tryToVerifyInvitingCall().

    {
        logMessage(
            "<div class='logDiv'>" + Log.nowMillis () 
                     + "&nbsp;&nbsp;<span class='" + cssClass + "'>"
                     + Log.EscapeHTML( str )
                     + "</span></div>"
            );
    }
void CryptoPhoneApp.reportIncomingTextMessage ( String  cssClass,
String  userId,
String  message 
)

Reports incoming message.

Definition at line 936 of file CryptoPhoneApp.java.

References logMessage().

Referenced by deferredOnInstantMessage(), and sendInstantMessage().

    {
        logMessage(
                "<div class='logDiv'>" + Log.nowMillis () 
                         + "&nbsp;&nbsp;" 
                         + Log.EscapeHTML( userId ).trim () 
                         + ": <span class='" + cssClass + "'>"
                         + Log.EscapeHTML( message ).trim ()
                         + "</span></div>"
                );
    }
void CryptoPhoneApp.secureDialButton_Clicked (  ) [private]

Performs :invite+ command.

Definition at line 624 of file CryptoPhoneApp.java.

References acceptIncomingCall(), executeCommand(), lastMessageFromPBX, and tokenizeInputMessage().

Referenced by actionPerformed().

    {
        /* If there is outstanding INVITE waiting to be accepted,
         * do accept incoming call instead of making new outgoing call.
         */
        if ( this.lastMessageFromPBX == null ) {
            executeCommand( ":invite+", tokenizeInputMessage () );
        } else {
            acceptIncomingCall( /*secured*/ true );
        }
    }
void CryptoPhoneApp.sendButton_Clicked (  ) [private]

Parses input text entered by the user in inputMsg.

Definition at line 589 of file CryptoPhoneApp.java.

References defaultInputMsg, inputMsg, and parseInputMessage().

Referenced by actionPerformed().

    {
        if ( defaultInputMsg.equalsIgnoreCase( inputMsg.getText () ) ) { 
            return; // ignore default input message
        }

        parseInputMessage ();
    }
void CryptoPhoneApp.sendInstantMessage ( String  message,
boolean  forceUnencrypted 
) [private]

Sends chat message (encrypted if we have established secure channel with the user).

Definition at line 1121 of file CryptoPhoneApp.java.

References crypto.SymmetricCipher.encrypt(), protocol.DatagramChannel.getRemotePeer(), protocol.RemotePeer.getRemoteUserId(), protocol.DatagramChannel.getUsedSymmetricCipher(), getUserId(), inputMsg, pbxChannel, reportIncomingTextMessage(), pbx.PBXClient.send(), pbx.PBXClient.sendInstantMessage(), and udpChannel.

Referenced by executeCommand(), and parseInputMessage().

    {
        /* Get symmetric ciphering engine for PDUs and messages, if any.
         */
        RemotePeer remotePeer = udpChannel.getRemotePeer ();
        SymmetricCipher cipher = udpChannel.getUsedSymmetricCipher ();
        if ( forceUnencrypted || remotePeer == null || cipher == null ) 
        {
            /* Send un-encrypted message if there is no common ciphering engine 
             */
            pbxChannel.send( message, getUserId () );
            inputMsg.setText( "" );
            return;
        }

        /* Send encrypted message to peer and echo the highlighted message back to our 
         * user. Wwe must echo the message because our PBXClient will not catch chat 
         * servers broadcast with the encrypted message, as the instant message will 
         * be explicitly directed to the remote peer. 
         */
        String secret = cipher.encrypt( message );
        if ( secret != null )
        {
            pbxChannel.sendInstantMessage( remotePeer.getRemoteUserId(), secret );
            
            reportIncomingTextMessage( "secureMessage", 
                    getUserId() + " [encrypted]", message ); 
        }
    }
void CryptoPhoneApp.setPbxStatus ( String  str )

Updates status message by updating window title.

Definition at line 901 of file CryptoPhoneApp.java.

References appTitle, and pbxChannelStatus.

Referenced by mainTimerEvent().

    {
        final String strCopy = new String( str );
        
        java.awt.EventQueue.invokeLater( 
                new Runnable() {
                    public void run() {
                        synchronized( pbxChannelStatus )
                        {
                            pbxChannelStatus = appTitle + "; " + strCopy;
                            setTitle( pbxChannelStatus );
                        }
                    }
                }
            );
    }
void CryptoPhoneApp.startKryptofonServices (  )

Starts audio interface and UDP peer-to-peer channel.

Definition at line 532 of file CryptoPhoneApp.java.

References audioInterface, protocol.DatagramChannel.getLocalPort(), getUserId(), localUdpPort, udpChannel, and userId.

Referenced by CryptoPhoneApp().

    {
        audioInterface = new audio.AudioInterfacePCM ();
        udpChannel = new DatagramChannel( localUdpPort );
        
        /* Now, check if UDP channel is bound to the the local port that we requested.
         * If not, it means that we have multiple instance of the CryptoPhoneApp 
         * running possibly with the same user ID. To fix this, we're going to 
         * adjust our user ID with the suffix containing distance from the originally
         * requested UDP port, e.g. if we've requested port 47000 and now bound to 47001,
         * then we will adjust original 'username' to be 'username-2'.
         * This helps testing when starting multiple instances of the CryptoPhoneApp
         * on the same single-user machine (like Windows or Mac). 
         */
        int udpDifference = udpChannel.getLocalPort () - localUdpPort;
        if ( udpDifference > 0 ) {
            userId.setText( getUserId() + "-" + ( udpDifference + 1 ) );
            Point winPos = getLocation ();
            winPos.x += 40 * udpDifference; winPos.y += 40 * udpDifference;
            setLocation( winPos );
        }
    }
void CryptoPhoneApp.stopKryptofonServices (  )

Stops audio interface and UDP peer-to-peer channel.

Definition at line 558 of file CryptoPhoneApp.java.

References audioInterface, audio.AudioInterface.cleanUp(), executeCommand(), protocol.DatagramChannel.stop(), audio.AudioInterface.stopPlay(), audio.AudioInterface.stopRecording(), and udpChannel.

Referenced by executeCommand(), and formWindowClosing().

    {
        /* Clear existing call, if any
         */
        executeCommand( ":bye", null );

        /* Stop listening UDP
         */
        if ( udpChannel != null ) {
            udpChannel.stop ();
        }

        /* Stop audio services
         */
        if ( audioInterface != null ) {
            audioInterface.stopPlay ();
            audioInterface.stopRecording ();
            audioInterface.cleanUp ();
        }

        /* Done
         */
        udpChannel = null;
        audioInterface = null;
    }
String [] CryptoPhoneApp.tokenizeInputMessage (  ) [private]

Tokenizes inputMsg into words and returns array of strings.

Definition at line 1029 of file CryptoPhoneApp.java.

References defaultInputMsg, and inputMsg.

Referenced by dialButton_Clicked(), hangupButton_Clicked(), parseInputMessage(), and secureDialButton_Clicked().

    {
        String message = inputMsg.getText();
        
        if ( defaultInputMsg.equalsIgnoreCase( message ) ) { 
            return new String[0]; // ignore default input message
        }

        /* Split string into words, removing all leading, trailing 
         * and superfluous white-spaces between words
         */
        String[] words = message.trim().split( "\\s{1,}" );
        
        if ( words.length >= 1 && words[0].isEmpty () ) {
            return new String[0]; // if contains empty words, then it is really empty
        }

        return words;
    }
PublicEncryptor CryptoPhoneApp.tryToVerifyInvitingCall ( boolean  silent ) [private]

Verifies invitor's public key (signed by invitor's private key) against the public keys from authorized keys file.

Definition at line 1775 of file CryptoPhoneApp.java.

References crypto.PublicEncryptor.getVerificatorName(), protocol.DatagramChannel.hasRemotePeer(), crypto.PublicEncryptor.isActive(), crypto.PublicEncryptor.isVerified(), lastMessageFromPBX, report(), securityState, ui.JSecState.setState(), and udpChannel.

Referenced by acceptIncomingCall(), and deferredOnInvite().

    {
        if ( this.lastMessageFromPBX == null ) { // There is no INVITE to accept
            return null;
        }
        
        PBXClient.ControlMessage m = this.lastMessageFromPBX;
        String remoteId = m.getVerboseRemote ();

        /* Can accept only if there is no call in progress.
         */
        if ( udpChannel.hasRemotePeer () ) {
            return null;
        }
        
        /* Deserialize remote public key.
         * Deserialization also verifies the public key against authorized keys.
         * \see constructor of the PublicEncryptor
         */
        PublicEncryptor pubKey = null;
        
        if ( m.secret != null ) 
        {
            pubKey = new PublicEncryptor( m.secret, m.peerUserId );
            if ( ! pubKey.isActive () ) {
                pubKey = null;
            }
        }

        if ( silent ) {
            return pubKey;
        }
        
        /* If not silent, be loud...
         */
        if ( pubKey != null && pubKey.isActive () )
        {
            if ( ! pubKey.isVerified () ) 
            {
                securityState.setState( JSecState.State.UNVERIFIED );
                report( "logError", "Invite from " + remoteId
                        + " could not be authenticated." );
            }
            else 
            {
                securityState.setState( JSecState.State.VERIFIED );
                report( "logOk", "Invite from " + remoteId
                        + " authenticated with public key '" 
                        + pubKey.getVerificatorName () + "'" );
            }
        }
        else
        {
            securityState.setState( JSecState.State.UNSECURED );
            report( "logError", "The call will be without encryption." );
        }

        return pubKey;
    }

Member Data Documentation

final String CryptoPhoneApp.appTitle = "IP1-10: Kryptofon" [static, private]

The common application title prefix.

Definition at line 77 of file CryptoPhoneApp.java.

Referenced by acceptIncomingCall(), CryptoPhoneApp(), deferredOnAccept(), deferredOnInvite(), and setPbxStatus().

The instance of the Audio interface used to access microphone and speaker.

Definition at line 141 of file CryptoPhoneApp.java.

Referenced by acceptIncomingCall(), deferredOnAccept(), deferredOnBye(), deferredOnInvite(), deferredOnRing(), executeCommand(), startKryptofonServices(), and stopKryptofonServices().

JCheckBox CryptoPhoneApp.autoAnswer [private]

Definition at line 188 of file CryptoPhoneApp.java.

Referenced by createEventListeners(), CryptoPhoneApp(), and deferredOnInvite().

String CryptoPhoneApp.currentInvite = null [private]

The remote peer (its user id) that we are currently inviting to a call.

Null if we are not inviting anyone.

Definition at line 157 of file CryptoPhoneApp.java.

Referenced by deferredOnAccept(), deferredOnBye(), deferredOnRing(), executeCommand(), and mainTimerEvent().

final String CryptoPhoneApp.defaultInputMsg = "<type in message, command or command arguments here>" [static, private]

The initial message content of the input text message field.

Definition at line 82 of file CryptoPhoneApp.java.

Referenced by CryptoPhoneApp(), keyPressed(), parseInputMessage(), sendButton_Clicked(), and tokenizeInputMessage().

final String CryptoPhoneApp.defaultLogAreaDumpFilename = "mykf-log-area-" [static, private]

The default file name where to dump log area contents with :dump command.

Definition at line 89 of file CryptoPhoneApp.java.

Referenced by dumpLogArea().

JLabel CryptoPhoneApp.idLabel [private]

Definition at line 186 of file CryptoPhoneApp.java.

Referenced by createLayout(), and CryptoPhoneApp().

JLabel CryptoPhoneApp.imsgLabel [private]

Definition at line 184 of file CryptoPhoneApp.java.

Referenced by createLayout(), and CryptoPhoneApp().

JTextField CryptoPhoneApp.inputMsg [private]
int CryptoPhoneApp.inviteTimeout = -1 [private]

Timer used to detect unresolved invite (i.e.

invite to non-existing peer). Value -1 means 'disabled'.

Definition at line 163 of file CryptoPhoneApp.java.

Referenced by deferredOnAccept(), deferredOnBye(), deferredOnRing(), executeCommand(), and mainTimerEvent().

PBXClient.ControlMessage CryptoPhoneApp.lastMessageFromPBX = null [private]

The last PBX control message sent to us (waiting to be handled)

Definition at line 146 of file CryptoPhoneApp.java.

Referenced by acceptIncomingCall(), deferredOnAccept(), deferredOnBye(), deferredOnInvite(), dialButton_Clicked(), executeCommand(), secureDialButton_Clicked(), and tryToVerifyInvitingCall().

int CryptoPhoneApp.localUdpPort = 47000 [private]

The default local UDP port.

Definition at line 130 of file CryptoPhoneApp.java.

Referenced by startKryptofonServices().

JEditorPane CryptoPhoneApp.logArea [private]

The log area formatted in HTML.

Definition at line 174 of file CryptoPhoneApp.java.

Referenced by clearLogArea(), createEventListeners(), createLayout(), CryptoPhoneApp(), dumpLogArea(), and logMessage().

Timer CryptoPhoneApp.mainTimer = null [private]

Main timer (elapses every 1000 ms)

Definition at line 114 of file CryptoPhoneApp.java.

Referenced by actionPerformed(), and CryptoPhoneApp().

boolean CryptoPhoneApp.monitorIfPeerIsSendingVoice = false [private]

Indicates whether to monitor if peer is sending voice PDUs to us.

Should be set to 'true' always when set call established.

Definition at line 169 of file CryptoPhoneApp.java.

Referenced by acceptIncomingCall(), deferredOnAccept(), and mainTimerEvent().

The instance of PBX client connected to remote chat server.

Definition at line 104 of file CryptoPhoneApp.java.

Referenced by acceptIncomingCall(), CryptoPhoneApp(), deferredOnInvite(), executeCommand(), formWindowClosing(), mainTimerEvent(), parseInputMessage(), and sendInstantMessage().

String CryptoPhoneApp.pbxChannelStatus = "" [private]

The last status message of the PBX channel (posted by the setPbxStatus()).

Definition at line 109 of file CryptoPhoneApp.java.

Referenced by deferredOnBye(), executeCommand(), and setPbxStatus().

Retry counter of number of failed reconnecting attempts.

Definition at line 125 of file CryptoPhoneApp.java.

Referenced by executeCommand(), and mainTimerEvent().

int CryptoPhoneApp.reconnectTimeout = -1 [private]

The reconnect delay timer (for timing delay between two reconnections).

Value -1 means 'disabled'.

Definition at line 120 of file CryptoPhoneApp.java.

Referenced by mainTimerEvent().

The last public key received from remote peer.

Definition at line 151 of file CryptoPhoneApp.java.

Referenced by acceptIncomingCall(), deferredOnBye(), deferredOnRing(), and executeCommand().

final long CryptoPhoneApp.serialVersionUID = -1830703904673318918L [static, private]

Implements java.io.Serializable interface.

Definition at line 72 of file CryptoPhoneApp.java.

String CryptoPhoneApp.serverName = "atlas.dsv.su.se" [private]

The host name or IP address of the remote chat server.

Definition at line 94 of file CryptoPhoneApp.java.

Referenced by CryptoPhoneApp(), executeCommand(), and mainTimerEvent().

int CryptoPhoneApp.serverPort = 9494 [private]

The TCP port where to connect to on remote chat server.

Definition at line 99 of file CryptoPhoneApp.java.

Referenced by CryptoPhoneApp(), executeCommand(), and mainTimerEvent().

The instance of the UDP transceiver responsible for peer-to-peer communication between two Kryptofons.

Definition at line 136 of file CryptoPhoneApp.java.

Referenced by acceptIncomingCall(), deferredOnAccept(), deferredOnBye(), deferredOnInstantMessage(), deferredOnInvite(), deferredOnRing(), executeCommand(), mainTimerEvent(), sendInstantMessage(), startKryptofonServices(), stopKryptofonServices(), and tryToVerifyInvitingCall().

JTextField CryptoPhoneApp.userId [private]

The documentation for this class was generated from the following file: