question: @ Override public synchronized OtrSession openSession ( Send < Bytestring > send ) throws InterruptedException , IOException { if ( send == null ) throw new NullPointerException ( ) ; Chan < Boolean > chan = new BasicChan < > ( 1 ) ; OtrSendAlice alice = new OtrSendAlice ( send , chan ) ; Session < Address , Bytestring > session = peer . openSession ( alice ) ; if ( session == null ) return null ; final SessionID sessionID = new SessionID ( "" , "" , "" ) ; OtrPolicy policy = new OtrPolicyImpl ( OtrPolicy . ALLOW_V2 | OtrPolicy . ALLOW_V3 | OtrPolicy . ERROR_START_AKE ) ; SessionImpl sessionImpl = new SessionImpl ( sessionID , new SendOtrEngineHost ( policy , session ) ) ; alice . sessionImpl = sessionImpl ; String query = "?OTRv23?" ; session . send ( new Bytestring ( query . getBytes ( ) ) ) ; Boolean result = chan . receive ( ) ; if ( result ) { } else { chan . close ( ) ; session . close ( ) ; return null ; } return new OtrSession ( session , sessionImpl ) ; }
target:  The openSession() method starts the OTR protocol.  It creates a BasicChan object that is passed into OtrSendAlice and when the key exchange is complete, this Chan "chan" is notified and an OtrSession object is returned.  We also create a SessionImpl object for handling messages and pass that into both our OtrSendAlice object and the returned OtrSession object.  To start the actual protocol, a specific string needs to be crafted.  In our implementation, we used "?OTRv23?" which means we are initializing OTR version 3, with version 2 as a backup if version 3 is not available.  Other protocol strings are possible.  We then call chan.receive(), and when the key exchange in OtrSendAlice returns, we check to see if the key exchange was successful or not. If it is, we return a new OtrSession object.  Else, we shut everything down. Note: The OtrPolicy variable allows OTRv2 and OTRv3.  This can be changed if the user desires different versions of OTR.