return;
}
}
RequestEvent sipEvent;
if (sipStack.isLoggingEnabled(LogLevels.TRACE_DEBUG)) {
sipStack.getStackLogger().logDebug(
sipRequest.getMethod() + " transaction.isMapped = "
+ transaction.isTransactionMapped());
}
/*
* RFC 3265: Each event package MUST specify whether forked SUBSCRIBE
* requests are allowed to install multiple subscriptions. If such
* behavior is not allowed, the first potential dialog- establishing
* message will create a dialog. All subsequent NOTIFY messages which
* correspond to the SUBSCRIBE message (i.e., match "To", "From", "From"
* header "tag" parameter, "Call-ID", "CSeq", "Event", and "Event"
* header "id" parameter) but which do not match the dialog would be
* rejected with a 481 response. Note that the 200-class response to the
* SUBSCRIBE can arrive after a matching NOTIFY has been received; such
* responses might not correlate to the same dialog established by the
* NOTIFY. Except as required to complete the SUBSCRIBE transaction,
* such non-matching 200-class responses are ignored.
*/
if (dialog == null && sipRequestMethod.equals(Request.NOTIFY)) {
SIPClientTransaction pendingSubscribeClientTx = sipStack
.findSubscribeTransaction(sipRequest, listeningPoint);
if (sipStack.isLoggingEnabled(LogLevels.TRACE_DEBUG)) {
sipStack.getStackLogger().logDebug(
"PROCESSING NOTIFY DIALOG == null "
+ pendingSubscribeClientTx);
}
/*
* RFC 3265: Upon receiving a NOTIFY request, the subscriber should
* check that it matches at least one of its outstanding
* subscriptions; if not, it MUST return a
* "481 Subscription does not exist" response unless another 400- or
* -class response is more appropriate.
*/
if (sipProvider.isAutomaticDialogSupportEnabled()
&& pendingSubscribeClientTx == null
&& !sipStack.isDeliverUnsolicitedNotify()) {
/*
* This is the case of the UAC receiving a Stray NOTIFY for
* which it has not previously sent out a SUBSCRIBE and for
* which it does not have an established dialog.
*/
try {
if (sipStack.isLoggingEnabled(LogLevels.TRACE_DEBUG)) {
sipStack.getStackLogger().logDebug(
"Could not find Subscription for Notify Tx.");
}
Response errorResponse = sipRequest
.createResponse(Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST);
errorResponse
.setReasonPhrase("Subscription does not exist");
sipProvider.sendResponse(errorResponse);
return;
} catch (Exception ex) {
sipStack
.getStackLogger()
.logError(
"Exception while sending error response statelessly",
ex);
return;
}
}
// If the server transaction cannot be found or if it
// aleady has a dialog attached to it then just assign the
// notify to this dialog and pass it up.
if (pendingSubscribeClientTx != null) {
// The response to the pending subscribe tx can try to create
// a dialog at the same time that the notify is trying to
// create a dialog. Thus we cannot process both at the
// same time.
transaction.setPendingSubscribe(pendingSubscribeClientTx);
// The transaction gets assigned to the dialog from the
// outgoing subscribe. First see if anybody claimed the
// default Dialog for the outgoing Subscribe request.
SIPDialog subscriptionDialog = (SIPDialog) pendingSubscribeClientTx
.getDefaultDialog();
// TODO -- refactor this. Can probably be written far cleaner.
if (subscriptionDialog == null
|| subscriptionDialog.getDialogId() == null
|| !subscriptionDialog.getDialogId().equals(dialogId)) {
// Notify came in before you could assign a response to
// the subscribe.
// grab the default dialog and assign it to the tags in
// the notify.
if (subscriptionDialog != null
&& subscriptionDialog.getDialogId() == null) {
subscriptionDialog.setDialogId(dialogId);
} else {
subscriptionDialog = pendingSubscribeClientTx
.getDialog(dialogId);
}
if (sipStack.isLoggingEnabled(LogLevels.TRACE_DEBUG)) {
sipStack.getStackLogger().logDebug(
"PROCESSING NOTIFY Subscribe DIALOG "
+ subscriptionDialog);
}
// The user could have createed a dialog before sending out
// the SUBSCRIBE on the subscribe tx.
if (subscriptionDialog == null
&& (sipProvider.isAutomaticDialogSupportEnabled() || pendingSubscribeClientTx
.getDefaultDialog() != null)) {
Event event = (Event) sipRequest
.getHeader(EventHeader.NAME);
if (sipStack.isEventForked(event.getEventType())) {
subscriptionDialog = SIPDialog.createFromNOTIFY(
pendingSubscribeClientTx, transaction);
}
}
if (subscriptionDialog != null) {
transaction.setDialog(subscriptionDialog, dialogId);
if (subscriptionDialog.getState() != DialogState.CONFIRMED) {
subscriptionDialog
.setPendingRouteUpdateOn202Response(sipRequest);
}
subscriptionDialog.setState(DialogState.CONFIRMED
.getValue());
sipStack.putDialog(subscriptionDialog);
pendingSubscribeClientTx.setDialog(subscriptionDialog,
dialogId);
if (!transaction.isTransactionMapped()) {
this.sipStack.mapTransaction(transaction);
// Let the listener see it if it just got
// created.
// otherwise, we have already processed the tx
// so
// we dont want the listener to see it.
transaction.setPassToListener();
try {
this.sipStack.addTransaction(transaction);
} catch (Exception ex) {
}
}
}
} else {
// The subscription default dialog is our dialog.
// Found a subscrbe dialog for the NOTIFY
// So map the tx.
transaction.setDialog(subscriptionDialog, dialogId);
dialog = subscriptionDialog;
if (!transaction.isTransactionMapped()) {
this.sipStack.mapTransaction(transaction);
// Let the listener see it if it just got created.
// otherwise, we have already processed the tx so
// we dont want the listener to see it.
transaction.setPassToListener();
try {
this.sipStack.addTransaction(transaction);
} catch (Exception ex) {
}
}
sipStack.putDialog(subscriptionDialog);
if (pendingSubscribeClientTx != null) {
subscriptionDialog
.addTransaction(pendingSubscribeClientTx);
pendingSubscribeClientTx.setDialog(subscriptionDialog,
dialogId);
}
}
if (transaction != null
&& ((SIPServerTransaction) transaction)
.isTransactionMapped()) {
// Shadow transaction has been created and the stack
// knows
// about it.
sipEvent = new RequestEvent((SipProvider) sipProvider,
(ServerTransaction) transaction,
subscriptionDialog, (Request) sipRequest);
} else {
/*
* Shadow transaction has been created but the stack does
* not know about it.
*/
sipEvent = new RequestEvent((SipProvider) sipProvider,
null, subscriptionDialog, (Request) sipRequest);
}
} else {
if (sipStack.isLoggingEnabled(LogLevels.TRACE_DEBUG)) {
sipStack.getStackLogger().logDebug(
"could not find subscribe tx");
}
// Got a notify out of the blue - just pass it up
// for stateless handling by the application.
sipEvent = new RequestEvent(sipProvider, null, null,
(Request) sipRequest);
}
} else {
// For a dialog creating event - set the transaction to null.
// The listener can create the dialog if needed.
if (transaction != null
&& (((SIPServerTransaction) transaction)
.isTransactionMapped())) {
sipEvent = new RequestEvent(sipProvider,
(ServerTransaction) transaction, dialog,
(Request) sipRequest);
} else {
sipEvent = new RequestEvent(sipProvider, null, dialog,
(Request) sipRequest);
}
}
sipProvider.handleEvent(sipEvent, transaction);