@Test // For github issue #600, At the DB the IncomingPhoneNumber is '+2222' and we dial '2222',
        // Restcomm should find this number even without the '+'
  public synchronized void testDialClientAliceWithoutPlusSign()
      throws InterruptedException, ParseException {
    stubFor(
        get(urlPathEqualTo("/1111"))
            .willReturn(
                aResponse()
                    .withStatus(200)
                    .withHeader("Content-Type", "text/xml")
                    .withBody(dialClientRcml)));

    // Phone2 register as alice
    SipURI uri = aliceSipStack.getAddressFactory().createSipURI(null, "127.0.0.1:5080");
    assertTrue(alicePhone.register(uri, "alice", "1234", aliceContact, 3600, 3600));

    // Prepare second phone to receive call
    SipCall aliceCall = alicePhone.createSipCall();
    aliceCall.listenForIncomingCall();

    // Create outgoing call with first phone
    final SipCall bobCall = bobPhone.createSipCall();
    bobCall.initiateOutgoingCall(
        bobContact, "sip:[email protected]:5080", null, body, "application", "sdp", null, null);
    assertLastOperationSuccess(bobCall);
    assertTrue(bobCall.waitOutgoingCallResponse(5 * 1000));
    final int response = bobCall.getLastReceivedResponse().getStatusCode();
    assertTrue(response == Response.TRYING || response == Response.RINGING);

    if (response == Response.TRYING) {
      assertTrue(bobCall.waitOutgoingCallResponse(5 * 1000));
      assertEquals(Response.RINGING, bobCall.getLastReceivedResponse().getStatusCode());
    }

    assertTrue(bobCall.waitOutgoingCallResponse(5 * 1000));
    assertEquals(Response.OK, bobCall.getLastReceivedResponse().getStatusCode());

    bobCall.sendInviteOkAck();
    assertTrue(!(bobCall.getLastReceivedResponse().getStatusCode() >= 400));

    assertTrue(aliceCall.waitForIncomingCall(30 * 1000));
    assertTrue(aliceCall.sendIncomingCallResponse(Response.RINGING, "Ringing-Alice", 3600));
    String receivedBody = new String(aliceCall.getLastReceivedRequest().getRawContent());
    assertTrue(
        aliceCall.sendIncomingCallResponse(
            Response.OK, "OK-Alice", 3600, receivedBody, "application", "sdp", null, null));
    assertTrue(aliceCall.waitForAck(50 * 1000));

    Thread.sleep(3000);

    // hangup.
    bobCall.disconnect();

    aliceCall.listenForDisconnect();
    assertTrue(aliceCall.waitForDisconnect(30 * 1000));
    assertTrue(aliceCall.respondToDisconnect());
  }
  @Test
  // Non regression test for
  // https://bitbucket.org/telestax/telscale-restcomm/issue/132/implement-twilio-sip-out
  // with Dial Action screening
  public synchronized void testDialSipDialTagScreening180Decline()
      throws InterruptedException, ParseException {
    stubFor(
        get(urlPathEqualTo("/1111"))
            .willReturn(
                aResponse()
                    .withStatus(200)
                    .withHeader("Content-Type", "text/xml")
                    .withBody(dialSipDialScreeningRcml)));

    stubFor(
        get(urlPathEqualTo("/screening"))
            .willReturn(
                aResponse()
                    .withStatus(200)
                    .withHeader("Content-Type", "text/xml")
                    .withBody(screeningRcml)));

    stubFor(
        get(urlPathEqualTo("/action"))
            .willReturn(
                aResponse()
                    .withStatus(200)
                    .withHeader("Content-Type", "text/xml")
                    .withBody(sipDialUrlActionRcml)));

    // Phone2 register as alice
    SipURI uri = aliceSipStack.getAddressFactory().createSipURI(null, "127.0.0.1:5080");
    assertTrue(alicePhone.register(uri, "alice", "1234", aliceContact, 3600, 3600));

    // Prepare second phone to receive call
    SipCall aliceCall = alicePhone.createSipCall();
    aliceCall.listenForIncomingCall();

    // Create outgoing call with first phone
    final SipCall bobCall = bobPhone.createSipCall();
    bobCall.initiateOutgoingCall(
        bobContact, dialRestcomm, null, body, "application", "sdp", null, null);
    assertLastOperationSuccess(bobCall);
    assertTrue(bobCall.waitOutgoingCallResponse(5 * 1000));
    final int response = bobCall.getLastReceivedResponse().getStatusCode();
    assertTrue(response == Response.TRYING || response == Response.RINGING);

    if (response == Response.TRYING) {
      assertTrue(bobCall.waitOutgoingCallResponse(5 * 1000));
      assertEquals(Response.RINGING, bobCall.getLastReceivedResponse().getStatusCode());
    }

    assertTrue(bobCall.waitOutgoingCallResponse(5 * 1000));
    assertEquals(Response.OK, bobCall.getLastReceivedResponse().getStatusCode());

    bobCall.sendInviteOkAck();
    assertTrue(!(bobCall.getLastReceivedResponse().getStatusCode() >= 400));

    bobCall.listenForDisconnect();

    assertTrue(aliceCall.waitForIncomingCall(30 * 1000));
    MessageExt invite = (MessageExt) aliceCall.getLastReceivedRequest().getMessage();
    assertNotNull(invite);
    assertEquals(Request.INVITE, invite.getCSeqHeader().getMethod());
    Header mycustomheader = invite.getHeader("X-mycustomheader");
    Header myotherheader = invite.getHeader("X-myotherheader");
    assertNotNull(mycustomheader);
    assertNotNull(myotherheader);

    String receivedBody = new String(aliceCall.getLastReceivedRequest().getRawContent());

    assertTrue(
        aliceCall.sendIncomingCallResponse(
            Response.RINGING, "Ringing", 3600, receivedBody, "application", "sdp", null, null));

    ArrayList<String> headers = new ArrayList<String>();
    Header customHeader =
        aliceSipStack.getHeaderFactory().createHeader("X-mycustomheader", "customValue");
    Header otherHeader =
        aliceSipStack.getHeaderFactory().createHeader("X-myothereader", "customOtherValue");
    headers.add(customHeader.toString());
    headers.add(otherHeader.toString());
    assertTrue(
        aliceCall.sendIncomingCallResponse(
            Response.DECLINE, "Declined", 3600, receivedBody, "application", "sdp", headers, null));
    assertTrue(aliceCall.waitForAck(50 * 1000));

    assertTrue(bobCall.waitForDisconnect(5000));
    assertTrue(bobCall.respondToDisconnect());
  }
  //    @Ignore
  @Test
  // Non regression test for
  // https://bitbucket.org/telestax/telscale-restcomm/issue/132/implement-twilio-sip-out
  // in auth manner
  public synchronized void testDialSipAuth() throws InterruptedException, ParseException {
    stubFor(
        get(urlPathEqualTo("/1111"))
            .willReturn(
                aResponse()
                    .withStatus(200)
                    .withHeader("Content-Type", "text/xml")
                    .withBody(dialSipAuthRcml)));

    // Phone2 register as alice
    SipURI uri = aliceSipStack.getAddressFactory().createSipURI(null, "127.0.0.1:5080");
    assertTrue(alicePhone.register(uri, "alice", "1234", aliceContact, 3600, 3600));

    // Prepare second phone to receive call
    SipCall aliceCall = alicePhone.createSipCall();
    aliceCall.listenForIncomingCall();

    // Create outgoing call with first phone
    final SipCall bobCall = bobPhone.createSipCall();
    bobCall.initiateOutgoingCall(
        bobContact, dialRestcomm, null, body, "application", "sdp", null, null);
    assertLastOperationSuccess(bobCall);
    assertTrue(bobCall.waitOutgoingCallResponse(5 * 1000));
    final int response = bobCall.getLastReceivedResponse().getStatusCode();
    assertTrue(response == Response.TRYING || response == Response.RINGING);

    if (response == Response.TRYING) {
      assertTrue(bobCall.waitOutgoingCallResponse(5 * 1000));
      assertEquals(Response.RINGING, bobCall.getLastReceivedResponse().getStatusCode());
    }

    assertTrue(bobCall.waitOutgoingCallResponse(5 * 1000));
    assertEquals(Response.OK, bobCall.getLastReceivedResponse().getStatusCode());

    bobCall.sendInviteOkAck();
    assertTrue(!(bobCall.getLastReceivedResponse().getStatusCode() >= 400));

    assertTrue(aliceCall.waitForIncomingCall(30 * 1000));
    MessageExt invite = (MessageExt) aliceCall.getLastReceivedRequest().getMessage();
    assertNotNull(invite);
    assertEquals(Request.INVITE, invite.getCSeqHeader().getMethod());
    Header mycustomheader = invite.getHeader("X-mycustomheader");
    Header myotherheader = invite.getHeader("X-myotherheader");
    assertNotNull(mycustomheader);
    assertNotNull(myotherheader);

    DigestServerAuthenticationMethod dsam = new DigestServerAuthenticationMethod();
    dsam.initialize(); // it should read values from file, now all static

    ProxyAuthenticateHeader proxyAuthenticate =
        aliceSipStack.getHeaderFactory().createProxyAuthenticateHeader(dsam.getScheme());
    proxyAuthenticate.setParameter("realm", dsam.getRealm(null));
    proxyAuthenticate.setParameter("nonce", dsam.generateNonce());
    // proxyAuthenticateImpl.setParameter("domain",authenticationMethod.getDomain());
    proxyAuthenticate.setParameter("opaque", "");

    proxyAuthenticate.setParameter("algorithm", dsam.getAlgorithm());
    ArrayList<Header> headers = new ArrayList<Header>();
    headers.add(proxyAuthenticate);
    assertTrue(
        aliceCall.sendIncomingCallResponse(
            Response.PROXY_AUTHENTICATION_REQUIRED, "Non authorized", 3600, headers, null, null));

    assertTrue(aliceCall.waitForIncomingCall(30 * 1000));
    invite = (MessageExt) aliceCall.getLastReceivedRequest().getMessage();
    assertNotNull(invite.getHeader(ProxyAuthorizationHeader.NAME));

    ProxyAuthorizationHeader proxyAuthorization =
        (ProxyAuthorizationHeader) invite.getHeader(ProxyAuthorizationHeader.NAME);

    boolean res = dsam.doAuthenticate("alice", "1234", proxyAuthorization, (Request) invite);
    assertTrue(res);

    assertTrue(aliceCall.sendIncomingCallResponse(Response.RINGING, "Ringing-Alice", 3600));
    String receivedBody = new String(aliceCall.getLastReceivedRequest().getRawContent());
    assertTrue(
        aliceCall.sendIncomingCallResponse(
            Response.OK, "OK-Alice", 3600, receivedBody, "application", "sdp", null, null));
    assertTrue(aliceCall.waitForAck(50 * 1000));
    aliceCall.listenForDisconnect();

    Thread.sleep(3000);

    // hangup.
    bobCall.disconnect();

    assertTrue(aliceCall.waitForDisconnect(30 * 1000));
  }
  // Non regression test for https://telestax.atlassian.net/browse/RESTCOMM-585
  @Test
  public synchronized void testDialWithCustomHeaders() throws InterruptedException, ParseException {
    // Received request: GET
    // /rcml?CallSid=CA154c8c93d7eb439989a6ea42915b6c1b&AccountSid=ACae6e420f425248d6a26948c17a9e2acf&From=bob&To=%2B17778&
    // CallStatus=ringing&ApiVersion=2012-04-24&Direction=inbound&CallerName&ForwardedFrom&SipHeader_X-MyCustom-Header1=Value1&SipHeader_X-MyCustom-Header2=Value2 HTTP/1.1
    stubFor(
        get(urlPathEqualTo("/1111"))
            .withQueryParam("SipHeader_X-MyCustom-Header1", containing("Value1"))
            .withQueryParam("SipHeader_X-MyCustom-Header2", containing("Value2"))
            .willReturn(
                aResponse()
                    .withStatus(200)
                    .withHeader("Content-Type", "text/xml")
                    .withBody(playRcml)));

    ArrayList<String> additionalHeaders = new ArrayList<String>();
    additionalHeaders.add(
        bobPhone
            .getParent()
            .getHeaderFactory()
            .createHeader("X-MyCustom-Header1", "Value1")
            .toString());
    additionalHeaders.add(
        bobPhone
            .getParent()
            .getHeaderFactory()
            .createHeader("X-MyCustom-Header2", "Value2")
            .toString());

    // Initiate a call using Bob
    final SipCall bobCall = bobPhone.createSipCall();

    bobCall.initiateOutgoingCall(
        bobContact, dialRestcomm, null, body, "application", "sdp", additionalHeaders, null);
    assertLastOperationSuccess(bobCall);

    assertTrue(bobCall.waitOutgoingCallResponse(5 * 1000));

    final int response = bobCall.getLastReceivedResponse().getStatusCode();
    assertTrue(response == Response.TRYING || response == Response.RINGING);
    if (response == Response.TRYING) {
      assertTrue(bobCall.waitOutgoingCallResponse(5 * 1000));
      assertEquals(Response.RINGING, bobCall.getLastReceivedResponse().getStatusCode());
    }

    assertTrue(bobCall.waitOutgoingCallResponse(5 * 1000));
    assertEquals(Response.OK, bobCall.getLastReceivedResponse().getStatusCode());
    bobCall.sendInviteOkAck();
    assertTrue(!(bobCall.getLastReceivedResponse().getStatusCode() >= 400));

    bobCall.listenForDisconnect();

    Thread.sleep(1000);

    assertTrue(bobCall.waitForDisconnect(5 * 1000));
    assertTrue(bobCall.respondToDisconnect());
  }
  // Non regression test for https://github.com/Mobicents/RestComm/issues/612
  @Test
  public synchronized void testRecord_ExecuteRCML_ReturnedFromActionURL()
      throws InterruptedException, ParseException {

    stubFor(
        get(urlPathEqualTo("/1111"))
            .willReturn(
                aResponse()
                    .withStatus(200)
                    .withHeader("Content-Type", "text/xml")
                    .withBody(recordWithActionRcml)));

    stubFor(
        get(urlPathEqualTo("/recordAction"))
            .willReturn(
                aResponse()
                    .withStatus(200)
                    .withHeader("Content-Type", "text/xml")
                    .withBody(actionUrlRcml)));

    // Prepare Fotini phone to receive a call
    final SipCall aliceCall = alicePhone.createSipCall();
    aliceCall.listenForIncomingCall();

    // Initiate a call using Bob
    final SipCall bobCall = bobPhone.createSipCall();

    bobCall.initiateOutgoingCall(
        bobContact, dialRestcomm, null, body, "application", "sdp", null, null);
    assertLastOperationSuccess(bobCall);

    assertTrue(bobCall.waitOutgoingCallResponse(5 * 1000));

    final int response = bobCall.getLastReceivedResponse().getStatusCode();
    assertTrue(response == Response.TRYING || response == Response.RINGING);
    if (response == Response.TRYING) {
      assertTrue(bobCall.waitOutgoingCallResponse(5 * 1000));
      assertEquals(Response.RINGING, bobCall.getLastReceivedResponse().getStatusCode());
    }

    assertTrue(bobCall.waitOutgoingCallResponse(5 * 1000));
    assertEquals(Response.OK, bobCall.getLastReceivedResponse().getStatusCode());
    bobCall.sendInviteOkAck();
    assertTrue(!(bobCall.getLastReceivedResponse().getStatusCode() >= 400));

    // At this point bob leaves a voicemail

    // Now Fotini should receive a call
    assertTrue(aliceCall.waitForIncomingCall(30 * 1000));
    assertTrue(aliceCall.sendIncomingCallResponse(100, "Trying-Fotini", 600));
    assertTrue(aliceCall.sendIncomingCallResponse(180, "Ringing-Fotini", 600));
    String receivedBody = new String(aliceCall.getLastReceivedRequest().getRawContent());
    assertTrue(
        aliceCall.sendIncomingCallResponse(
            Response.OK, "OK-Fotini", 3600, receivedBody, "application", "sdp", null, null));
    assertTrue(aliceCall.waitForAck(5000));
    aliceCall.listenForDisconnect();

    Thread.sleep(2000);

    // hangup.

    assertTrue(bobCall.disconnect());

    assertTrue(aliceCall.waitForDisconnect(50 * 1000));
    assertTrue(aliceCall.respondToDisconnect());
  }
  @Test
  public void testBothSides() throws Exception {
    assertTrue(ua.register("amit", "a1b2c3d4", null, 600, 5000));

    SipPhone ub =
        sipStack2.createSipPhone(PROXY_HOST, PROXY_PROTO, PROXY_PORT, "sip:[email protected]");
    assertTrue(ub.register("becky", "a1b2c3d4", null, 600, 5000));

    SipCall callA = ua.createSipCall();
    SipCall callB = ub.createSipCall();

    callB.listenForIncomingCall();
    Thread.sleep(100);

    callA.initiateOutgoingCall("sip:[email protected]", null); // "127.0.0.1:4000/UDP"
    assertLastOperationSuccess("a initiate call - " + callA.format(), callA);

    callB.waitForIncomingCall(3000);
    assertLastOperationSuccess("b wait incoming call - " + callB.format(), callB);

    callB.sendIncomingCallResponse(Response.RINGING, null, -1);
    assertLastOperationSuccess("b send RINGING - " + callB.format(), callB);

    Thread.sleep(1000);

    callB.sendIncomingCallResponse(Response.OK, "Answer - Hello world", 0);
    assertLastOperationSuccess("b send OK - " + callB.format(), callB);

    callA.waitOutgoingCallResponse(10000);
    assertLastOperationSuccess("a wait 1st response - " + callA.format(), callA);
    assertTrue(
        "Unexpected 1st response received",
        (callA.getReturnCode() == Response.RINGING || callA.getReturnCode() == Response.TRYING));
    if (callA.getLastReceivedResponse().getStatusCode() == Response.RINGING) {
      assertNotNull(
          "Default response reason not sent", callA.getLastReceivedResponse().getReasonPhrase());
      assertEquals(
          "Unexpected default reason",
          "Ringing",
          callA.getLastReceivedResponse().getReasonPhrase());
    }

    callA.waitOutgoingCallResponse(5000);
    assertLastOperationSuccess("a wait 2nd response - " + callA.format(), callA);
    callA.waitOutgoingCallResponse(2000);

    assertEquals(
        "Unexpected final response received",
        Response.OK,
        callA.getLastReceivedResponse().getStatusCode());

    callA.sendInviteOkAck();
    assertLastOperationSuccess("Failure sending ACK - " + callA.format(), callA);

    Thread.sleep(1000);

    callA.listenForDisconnect();
    assertLastOperationSuccess("a listen disc - " + callA.format(), callA);

    callB.disconnect();
    assertLastOperationSuccess("b disc - " + callB.format(), callB);

    callA.waitForDisconnect(5000);
    assertLastOperationSuccess("a wait disc - " + callA.format(), callA);

    callA.respondToDisconnect();
    assertLastOperationSuccess("a respond to disc - " + callA.format(), callA);

    Thread.sleep(1000);
    ub.dispose();
  }