/**
  * Inherited from TransactionClientListener. When an TransactionClientListener goes into the
  * "Terminated" state, receiving a 2xx response
  *
  * <p>If called for a INVITE transaction, it updates the dialog information, moves to D_CALL
  * state, add a listener to the SipProvider, creates a new AckTransactionClient(ack,this), and
  * fires <i>onSuccessResponse(this,code,body,msg)</i>.
  *
  * <p>If called for a BYE transaction, it moves to D_CLOSE state, removes the listener from
  * SipProvider, and fires <i>onClose(this,msg)</i>.
  */
 public void onTransSuccessResponse(TransactionClient tc, Message msg) {
   printLog("inside onTransSuccessResponse(tc,msg)", LogLevel.LOW);
   if (tc.getTransactionMethod().equals(SipMethods.INVITE)) {
     if (!verifyStatus(statusIs(D_INVITING) || statusIs(D_ReINVITING))) return;
     StatusLine statusline = msg.getStatusLine();
     int code = statusline.getCode();
     if (!verifyThat(
         code >= 200 && code < 300 && msg.getTransactionMethod().equals(SipMethods.INVITE),
         "2xx for invite was expected")) return;
     boolean re_inviting = statusIs(D_ReINVITING);
     changeStatus(D_CALL);
     update(Dialog.UAC, msg);
     if (invite_offer) { // invite_req=MessageFactory.createRequest(SipMethods.ACK,dialog_state,sdp.toString());
       // ack=MessageFactory.createRequest(this,SipMethods.ACK,null);
       ack_req = MessageFactory.create2xxAckRequest(this, null);
       AckTransactionClient ack_tc = new AckTransactionClient(sip_provider, ack_req, null);
       ack_tc.request();
     }
     if (!re_inviting) {
       listener.onDlgInviteSuccessResponse(this, code, statusline.getReason(), msg.getBody(), msg);
       listener.onDlgCall(this);
     } else
       listener.onDlgReInviteSuccessResponse(
           this, code, statusline.getReason(), msg.getBody(), msg);
   } else if (tc.getTransactionMethod().equals(SipMethods.BYE)) {
     if (!verifyStatus(statusIs(D_BYEING))) return;
     StatusLine statusline = msg.getStatusLine();
     int code = statusline.getCode();
     verifyThat(code >= 200 && code < 300, "2xx for bye was expected");
     changeStatus(D_CLOSE);
     listener.onDlgByeSuccessResponse(this, code, statusline.getReason(), msg);
     listener.onDlgClose(this);
   }
 }
 /** Sends the ack when offer/answer is in 2xx/ack */
 public void ackWithAnswer(Message ack) {
   ack_req = ack;
   // reset the offer/answer flag to the default value
   invite_offer = true;
   AckTransactionClient ack_tc = new AckTransactionClient(sip_provider, ack, null);
   ack_tc.request();
 }
 /**
  * Inherited from class SipProviderListener. Called when a new message is received (out of any
  * ongoing transaction) for the current InviteDialog. Always checks for out-of-date methods (CSeq
  * header sequence number).
  *
  * <p>If the message is ACK(2xx/INVITE) request, it moves to D_CALL state, and fires
  * <i>onDlgAck(this,body,msg)</i>.
  *
  * <p>If the message is 2xx(INVITE) response, it create a new AckTransactionClient
  *
  * <p>If the message is BYE, it moves to D_BYED state, removes the listener from SipProvider,
  * fires onDlgBye(this,msg) then it responds with 200 OK, moves to D_CLOSE state and fires
  * onDlgClose(this)
  */
 public void onReceivedMessage(SipProvider sip_provider, Message msg) {
   printLog("inside onReceivedMessage(sip_provider,message)", LogLevel.MEDIUM);
   if (msg.isRequest()
       && !(msg.isAck() || msg.isCancel())
       && msg.getCSeqHeader().getSequenceNumber() <= getRemoteCSeq()) {
     printLog("Request message is too late (CSeq too small): Message discarded", LogLevel.HIGH);
     return;
   }
   // invite received
   if (msg.isRequest() && msg.isInvite()) {
     verifyStatus(statusIs(D_INIT) || statusIs(D_CALL));
     // NOTE: if the invite_ts.listen() is used, you should not arrive
     // here with the D_INIT state..
     // however state D_INIT has been included for robustness against
     // further changes.
     if (statusIs(D_INIT)) changeStatus(D_INVITED);
     else changeStatus(D_ReINVITED);
     invite_req = msg;
     invite_ts = new InviteTransactionServer(sip_provider, invite_req, this);
     // ((TransactionServer)transaction).listen();
     update(Dialog.UAS, invite_req);
     if (statusIs(D_INVITED))
       listener.onDlgInvite(
           this,
           invite_req.getToHeader().getNameAddress(),
           invite_req.getFromHeader().getNameAddress(),
           invite_req.getBody(),
           invite_req);
     else listener.onDlgReInvite(this, invite_req.getBody(), invite_req);
   } else
   // ack (of 2xx of INVITE)
   if (msg.isRequest() && msg.isAck()) {
     if (!verifyStatus(statusIs(D_ACCEPTED) || statusIs(D_ReACCEPTED))) return;
     changeStatus(D_CALL);
     // terminates the AckTransactionServer
     ack_ts.terminate();
     listener.onDlgAck(this, msg.getBody(), msg);
     listener.onDlgCall(this);
   } else
   // keep sending ACK (if already sent) for any "200 OK" received
   if (msg.isResponse()) {
     if (!verifyStatus(statusIs(D_CALL))) return;
     int code = msg.getStatusLine().getCode();
     verifyThat(code >= 200 && code < 300, "code 2xx was expected");
     if (ack_req != null) {
       AckTransactionClient ack_tc = new AckTransactionClient(sip_provider, ack_req, null);
       ack_tc.request();
     }
   } else
   // bye received
   if (msg.isRequest() && msg.isBye()) {
     if (!verifyStatus(statusIs(D_CALL) || statusIs(D_BYEING))) return;
     changeStatus(D_BYED);
     bye_ts = new TransactionServer(sip_provider, msg, this);
     // automatically sends a 200 OK
     Message resp = MessageFactory.createResponse(msg, 200, SipResponses.reasonOf(200), null);
     respond(resp);
     listener.onDlgBye(this, msg);
     changeStatus(D_CLOSE);
     listener.onDlgClose(this);
   } else
   // cancel received
   if (msg.isRequest() && msg.isCancel()) {
     if (!verifyStatus(statusIs(D_INVITED) || statusIs(D_ReINVITED))) return;
     // create a CANCEL TransactionServer and send a 200 OK (CANCEL)
     TransactionServer ts = new TransactionServer(sip_provider, msg, null);
     // ts.listen();
     ts.respondWith(MessageFactory.createResponse(msg, 200, SipResponses.reasonOf(200), null));
     // automatically sends a 487 Cancelled
     Message resp =
         MessageFactory.createResponse(invite_req, 487, SipResponses.reasonOf(487), null);
     respond(resp);
     listener.onDlgCancel(this, msg);
   } else
   // any other request received
   if (msg.isRequest()) {
     TransactionServer ts = new TransactionServer(sip_provider, msg, null);
     // ts.listen();
     ts.respondWith(MessageFactory.createResponse(msg, 405, SipResponses.reasonOf(405), null));
   }
 }