diff --git a/src/net/java/sip/communicator/impl/protocol/sip/CallSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/CallSipImpl.java
index 268697f6c..7444519d0 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/CallSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/CallSipImpl.java
@@ -12,7 +12,7 @@
import javax.sip.*;
import javax.sip.address.*;
-import javax.sip.address.URI;
+import javax.sip.address.URI;//disambiguates java.net.URI
import javax.sip.header.*;
import javax.sip.message.*;
@@ -450,6 +450,60 @@ private CallPeerSipImpl createCallPeerFor(
return callPeer;
}
+
+ /**
+ * Processes an incoming INVITE that is meant to replace an existing
+ * CallPeerSipImpl that is participating in this call. Typically
+ * this would happen as a result of an attended transfer.
+ *
+ * @param jainSipProvider the JAIN-SIP SipProvider that received
+ * the request.
+ * @param serverTransaction the transaction containing the INVITE request.
+ * @param callPeerToReplace a reference to the CallPeer that this
+ * INVITE is trying to replace.
+ */
+ public void processReplacingInvite(SipProvider jainSipProvider,
+ ServerTransaction serverTransaction,
+ CallPeerSipImpl callPeerToReplace)
+ {
+ Request request = serverTransaction.getRequest();
+ CallPeerSipImpl newCallPeer
+ = createCallPeerFor(serverTransaction, jainSipProvider);
+ try
+ {
+ answerCallPeer(newCallPeer);
+ }
+ catch (OperationFailedException ex)
+ {
+ logger.error(
+ "Failed to auto-answer the referred call peer "
+ + newCallPeer, ex);
+ /*
+ * RFC 3891 says an appropriate error response MUST be returned
+ * and callPeerToReplace must be left unchanged.
+ */
+ //TODO should we send a response here?
+ return;
+ }
+
+
+
+ //we just accepted the new peer and if we got here then it went well
+ //now let's hangup the other call.
+ try
+ {
+ hangupCallPeer(callPeerToReplace);
+ }
+ catch (OperationFailedException ex)
+ {
+ logger.error("Failed to hangup the referer "
+ + callPeerToReplace, ex);
+ callPeerToReplace.setState(
+ CallPeerState.FAILED, "Internal Error: " + ex);
+ }
+
+ }
+
/**
* Creates a new call and sends a RINGING response.
*
@@ -460,62 +514,87 @@ private CallPeerSipImpl createCallPeerFor(
public CallPeerSipImpl processInvite(SipProvider jainSipProvider,
ServerTransaction serverTransaction)
{
- Request request = serverTransaction.getRequest();
+ Request invite = serverTransaction.getRequest();
CallPeerSipImpl peer
= createCallPeerFor(serverTransaction, jainSipProvider);
- return peer;
- }
-
- public void processReInvite(SipProvider jainSipProvider,
- ServerTransaction serverTransaction)
- {
- Request request = serverTransaction.getRequest();
-
- }
-
- public void processReplacingInvite(SipProvider jainSipProvider,
- ServerTransaction serverTransaction)
- {
- Request request = serverTransaction.getRequest();
+ // extract the SDP description.
+ // beware: SDP description may be in ACKs so it could be that there's
+ // nothing here - bug report Laurent Michel
+ ContentLengthHeader cl = invite.getContentLength();
+ if (cl != null && cl.getContentLength() > 0)
+ {
+ peer.setSdpDescription(new String(invite.getRawContent()));
+ }
- if ((statusCode == Response.OK) && (callPeerToReplace != null))
+ //send a ringing reply
+ Response response = null;
+ try
{
- boolean sayBye = false;
+ response = this.messageFactory.createResponse(Response.RINGING, invite);
- try
- {
- answerCallPeer(callPeer);
- sayBye = true;
- }
- catch (OperationFailedException ex)
- {
- logger.error(
- "Failed to auto-answer the referred call peer "
- + callPeer, ex);
- /*
- * RFC 3891 says an appropriate error response MUST be returned
- * and callPeerToReplace must be left unchanged.
- */
- }
- if (sayBye)
+ //set the contact header
+ response.setHeader(getProtocolProvider()
+ .getContactHeaderForResponse(invite));
+
+ //add the SDP
+ if (statusCode == Response.OK)
{
try
{
- hangupCallPeer(callPeerToReplace);
+ attachSDP(callPeer, response);
}
catch (OperationFailedException ex)
{
- logger.error("Failed to hangup the referer "
- + callPeerToReplace, ex);
- callPeerToReplace.setState(
- CallPeerState.FAILED, "Internal Error: " + ex);
+ logger.error("Error while trying to send response "
+ + response, ex);
+ callPeer.setState(CallPeerState.FAILED,
+ "Internal Error: " + ex.getMessage());
+ return;
}
}
- // Even if there was a failure, we cannot just send Response.OK.
+ }
+ catch (ParseException ex)
+ {
+ logger.error("Error while trying to send a response", ex);
+ callPeer.setState(CallPeerState.FAILED,
+ "Internal Error: " + ex.getMessage());
return;
}
+ try
+ {
+ logger.trace("will send " + statusCode + " response: ");
+ serverTransaction.sendResponse(response);
+ logger.debug("sent a " + statusCode + " response: "
+ + response);
+ }
+ catch (Exception ex)
+ {
+ logger.error("Error while trying to send a request", ex);
+ callPeer.setState(CallPeerState.FAILED,
+ "Internal Error: " + ex.getMessage());
+ return;
+ }
+
+ if (statusCode == Response.OK)
+ {
+ try
+ {
+ setMediaFlagsForPeer(callPeer, response);
+ }
+ catch (OperationFailedException ex)
+ {
+ logger.error("Error after sending response " + response, ex);
+ }
+ }
+ return peer;
+ }
+
+ public void processReInvite(SipProvider jainSipProvider,
+ ServerTransaction serverTransaction)
+ {
+ Request request = serverTransaction.getRequest();
}
}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java
index 3df47e5e9..8b7fb8d8c 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java
@@ -277,11 +277,11 @@ else if (on)
* specified call peer with the sent invite
* @throws OperationFailedException
*/
- void sendInviteRequest(CallPeerSipImpl sipPeer,
- String sdpOffer) throws OperationFailedException
+ void sendInviteRequest(CallPeerSipImpl sipPeer, String sdpOffer)
+ throws OperationFailedException
{
Dialog dialog = sipPeer.getDialog();
- Request invite = createRequest(dialog, Request.INVITE);
+ Request invite = messageFactory.createRequest(dialog, Request.INVITE);
try
{
@@ -311,8 +311,10 @@ void sendInviteRequest(CallPeerSipImpl sipPeer,
* request is to be sent
* @throws OperationFailedException
*/
- private void sendRequest(SipProvider sipProvider, Request request,
- Dialog dialog) throws OperationFailedException
+ private void sendRequest(SipProvider sipProvider,
+ Request request,
+ Dialog dialog)
+ throws OperationFailedException
{
ClientTransaction clientTransaction = null;
try
@@ -1223,6 +1225,7 @@ private void processInvite(SipProvider sourceProvider,
}
else
{
+ //this is a reINVITE.
callSipImpl.processReInvite(sourceProvider, serverTransaction);
}
@@ -1244,7 +1247,7 @@ private void originalProcessInvite(SipProvider sourceProvider,
Dialog dialog = serverTransaction.getDialog();
CallPeerSipImpl callPeer =
activeCallsRepository.findCallPeer(dialog);
- int statusCode;
+ int statusCode = 0;
CallPeerSipImpl callPeerToReplace = null;
if (callPeer == null)
@@ -1288,29 +1291,24 @@ private void originalProcessInvite(SipProvider sourceProvider,
// Send statusCode
//...
Response response = null;
-
try
{
response = protocolProvider.getMessageFactory()
.createResponse(statusCode, invite);
- protocolProvider.attachToTag(response, dialog);
// set our display name
((ToHeader) response.getHeader(ToHeader.NAME)).getAddress()
.setDisplayName(protocolProvider.getOurDisplayName());
- // extract our intended destination which should be in the from
- Address callerAddress =
- ((FromHeader) response.getHeader(FromHeader.NAME))
- .getAddress();
response.setHeader(protocolProvider
- .getContactHeader(callerAddress));
+ .getContactHeaderForResponse(invite));
+ //add the SDP
if (statusCode == Response.OK)
{
try
{
- processInviteSendingResponse(callPeer, response);
+ attachSDP(callPeer, response);
}
catch (OperationFailedException ex)
{
@@ -1331,9 +1329,9 @@ private void originalProcessInvite(SipProvider sourceProvider,
}
try
{
- logger.trace("will send " + statusCodeString + " response: ");
+ logger.trace("will send " + statusCode + " response: ");
serverTransaction.sendResponse(response);
- logger.debug("sent a " + statusCodeString + " response: "
+ logger.debug("sent a " + statusCode + " response: "
+ response);
}
catch (Exception ex)
@@ -1348,7 +1346,7 @@ private void originalProcessInvite(SipProvider sourceProvider,
{
try
{
- processInviteSentResponse(callPeer, response);
+ setMediaFlagsForPeer(callPeer, response);
}
catch (OperationFailedException ex)
{
@@ -1370,8 +1368,8 @@ private void originalProcessInvite(SipProvider sourceProvider,
* @throws OperationFailedException
* @throws ParseException
*/
- private void processInviteSendingResponse(CallPeer peer,
- Response response) throws OperationFailedException, ParseException
+ private void attachSDP(CallPeer peer, Response response)
+ throws OperationFailedException, ParseException
{
/*
* At the time of this writing, we're only getting called because a
@@ -1416,8 +1414,8 @@ private void processInviteSendingResponse(CallPeer peer,
* @throws OperationFailedException
* @throws ParseException
*/
- private void processInviteSentResponse(CallPeer peer,
- Response response) throws OperationFailedException
+ private void setMediaFlagsForPeer(CallPeer peer, Response response)
+ throws OperationFailedException
{
/*
* At the time of this writing, we're only getting called because a
@@ -1665,11 +1663,9 @@ private void processCancel(ServerTransaction serverTransaction,
ServerTransaction inviteTran = (ServerTransaction) tran;
Request invite = callPeer.getFirstTransaction().getRequest();
- Response requestTerminated =
- protocolProvider.getMessageFactory().createResponse(
- Response.REQUEST_TERMINATED, invite);
- protocolProvider.attachToTag(requestTerminated, callPeer
- .getDialog());
+ Response requestTerminated = protocolProvider.getMessageFactory()
+ .createResponse(Response.REQUEST_TERMINATED, invite);
+
inviteTran.sendResponse(requestTerminated);
if (logger.isDebugEnabled())
logger.debug("sent request terminated response:\n"
@@ -1724,10 +1720,8 @@ private void processRefer(ServerTransaction serverTransaction,
Response accepted = null;
try
{
- accepted =
- protocolProvider.getMessageFactory().createResponse(
+ accepted = protocolProvider.getMessageFactory().createResponse(
Response.ACCEPTED, referRequest);
- protocolProvider.attachToTag(accepted, dialog);
}
catch (ParseException ex)
{
@@ -2069,7 +2063,7 @@ private void sendReferNotifyRequest(Dialog dialog,
String subscriptionState, String reasonCode, Object content,
SipProvider sipProvider) throws OperationFailedException
{
- Request notify = createRequest(dialog, Request.NOTIFY);
+ Request notify = messageFactory.createRequest(dialog, Request.NOTIFY);
HeaderFactory headerFactory = protocolProvider.getHeaderFactory();
// Populate the request.
@@ -2088,8 +2082,8 @@ private void sendReferNotifyRequest(Dialog dialog,
SubscriptionStateHeader ssHeader = null;
try
{
- ssHeader =
- headerFactory.createSubscriptionStateHeader(subscriptionState);
+ ssHeader = headerFactory
+ .createSubscriptionStateHeader(subscriptionState);
if (reasonCode != null)
ssHeader.setReasonCode(reasonCode);
}
@@ -2105,8 +2099,8 @@ private void sendReferNotifyRequest(Dialog dialog,
ContentTypeHeader ctHeader = null;
try
{
- ctHeader =
- headerFactory.createContentTypeHeader("message", "sipfrag");
+ ctHeader = headerFactory
+ .createContentTypeHeader("message", "sipfrag");
}
catch (ParseException ex)
{
@@ -2379,8 +2373,7 @@ private void sayBusyHere(CallPeerSipImpl callPeer)
try
{
busyHere = messageFactory.createResponse(
- Response.BUSY_HERE, request);
- protocolProvider.attachToTag(busyHere, callPeer.getDialog());
+ Response.BUSY_HERE, request);
}
catch (ParseException ex)
{
@@ -2571,7 +2564,6 @@ private Response createOKResponse(Request request, Dialog containingDialog)
throws ParseException
{
Response ok = messageFactory.createResponse(Response.OK, request);
- protocolProvider.attachToTag(ok, containingDialog);
return ok;
}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java
index f847d4323..bdd7dcbfe 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java
@@ -1126,12 +1126,14 @@ public ContactHeader getContactHeader(SipURI intendedDestination)
Address contactAddress = addressFactory.createAddress( contactURI );
+ String ourDisplayName = getOurDisplayName();
if (ourDisplayName != null)
{
contactAddress.setDisplayName(ourDisplayName);
}
registrationContactHeader = headerFactory.createContactHeader(
contactAddress);
+
logger.debug("generated contactHeader:"
+ registrationContactHeader);
}
@@ -2000,8 +2002,9 @@ public UserAgentHeader getSipCommUserAgentHeader()
* Generates a ToTag and attaches it to the to header of response.
*
* @param response the response that is to get the ToTag.
- * @param containingDialog the Dialog instance that is to extract a unique
- * Tag value (containingDialog.hashCode())
+ * @param containingDialog the Dialog instance that the response
+ * would be sent in or null if we are not aware of the
+ * Dialog when calling this method.
*/
public void attachToTag(Response response, Dialog containingDialog)
{
@@ -2011,7 +2014,8 @@ public void attachToTag(Response response, Dialog containingDialog)
return;
}
- if(containingDialog.getLocalTag() != null)
+ if( containingDialog != null
+ && containingDialog.getLocalTag() != null)
{
logger.debug("We seem to already have a tag in this dialog. "
+"Returning");
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/SipMessageFactory.java b/src/net/java/sip/communicator/impl/protocol/sip/SipMessageFactory.java
index 64921abc9..d08a4ef85 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/SipMessageFactory.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/SipMessageFactory.java
@@ -6,6 +6,7 @@
*/
package net.java.sip.communicator.impl.protocol.sip;
+import gov.nist.javax.sip.header.*;
import gov.nist.javax.sip.header.extensions.*;
import java.text.*;
@@ -253,6 +254,27 @@ private Message attachScSpecifics(Message message)
SipApplicationData.setApplicationData(message,
SipApplicationData.KEY_SERVICE, this.protocolProvider);
+ //the jain-sip semantics allow the application to "forget" attaching a
+ //To tag to a response so let's make sure we do this here
+ if(message instanceof Response)
+ {
+ FromHeader from = (FromHeader)message.getHeader(From.NAME);
+ String fromTag = (from == null) ? null : from.getTag();
+ Response response = (Response)message;
+
+ //if there's a from tag and this is a non-failure response,
+ //then we are adding a to tag.
+ if(fromTag != null && fromTag.trim().length() > 0
+ && response.getStatusCode() > 100
+ && response.getStatusCode() < 300)
+ {
+ protocolProvider.attachToTag(response, null);
+ }
+ }
+
+ //add a contact header.
+ attachContactHeader(message);
+
// User Agent
UserAgentHeader userAgentHeader
= protocolProvider.getSipCommUserAgentHeader();
@@ -267,7 +289,26 @@ private Message attachScSpecifics(Message message)
return message;
}
- //---------------- higher level methods ----------------------------------
+ /**
+ * The method tries to determine an address that would be reachable by the
+ * destination of message and then creates a ContactHeader
+ * out of it and attaches it to the message. The method takes into
+ * account both Requests and Responses. The method
+ * is meant to be used only for messages that have been otherwise
+ * initialized (in particular the Request URI in requests or the Via
+ * headers in responses.).
+ *
+ * @param message the message that we'd like to attach a
+ * ContactHeader to.
+ *
+ * @return a reference to the message that was also passed as
+ * a parameter in order to allow for more agility when using the method.
+ */
+ private Message attachContactHeader(Message message)
+ {
+ //creates a Contact header
+ }
+
/**
* Creates a new {@link Request} of a specific method which is to be sent in
* a specific Dialog and populates its generally-necessary
@@ -298,8 +339,6 @@ public Request createRequest(Dialog dialog, String method)
OperationFailedException.INTERNAL_ERROR, ex, logger);
}
- attachScSpecifics(request);
-
//override the via and contact headers as jain-sip is generating one
//from the listening point which is 0.0.0.0 or ::0
ArrayList viaHeaders
@@ -309,22 +348,28 @@ public Request createRequest(Dialog dialog, String method)
request.setHeader(protocolProvider
.getContactHeader(dialog.getRemoteParty()));
+ //now that we've set the Via headers right, we can attach our SC
+ //specifics
+ attachScSpecifics(request);
+
// We have a dialog here so let's try and pre-authenticate the request.
preAuthenticateRequest(request);
return request;
}
+ //---------------- higher level methods ----------------------------------
/**
* Creates an invite request destined for callee.
*
* @param toAddress the sip address of the callee that the request is meant
- * for.
+ * for.
+ *
+ * @return a newly created sip Request destined for
+ * callee.
*
- * @return a newly created sip Request destined for callee
- * .
* @throws OperationFailedException with the corresponding code if creating
- * the request fails.
+ * the request fails.
* @throws IllegalArgumentException if toAddress does not appear
* to be a valid destination.
*/
@@ -372,8 +417,7 @@ public Request createInviteRequest( Address toAddress)
try
{
// FromHeader
- fromHeader =
- headerFactory.createFromHeader(
+ fromHeader = headerFactory.createFromHeader(
protocolProvider.getOurSipAddress(toAddress), localTag);
// ToHeader