public boolean isMessagePartOfTransaction(SIPMessage messageToTest) {
// List of Via headers in the message to test
ViaList viaHeaders;
// Topmost Via header in the list
Via topViaHeader;
// Branch code in the topmost Via header
String messageBranch;
// Flags whether the select message is part of this transaction
boolean transactionMatches;
transactionMatches = false;
String method = messageToTest.getCSeq().getMethod();
// Invite Server transactions linger in the terminated state in the
// transaction
// table and are matched to compensate for
// http://bugs.sipit.net/show_bug.cgi?id=769
if ((method.equals(Request.INVITE) || !isTerminated())) {
// Get the topmost Via header and its branch parameter
viaHeaders = messageToTest.getViaHeaders();
if (viaHeaders != null) {
topViaHeader = (Via) viaHeaders.getFirst();
messageBranch = topViaHeader.getBranch();
if (messageBranch != null) {
// If the branch parameter exists but
// does not start with the magic cookie,
if (!messageBranch.toLowerCase().startsWith(
SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE)) {
// Flags this as old
// (RFC2543-compatible) client
// version
messageBranch = null;
}
}
// If a new branch parameter exists,
if (messageBranch != null && this.getBranch() != null) {
if (method.equals(Request.CANCEL)) {
// Cancel is handled as a special case because it
// shares the same same branch id of the invite
// that it is trying to cancel.
transactionMatches = this.getMethod().equals(Request.CANCEL)
&& getBranch().equalsIgnoreCase(messageBranch)
&& topViaHeader.getSentBy().equals(
((Via) getOriginalRequest().getViaHeaders().getFirst())
.getSentBy());
} else {
// Matching server side transaction with only the
// branch parameter.
transactionMatches = getBranch().equalsIgnoreCase(messageBranch)
&& topViaHeader.getSentBy().equals(
((Via) getOriginalRequest().getViaHeaders().getFirst())
.getSentBy());
}
} else {
// This is an RFC2543-compliant message; this code is here
// for backwards compatibility.
// It is a weak check.
// If RequestURI, To tag, From tag, CallID, CSeq number, and
// top Via headers are the same, the
// SIPMessage matches this transaction. An exception is for
// a CANCEL request, which is not deemed
// to be part of an otherwise-matching INVITE transaction.
String originalFromTag = super.fromTag;
String thisFromTag = messageToTest.getFrom().getTag();
boolean skipFrom = (originalFromTag == null || thisFromTag == null);
String originalToTag = super.toTag;
String thisToTag = messageToTest.getTo().getTag();
boolean skipTo = (originalToTag == null || thisToTag == null);
boolean isResponse = (messageToTest instanceof SIPResponse);
// Issue #96: special case handling for a CANCEL request -
// the CSeq method of the original request must
// be CANCEL for it to have a chance at matching.
if (messageToTest.getCSeq().getMethod().equalsIgnoreCase(Request.CANCEL)
&& !getOriginalRequest().getCSeq().getMethod().equalsIgnoreCase(
Request.CANCEL)) {
transactionMatches = false;
} else if ((isResponse || getOriginalRequest().getRequestURI().equals(
((SIPRequest) messageToTest).getRequestURI()))
&& (skipFrom || originalFromTag != null && originalFromTag.equalsIgnoreCase(thisFromTag))
&& (skipTo || originalToTag != null && originalToTag.equalsIgnoreCase(thisToTag))
&& getOriginalRequest().getCallId().getCallId().equalsIgnoreCase(
messageToTest.getCallId().getCallId())
&& getOriginalRequest().getCSeq().getSeqNumber() == messageToTest
.getCSeq().getSeqNumber()
&& ((!messageToTest.getCSeq().getMethod().equals(Request.CANCEL)) || getOriginalRequest()
.getMethod().equals(messageToTest.getCSeq().getMethod()))
&& topViaHeader.equals(getOriginalRequest().getViaHeaders()
.getFirst())) {
transactionMatches = true;
}